| author | |
| committer | |
| log | 402b03c4a9d0a4d2c69cf5914c131f6efa4bc4c9 |
| tree | 6666e67a07fce13ac2e216a63909b5c307f10dad |
| parent | c180ef86afee17e36135b653fb6256cff46f4e69 |
| parent | 6a0c4289974dbe27d8980425e7e6061078ecf896 |
9 files changed, 188 insertions(+), 42 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+10-6| ... | ... | @@ -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"); |
| ... | ... | @@ -866,7 +867,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 866 | 867 | addLLVMFnAttr(fn_val, "noreturn"); |
| 867 | 868 | addLLVMFnAttr(fn_val, "cold"); |
| 868 | 869 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 869 | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); | |
| 870 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); | |
| 870 | 871 | addLLVMFnAttr(fn_val, "nounwind"); |
| 871 | 872 | if (g->build_mode == BuildModeDebug) { |
| 872 | 873 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); |
| ... | ... | @@ -923,7 +924,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 923 | 924 | |
| 924 | 925 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { |
| 925 | 926 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 926 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, LLVMFastCallConv, false, ""); | |
| 927 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified), | |
| 928 | false, ""); | |
| 927 | 929 | LLVMBuildUnreachable(g->builder); |
| 928 | 930 | } |
| 929 | 931 | |
| ... | ... | @@ -3379,6 +3381,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3379 | 3381 | case IrInstructionIdSetEvalBranchQuota: |
| 3380 | 3382 | case IrInstructionIdPtrTypeOf: |
| 3381 | 3383 | case IrInstructionIdOpaqueType: |
| 3384 | case IrInstructionIdSetAlignStack: | |
| 3382 | 3385 | zig_unreachable(); |
| 3383 | 3386 | case IrInstructionIdReturn: |
| 3384 | 3387 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -4784,6 +4787,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4784 | 4787 | create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); |
| 4785 | 4788 | create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); |
| 4786 | 4789 | create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); |
| 4790 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); | |
| 4787 | 4791 | } |
| 4788 | 4792 | |
| 4789 | 4793 | 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+2-2| ... | ... | @@ -423,7 +423,7 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 423 | 423 | if (g->have_winmain) { |
| 424 | 424 | lj->args.append("-ENTRY:WinMain"); |
| 425 | 425 | } else { |
| 426 | lj->args.append("-ENTRY:_start"); | |
| 426 | lj->args.append("-ENTRY:WinMainCRTStartup"); | |
| 427 | 427 | } |
| 428 | 428 | } |
| 429 | 429 | |
| ... | ... | @@ -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+10-7| ... | ... | @@ -5,12 +5,13 @@ const root = @import("@root"); |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | 7 | |
| 8 | const is_windows = builtin.os == builtin.Os.windows; | |
| 8 | 9 | const want_main_symbol = builtin.link_libc; |
| 9 | const want_start_symbol = !want_main_symbol; | |
| 10 | const want_start_symbol = !want_main_symbol and !is_windows; | |
| 11 | const want_WinMainCRTStartup = is_windows and !builtin.link_libc; | |
| 10 | 12 | |
| 11 | 13 | var argc_ptr: &usize = undefined; |
| 12 | 14 | |
| 13 | const is_windows = builtin.os == builtin.Os.windows; | |
| 14 | 15 | |
| 15 | 16 | export nakedcc fn _start() -> noreturn { |
| 16 | 17 | if (!want_start_symbol) { |
| ... | ... | @@ -18,10 +19,6 @@ export nakedcc fn _start() -> noreturn { |
| 18 | 19 | unreachable; |
| 19 | 20 | } |
| 20 | 21 | |
| 21 | if (is_windows) { | |
| 22 | windowsCallMainAndExit() | |
| 23 | } | |
| 24 | ||
| 25 | 22 | switch (builtin.arch) { |
| 26 | 23 | builtin.Arch.x86_64 => { |
| 27 | 24 | argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); |
| ... | ... | @@ -34,7 +31,13 @@ export nakedcc fn _start() -> noreturn { |
| 34 | 31 | posixCallMainAndExit() |
| 35 | 32 | } |
| 36 | 33 | |
| 37 | fn windowsCallMainAndExit() -> noreturn { | |
| 34 | export fn WinMainCRTStartup() -> noreturn { | |
| 35 | if (!want_WinMainCRTStartup) { | |
| 36 | @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal); | |
| 37 | unreachable; | |
| 38 | } | |
| 39 | @setAlignStack(16); | |
| 40 | ||
| 38 | 41 | std.debug.user_main_fn = root.main; |
| 39 | 42 | root.main() %% std.os.windows.ExitProcess(1); |
| 40 | 43 | std.os.windows.ExitProcess(0); |
std/special/compiler_rt/index.zig+25-27| ... | ... | @@ -129,8 +129,9 @@ export nakedcc fn _chkstk() align(4) { |
| 129 | 129 | @setGlobalLinkage(_chkstk, strong_linkage); |
| 130 | 130 | asm volatile ( |
| 131 | 131 | \\ push %%ecx |
| 132 | \\ push %%eax | |
| 132 | 133 | \\ cmp $0x1000,%%eax |
| 133 | \\ lea 8(%%esp),%%ecx // esp before calling this routine -> ecx | |
| 134 | \\ lea 12(%%esp),%%ecx | |
| 134 | 135 | \\ jb 1f |
| 135 | 136 | \\ 2: |
| 136 | 137 | \\ sub $0x1000,%%ecx |
| ... | ... | @@ -141,12 +142,8 @@ export nakedcc fn _chkstk() align(4) { |
| 141 | 142 | \\ 1: |
| 142 | 143 | \\ sub %%eax,%%ecx |
| 143 | 144 | \\ test %%ecx,(%%ecx) |
| 144 | \\ | |
| 145 | \\ lea 4(%%esp),%%eax // load pointer to the return address into eax | |
| 146 | \\ mov %%ecx,%%esp // install the new top of stack pointer into esp | |
| 147 | \\ mov -4(%%eax),%%ecx // restore ecx | |
| 148 | \\ push (%%eax) // push return address onto the stack | |
| 149 | \\ sub %%esp,%%eax // restore the original value in eax | |
| 145 | \\ pop %%eax | |
| 146 | \\ pop %%ecx | |
| 150 | 147 | \\ ret |
| 151 | 148 | ); |
| 152 | 149 | unreachable; |
| ... | ... | @@ -155,32 +152,33 @@ export nakedcc fn _chkstk() align(4) { |
| 155 | 152 | @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); |
| 156 | 153 | } |
| 157 | 154 | |
| 155 | // TODO The implementation from compiler-rt causes crashes and | |
| 156 | // the implementation from disassembled ntdll seems to depend on | |
| 157 | // thread local storage. So we have given up this safety check | |
| 158 | // and simply have `ret`. | |
| 158 | 159 | export nakedcc fn __chkstk() align(4) { |
| 159 | 160 | @setDebugSafety(this, false); |
| 160 | 161 | |
| 161 | 162 | if (win64_nocrt) { |
| 162 | 163 | @setGlobalLinkage(__chkstk, strong_linkage); |
| 163 | 164 | asm volatile ( |
| 164 | \\ push %%rcx | |
| 165 | \\ cmp $0x1000,%%rax | |
| 166 | \\ lea 16(%%rsp),%%rcx // rsp before calling this routine -> rcx | |
| 167 | \\ jb 1f | |
| 168 | \\ 2: | |
| 169 | \\ sub $0x1000,%%rcx | |
| 170 | \\ test %%rcx,(%%rcx) | |
| 171 | \\ sub $0x1000,%%rax | |
| 172 | \\ cmp $0x1000,%%rax | |
| 173 | \\ ja 2b | |
| 174 | \\ 1: | |
| 175 | \\ sub %%rax,%%rcx | |
| 176 | \\ test %%rcx,(%%rcx) | |
| 177 | \\ | |
| 178 | \\ lea 8(%%rsp),%%rax // load pointer to the return address into rax | |
| 179 | \\ mov %%rcx,%%rsp // install the new top of stack pointer into rsp | |
| 180 | \\ mov -8(%%rax),%%rcx // restore rcx | |
| 181 | \\ push (%%rax) // push return address onto the stack | |
| 182 | \\ sub %%rsp,%%rax // restore the original value in rax | |
| 183 | \\ ret | |
| 165 | \\ push %%rcx | |
| 166 | \\ push %%rax | |
| 167 | \\ cmp $0x1000,%%rax | |
| 168 | \\ lea 24(%%rsp),%%rcx | |
| 169 | \\ jb 1f | |
| 170 | \\2: | |
| 171 | \\ sub $0x1000,%%rcx | |
| 172 | \\ test %%rcx,(%%rcx) | |
| 173 | \\ sub $0x1000,%%rax | |
| 174 | \\ cmp $0x1000,%%rax | |
| 175 | \\ ja 2b | |
| 176 | \\1: | |
| 177 | \\ sub %%rax,%%rcx | |
| 178 | \\ test %%rcx,(%%rcx) | |
| 179 | \\ pop %%rax | |
| 180 | \\ pop %%rcx | |
| 181 | \\ ret | |
| 184 | 182 | ); |
| 185 | 183 | unreachable; |
| 186 | 184 | } |
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 | } |