authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-04-25 16:40:41+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-04-25 16:40:41+02:00
log50a8124f45cd0994b52af3fd166dd3bda48f4b99
tree1e5c4a6bcd6a9b233f9aa198a07663aa9a9ddb37
parent37b05742ff1544bccf7c8ae9b12c6707a5a54df2

stage1: Change how the Frame alignment is computed

The code would previously assume every function would start at addresses being multiples of 16, this is not true beside some specific cases. Moreover LLVM picks different alignment values depending on whether it's trying to generate dense or fast code. Let's use the minimum guaranteed alignment as base value, computed according to how big the opcodes are. The alignment of function pointers is always 1, a safe value that won't cause any error at runtime. Note that this was already the case before this commit, here we're making this choice explicit. Let the 'alignment' field for TypeInfo of fn types reflect the ABI alignment used by the compiler, make this field behave similarly to the 'alignment' one for pointers.

5 files changed, 42 insertions(+), 13 deletions(-)

src/stage1/analyze.cpp+6-9
...@@ -4770,10 +4770,10 @@ Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) {...@@ -4770,10 +4770,10 @@ Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) {
4770}4770}
47714771
4772static uint32_t get_async_frame_align_bytes(CodeGen *g) {4772static uint32_t get_async_frame_align_bytes(CodeGen *g) {
4773 uint32_t a = g->pointer_size_bytes * 2;4773 // Due to how the frame structure is built the minimum alignment is the one
4774 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw4774 // of a usize (or pointer).
4775 if (a < 8) a = 8;4775 // label (grep this): [fn_frame_struct_layout]
4776 return a;4776 return max(g->builtin_types.entry_usize->abi_align, target_fn_align(g->zig_target));
4777}4777}
47784778
4779uint32_t get_ptr_align(CodeGen *g, ZigType *type) {4779uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
...@@ -4789,11 +4789,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {...@@ -4789,11 +4789,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4789 return (ptr_type->data.pointer.explicit_alignment == 0) ?4789 return (ptr_type->data.pointer.explicit_alignment == 0) ?
4790 get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;4790 get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;
4791 } else if (ptr_type->id == ZigTypeIdFn) {4791 } else if (ptr_type->id == ZigTypeIdFn) {
4792 // I tried making this use LLVMABIAlignmentOfType but it trips this assertion in LLVM:4792 return (ptr_type->data.fn.fn_type_id.alignment == 0) ?
4793 // "Cannot getTypeInfo() on a type that is unsized!"4793 target_fn_ptr_align(g->zig_target) : ptr_type->data.fn.fn_type_id.alignment;
4794 // when getting the alignment of `?fn() callconv(.C) void`.
4795 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html
4796 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
4797 } else if (ptr_type->id == ZigTypeIdAnyFrame) {4794 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
4798 return get_async_frame_align_bytes(g);4795 return get_async_frame_align_bytes(g);
4799 } else {4796 } else {
src/stage1/ir.cpp+2-2
...@@ -26079,11 +26079,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -26079,11 +26079,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
26079 fields[0]->special = ConstValSpecialStatic;26079 fields[0]->special = ConstValSpecialStatic;
26080 fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention");26080 fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention");
26081 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);26081 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);
26082 // alignment: u2926082 // alignment: comptime_int
26083 ensure_field_index(result->type, "alignment", 1);26083 ensure_field_index(result->type, "alignment", 1);
26084 fields[1]->special = ConstValSpecialStatic;26084 fields[1]->special = ConstValSpecialStatic;
26085 fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int;26085 fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int;
26086 bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment);26086 bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(ira->codegen, type_entry));
26087 // is_generic: bool26087 // is_generic: bool
26088 ensure_field_index(result->type, "is_generic", 2);26088 ensure_field_index(result->type, "is_generic", 2);
26089 bool is_generic = type_entry->data.fn.is_generic;26089 bool is_generic = type_entry->data.fn.is_generic;
src/stage1/target.cpp+32-1
...@@ -1253,6 +1253,37 @@ bool target_is_ppc(const ZigTarget *target) {...@@ -1253,6 +1253,37 @@ bool target_is_ppc(const ZigTarget *target) {
1253 target->arch == ZigLLVM_ppc64le;1253 target->arch == ZigLLVM_ppc64le;
1254}1254}
12551255
1256// Returns the minimum alignment for every function pointer on the given
1257// architecture.
1258unsigned target_fn_ptr_align(const ZigTarget *target) {
1259 // TODO This is a pessimization but is always correct.
1260 return 1;
1261}
1262
1263// Returns the minimum alignment for every function on the given architecture.
1256unsigned target_fn_align(const ZigTarget *target) {1264unsigned target_fn_align(const ZigTarget *target) {
1257 return 16;1265 switch (target->arch) {
1266 case ZigLLVM_riscv32:
1267 case ZigLLVM_riscv64:
1268 // TODO If the C extension is not present the value is 4.
1269 return 2;
1270 case ZigLLVM_ppc:
1271 case ZigLLVM_ppcle:
1272 case ZigLLVM_ppc64:
1273 case ZigLLVM_ppc64le:
1274 case ZigLLVM_aarch64:
1275 case ZigLLVM_aarch64_be:
1276 case ZigLLVM_aarch64_32:
1277 case ZigLLVM_sparc:
1278 case ZigLLVM_sparcel:
1279 case ZigLLVM_sparcv9:
1280 case ZigLLVM_mips:
1281 case ZigLLVM_mipsel:
1282 case ZigLLVM_mips64:
1283 case ZigLLVM_mips64el:
1284 return 4;
1285
1286 default:
1287 return 1;
1288 }
1258}1289}
src/stage1/target.hpp+1
...@@ -98,6 +98,7 @@ size_t target_libc_count(void);...@@ -98,6 +98,7 @@ size_t target_libc_count(void);
98void target_libc_enum(size_t index, ZigTarget *out_target);98void target_libc_enum(size_t index, ZigTarget *out_target);
99bool target_libc_needs_crti_crtn(const ZigTarget *target);99bool target_libc_needs_crti_crtn(const ZigTarget *target);
100100
101unsigned target_fn_ptr_align(const ZigTarget *target);
101unsigned target_fn_align(const ZigTarget *target);102unsigned target_fn_align(const ZigTarget *target);
102103
103#endif104#endif
test/stage1/behavior/type_info.zig+1-1
...@@ -306,7 +306,7 @@ test "type info: function type info" {...@@ -306,7 +306,7 @@ test "type info: function type info" {
306fn testFunction() void {306fn testFunction() void {
307 const fn_info = @typeInfo(@TypeOf(foo));307 const fn_info = @typeInfo(@TypeOf(foo));
308 expect(fn_info == .Fn);308 expect(fn_info == .Fn);
309 expect(fn_info.Fn.alignment == 0);309 expect(fn_info.Fn.alignment > 0);
310 expect(fn_info.Fn.calling_convention == .C);310 expect(fn_info.Fn.calling_convention == .C);
311 expect(!fn_info.Fn.is_generic);311 expect(!fn_info.Fn.is_generic);
312 expect(fn_info.Fn.args.len == 2);312 expect(fn_info.Fn.args.len == 2);