authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-02 22:00:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-03 00:29:27-04:00
logf1bd02e6f46821415d96f54f6a3258159ba5a9c5
treeb9ccd45ba8b9aa047ae2ba4dc071f219167a2aa9
parentc180ef86afee17e36135b653fb6256cff46f4e69

add @setAlignStack builtin


8 files changed, 158 insertions(+), 5 deletions(-)

src/all_types.hpp+10
...@@ -1191,6 +1191,8 @@ struct FnTableEntry {...@@ -1191,6 +1191,8 @@ struct FnTableEntry {
1191 Buf *section_name;1191 Buf *section_name;
1192 AstNode *set_global_linkage_node;1192 AstNode *set_global_linkage_node;
1193 GlobalLinkageId linkage;1193 GlobalLinkageId linkage;
1194 AstNode *set_alignstack_node;
1195 uint32_t alignstack_value;
1194};1196};
11951197
1196uint32_t fn_table_entry_hash(FnTableEntry*);1198uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -1254,6 +1256,7 @@ enum BuiltinFnId {...@@ -1254,6 +1256,7 @@ enum BuiltinFnId {
1254 BuiltinFnIdSetEvalBranchQuota,1256 BuiltinFnIdSetEvalBranchQuota,
1255 BuiltinFnIdAlignCast,1257 BuiltinFnIdAlignCast,
1256 BuiltinFnIdOpaqueType,1258 BuiltinFnIdOpaqueType,
1259 BuiltinFnIdSetAlignStack,
1257};1260};
12581261
1259struct BuiltinFnEntry {1262struct BuiltinFnEntry {
...@@ -1860,6 +1863,7 @@ enum IrInstructionId {...@@ -1860,6 +1863,7 @@ enum IrInstructionId {
1860 IrInstructionIdPtrTypeOf,1863 IrInstructionIdPtrTypeOf,
1861 IrInstructionIdAlignCast,1864 IrInstructionIdAlignCast,
1862 IrInstructionIdOpaqueType,1865 IrInstructionIdOpaqueType,
1866 IrInstructionIdSetAlignStack,
1863};1867};
18641868
1865struct IrInstruction {1869struct IrInstruction {
...@@ -2654,6 +2658,12 @@ struct IrInstructionOpaqueType {...@@ -2654,6 +2658,12 @@ struct IrInstructionOpaqueType {
2654 IrInstruction base;2658 IrInstruction base;
2655};2659};
26562660
2661struct IrInstructionSetAlignStack {
2662 IrInstruction base;
2663
2664 IrInstruction *align_bytes;
2665};
2666
2657static const size_t slice_ptr_index = 0;2667static const size_t slice_ptr_index = 0;
2658static const size_t slice_len_index = 1;2668static const size_t slice_len_index = 1;
26592669
src/codegen.cpp+7-4
...@@ -410,6 +410,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -410,6 +410,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
410 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");410 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
411 break;411 break;
412 case FnInlineAuto:412 case FnInlineAuto:
413 if (fn_table_entry->alignstack_value != 0) {
414 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
415 }
413 break;416 break;
414 }417 }
415418
...@@ -452,10 +455,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -452,10 +455,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
452 }455 }
453 }456 }
454457
455 if (g->zig_target.os == ZigLLVM_Win32 && g->zig_target.arch.arch == ZigLLVM_x86_64 &&458 if (fn_table_entry->alignstack_value != 0) {
456 fn_type->data.fn.fn_type_id.cc != CallingConventionNaked)459 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value);
457 {
458 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", 16);
459 }460 }
460461
461 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");462 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
...@@ -3379,6 +3380,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3379,6 +3380,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3379 case IrInstructionIdSetEvalBranchQuota:3380 case IrInstructionIdSetEvalBranchQuota:
3380 case IrInstructionIdPtrTypeOf:3381 case IrInstructionIdPtrTypeOf:
3381 case IrInstructionIdOpaqueType:3382 case IrInstructionIdOpaqueType:
3383 case IrInstructionIdSetAlignStack:
3382 zig_unreachable();3384 zig_unreachable();
3383 case IrInstructionIdReturn:3385 case IrInstructionIdReturn:
3384 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);3386 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
...@@ -4784,6 +4786,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4784,6 +4786,7 @@ static void define_builtin_fns(CodeGen *g) {
4784 create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);4786 create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
4785 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);4787 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
4786 create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);4788 create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
4789 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
4787}4790}
47884791
4789static const char *bool_to_str(bool b) {4792static const char *bool_to_str(bool b) {
src/ir.cpp+71
...@@ -563,6 +563,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) {...@@ -563,6 +563,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) {
563 return IrInstructionIdOpaqueType;563 return IrInstructionIdOpaqueType;
564}564}
565565
566static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *) {
567 return IrInstructionIdSetAlignStack;
568}
569
566template<typename T>570template<typename T>
567static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {571static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
568 T *special_instruction = allocate<T>(1);572 T *special_instruction = allocate<T>(1);
...@@ -2248,6 +2252,17 @@ static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode...@@ -2248,6 +2252,17 @@ static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode
2248 return &instruction->base;2252 return &instruction->base;
2249}2253}
22502254
2255static 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
2251static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {2266static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
2252 return nullptr;2267 return nullptr;
2253}2268}
...@@ -2970,6 +2985,13 @@ static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType...@@ -2970,6 +2985,13 @@ static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType
2970 return nullptr;2985 return nullptr;
2971}2986}
29722987
2988static 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
2973static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {2995static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
2974 switch (instruction->id) {2996 switch (instruction->id) {
2975 case IrInstructionIdInvalid:2997 case IrInstructionIdInvalid:
...@@ -3170,6 +3192,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -3170,6 +3192,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
3170 return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);3192 return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);
3171 case IrInstructionIdOpaqueType:3193 case IrInstructionIdOpaqueType:
3172 return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);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 zig_unreachable();3198 zig_unreachable();
3175}3199}
...@@ -4596,6 +4620,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4596,6 +4620,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4596 }4620 }
4597 case BuiltinFnIdOpaqueType:4621 case BuiltinFnIdOpaqueType:
4598 return ir_build_opaque_type(irb, scope, node);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 zig_unreachable();4633 zig_unreachable();
4601}4634}
...@@ -15264,6 +15297,41 @@ static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInst...@@ -15264,6 +15297,41 @@ static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInst
15264 return ira->codegen->builtin_types.entry_type;15297 return ira->codegen->builtin_types.entry_type;
15265}15298}
1526615299
15300static 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
15267static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {15335static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
15268 switch (instruction->id) {15336 switch (instruction->id) {
15269 case IrInstructionIdInvalid:15337 case IrInstructionIdInvalid:
...@@ -15452,6 +15520,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15452,6 +15520,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15452 return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);15520 return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
15453 case IrInstructionIdOpaqueType:15521 case IrInstructionIdOpaqueType:
15454 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);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 zig_unreachable();15526 zig_unreachable();
15457}15527}
...@@ -15564,6 +15634,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15564,6 +15634,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15564 case IrInstructionIdPanic:15634 case IrInstructionIdPanic:
15565 case IrInstructionIdSetEvalBranchQuota:15635 case IrInstructionIdSetEvalBranchQuota:
15566 case IrInstructionIdPtrTypeOf:15636 case IrInstructionIdPtrTypeOf:
15637 case IrInstructionIdSetAlignStack:
15567 return true;15638 return true;
15568 case IrInstructionIdPhi:15639 case IrInstructionIdPhi:
15569 case IrInstructionIdUnOp:15640 case IrInstructionIdUnOp:
src/ir_print.cpp+9
...@@ -948,6 +948,12 @@ static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruct...@@ -948,6 +948,12 @@ static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruct
948 fprintf(irp->f, "@OpaqueType()");948 fprintf(irp->f, "@OpaqueType()");
949}949}
950950
951static 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
951static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {957static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
952 ir_print_prefix(irp, instruction);958 ir_print_prefix(irp, instruction);
953 switch (instruction->id) {959 switch (instruction->id) {
...@@ -1247,6 +1253,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1247,6 +1253,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1247 case IrInstructionIdOpaqueType:1253 case IrInstructionIdOpaqueType:
1248 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);1254 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
1249 break;1255 break;
1256 case IrInstructionIdSetAlignStack:
1257 ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction);
1258 break;
1250 }1259 }
1251 fprintf(irp->f, "\n");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,7 +846,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
846 buf_resize(&lj.out_file, 0);846 buf_resize(&lj.out_file, 0);
847 }847 }
848848
849 if (g->verbose) {849 if (g->verbose || g->verbose_ir) {
850 fprintf(stderr, "\nOptimization:\n");850 fprintf(stderr, "\nOptimization:\n");
851 fprintf(stderr, "---------------\n");851 fprintf(stderr, "---------------\n");
852 LLVMDumpModule(g->module);852 LLVMDumpModule(g->module);
std/special/bootstrap.zig+9
...@@ -19,6 +19,14 @@ export nakedcc fn _start() -> noreturn {...@@ -19,6 +19,14 @@ export nakedcc fn _start() -> noreturn {
19 }19 }
2020
21 if (is_windows) {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 windowsCallMainAndExit()30 windowsCallMainAndExit()
23 }31 }
2432
...@@ -35,6 +43,7 @@ export nakedcc fn _start() -> noreturn {...@@ -35,6 +43,7 @@ export nakedcc fn _start() -> noreturn {
35}43}
3644
37fn windowsCallMainAndExit() -> noreturn {45fn windowsCallMainAndExit() -> noreturn {
46 @setAlignStack(16);
38 std.debug.user_main_fn = root.main;47 std.debug.user_main_fn = root.main;
39 root.main() %% std.os.windows.ExitProcess(1);48 root.main() %% std.os.windows.ExitProcess(1);
40 std.os.windows.ExitProcess(0);49 std.os.windows.ExitProcess(0);
test/cases/align.zig+18
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const builtin = @import("builtin");
23
3var foo: u8 align(4) = 100;4var foo: u8 align(4) = 100;
45
...@@ -180,3 +181,20 @@ fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) {...@@ -180,3 +181,20 @@ fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) {
180fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) {181fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) {
181 assert(@typeOf(&ptr[index]) == T);182 assert(@typeOf(&ptr[index]) == T);
182}183}
184
185
186test "alignstack" {
187 fnWithAlignedStack();
188}
189
190fn 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,4 +2153,37 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2153 \\}2153 \\}
2154 ,2154 ,
2155 ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'");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}