authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-02 00:36:57+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-02 19:31:32-04:00
log83bb98e13b19d417c9a8de819b98a1566718b993
tree04f9e65daaadd009ea06af7c603ff922f0262ba3
parenta0a587ff85d3785f99c475d9e0d5f1eb9e27bd26

stage2 llvm: properly align error union payload


2 files changed, 78 insertions(+), 14 deletions(-)

src/codegen/llvm.zig+60-14
......@@ -1270,7 +1270,8 @@ pub const Object = struct {
12701270 offset = std.mem.alignForwardGeneric(u64, offset, payload_align);
12711271 const payload_offset = offset;
12721272
1273 const fields: [2]*llvm.DIType = .{
1273 var len: u8 = 2;
1274 var fields: [3]*llvm.DIType = .{
12741275 dib.createMemberType(
12751276 fwd_decl.toScope(),
12761277 "tag",
......@@ -1293,8 +1294,22 @@ pub const Object = struct {
12931294 0, // flags
12941295 try o.lowerDebugType(payload_ty, .full),
12951296 ),
1297 undefined,
12961298 };
12971299
1300 const error_size = Type.anyerror.abiSize(target);
1301 if (payload_align > error_size) {
1302 fields[2] = fields[1];
1303 const pad_len = @intCast(u32, payload_align - error_size);
1304 fields[1] = dib.createArrayType(
1305 pad_len * 8,
1306 8,
1307 try o.lowerDebugType(Type.u8, .full),
1308 @intCast(c_int, pad_len),
1309 );
1310 len += 1;
1311 }
1312
12981313 const full_di_ty = dib.createStructType(
12991314 compile_unit_scope,
13001315 name.ptr,
......@@ -1305,7 +1320,7 @@ pub const Object = struct {
13051320 0, // flags
13061321 null, // derived from
13071322 &fields,
1308 fields.len,
1323 len,
13091324 0, // run time lang
13101325 null, // vtable holder
13111326 "", // unique id
......@@ -2156,8 +2171,16 @@ pub const DeclGen = struct {
21562171 }
21572172 const llvm_payload_type = try dg.llvmType(payload_type);
21582173
2159 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
2160 return dg.context.structType(&fields, fields.len, .False);
2174 const payload_align = payload_type.abiAlignment(target);
2175 const error_size = error_type.abiSize(target);
2176 if (payload_align > error_size) {
2177 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
2178 const fields: [3]*const llvm.Type = .{ llvm_error_type, pad_type, llvm_payload_type };
2179 return dg.context.structType(&fields, fields.len, .False);
2180 } else {
2181 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
2182 return dg.context.structType(&fields, fields.len, .False);
2183 }
21612184 },
21622185 .ErrorSet => {
21632186 return dg.context.intType(16);
......@@ -2687,8 +2710,8 @@ pub const DeclGen = struct {
26872710 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
26882711 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
26892712 }
2690
2691 const fields: [2]*const llvm.Value = .{
2713 var len: u8 = 2;
2714 var fields: [3]*const llvm.Value = .{
26922715 try dg.genTypedValue(.{
26932716 .ty = error_type,
26942717 .val = if (is_pl) Value.initTag(.zero) else tv.val,
......@@ -2697,8 +2720,18 @@ pub const DeclGen = struct {
26972720 .ty = payload_type,
26982721 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
26992722 }),
2723 undefined,
27002724 };
2701 return dg.context.constStruct(&fields, fields.len, .False);
2725
2726 const payload_align = payload_type.abiAlignment(target);
2727 const error_size = error_type.abiSize(target);
2728 if (payload_align > error_size) {
2729 fields[2] = fields[1];
2730 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
2731 fields[1] = pad_type.getUndef();
2732 len += 1;
2733 }
2734 return dg.context.constStruct(&fields, len, .False);
27022735 },
27032736 .Struct => {
27042737 const llvm_struct_ty = try dg.llvmType(tv.ty);
......@@ -3143,10 +3176,11 @@ pub const DeclGen = struct {
31433176 break :blk parent_llvm_ptr;
31443177 }
31453178
3179 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
31463180 const llvm_u32 = dg.context.intType(32);
31473181 const indices: [2]*const llvm.Value = .{
31483182 llvm_u32.constInt(0, .False),
3149 llvm_u32.constInt(1, .False),
3183 llvm_u32.constInt(payload_offset, .False),
31503184 };
31513185 break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
31523186 },
......@@ -4834,11 +4868,14 @@ pub const FuncGen = struct {
48344868 const result_ty = self.air.getRefType(ty_op.ty);
48354869 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
48364870
4871 const target = self.dg.module.getTarget();
4872 const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
4873
48374874 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;
48384875 if (operand_is_ptr or isByRef(payload_ty)) {
4839 return self.builder.buildStructGEP(operand, 1, "");
4876 return self.builder.buildStructGEP(operand, offset, "");
48404877 }
4841 return self.builder.buildExtractValue(operand, 1, "");
4878 return self.builder.buildExtractValue(operand, offset, "");
48424879 }
48434880
48444881 fn airErrUnionErr(
......@@ -4894,9 +4931,12 @@ pub const FuncGen = struct {
48944931 // Then return the payload pointer (only if it is used).
48954932 if (self.liveness.isUnused(inst))
48964933 return null;
4934
4935 const target = self.dg.module.getTarget();
4936 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
48974937 const indices: [2]*const llvm.Value = .{
48984938 index_type.constNull(), // dereference the pointer
4899 index_type.constInt(1, .False), // second field is the payload
4939 index_type.constInt(payload_offset, .False), // second field is the payload
49004940 };
49014941 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
49024942 }
......@@ -4941,11 +4981,14 @@ pub const FuncGen = struct {
49414981 const inst_ty = self.air.typeOfIndex(inst);
49424982 const ok_err_code = self.context.intType(16).constNull();
49434983 const err_un_llvm_ty = try self.dg.llvmType(inst_ty);
4984
4985 const target = self.dg.module.getTarget();
4986 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
49444987 if (isByRef(inst_ty)) {
49454988 const result_ptr = self.buildAlloca(err_un_llvm_ty);
49464989 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
49474990 _ = self.builder.buildStore(ok_err_code, err_ptr);
4948 const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, "");
4991 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
49494992 var ptr_ty_payload: Type.Payload.ElemType = .{
49504993 .base = .{ .tag = .single_mut_pointer },
49514994 .data = payload_ty,
......@@ -4956,7 +4999,7 @@ pub const FuncGen = struct {
49564999 }
49575000
49585001 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, "");
4959 return self.builder.buildInsertValue(partial, operand, 1, "");
5002 return self.builder.buildInsertValue(partial, operand, payload_offset, "");
49605003 }
49615004
49625005 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
......@@ -4970,11 +5013,14 @@ pub const FuncGen = struct {
49705013 return operand;
49715014 }
49725015 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
5016
5017 const target = self.dg.module.getTarget();
5018 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
49735019 if (isByRef(err_un_ty)) {
49745020 const result_ptr = self.buildAlloca(err_un_llvm_ty);
49755021 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
49765022 _ = self.builder.buildStore(operand, err_ptr);
4977 const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, "");
5023 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
49785024 var ptr_ty_payload: Type.Payload.ElemType = .{
49795025 .base = .{ .tag = .single_mut_pointer },
49805026 .data = payload_ty,
test/behavior/error.zig+18
......@@ -644,3 +644,21 @@ test "coerce error set to the current inferred error set" {
644644 };
645645 S.foo() catch {};
646646}
647
648test "error union payload is properly aligned" {
649 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
650 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
651 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
653
654 const S = struct {
655 a: u128,
656 b: u128,
657 c: u128,
658 fn foo() error{}!@This() {
659 return @This(){ .a = 1, .b = 2, .c = 3 };
660 }
661 };
662 const blk = S.foo() catch unreachable;
663 if (blk.a != 1) unreachable;
664}