| author | |
| committer | |
| log | f1bd02e6f46821415d96f54f6a3258159ba5a9c5 |
| tree | b9ccd45ba8b9aa047ae2ba4dc071f219167a2aa9 |
| parent | c180ef86afee17e36135b653fb6256cff46f4e69 |
8 files changed, 158 insertions(+), 5 deletions(-)
src/all_types.hpp+10| ... | ... | @@ -1191,6 +1191,8 @@ struct FnTableEntry { |
| 1191 | 1191 | Buf *section_name; |
| 1192 | 1192 | AstNode *set_global_linkage_node; |
| 1193 | 1193 | GlobalLinkageId linkage; |
| 1194 | AstNode *set_alignstack_node; | |
| 1195 | uint32_t alignstack_value; | |
| 1194 | 1196 | }; |
| 1195 | 1197 | |
| 1196 | 1198 | uint32_t fn_table_entry_hash(FnTableEntry*); |
| ... | ... | @@ -1254,6 +1256,7 @@ enum BuiltinFnId { |
| 1254 | 1256 | BuiltinFnIdSetEvalBranchQuota, |
| 1255 | 1257 | BuiltinFnIdAlignCast, |
| 1256 | 1258 | BuiltinFnIdOpaqueType, |
| 1259 | BuiltinFnIdSetAlignStack, | |
| 1257 | 1260 | }; |
| 1258 | 1261 | |
| 1259 | 1262 | struct BuiltinFnEntry { |
| ... | ... | @@ -1860,6 +1863,7 @@ enum IrInstructionId { |
| 1860 | 1863 | IrInstructionIdPtrTypeOf, |
| 1861 | 1864 | IrInstructionIdAlignCast, |
| 1862 | 1865 | IrInstructionIdOpaqueType, |
| 1866 | IrInstructionIdSetAlignStack, | |
| 1863 | 1867 | }; |
| 1864 | 1868 | |
| 1865 | 1869 | struct IrInstruction { |
| ... | ... | @@ -2654,6 +2658,12 @@ struct IrInstructionOpaqueType { |
| 2654 | 2658 | IrInstruction base; |
| 2655 | 2659 | }; |
| 2656 | 2660 | |
| 2661 | struct IrInstructionSetAlignStack { | |
| 2662 | IrInstruction base; | |
| 2663 | ||
| 2664 | IrInstruction *align_bytes; | |
| 2665 | }; | |
| 2666 | ||
| 2657 | 2667 | static const size_t slice_ptr_index = 0; |
| 2658 | 2668 | static const size_t slice_len_index = 1; |
| 2659 | 2669 |
src/codegen.cpp+7-4| ... | ... | @@ -410,6 +410,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 410 | 410 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); |
| 411 | 411 | break; |
| 412 | 412 | case FnInlineAuto: |
| 413 | if (fn_table_entry->alignstack_value != 0) { | |
| 414 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); | |
| 415 | } | |
| 413 | 416 | break; |
| 414 | 417 | } |
| 415 | 418 | |
| ... | ... | @@ -452,10 +455,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 452 | 455 | } |
| 453 | 456 | } |
| 454 | 457 | |
| 455 | if (g->zig_target.os == ZigLLVM_Win32 && g->zig_target.arch.arch == ZigLLVM_x86_64 && | |
| 456 | fn_type->data.fn.fn_type_id.cc != CallingConventionNaked) | |
| 457 | { | |
| 458 | addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", 16); | |
| 458 | if (fn_table_entry->alignstack_value != 0) { | |
| 459 | addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value); | |
| 459 | 460 | } |
| 460 | 461 | |
| 461 | 462 | addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind"); |
| ... | ... | @@ -3379,6 +3380,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3379 | 3380 | case IrInstructionIdSetEvalBranchQuota: |
| 3380 | 3381 | case IrInstructionIdPtrTypeOf: |
| 3381 | 3382 | case IrInstructionIdOpaqueType: |
| 3383 | case IrInstructionIdSetAlignStack: | |
| 3382 | 3384 | zig_unreachable(); |
| 3383 | 3385 | case IrInstructionIdReturn: |
| 3384 | 3386 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -4784,6 +4786,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4784 | 4786 | create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); |
| 4785 | 4787 | create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); |
| 4786 | 4788 | create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); |
| 4789 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); | |
| 4787 | 4790 | } |
| 4788 | 4791 | |
| 4789 | 4792 | static const char *bool_to_str(bool b) { |
src/ir.cpp+71| ... | ... | @@ -563,6 +563,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { |
| 563 | 563 | return IrInstructionIdOpaqueType; |
| 564 | 564 | } |
| 565 | 565 | |
| 566 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *) { | |
| 567 | return IrInstructionIdSetAlignStack; | |
| 568 | } | |
| 569 | ||
| 566 | 570 | template<typename T> |
| 567 | 571 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 568 | 572 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2248,6 +2252,17 @@ static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode |
| 2248 | 2252 | return &instruction->base; |
| 2249 | 2253 | } |
| 2250 | 2254 | |
| 2255 | static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2256 | IrInstruction *align_bytes) | |
| 2257 | { | |
| 2258 | IrInstructionSetAlignStack *instruction = ir_build_instruction<IrInstructionSetAlignStack>(irb, scope, source_node); | |
| 2259 | instruction->align_bytes = align_bytes; | |
| 2260 | ||
| 2261 | ir_ref_instruction(align_bytes, irb->current_basic_block); | |
| 2262 | ||
| 2263 | return &instruction->base; | |
| 2264 | } | |
| 2265 | ||
| 2251 | 2266 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2252 | 2267 | return nullptr; |
| 2253 | 2268 | } |
| ... | ... | @@ -2970,6 +2985,13 @@ static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType |
| 2970 | 2985 | return nullptr; |
| 2971 | 2986 | } |
| 2972 | 2987 | |
| 2988 | static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlignStack *instruction, size_t index) { | |
| 2989 | switch (index) { | |
| 2990 | case 0: return instruction->align_bytes; | |
| 2991 | default: return nullptr; | |
| 2992 | } | |
| 2993 | } | |
| 2994 | ||
| 2973 | 2995 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2974 | 2996 | switch (instruction->id) { |
| 2975 | 2997 | case IrInstructionIdInvalid: |
| ... | ... | @@ -3170,6 +3192,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3170 | 3192 | return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index); |
| 3171 | 3193 | case IrInstructionIdOpaqueType: |
| 3172 | 3194 | return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index); |
| 3195 | case IrInstructionIdSetAlignStack: | |
| 3196 | return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index); | |
| 3173 | 3197 | } |
| 3174 | 3198 | zig_unreachable(); |
| 3175 | 3199 | } |
| ... | ... | @@ -4596,6 +4620,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4596 | 4620 | } |
| 4597 | 4621 | case BuiltinFnIdOpaqueType: |
| 4598 | 4622 | return ir_build_opaque_type(irb, scope, node); |
| 4623 | case BuiltinFnIdSetAlignStack: | |
| 4624 | { | |
| 4625 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4626 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4627 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4628 | return arg0_value; | |
| 4629 | ||
| 4630 | return ir_build_set_align_stack(irb, scope, node, arg0_value); | |
| 4631 | } | |
| 4599 | 4632 | } |
| 4600 | 4633 | zig_unreachable(); |
| 4601 | 4634 | } |
| ... | ... | @@ -15264,6 +15297,41 @@ static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInst |
| 15264 | 15297 | return ira->codegen->builtin_types.entry_type; |
| 15265 | 15298 | } |
| 15266 | 15299 | |
| 15300 | static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) { | |
| 15301 | uint32_t align_bytes; | |
| 15302 | IrInstruction *align_bytes_inst = instruction->align_bytes->other; | |
| 15303 | if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes)) | |
| 15304 | return ira->codegen->builtin_types.entry_invalid; | |
| 15305 | ||
| 15306 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 15307 | if (fn_entry == nullptr) { | |
| 15308 | ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack outside function")); | |
| 15309 | return ira->codegen->builtin_types.entry_invalid; | |
| 15310 | } | |
| 15311 | if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionNaked) { | |
| 15312 | ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack in naked function")); | |
| 15313 | return ira->codegen->builtin_types.entry_invalid; | |
| 15314 | } | |
| 15315 | ||
| 15316 | if (fn_entry->fn_inline == FnInlineAlways) { | |
| 15317 | ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack in inline function")); | |
| 15318 | return ira->codegen->builtin_types.entry_invalid; | |
| 15319 | } | |
| 15320 | ||
| 15321 | if (fn_entry->set_alignstack_node != nullptr) { | |
| 15322 | ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, | |
| 15323 | buf_sprintf("alignstack set twice")); | |
| 15324 | add_error_note(ira->codegen, msg, fn_entry->set_alignstack_node, buf_sprintf("first set here")); | |
| 15325 | return ira->codegen->builtin_types.entry_invalid; | |
| 15326 | } | |
| 15327 | ||
| 15328 | fn_entry->set_alignstack_node = instruction->base.source_node; | |
| 15329 | fn_entry->alignstack_value = align_bytes; | |
| 15330 | ||
| 15331 | ir_build_const_from(ira, &instruction->base); | |
| 15332 | return ira->codegen->builtin_types.entry_void; | |
| 15333 | } | |
| 15334 | ||
| 15267 | 15335 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 15268 | 15336 | switch (instruction->id) { |
| 15269 | 15337 | case IrInstructionIdInvalid: |
| ... | ... | @@ -15452,6 +15520,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15452 | 15520 | return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); |
| 15453 | 15521 | case IrInstructionIdOpaqueType: |
| 15454 | 15522 | return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); |
| 15523 | case IrInstructionIdSetAlignStack: | |
| 15524 | return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction); | |
| 15455 | 15525 | } |
| 15456 | 15526 | zig_unreachable(); |
| 15457 | 15527 | } |
| ... | ... | @@ -15564,6 +15634,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15564 | 15634 | case IrInstructionIdPanic: |
| 15565 | 15635 | case IrInstructionIdSetEvalBranchQuota: |
| 15566 | 15636 | case IrInstructionIdPtrTypeOf: |
| 15637 | case IrInstructionIdSetAlignStack: | |
| 15567 | 15638 | return true; |
| 15568 | 15639 | case IrInstructionIdPhi: |
| 15569 | 15640 | case IrInstructionIdUnOp: |
src/ir_print.cpp+9| ... | ... | @@ -948,6 +948,12 @@ static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruct |
| 948 | 948 | fprintf(irp->f, "@OpaqueType()"); |
| 949 | 949 | } |
| 950 | 950 | |
| 951 | static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *instruction) { | |
| 952 | fprintf(irp->f, "@setAlignStack("); | |
| 953 | ir_print_other_instruction(irp, instruction->align_bytes); | |
| 954 | fprintf(irp->f, ")"); | |
| 955 | } | |
| 956 | ||
| 951 | 957 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 952 | 958 | ir_print_prefix(irp, instruction); |
| 953 | 959 | switch (instruction->id) { |
| ... | ... | @@ -1247,6 +1253,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1247 | 1253 | case IrInstructionIdOpaqueType: |
| 1248 | 1254 | ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); |
| 1249 | 1255 | break; |
| 1256 | case IrInstructionIdSetAlignStack: | |
| 1257 | ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction); | |
| 1258 | break; | |
| 1250 | 1259 | } |
| 1251 | 1260 | fprintf(irp->f, "\n"); |
| 1252 | 1261 | } |
src/link.cpp+1-1| ... | ... | @@ -846,7 +846,7 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 846 | 846 | buf_resize(&lj.out_file, 0); |
| 847 | 847 | } |
| 848 | 848 | |
| 849 | if (g->verbose) { | |
| 849 | if (g->verbose || g->verbose_ir) { | |
| 850 | 850 | fprintf(stderr, "\nOptimization:\n"); |
| 851 | 851 | fprintf(stderr, "---------------\n"); |
| 852 | 852 | LLVMDumpModule(g->module); |
std/special/bootstrap.zig+9| ... | ... | @@ -19,6 +19,14 @@ export nakedcc fn _start() -> noreturn { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | if (is_windows) { |
| 22 | if (builtin.arch == builtin.Arch.x86_64) { | |
| 23 | // Align the stack pointer to 16 bytes. | |
| 24 | asm volatile ( | |
| 25 | \\ and $0xfffffffffffffff0,%%rsp | |
| 26 | \\ sub $0x10,%%rsp | |
| 27 | :::"rsp" | |
| 28 | ); | |
| 29 | } | |
| 22 | 30 | windowsCallMainAndExit() |
| 23 | 31 | } |
| 24 | 32 | |
| ... | ... | @@ -35,6 +43,7 @@ export nakedcc fn _start() -> noreturn { |
| 35 | 43 | } |
| 36 | 44 | |
| 37 | 45 | fn windowsCallMainAndExit() -> noreturn { |
| 46 | @setAlignStack(16); | |
| 38 | 47 | std.debug.user_main_fn = root.main; |
| 39 | 48 | root.main() %% std.os.windows.ExitProcess(1); |
| 40 | 49 | std.os.windows.ExitProcess(0); |
test/cases/align.zig+18| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const assert = @import("std").debug.assert; |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | var foo: u8 align(4) = 100; |
| 4 | 5 | |
| ... | ... | @@ -180,3 +181,20 @@ fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) { |
| 180 | 181 | fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) { |
| 181 | 182 | assert(@typeOf(&ptr[index]) == T); |
| 182 | 183 | } |
| 184 | ||
| 185 | ||
| 186 | test "alignstack" { | |
| 187 | fnWithAlignedStack(); | |
| 188 | } | |
| 189 | ||
| 190 | fn fnWithAlignedStack() { | |
| 191 | @setAlignStack(1024); | |
| 192 | const stack_address = if (builtin.arch == builtin.Arch.x86_64) { | |
| 193 | asm volatile ("" :[rsp] "={rsp}"(-> usize)) | |
| 194 | } else if (builtin.arch == builtin.Arch.i386) { | |
| 195 | asm volatile ("" :[esp] "={esp}"(-> usize)) | |
| 196 | } else { | |
| 197 | return; | |
| 198 | }; | |
| 199 | assert(stack_address % 1024 == 0); | |
| 200 | } |
test/compile_errors.zig+33| ... | ... | @@ -2153,4 +2153,37 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2153 | 2153 | \\} |
| 2154 | 2154 | , |
| 2155 | 2155 | ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); |
| 2156 | ||
| 2157 | cases.add("@setAlignStack outside function", | |
| 2158 | \\comptime { | |
| 2159 | \\ @setAlignStack(16); | |
| 2160 | \\} | |
| 2161 | , | |
| 2162 | ".tmp_source.zig:2:5: error: @setAlignStack outside function"); | |
| 2163 | ||
| 2164 | cases.add("@setAlignStack in naked function", | |
| 2165 | \\export nakedcc fn entry() { | |
| 2166 | \\ @setAlignStack(16); | |
| 2167 | \\} | |
| 2168 | , | |
| 2169 | ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); | |
| 2170 | ||
| 2171 | cases.add("@setAlignStack in inline function", | |
| 2172 | \\export fn entry() { | |
| 2173 | \\ foo(); | |
| 2174 | \\} | |
| 2175 | \\inline fn foo() { | |
| 2176 | \\ @setAlignStack(16); | |
| 2177 | \\} | |
| 2178 | , | |
| 2179 | ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); | |
| 2180 | ||
| 2181 | cases.add("@setAlignStack set twice", | |
| 2182 | \\export fn entry() { | |
| 2183 | \\ @setAlignStack(16); | |
| 2184 | \\ @setAlignStack(16); | |
| 2185 | \\} | |
| 2186 | , | |
| 2187 | ".tmp_source.zig:3:5: error: alignstack set twice", | |
| 2188 | ".tmp_source.zig:2:5: note: first set here"); | |
| 2156 | 2189 | } |