| author | |
| committer | |
| log | 7c91a055c120f9fdad122aad294a40a37510a6a6 |
| tree | 60fd7fedf3b6553273f781eeb89c63f3068dec19 |
| parent | 04612d25d7d33e8c3f08301d668ab94fe7479c84 |
| parent | 62c25af8021fc399c9a8c667dd986a458b40a7dd |
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 { |
| 1439 | 1440 | ||
| 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 | }; |
| 2107 | 2108 | ||
| 2108 | struct IrInstructionConst { | 2109 | struct 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 | } |
| 845 | 845 | ||
| ... | @@ -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) { |
| 988 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | 988 | static 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 | } |
| 994 | 994 | ||
| ... | @@ -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 | } |
| 2318 | 2318 | ||
| 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 | } | ||
| 2321 | 2331 | ||
| 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, ""); |
| 2325 | 2335 | ||
| 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 |
| 928 | 928 | ||
| 929 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, | 929 | static 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; |
| 940 | 940 | ||
| ... | @@ -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 |
| 948 | 948 | ||
| 949 | static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, | 949 | static 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; | ||
| 4695 | 4697 | ||
| 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 | } |
| 4806 | 4808 | ||
| 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 | } |
| 4809 | 4811 | ||
| 4810 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 4812 | static 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: |
| 10617 | 10619 | ||
| 10618 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 10620 | static 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 |
| 10876 | 10878 | ||
| 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 | } |
| 10882 | 10884 | ||
| ... | @@ -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 |
| 10900 | 10902 | ||
| 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); |
| 10904 | 10906 | ||
| 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; |
| 10960 | 10962 | ||
| 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); |
| 10963 | 10965 | ||
| 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 |
| 11014 | 11016 | ||
| 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 |
| 175 | 175 | ||
| 176 | 176 | ||
| 177 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 177 | LLVMValueRef 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 { |
| 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 45 | bool 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); |
| 47 | 47 | ||
| 48 | enum ZigLLVM_FnInline { | ||
| 49 | ZigLLVM_FnInlineAuto, | ||
| 50 | ZigLLVM_FnInlineAlways, | ||
| 51 | ZigLLVM_FnInlineNever, | ||
| 52 | }; | ||
| 48 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | 53 | LLVMValueRef 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); |
| 50 | 55 | ||
| 51 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | 56 | LLVMValueRef 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; |
| 977 | 977 | ||
| 978 | error OutOfMemory; | 978 | error OutOfMemory; |
| 979 | 979 | ||
| 980 | fn globalAlloc(self: &mem.Allocator, n: usize, alignment: usize) -> %[]u8 { | 980 | fn 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 | } |
| 993 | 993 | ||
| 994 | fn globalRealloc(self: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 { | 994 | fn 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 | }; |
| 18 | 18 | ||
| 19 | fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 { | 19 | fn 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 | } |
| 26 | 26 | ||
| 27 | fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 { | 27 | fn 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 | } |
| 108 | 108 | ||
| 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 | } |
| 123 | 123 | ||
| 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; |
| 7 | 7 | ||
| 8 | pub const Allocator = struct { | 8 | pub const Allocator = struct { |
| 9 | /// Allocate byte_count bytes and return them in a slice, with the | 9 | /// 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, |
| 12 | 12 | ||
| 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.ptr | 14 | /// * `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 must | 17 | /// 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, | ||
| 19 | 21 | ||
| 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), |
| 22 | 24 | ||
| 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 | } |
| 27 | 29 | ||
| 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 | } |
| 31 | 33 | ||
| 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 | } |
| 37 | 45 | ||
| 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 | } |
| 42 | 56 | ||
| 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 | } |
| 50 | 61 | ||
| 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 { |
| 59 | 76 | ||
| 60 | assert(n <= old_mem.len); | 77 | assert(n <= old_mem.len); |
| 61 | 78 | ||
| 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 because | 79 | // 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; |
| 68 | 82 | ||
| 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 | } |
| 72 | 86 | ||
| 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 | } |
| 1424 | 1424 | ||
| 1425 | /// Caller must call freeArgs on result. | ||
| 1426 | pub 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 | |||
| 1463 | pub 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 | |||
| 1425 | test "windows arg parsing" { | 1473 | test "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 | } |
| 33 | 35 | ||
| 34 | export fn WinMainCRTStartup() -> noreturn { | 36 | export 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) { |
| 444 | 444 | ||
| 445 | tc | 445 | 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, | ||
| 192 | 193 | ||
| 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 | }; |
| 205 | 210 | ||
| 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, | ||
| 213 | 219 | ||
| 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) -> &RunCompareOutputStep | 221 | 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; |
| 234 | 242 | ||
| 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 | } | ||
| 236 | 251 | ||
| 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); |
| 238 | 253 | ||
| 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(); |
| 241 | 256 | ||
| 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 | } |
| 421 | 437 | ||
| 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); |
| 425 | 441 | ||
| 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 | } |
| 448 | 464 | ||
| 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); |
| 452 | 468 | ||
| 453 | self.step.dependOn(&run_and_cmp_output.step); | 469 | self.step.dependOn(&run_and_cmp_output.step); |