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 {
11911191 Buf *section_name;
11921192 AstNode *set_global_linkage_node;
11931193 GlobalLinkageId linkage;
1194 AstNode *set_alignstack_node;
1195 uint32_t alignstack_value;
11941196};
11951197
11961198uint32_t fn_table_entry_hash(FnTableEntry*);
......@@ -1254,6 +1256,7 @@ enum BuiltinFnId {
12541256 BuiltinFnIdSetEvalBranchQuota,
12551257 BuiltinFnIdAlignCast,
12561258 BuiltinFnIdOpaqueType,
1259 BuiltinFnIdSetAlignStack,
12571260};
12581261
12591262struct BuiltinFnEntry {
......@@ -1860,6 +1863,7 @@ enum IrInstructionId {
18601863 IrInstructionIdPtrTypeOf,
18611864 IrInstructionIdAlignCast,
18621865 IrInstructionIdOpaqueType,
1866 IrInstructionIdSetAlignStack,
18631867};
18641868
18651869struct IrInstruction {
......@@ -2654,6 +2658,12 @@ struct IrInstructionOpaqueType {
26542658 IrInstruction base;
26552659};
26562660
2661struct IrInstructionSetAlignStack {
2662 IrInstruction base;
2663
2664 IrInstruction *align_bytes;
2665};
2666
26572667static const size_t slice_ptr_index = 0;
26582668static 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) {
410410 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
411411 break;
412412 case FnInlineAuto:
413 if (fn_table_entry->alignstack_value != 0) {
414 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
415 }
413416 break;
414417 }
415418
......@@ -452,10 +455,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
452455 }
453456 }
454457
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);
459460 }
460461
461462 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
......@@ -3379,6 +3380,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
33793380 case IrInstructionIdSetEvalBranchQuota:
33803381 case IrInstructionIdPtrTypeOf:
33813382 case IrInstructionIdOpaqueType:
3383 case IrInstructionIdSetAlignStack:
33823384 zig_unreachable();
33833385 case IrInstructionIdReturn:
33843386 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
......@@ -4784,6 +4786,7 @@ static void define_builtin_fns(CodeGen *g) {
47844786 create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
47854787 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
47864788 create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
4789 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
47874790}
47884791
47894792static const char *bool_to_str(bool b) {
src/ir.cpp+71
......@@ -563,6 +563,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) {
563563 return IrInstructionIdOpaqueType;
564564}
565565
566static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *) {
567 return IrInstructionIdSetAlignStack;
568}
569
566570template<typename T>
567571static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
568572 T *special_instruction = allocate<T>(1);
......@@ -2248,6 +2252,17 @@ static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode
22482252 return &instruction->base;
22492253}
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
22512266static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
22522267 return nullptr;
22532268}
......@@ -2970,6 +2985,13 @@ static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType
29702985 return nullptr;
29712986}
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
29732995static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
29742996 switch (instruction->id) {
29752997 case IrInstructionIdInvalid:
......@@ -3170,6 +3192,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
31703192 return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);
31713193 case IrInstructionIdOpaqueType:
31723194 return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
3195 case IrInstructionIdSetAlignStack:
3196 return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index);
31733197 }
31743198 zig_unreachable();
31753199}
......@@ -4596,6 +4620,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
45964620 }
45974621 case BuiltinFnIdOpaqueType:
45984622 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 }
45994632 }
46004633 zig_unreachable();
46014634}
......@@ -15264,6 +15297,41 @@ static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInst
1526415297 return ira->codegen->builtin_types.entry_type;
1526515298}
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
1526715335static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1526815336 switch (instruction->id) {
1526915337 case IrInstructionIdInvalid:
......@@ -15452,6 +15520,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1545215520 return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
1545315521 case IrInstructionIdOpaqueType:
1545415522 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
15523 case IrInstructionIdSetAlignStack:
15524 return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
1545515525 }
1545615526 zig_unreachable();
1545715527}
......@@ -15564,6 +15634,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1556415634 case IrInstructionIdPanic:
1556515635 case IrInstructionIdSetEvalBranchQuota:
1556615636 case IrInstructionIdPtrTypeOf:
15637 case IrInstructionIdSetAlignStack:
1556715638 return true;
1556815639 case IrInstructionIdPhi:
1556915640 case IrInstructionIdUnOp:
src/ir_print.cpp+9
......@@ -948,6 +948,12 @@ static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruct
948948 fprintf(irp->f, "@OpaqueType()");
949949}
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
951957static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
952958 ir_print_prefix(irp, instruction);
953959 switch (instruction->id) {
......@@ -1247,6 +1253,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12471253 case IrInstructionIdOpaqueType:
12481254 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
12491255 break;
1256 case IrInstructionIdSetAlignStack:
1257 ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction);
1258 break;
12501259 }
12511260 fprintf(irp->f, "\n");
12521261}
src/link.cpp+1-1
......@@ -846,7 +846,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
846846 buf_resize(&lj.out_file, 0);
847847 }
848848
849 if (g->verbose) {
849 if (g->verbose || g->verbose_ir) {
850850 fprintf(stderr, "\nOptimization:\n");
851851 fprintf(stderr, "---------------\n");
852852 LLVMDumpModule(g->module);
std/special/bootstrap.zig+9
......@@ -19,6 +19,14 @@ export nakedcc fn _start() -> noreturn {
1919 }
2020
2121 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 }
2230 windowsCallMainAndExit()
2331 }
2432
......@@ -35,6 +43,7 @@ export nakedcc fn _start() -> noreturn {
3543}
3644
3745fn windowsCallMainAndExit() -> noreturn {
46 @setAlignStack(16);
3847 std.debug.user_main_fn = root.main;
3948 root.main() %% std.os.windows.ExitProcess(1);
4049 std.os.windows.ExitProcess(0);
test/cases/align.zig+18
......@@ -1,4 +1,5 @@
11const assert = @import("std").debug.assert;
2const builtin = @import("builtin");
23
34var foo: u8 align(4) = 100;
45
......@@ -180,3 +181,20 @@ fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) {
180181fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) {
181182 assert(@typeOf(&ptr[index]) == T);
182183}
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) {
21532153 \\}
21542154 ,
21552155 ".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");
21562189}