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 {...@@ -1270,6 +1270,7 @@ enum BuiltinFnId {
1270 BuiltinFnIdFieldParentPtr,1270 BuiltinFnIdFieldParentPtr,
1271 BuiltinFnIdOffsetOf,1271 BuiltinFnIdOffsetOf,
1272 BuiltinFnIdInlineCall,1272 BuiltinFnIdInlineCall,
1273 BuiltinFnIdNoInlineCall,
1273 BuiltinFnIdTypeId,1274 BuiltinFnIdTypeId,
1274 BuiltinFnIdShlExact,1275 BuiltinFnIdShlExact,
1275 BuiltinFnIdShrExact,1276 BuiltinFnIdShrExact,
...@@ -1439,7 +1440,7 @@ struct CodeGen {...@@ -1439,7 +1440,7 @@ struct CodeGen {
14391440
1440 struct {1441 struct {
1441 TypeTableEntry *entry_bool;1442 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]
1443 TypeTableEntry *entry_c_int[CIntTypeCount];1444 TypeTableEntry *entry_c_int[CIntTypeCount];
1444 TypeTableEntry *entry_c_longdouble;1445 TypeTableEntry *entry_c_longdouble;
1445 TypeTableEntry *entry_c_void;1446 TypeTableEntry *entry_c_void;
...@@ -2102,7 +2103,7 @@ struct IrInstructionCall {...@@ -2102,7 +2103,7 @@ struct IrInstructionCall {
2102 IrInstruction **args;2103 IrInstruction **args;
2103 bool is_comptime;2104 bool is_comptime;
2104 LLVMValueRef tmp_ptr;2105 LLVMValueRef tmp_ptr;
2105 bool is_inline;2106 FnInline fn_inline;
2106};2107};
21072108
2108struct IrInstructionConst {2109struct 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...@@ -3818,12 +3818,14 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b
3818 index = 6;3818 index = 6;
3819 } else if (size_in_bits == 16) {3819 } else if (size_in_bits == 16) {
3820 index = 7;3820 index = 7;
3821 } else if (size_in_bits == 32) {3821 } else if (size_in_bits == 29) {
3822 index = 8;3822 index = 8;
3823 } else if (size_in_bits == 64) {3823 } else if (size_in_bits == 32) {
3824 index = 9;3824 index = 9;
3825 } else if (size_in_bits == 128) {3825 } else if (size_in_bits == 64) {
3826 index = 10;3826 index = 10;
3827 } else if (size_in_bits == 128) {
3828 index = 11;
3827 } else {3829 } else {
3828 return nullptr;3830 return nullptr;
3829 }3831 }
src/codegen.cpp+17-5
...@@ -839,7 +839,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {...@@ -839,7 +839,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
839 assert(g->panic_fn != nullptr);839 assert(g->panic_fn != nullptr);
840 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);840 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
841 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);841 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, "");
843 LLVMBuildUnreachable(g->builder);843 LLVMBuildUnreachable(g->builder);
844}844}
845845
...@@ -988,7 +988,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -988,7 +988,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
988static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {988static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
989 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);989 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
990 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),990 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
991 false, "");991 ZigLLVM_FnInlineAuto, "");
992 LLVMBuildUnreachable(g->builder);992 LLVMBuildUnreachable(g->builder);
993}993}
994994
...@@ -2316,12 +2316,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2316,12 +2316,22 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2316 }2316 }
2317 }2317 }
23182318
2319 bool want_always_inline = (instruction->fn_entry != nullptr &&2319 ZigLLVM_FnInline fn_inline;
2320 instruction->fn_entry->fn_inline == FnInlineAlways) || instruction->is_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
2322 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);2332 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
2323 LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,2333 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
2326 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {2336 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
2327 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];2337 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
...@@ -4634,6 +4644,7 @@ static const uint8_t int_sizes_in_bits[] = {...@@ -4634,6 +4644,7 @@ static const uint8_t int_sizes_in_bits[] = {
4634 7,4644 7,
4635 8,4645 8,
4636 16,4646 16,
4647 29,
4637 32,4648 32,
4638 64,4649 64,
4639 128,4650 128,
...@@ -4971,6 +4982,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4971,6 +4982,7 @@ static void define_builtin_fns(CodeGen *g) {
4971 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);4982 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
4972 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);4983 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
4973 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);4984 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
4985 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
4974 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);4986 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
4975 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);4987 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
4976 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);4988 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...@@ -928,13 +928,13 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
928928
929static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,929static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
930 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,930 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)
932{932{
933 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);933 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
934 call_instruction->fn_entry = fn_entry;934 call_instruction->fn_entry = fn_entry;
935 call_instruction->fn_ref = fn_ref;935 call_instruction->fn_ref = fn_ref;
936 call_instruction->is_comptime = is_comptime;936 call_instruction->is_comptime = is_comptime;
937 call_instruction->is_inline = is_inline;937 call_instruction->fn_inline = fn_inline;
938 call_instruction->args = args;938 call_instruction->args = args;
939 call_instruction->arg_count = arg_count;939 call_instruction->arg_count = arg_count;
940940
...@@ -948,10 +948,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -948,10 +948,10 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
948948
949static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,949static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
950 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,950 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)
952{952{
953 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,953 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);
955 ir_link_new_instruction(new_instruction, old_instruction);955 ir_link_new_instruction(new_instruction, old_instruction);
956 return new_instruction;956 return new_instruction;
957}957}
...@@ -4672,6 +4672,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4672,6 +4672,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4672 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);4672 return ir_build_offset_of(irb, scope, node, arg0_value, arg1_value);
4673 }4673 }
4674 case BuiltinFnIdInlineCall:4674 case BuiltinFnIdInlineCall:
4675 case BuiltinFnIdNoInlineCall:
4675 {4676 {
4676 if (node->data.fn_call_expr.params.length == 0) {4677 if (node->data.fn_call_expr.params.length == 0) {
4677 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));4678 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...@@ -4692,8 +4693,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4692 if (args[i] == irb->codegen->invalid_instruction)4693 if (args[i] == irb->codegen->invalid_instruction)
4693 return args[i];4694 return args[i];
4694 }4695 }
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);
4697 }4699 }
4698 case BuiltinFnIdTypeId:4700 case BuiltinFnIdTypeId:
4699 {4701 {
...@@ -4804,7 +4806,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node...@@ -4804,7 +4806,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
4804 return args[i];4806 return args[i];
4805 }4807 }
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);
4808}4810}
48094811
4810static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {4812static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -10617,7 +10619,7 @@ no_mem_slot:...@@ -10617,7 +10619,7 @@ no_mem_slot:
1061710619
10618static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,10620static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
10619 FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,10621 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)
10621{10623{
10622 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;10624 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
10623 size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;10625 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...@@ -10876,7 +10878,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1087610878
10877 if (type_requires_comptime(return_type)) {10879 if (type_requires_comptime(return_type)) {
10878 // Throw out our work and call the function as if it were comptime.10880 // 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);
10880 }10882 }
10881 }10883 }
1088210884
...@@ -10900,7 +10902,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10900,7 +10902,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1090010902
10901 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;10903 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
10902 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,10904 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
10905 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;10907 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
10906 ir_add_alloca(ira, new_call_instruction, return_type);10908 ir_add_alloca(ira, new_call_instruction, return_type);
...@@ -10959,7 +10961,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10959,7 +10961,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10959 return ira->codegen->builtin_types.entry_invalid;10961 return ira->codegen->builtin_types.entry_invalid;
1096010962
10961 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,10963 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
10964 ir_add_alloca(ira, new_call_instruction, return_type);10966 ir_add_alloca(ira, new_call_instruction, return_type);
10965 return ir_finish_anal(ira, return_type);10967 return ir_finish_anal(ira, return_type);
...@@ -10998,13 +11000,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction...@@ -10998,13 +11000,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
10998 } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {11000 } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
10999 FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);11001 FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
11000 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,11002 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);
11002 } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {11004 } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
11003 assert(fn_ref->value.special == ConstValSpecialStatic);11005 assert(fn_ref->value.special == ConstValSpecialStatic);
11004 FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;11006 FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
11005 IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;11007 IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
11006 return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,11008 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);
11008 } else {11010 } else {
11009 ir_add_error_node(ira, fn_ref->source_node,11011 ir_add_error_node(ira, fn_ref->source_node,
11010 buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));11012 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...@@ -11014,7 +11016,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
1101411016
11015 if (fn_ref->value.type->id == TypeTableEntryIdFn) {11017 if (fn_ref->value.type->id == TypeTableEntryIdFn) {
11016 return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type,11018 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);
11018 } else {11020 } else {
11019 ir_add_error_node(ira, fn_ref->source_node,11021 ir_add_error_node(ira, fn_ref->source_node,
11020 buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));11022 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...@@ -175,12 +175,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
175175
176176
177LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,177LLVMValueRef 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)
179{179{
180 CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);180 CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name);
181 call_inst->setCallingConv(CC);181 call_inst->setCallingConv(CC);
182 if (always_inline) {182 switch (fn_inline) {
183 call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline);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;
184 }191 }
185 return wrap(unwrap(B)->Insert(call_inst));192 return wrap(unwrap(B)->Insert(call_inst));
186}193}
src/zig_llvm.hpp+6-1
...@@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType {...@@ -45,8 +45,13 @@ enum ZigLLVM_EmitOutputType {
45bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,45bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
46 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);46 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};
48LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,53LLVMValueRef 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
51LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,56LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
52 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,57 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
std/debug.zig+2-2
...@@ -977,7 +977,7 @@ var some_mem_index: usize = 0;...@@ -977,7 +977,7 @@ var some_mem_index: usize = 0;
977977
978error OutOfMemory;978error OutOfMemory;
979979
980fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {980fn globalAlloc(self: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
981 const addr = @ptrToInt(&some_mem[some_mem_index]);981 const addr = @ptrToInt(&some_mem[some_mem_index]);
982 const rem = @rem(addr, alignment);982 const rem = @rem(addr, alignment);
983 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);983 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 {...@@ -991,7 +991,7 @@ fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 {
991 return result;991 return result;
992}992}
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 {
995 if (new_size <= old_mem.len) {995 if (new_size <= old_mem.len) {
996 return old_mem[0..new_size];996 return old_mem[0..new_size];
997 } else {997 } else {
std/heap.zig+4-4
...@@ -16,7 +16,7 @@ pub var c_allocator = Allocator {...@@ -16,7 +16,7 @@ pub var c_allocator = Allocator {
16 .freeFn = cFree,16 .freeFn = cFree,
17};17};
1818
19fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {19fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 {
20 if (c.malloc(usize(n))) |buf| {20 if (c.malloc(usize(n))) |buf| {
21 @ptrCast(&u8, buf)[0..n]21 @ptrCast(&u8, buf)[0..n]
22 } else {22 } else {
...@@ -24,7 +24,7 @@ fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {...@@ -24,7 +24,7 @@ fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
24 }24 }
25}25}
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 {
28 if (new_size <= old_mem.len) {28 if (new_size <= old_mem.len) {
29 old_mem[0..new_size]29 old_mem[0..new_size]
30 } else {30 } else {
...@@ -106,7 +106,7 @@ pub const IncrementingAllocator = struct {...@@ -106,7 +106,7 @@ pub const IncrementingAllocator = struct {
106 return self.bytes.len - self.end_index;106 return self.bytes.len - self.end_index;
107 }107 }
108108
109 fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {109 fn alloc(allocator: &Allocator, n: usize, alignment: u29) -> %[]u8 {
110 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);110 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
111 const addr = @ptrToInt(&self.bytes[self.end_index]);111 const addr = @ptrToInt(&self.bytes[self.end_index]);
112 const rem = @rem(addr, alignment);112 const rem = @rem(addr, alignment);
...@@ -121,7 +121,7 @@ pub const IncrementingAllocator = struct {...@@ -121,7 +121,7 @@ pub const IncrementingAllocator = struct {
121 return result;121 return result;
122 }122 }
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 {
125 if (new_size <= old_mem.len) {125 if (new_size <= old_mem.len) {
126 return old_mem[0..new_size];126 return old_mem[0..new_size];
127 } else {127 } else {
std/mem.zig+34-20
...@@ -7,22 +7,24 @@ pub const Cmp = math.Cmp;...@@ -7,22 +7,24 @@ pub const Cmp = math.Cmp;
77
8pub const Allocator = struct {8pub const Allocator = struct {
9 /// Allocate byte_count bytes and return them in a slice, with the9 /// Allocate byte_count bytes and return them in a slice, with the
10 /// slicer's pointer aligned at least to alignment bytes.10 /// slice's pointer aligned at least to alignment bytes.
11 allocFn: fn (self: &Allocator, byte_count: usize, alignment: usize) -> %[]u8,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.13 /// If `new_byte_count > old_mem.len`:
14 /// Guaranteed: alignment >= alignment of old_mem.ptr14 /// * `old_mem.len` is the same as what was returned from allocFn or reallocFn.
15 /// * alignment >= alignment of old_mem.ptr
15 ///16 ///
16 /// If `new_byte_count` is less than or equal to `old_mem.len` this function must17 /// If `new_byte_count <= old_mem.len`:
17 /// return successfully.18 /// * this function must return successfully.
18 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: usize) -> %[]u8,19 /// * alignment <= alignment of old_mem.ptr
20 reallocFn: fn (self: &Allocator, old_mem: []u8, new_byte_count: usize, alignment: u29) -> %[]u8,
1921
20 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`22 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
21 freeFn: fn (self: &Allocator, old_mem: []u8),23 freeFn: fn (self: &Allocator, old_mem: []u8),
2224
23 fn create(self: &Allocator, comptime T: type) -> %&T {25 fn create(self: &Allocator, comptime T: type) -> %&T {
24 const slice = %return self.alloc(T, 1);26 const slice = %return self.alloc(T, 1);
25 &slice[0]27 return &slice[0];
26 }28 }
2729
28 fn destroy(self: &Allocator, ptr: var) {30 fn destroy(self: &Allocator, ptr: var) {
...@@ -30,28 +32,43 @@ pub const Allocator = struct {...@@ -30,28 +32,43 @@ pub const Allocator = struct {
30 }32 }
3133
32 fn alloc(self: &Allocator, comptime T: type, n: usize) -> %[]T {34 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 {
33 const byte_count = %return math.mul(usize, @sizeOf(T), n);41 const byte_count = %return math.mul(usize, @sizeOf(T), n);
34 const byte_slice = %return self.allocFn(self, byte_count, @alignOf(T));42 const byte_slice = %return self.allocFn(self, byte_count, alignment);
35 ([]T)(@alignCast(@alignOf(T), byte_slice))43 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
36 }44 }
3745
38 fn realloc(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> %[]T {46 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 {
39 if (old_mem.len == 0) {53 if (old_mem.len == 0) {
40 return self.alloc(T, n);54 return self.alloc(T, n);
41 }55 }
4256
43 // Assert that old_mem.ptr is properly aligned.
44 const aligned_old_mem = @alignCast(@alignOf(T), old_mem);
45
46 const byte_count = %return math.mul(usize, @sizeOf(T), n);57 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));58 const byte_slice = %return self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
48 return ([]T)(@alignCast(@alignOf(T), byte_slice));59 return ([]T)(@alignCast(alignment, byte_slice));
49 }60 }
5061
51 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.62 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
52 /// Unlike `realloc`, this function cannot fail.63 /// Unlike `realloc`, this function cannot fail.
53 /// Shrinking to 0 is the same as calling `free`.64 /// Shrinking to 0 is the same as calling `free`.
54 fn shrink(self: &Allocator, comptime T: type, old_mem: []T, n: usize) -> []T {65 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 {
55 if (n == 0) {72 if (n == 0) {
56 self.free(old_mem);73 self.free(old_mem);
57 return old_mem[0..0];74 return old_mem[0..0];
...@@ -59,15 +76,12 @@ pub const Allocator = struct {...@@ -59,15 +76,12 @@ pub const Allocator = struct {
5976
60 assert(n <= old_mem.len);77 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
65 // Here we skip the overflow checking on the multiplication because79 // Here we skip the overflow checking on the multiplication because
66 // n <= old_mem.len and the multiplication didn't overflow for that operation.80 // n <= old_mem.len and the multiplication didn't overflow for that operation.
67 const byte_count = @sizeOf(T) * n;81 const byte_count = @sizeOf(T) * n;
6882
69 const byte_slice = %%self.reallocFn(self, ([]u8)(aligned_old_mem), byte_count, @alignOf(T));83 const byte_slice = %%self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment);
70 return ([]T)(@alignCast(@alignOf(T), byte_slice));84 return ([]T)(@alignCast(alignment, byte_slice));
71 }85 }
7286
73 fn free(self: &Allocator, memory: var) {87 fn free(self: &Allocator, memory: var) {
std/os/index.zig+48
...@@ -1422,6 +1422,54 @@ pub fn args() -> ArgIterator {...@@ -1422,6 +1422,54 @@ pub fn args() -> ArgIterator {
1422 return ArgIterator.init();1422 return ArgIterator.init();
1423}1423}
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
1425test "windows arg parsing" {1473test "windows arg parsing" {
1426 testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"});1474 testWindowsCmdLine(c"a b\tc d", [][]const u8{"a", "b", "c", "d"});
1427 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{"abc", "d", "e"});1475 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 {...@@ -28,7 +28,9 @@ export nakedcc fn _start() -> noreturn {
28 },28 },
29 else => @compileError("unsupported arch"),29 else => @compileError("unsupported arch"),
30 }30 }
31 posixCallMainAndExit()31 // If LLVM inlines stack variables into _start, they will overwrite
32 // the command line argument data.
33 @noInlineCall(posixCallMainAndExit);
32}34}
3335
34export fn WinMainCRTStartup() -> noreturn {36export fn WinMainCRTStartup() -> noreturn {
test/compare_output.zig+82
...@@ -444,4 +444,86 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -444,4 +444,86 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
444444
445 tc445 tc
446 });446 });
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 });
447}529}
test/tests.zig+20-4
...@@ -189,6 +189,7 @@ pub const CompareOutputContext = struct {...@@ -189,6 +189,7 @@ pub const CompareOutputContext = struct {
189 expected_output: []const u8,189 expected_output: []const u8,
190 link_libc: bool,190 link_libc: bool,
191 special: Special,191 special: Special,
192 cli_args: []const []const u8,
192193
193 const SourceFile = struct {194 const SourceFile = struct {
194 filename: []const u8,195 filename: []const u8,
...@@ -201,6 +202,10 @@ pub const CompareOutputContext = struct {...@@ -201,6 +202,10 @@ pub const CompareOutputContext = struct {
201 .source = source,202 .source = source,
202 });203 });
203 }204 }
205
206 pub fn setCommandLineArgs(self: &TestCase, args: []const []const u8) {
207 self.cli_args = args;
208 }
204 };209 };
205210
206 const RunCompareOutputStep = struct {211 const RunCompareOutputStep = struct {
...@@ -210,9 +215,11 @@ pub const CompareOutputContext = struct {...@@ -210,9 +215,11 @@ pub const CompareOutputContext = struct {
210 name: []const u8,215 name: []const u8,
211 expected_output: []const u8,216 expected_output: []const u8,
212 test_index: usize,217 test_index: usize,
218 cli_args: []const []const u8,
213219
214 pub fn create(context: &CompareOutputContext, exe_path: []const u8,220 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
215 name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep221 name: []const u8, expected_output: []const u8,
222 cli_args: []const []const u8) -> &RunCompareOutputStep
216 {223 {
217 const allocator = context.b.allocator;224 const allocator = context.b.allocator;
218 const ptr = %%allocator.create(RunCompareOutputStep);225 const ptr = %%allocator.create(RunCompareOutputStep);
...@@ -223,6 +230,7 @@ pub const CompareOutputContext = struct {...@@ -223,6 +230,7 @@ pub const CompareOutputContext = struct {
223 .expected_output = expected_output,230 .expected_output = expected_output,
224 .test_index = context.test_index,231 .test_index = context.test_index,
225 .step = build.Step.init("RunCompareOutput", allocator, make),232 .step = build.Step.init("RunCompareOutput", allocator, make),
233 .cli_args = cli_args,
226 };234 };
227 context.test_index += 1;235 context.test_index += 1;
228 return ptr;236 return ptr;
...@@ -233,10 +241,17 @@ pub const CompareOutputContext = struct {...@@ -233,10 +241,17 @@ pub const CompareOutputContext = struct {
233 const b = self.context.b;241 const b = self.context.b;
234242
235 const full_exe_path = b.pathFromRoot(self.exe_path);243 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
237 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);252 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);
240 defer child.deinit();255 defer child.deinit();
241256
242 child.stdin_behavior = StdIo.Ignore;257 child.stdin_behavior = StdIo.Ignore;
...@@ -364,6 +379,7 @@ pub const CompareOutputContext = struct {...@@ -364,6 +379,7 @@ pub const CompareOutputContext = struct {
364 .expected_output = expected_output,379 .expected_output = expected_output,
365 .link_libc = false,380 .link_libc = false,
366 .special = special,381 .special = special,
382 .cli_args = []const []const u8{},
367 };383 };
368 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";384 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";
369 tc.addSourceFile(root_src_name, source);385 tc.addSourceFile(root_src_name, source);
...@@ -420,7 +436,7 @@ pub const CompareOutputContext = struct {...@@ -420,7 +436,7 @@ pub const CompareOutputContext = struct {
420 }436 }
421437
422 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,438 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(), annotated_case_name,
423 case.expected_output);439 case.expected_output, case.cli_args);
424 run_and_cmp_output.step.dependOn(&exe.step);440 run_and_cmp_output.step.dependOn(&exe.step);
425441
426 self.step.dependOn(&run_and_cmp_output.step);442 self.step.dependOn(&run_and_cmp_output.step);
...@@ -447,7 +463,7 @@ pub const CompareOutputContext = struct {...@@ -447,7 +463,7 @@ pub const CompareOutputContext = struct {
447 }463 }
448464
449 const run_and_cmp_output = RunCompareOutputStep.create(self, exe.getOutputPath(),465 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);
451 run_and_cmp_output.step.dependOn(&exe.step);467 run_and_cmp_output.step.dependOn(&exe.step);
452468
453 self.step.dependOn(&run_and_cmp_output.step);469 self.step.dependOn(&run_and_cmp_output.step);