authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-06 18:20:02-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-06 18:20:02-05:00
log7c91a055c120f9fdad122aad294a40a37510a6a6
tree60fd7fedf3b6553273f781eeb89c63f3068dec19
parent04612d25d7d33e8c3f08301d668ab94fe7479c84
parent62c25af8021fc399c9a8c667dd986a458b40a7dd

Merge branch 'master' into self-hosted


13 files changed, 249 insertions(+), 58 deletions(-)

src/all_types.hpp+3-2
......@@ -1270,6 +1270,7 @@ enum BuiltinFnId {
12701270 BuiltinFnIdFieldParentPtr,
12711271 BuiltinFnIdOffsetOf,
12721272 BuiltinFnIdInlineCall,
1273 BuiltinFnIdNoInlineCall,
12731274 BuiltinFnIdTypeId,
12741275 BuiltinFnIdShlExact,
12751276 BuiltinFnIdShrExact,
......@@ -1439,7 +1440,7 @@ struct CodeGen {
14391440
14401441 struct {
14411442 TypeTableEntry *entry_bool;
1442 TypeTableEntry *entry_int[2][11]; // [signed,unsigned][2,3,4,5,6,7,8,16,32,64,128]
1443 TypeTableEntry *entry_int[2][12]; // [signed,unsigned][2,3,4,5,6,7,8,16,29,32,64,128]
14431444 TypeTableEntry *entry_c_int[CIntTypeCount];
14441445 TypeTableEntry *entry_c_longdouble;
14451446 TypeTableEntry *entry_c_void;
......@@ -2102,7 +2103,7 @@ struct IrInstructionCall {
21022103 IrInstruction **args;
21032104 bool is_comptime;
21042105 LLVMValueRef tmp_ptr;
2105 bool is_inline;
2106 FnInline fn_inline;
21062107};
21072108
21082109struct IrInstructionConst {
src/analyze.cpp+5-3
......@@ -3818,12 +3818,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b
38183818 index = 6;
38193819 } else if (size_in_bits == 16) {
38203820 index = 7;
3821 } else if (size_in_bits == 32) {
3821 } else if (size_in_bits == 29) {
38223822 index = 8;
3823 } else if (size_in_bits == 64) {
3823 } else if (size_in_bits == 32) {
38243824 index = 9;
3825 } else if (size_in_bits == 128) {
3825 } else if (size_in_bits == 64) {
38263826 index = 10;
3827 } else if (size_in_bits == 128) {
3828 index = 11;
38273829 } else {
38283830 return nullptr;
38293831 }
src/codegen.cpp+17-5
......@@ -839,7 +839,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
839839 assert(g->panic_fn != nullptr);
840840 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
841841 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
842 ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, false, "");
842 ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");
843843 LLVMBuildUnreachable(g->builder);
844844}
845845
......@@ -988,7 +988,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
988988static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
989989 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
990990 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
991 false, "");
991 ZigLLVM_FnInlineAuto, "");
992992 LLVMBuildUnreachable(g->builder);
993993}
994994
......@@ -2316,12 +2316,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
23162316 }
23172317 }
23182318
2319 bool want_always_inline = (instruction->fn_entry != nullptr &&
2320 instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_inline;
2319 ZigLLVM_FnInline fn_inline;
2320 switch (instruction->fn_inline) {
2321 case FnInlineAuto:
2322 fn_inline = ZigLLVM_FnInlineAuto;
2323 break;
2324 case FnInlineAlways:
2325 fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways;
2326 break;
2327 case FnInlineNever:
2328 fn_inline = ZigLLVM_FnInlineNever;
2329 break;
2330 }
23212331
23222332 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
23232333 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
2324 gen_param_values, (unsigned)gen_param_index, llvm_cc, want_always_inline, "");
2334 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
23252335
23262336 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
23272337 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
......@@ -4634,6 +4644,7 @@ static const uint8_t int_sizes_in_bits[] = {
46344644 7,
46354645 8,
46364646 16,
4647 29,
46374648 32,
46384649 64,
46394650 128,
......@@ -4971,6 +4982,7 @@ static void define_builtin_fns(CodeGen *g) {
49714982 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
49724983 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
49734984 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
4985 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
49744986 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
49754987 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
49764988 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
src/ir.cpp+15-13
......@@ -928,13 +928,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
928928
929929static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
930930 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
931 bool is_comptime, bool is_inline)
931 bool is_comptime, FnInline fn_inline)
932932{
933933 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
934934 call_instruction->fn_entry = fn_entry;
935935 call_instruction->fn_ref = fn_ref;
936936 call_instruction->is_comptime = is_comptime;
937 call_instruction->is_inline = is_inline;
937 call_instruction->fn_inline = fn_inline;
938938 call_instruction->args = args;
939939 call_instruction->arg_count = arg_count;
940940
......@@ -948,10 +948,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
948948
949949static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
950950 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
951 bool is_comptime, bool is_inline)
951 bool is_comptime, FnInline fn_inline)
952952{
953953 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
954 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, is_inline);
954 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline);
955955 ir_link_new_instruction(new_instruction, old_instruction);
956956 return new_instruction;
957957}
......@@ -4672,6 +4672,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46724672 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
46734673 }
46744674 case BuiltinFnIdInlineCall:
4675 case BuiltinFnIdNoInlineCall:
46754676 {
46764677 if (node->data.fn_call_expr.params.length == 0) {
46774678 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
......@@ -4692,8 +4693,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46924693 if (args[i] == irb->codegen->invalid_instruction)
46934694 return args[i];
46944695 }
4696 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
46954697
4696 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, true);
4698 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline);
46974699 }
46984700 case BuiltinFnIdTypeId:
46994701 {
......@@ -4804,7 +4806,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
48044806 return args[i];
48054807 }
48064808
4807 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, false);
4809 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);
48084810}
48094811
48104812static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -10617,7 +10619,7 @@ no_mem_slot:
1061710619
1061810620static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
1061910621 FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
10620 IrInstruction *first_arg_ptr, bool comptime_fn_call, bool inline_fn_call)
10622 IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
1062110623{
1062210624 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
1062310625 size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;
......@@ -10876,7 +10878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1087610878
1087710879 if (type_requires_comptime(return_type)) {
1087810880 // Throw out our work and call the function as if it were comptime.
10879 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, false);
10881 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
1088010882 }
1088110883 }
1088210884
......@@ -10900,7 +10902,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1090010902
1090110903 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
1090210904 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
10903 impl_fn, nullptr, impl_param_count, casted_args, false, inline_fn_call);
10905 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline);
1090410906
1090510907 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1090610908 ir_add_alloca(ira, new_call_instruction, return_type);
......@@ -10959,7 +10961,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1095910961 return ira->codegen->builtin_types.entry_invalid;
1096010962
1096110963 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
10962 fn_entry, fn_ref, call_param_count, casted_args, false, inline_fn_call);
10964 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline);
1096310965
1096410966 ir_add_alloca(ira, new_call_instruction, return_type);
1096510967 return ir_finish_anal(ira, return_type);
......@@ -10998,13 +11000,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1099811000 } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1099911001 FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
1100011002 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
11001 fn_ref, nullptr, is_comptime, call_instruction->is_inline);
11003 fn_ref, nullptr, is_comptime, call_instruction->fn_inline);
1100211004 } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
1100311005 assert(fn_ref->value.special == ConstValSpecialStatic);
1100411006 FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
1100511007 IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
1100611008 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
11007 nullptr, first_arg_ptr, is_comptime, call_instruction->is_inline);
11009 nullptr, first_arg_ptr, is_comptime, call_instruction->fn_inline);
1100811010 } else {
1100911011 ir_add_error_node(ira, fn_ref->source_node,
1101011012 buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
......@@ -11014,7 +11016,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1101411016
1101511017 if (fn_ref->value.type->id == TypeTableEntryIdFn) {
1101611018 return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type,
11017 fn_ref, nullptr, false, false);
11019 fn_ref, nullptr, false, FnInlineAuto);
1101811020 } else {
1101911021 ir_add_error_node(ira, fn_ref->source_node,
1102011022 buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
src/zig_llvm.cpp+10-3
......@@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
175175
176176
177177LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
178 unsigned NumArgs, unsigned CC, bool always_inline, const char *Name)
178 unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name)
179179{
180180 CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
181181 call_inst->setCallingConv(CC);
182 if (always_inline) {
183 call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
182 switch (fn_inline) {
183 case ZigLLVM_FnInlineAuto:
184 break;
185 case ZigLLVM_FnInlineAlways:
186 call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);
187 break;
188 case ZigLLVM_FnInlineNever:
189 call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline);
190 break;
184191 }
185192 return wrap(unwrap(B)->Insert(call_inst));
186193}
src/zig_llvm.hpp+6-1
......@@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType {
4545bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
4646 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
4747
48enum ZigLLVM_FnInline {
49 ZigLLVM_FnInlineAuto,
50 ZigLLVM_FnInlineAlways,
51 ZigLLVM_FnInlineNever,
52};
4853LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
49 unsigned NumArgs, unsigned CC, bool always_inline, const char *Name);
54 unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name);
5055
5156LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
5257 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
std/debug.zig+2-2
......@@ -977,7 +977,7 @@ var some_mem_index: usize = 0;
977977
978978error OutOfMemory;
979979
980fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {
980fn globalAlloc(self: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
981981 const addr = @ptrToInt(&some_mem[some_mem_index]);
982982 const rem = @rem(addr, alignment);
983983 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
......@@ -991,7 +991,7 @@ fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {
991991 return result;
992992}
993993
994fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
994fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
995995 if (new_size <= old_mem.len) {
996996 return old_mem[0..new_size];
997997 } else {
std/heap.zig+4-4
......@@ -16,7 +16,7 @@ pub var c_allocator = Allocator {
1616 .freeFn = cFree,
1717};
1818
19fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
19fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
2020 if (c.malloc(usize(n))) |buf| {
2121 @ptrCast(&u8, buf)[0..n]
2222 } else {
......@@ -24,7 +24,7 @@ fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
2424 }
2525}
2626
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
2828 if (new_size <= old_mem.len) {
2929 old_mem[0..new_size]
3030 } else {
......@@ -106,7 +106,7 @@ pub const IncrementingAllocator = struct {
106106 return self.bytes.len - self.end_index;
107107 }
108108
109 fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {
109 fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 {
110110 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
111111 const addr = @ptrToInt(&self.bytes[self.end_index]);
112112 const rem = @rem(addr, alignment);
......@@ -121,7 +121,7 @@ pub const IncrementingAllocator = struct {
121121 return result;
122122 }
123123
124 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
124 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
125125 if (new_size <= old_mem.len) {
126126 return old_mem[0..new_size];
127127 } else {
std/mem.zig+34-20
......@@ -7,22 +7,24 @@ pub const Cmp = math.Cmp;
77
88pub const Allocator = struct {
99 /// Allocate byte_count bytes and return them in a slice, with the
10 /// slicer's pointer aligned at least to alignment bytes.
11 allocFn: fn (self: &Allocator, byte_count: usize, alignment: usize) -> %[]u8,
10 /// slice's pointer aligned at least to alignment bytes.
11 allocFn: fn (self: &Allocator, byte_count: usize, alignment: u29) -> %[]u8,
1212
13 /// Guaranteed: `old_mem.len` is the same as what was returned from allocFn or reallocFn.
14 /// Guaranteed: alignment >= alignment of old_mem.ptr
13 /// If `new_byte_count > old_mem.len`:
14 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
15 /// * alignment >= alignment of old_mem.ptr
1516 ///
16 /// If `new_byte_count` is less than or equal to `old_mem.len` this function must
17 /// return successfully.
18 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: usize) -> %[]u8,
17 /// If `new_byte_count <= old_mem.len`:
18 /// * this function must return successfully.
19 /// * alignment <= alignment of old_mem.ptr
20 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) -> %[]u8,
1921
2022 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
2123 freeFn: fn (self: &Allocator, old_mem: []u8),
2224
2325 fn create(self: &Allocator, comptime T: type) -> %&T {
2426 const slice = %return self.alloc(T, 1);
25 &slice[0]
27 return &slice[0];
2628 }
2729
2830 fn destroy(self: &Allocator, ptr: var) {
......@@ -30,28 +32,43 @@ pub const Allocator = struct {
3032 }
3133
3234 fn alloc(self: &Allocator, comptime T: type, n: usize) -> %[]T {
35 return self.alignedAlloc(T, @alignOf(T), n);
36 }
37
38 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
39 n: usize) -> %[]align(alignment) T
40 {
3341 const byte_count = %return math.mul(usize, @sizeOf(T), n);
34 const byte_slice = %return self.allocFn(self, byte_count, @alignOf(T));
35 ([]T)(@alignCast(@alignOf(T), byte_slice))
42 const byte_slice = %return self.allocFn(self, byte_count, alignment);
43 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
3644 }
3745
3846 fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> %[]T {
47 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
48 }
49
50 fn alignedRealloc(self: &Allocator, comptime T: type, comptime alignment: u29,
51 old_mem: []align(alignment) T, n: usize) -> %[]align(alignment) T
52 {
3953 if (old_mem.len == 0) {
4054 return self.alloc(T, n);
4155 }
4256
43 // Assert that old_mem.ptr is properly aligned.
44 const aligned_old_mem = @alignCast(@alignOf(T), old_mem);
45
4657 const byte_count = %return math.mul(usize, @sizeOf(T), n);
47 const byte_slice = %return self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T));
48 return ([]T)(@alignCast(@alignOf(T), byte_slice));
58 const byte_slice = %return self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
59 return ([]T)(@alignCast(alignment, byte_slice));
4960 }
5061
5162 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
5263 /// Unlike `realloc`, this function cannot fail.
5364 /// Shrinking to 0 is the same as calling `free`.
5465 fn shrink(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> []T {
66 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
67 }
68
69 fn alignedShrink(self: &Allocator, comptime T: type, comptime alignment: u29,
70 old_mem: []align(alignment) T, n: usize) -> []align(alignment) T
71 {
5572 if (n == 0) {
5673 self.free(old_mem);
5774 return old_mem[0..0];
......@@ -59,15 +76,12 @@ pub const Allocator = struct {
5976
6077 assert(n <= old_mem.len);
6178
62 // Assert that old_mem.ptr is properly aligned.
63 const aligned_old_mem = @alignCast(@alignOf(T), old_mem);
64
6579 // Here we skip the overflow checking on the multiplication because
6680 // n <= old_mem.len and the multiplication didn't overflow for that operation.
6781 const byte_count = @sizeOf(T) * n;
6882
69 const byte_slice = %%self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T));
70 return ([]T)(@alignCast(@alignOf(T), byte_slice));
83 const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
84 return ([]T)(@alignCast(alignment, byte_slice));
7185 }
7286
7387 fn free(self: &Allocator, memory: var) {
std/os/index.zig+48
......@@ -1422,6 +1422,54 @@ pub fn args() -> ArgIterator {
14221422 return ArgIterator.init();
14231423}
14241424
1425/// Caller must call freeArgs on result.
1426pub fn argsAlloc(allocator: &mem.Allocator) -> %[]const []u8 {
1427 // TODO refactor to only make 1 allocation.
1428 var it = args();
1429 var contents = %return Buffer.initSize(allocator, 0);
1430 defer contents.deinit();
1431
1432 var slice_list = ArrayList(usize).init(allocator);
1433 defer slice_list.deinit();
1434
1435 while (it.next(allocator)) |arg_or_err| {
1436 const arg = %return arg_or_err;
1437 defer allocator.free(arg);
1438 %return contents.append(arg);
1439 %return slice_list.append(arg.len);
1440 }
1441
1442 const contents_slice = contents.toSliceConst();
1443 const slice_sizes = slice_list.toSliceConst();
1444 const slice_list_bytes = %return math.mul(usize, @sizeOf([]u8), slice_sizes.len);
1445 const total_bytes = %return math.add(usize, slice_list_bytes, contents_slice.len);
1446 const buf = %return allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
1447 %defer allocator.free(buf);
1448
1449 const result_slice_list = ([][]u8)(buf[0..slice_list_bytes]);
1450 const result_contents = buf[slice_list_bytes..];
1451 mem.copy(u8, result_contents, contents_slice);
1452
1453 var contents_index: usize = 0;
1454 for (slice_sizes) |len, i| {
1455 const new_index = contents_index + len;
1456 result_slice_list[i] = result_contents[contents_index..new_index];
1457 contents_index = new_index;
1458 }
1459
1460 return result_slice_list;
1461}
1462
1463pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) {
1464 var total_bytes: usize = 0;
1465 for (args_alloc) |arg| {
1466 total_bytes += @sizeOf([]u8) + arg.len;
1467 }
1468 const unaligned_allocated_buf = @ptrCast(&u8, args_alloc.ptr)[0..total_bytes];
1469 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
1470 return allocator.free(aligned_allocated_buf);
1471}
1472
14251473test "windows arg parsing" {
14261474 testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"});
14271475 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"});
std/special/bootstrap.zig+3-1
......@@ -28,7 +28,9 @@ export nakedcc fn _start() -> noreturn {
2828 },
2929 else => @compileError("unsupported arch"),
3030 }
31 posixCallMainAndExit()
31 // If LLVM inlines stack variables into _start, they will overwrite
32 // the command line argument data.
33 @noInlineCall(posixCallMainAndExit);
3234}
3335
3436export fn WinMainCRTStartup() -> noreturn {
test/compare_output.zig+82
......@@ -444,4 +444,86 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
444444
445445 tc
446446 });
447
448 cases.addCase({
449 var tc = cases.create("parsing args",
450 \\const std = @import("std");
451 \\const io = std.io;
452 \\const os = std.os;
453 \\const allocator = std.debug.global_allocator;
454 \\
455 \\pub fn main() -> %void {
456 \\ var args_it = os.args();
457 \\ var stdout_file = %return io.getStdOut();
458 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
459 \\ const stdout = &stdout_adapter.stream;
460 \\ var index: usize = 0;
461 \\ _ = args_it.skip();
462 \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
463 \\ const arg = %return arg_or_err;
464 \\ %return stdout.print("{}: {}\n", index, arg);
465 \\ }
466 \\}
467 ,
468 \\0: first arg
469 \\1: 'a' 'b' \
470 \\2: bare
471 \\3: ba""re
472 \\4: "
473 \\5: last arg
474 \\
475 );
476
477 tc.setCommandLineArgs([][]const u8 {
478 "first arg",
479 "'a' 'b' \\",
480 "bare",
481 "ba\"\"re",
482 "\"",
483 "last arg",
484 });
485
486 tc
487 });
488
489 cases.addCase({
490 var tc = cases.create("parsing args new API",
491 \\const std = @import("std");
492 \\const io = std.io;
493 \\const os = std.os;
494 \\const allocator = std.debug.global_allocator;
495 \\
496 \\pub fn main() -> %void {
497 \\ var args_it = os.args();
498 \\ var stdout_file = %return io.getStdOut();
499 \\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
500 \\ const stdout = &stdout_adapter.stream;
501 \\ var index: usize = 0;
502 \\ _ = args_it.skip();
503 \\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
504 \\ const arg = %return arg_or_err;
505 \\ %return stdout.print("{}: {}\n", index, arg);
506 \\ }
507 \\}
508 ,
509 \\0: first arg
510 \\1: 'a' 'b' \
511 \\2: bare
512 \\3: ba""re
513 \\4: "
514 \\5: last arg
515 \\
516 );
517
518 tc.setCommandLineArgs([][]const u8 {
519 "first arg",
520 "'a' 'b' \\",
521 "bare",
522 "ba\"\"re",
523 "\"",
524 "last arg",
525 });
526
527 tc
528 });
447529}
test/tests.zig+20-4
......@@ -189,6 +189,7 @@ pub const CompareOutputContext = struct {
189189 expected_output: []const u8,
190190 link_libc: bool,
191191 special: Special,
192 cli_args: []const []const u8,
192193
193194 const SourceFile = struct {
194195 filename: []const u8,
......@@ -201,6 +202,10 @@ pub const CompareOutputContext = struct {
201202 .source = source,
202203 });
203204 }
205
206 pub fn setCommandLineArgs(self: &TestCase, args: []const []const u8) {
207 self.cli_args = args;
208 }
204209 };
205210
206211 const RunCompareOutputStep = struct {
......@@ -210,9 +215,11 @@ pub const CompareOutputContext = struct {
210215 name: []const u8,
211216 expected_output: []const u8,
212217 test_index: usize,
218 cli_args: []const []const u8,
213219
214220 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
215 name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep
221 name: []const u8, expected_output: []const u8,
222 cli_args: []const []const u8) -> &RunCompareOutputStep
216223 {
217224 const allocator = context.b.allocator;
218225 const ptr = %%allocator.create(RunCompareOutputStep);
......@@ -223,6 +230,7 @@ pub const CompareOutputContext = struct {
223230 .expected_output = expected_output,
224231 .test_index = context.test_index,
225232 .step = build.Step.init("RunCompareOutput", allocator, make),
233 .cli_args = cli_args,
226234 };
227235 context.test_index += 1;
228236 return ptr;
......@@ -233,10 +241,17 @@ pub const CompareOutputContext = struct {
233241 const b = self.context.b;
234242
235243 const full_exe_path = b.pathFromRoot(self.exe_path);
244 var args = ArrayList([]const u8).init(b.allocator);
245 defer args.deinit();
246
247 %%args.append(full_exe_path);
248 for (self.cli_args) |arg| {
249 %%args.append(arg);
250 }
236251
237252 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
238253
239 const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);
254 const child = %%os.ChildProcess.init(args.toSliceConst(), b.allocator);
240255 defer child.deinit();
241256
242257 child.stdin_behavior = StdIo.Ignore;
......@@ -364,6 +379,7 @@ pub const CompareOutputContext = struct {
364379 .expected_output = expected_output,
365380 .link_libc = false,
366381 .special = special,
382 .cli_args = []const []const u8{},
367383 };
368384 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";
369385 tc.addSourceFile(root_src_name, source);
......@@ -420,7 +436,7 @@ pub const CompareOutputContext = struct {
420436 }
421437
422438 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,
423 case.expected_output);
439 case.expected_output, case.cli_args);
424440 run_and_cmp_output.step.dependOn(&exe.step);
425441
426442 self.step.dependOn(&run_and_cmp_output.step);
......@@ -447,7 +463,7 @@ pub const CompareOutputContext = struct {
447463 }
448464
449465 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(),
450 annotated_case_name, case.expected_output);
466 annotated_case_name, case.expected_output, case.cli_args);
451467 run_and_cmp_output.step.dependOn(&exe.step);
452468
453469 self.step.dependOn(&run_and_cmp_output.step);