authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-03 00:58:57-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-03 00:58:57-04:00
log402b03c4a9d0a4d2c69cf5914c131f6efa4bc4c9
tree6666e67a07fce13ac2e216a63909b5c307f10dad
parentc180ef86afee17e36135b653fb6256cff46f4e69
parent6a0c4289974dbe27d8980425e7e6061078ecf896

Merge branch 'windows-alignment'


9 files changed, 188 insertions(+), 42 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+10-6
......@@ -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");
......@@ -866,7 +867,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
866867 addLLVMFnAttr(fn_val, "noreturn");
867868 addLLVMFnAttr(fn_val, "cold");
868869 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
869 LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv);
870 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
870871 addLLVMFnAttr(fn_val, "nounwind");
871872 if (g->build_mode == BuildModeDebug) {
872873 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
......@@ -923,7 +924,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
923924
924925static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
925926 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, "");
927929 LLVMBuildUnreachable(g->builder);
928930}
929931
......@@ -3379,6 +3381,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
33793381 case IrInstructionIdSetEvalBranchQuota:
33803382 case IrInstructionIdPtrTypeOf:
33813383 case IrInstructionIdOpaqueType:
3384 case IrInstructionIdSetAlignStack:
33823385 zig_unreachable();
33833386 case IrInstructionIdReturn:
33843387 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
......@@ -4784,6 +4787,7 @@ static void define_builtin_fns(CodeGen *g) {
47844787 create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
47854788 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
47864789 create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
4790 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
47874791}
47884792
47894793static 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+2-2
......@@ -423,7 +423,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
423423 if (g->have_winmain) {
424424 lj->args.append("-ENTRY:WinMain");
425425 } else {
426 lj->args.append("-ENTRY:_start");
426 lj->args.append("-ENTRY:WinMainCRTStartup");
427427 }
428428 }
429429
......@@ -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+10-7
......@@ -5,12 +5,13 @@ const root = @import("@root");
55const std = @import("std");
66const builtin = @import("builtin");
77
8const is_windows = builtin.os == builtin.Os.windows;
89const want_main_symbol = builtin.link_libc;
9const want_start_symbol = !want_main_symbol;
10const want_start_symbol = !want_main_symbol and !is_windows;
11const want_WinMainCRTStartup = is_windows and !builtin.link_libc;
1012
1113var argc_ptr: &usize = undefined;
1214
13const is_windows = builtin.os == builtin.Os.windows;
1415
1516export nakedcc fn _start() -> noreturn {
1617 if (!want_start_symbol) {
......@@ -18,10 +19,6 @@ export nakedcc fn _start() -> noreturn {
1819 unreachable;
1920 }
2021
21 if (is_windows) {
22 windowsCallMainAndExit()
23 }
24
2522 switch (builtin.arch) {
2623 builtin.Arch.x86_64 => {
2724 argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
......@@ -34,7 +31,13 @@ export nakedcc fn _start() -> noreturn {
3431 posixCallMainAndExit()
3532}
3633
37fn windowsCallMainAndExit() -> noreturn {
34export fn WinMainCRTStartup() -> noreturn {
35 if (!want_WinMainCRTStartup) {
36 @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal);
37 unreachable;
38 }
39 @setAlignStack(16);
40
3841 std.debug.user_main_fn = root.main;
3942 root.main() %% std.os.windows.ExitProcess(1);
4043 std.os.windows.ExitProcess(0);
std/special/compiler_rt/index.zig+25-27
......@@ -129,8 +129,9 @@ export nakedcc fn _chkstk() align(4) {
129129 @setGlobalLinkage(_chkstk, strong_linkage);
130130 asm volatile (
131131 \\ push %%ecx
132 \\ push %%eax
132133 \\ cmp $0x1000,%%eax
133 \\ lea 8(%%esp),%%ecx // esp before calling this routine -> ecx
134 \\ lea 12(%%esp),%%ecx
134135 \\ jb 1f
135136 \\ 2:
136137 \\ sub $0x1000,%%ecx
......@@ -141,12 +142,8 @@ export nakedcc fn _chkstk() align(4) {
141142 \\ 1:
142143 \\ sub %%eax,%%ecx
143144 \\ 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
150147 \\ ret
151148 );
152149 unreachable;
......@@ -155,32 +152,33 @@ export nakedcc fn _chkstk() align(4) {
155152 @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal);
156153}
157154
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`.
158159export nakedcc fn __chkstk() align(4) {
159160 @setDebugSafety(this, false);
160161
161162 if (win64_nocrt) {
162163 @setGlobalLinkage(__chkstk, strong_linkage);
163164 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
184182 );
185183 unreachable;
186184 }
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}