mirror of
https://github.com/ziglang/zig.git
synced 2024-11-16 17:15:37 +00:00
stage2 llvm: properly align error union payload
This commit is contained in:
parent
a0a587ff85
commit
83bb98e13b
@ -1270,7 +1270,8 @@ pub const Object = struct {
|
||||
offset = std.mem.alignForwardGeneric(u64, offset, payload_align);
|
||||
const payload_offset = offset;
|
||||
|
||||
const fields: [2]*llvm.DIType = .{
|
||||
var len: u8 = 2;
|
||||
var fields: [3]*llvm.DIType = .{
|
||||
dib.createMemberType(
|
||||
fwd_decl.toScope(),
|
||||
"tag",
|
||||
@ -1293,8 +1294,22 @@ pub const Object = struct {
|
||||
0, // flags
|
||||
try o.lowerDebugType(payload_ty, .full),
|
||||
),
|
||||
undefined,
|
||||
};
|
||||
|
||||
const error_size = Type.anyerror.abiSize(target);
|
||||
if (payload_align > error_size) {
|
||||
fields[2] = fields[1];
|
||||
const pad_len = @intCast(u32, payload_align - error_size);
|
||||
fields[1] = dib.createArrayType(
|
||||
pad_len * 8,
|
||||
8,
|
||||
try o.lowerDebugType(Type.u8, .full),
|
||||
@intCast(c_int, pad_len),
|
||||
);
|
||||
len += 1;
|
||||
}
|
||||
|
||||
const full_di_ty = dib.createStructType(
|
||||
compile_unit_scope,
|
||||
name.ptr,
|
||||
@ -1305,7 +1320,7 @@ pub const Object = struct {
|
||||
0, // flags
|
||||
null, // derived from
|
||||
&fields,
|
||||
fields.len,
|
||||
len,
|
||||
0, // run time lang
|
||||
null, // vtable holder
|
||||
"", // unique id
|
||||
@ -2156,8 +2171,16 @@ pub const DeclGen = struct {
|
||||
}
|
||||
const llvm_payload_type = try dg.llvmType(payload_type);
|
||||
|
||||
const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
|
||||
return dg.context.structType(&fields, fields.len, .False);
|
||||
const payload_align = payload_type.abiAlignment(target);
|
||||
const error_size = error_type.abiSize(target);
|
||||
if (payload_align > error_size) {
|
||||
const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
|
||||
const fields: [3]*const llvm.Type = .{ llvm_error_type, pad_type, llvm_payload_type };
|
||||
return dg.context.structType(&fields, fields.len, .False);
|
||||
} else {
|
||||
const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
|
||||
return dg.context.structType(&fields, fields.len, .False);
|
||||
}
|
||||
},
|
||||
.ErrorSet => {
|
||||
return dg.context.intType(16);
|
||||
@ -2687,8 +2710,8 @@ pub const DeclGen = struct {
|
||||
const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
|
||||
return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
|
||||
}
|
||||
|
||||
const fields: [2]*const llvm.Value = .{
|
||||
var len: u8 = 2;
|
||||
var fields: [3]*const llvm.Value = .{
|
||||
try dg.genTypedValue(.{
|
||||
.ty = error_type,
|
||||
.val = if (is_pl) Value.initTag(.zero) else tv.val,
|
||||
@ -2697,8 +2720,18 @@ pub const DeclGen = struct {
|
||||
.ty = payload_type,
|
||||
.val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
|
||||
}),
|
||||
undefined,
|
||||
};
|
||||
return dg.context.constStruct(&fields, fields.len, .False);
|
||||
|
||||
const payload_align = payload_type.abiAlignment(target);
|
||||
const error_size = error_type.abiSize(target);
|
||||
if (payload_align > error_size) {
|
||||
fields[2] = fields[1];
|
||||
const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));
|
||||
fields[1] = pad_type.getUndef();
|
||||
len += 1;
|
||||
}
|
||||
return dg.context.constStruct(&fields, len, .False);
|
||||
},
|
||||
.Struct => {
|
||||
const llvm_struct_ty = try dg.llvmType(tv.ty);
|
||||
@ -3143,10 +3176,11 @@ pub const DeclGen = struct {
|
||||
break :blk parent_llvm_ptr;
|
||||
}
|
||||
|
||||
const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
|
||||
const llvm_u32 = dg.context.intType(32);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
llvm_u32.constInt(0, .False),
|
||||
llvm_u32.constInt(1, .False),
|
||||
llvm_u32.constInt(payload_offset, .False),
|
||||
};
|
||||
break :blk parent_llvm_ptr.constInBoundsGEP(&indices, indices.len);
|
||||
},
|
||||
@ -4834,11 +4868,14 @@ pub const FuncGen = struct {
|
||||
const result_ty = self.air.getRefType(ty_op.ty);
|
||||
const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
|
||||
|
||||
const target = self.dg.module.getTarget();
|
||||
const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
|
||||
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;
|
||||
if (operand_is_ptr or isByRef(payload_ty)) {
|
||||
return self.builder.buildStructGEP(operand, 1, "");
|
||||
return self.builder.buildStructGEP(operand, offset, "");
|
||||
}
|
||||
return self.builder.buildExtractValue(operand, 1, "");
|
||||
return self.builder.buildExtractValue(operand, offset, "");
|
||||
}
|
||||
|
||||
fn airErrUnionErr(
|
||||
@ -4894,9 +4931,12 @@ pub const FuncGen = struct {
|
||||
// Then return the payload pointer (only if it is used).
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const target = self.dg.module.getTarget();
|
||||
const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(), // dereference the pointer
|
||||
index_type.constInt(1, .False), // second field is the payload
|
||||
index_type.constInt(payload_offset, .False), // second field is the payload
|
||||
};
|
||||
return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
|
||||
}
|
||||
@ -4941,11 +4981,14 @@ pub const FuncGen = struct {
|
||||
const inst_ty = self.air.typeOfIndex(inst);
|
||||
const ok_err_code = self.context.intType(16).constNull();
|
||||
const err_un_llvm_ty = try self.dg.llvmType(inst_ty);
|
||||
|
||||
const target = self.dg.module.getTarget();
|
||||
const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
|
||||
if (isByRef(inst_ty)) {
|
||||
const result_ptr = self.buildAlloca(err_un_llvm_ty);
|
||||
const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
|
||||
_ = self.builder.buildStore(ok_err_code, err_ptr);
|
||||
const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, "");
|
||||
const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
|
||||
var ptr_ty_payload: Type.Payload.ElemType = .{
|
||||
.base = .{ .tag = .single_mut_pointer },
|
||||
.data = payload_ty,
|
||||
@ -4956,7 +4999,7 @@ pub const FuncGen = struct {
|
||||
}
|
||||
|
||||
const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, "");
|
||||
return self.builder.buildInsertValue(partial, operand, 1, "");
|
||||
return self.builder.buildInsertValue(partial, operand, payload_offset, "");
|
||||
}
|
||||
|
||||
fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
@ -4970,11 +5013,14 @@ pub const FuncGen = struct {
|
||||
return operand;
|
||||
}
|
||||
const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
|
||||
|
||||
const target = self.dg.module.getTarget();
|
||||
const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
|
||||
if (isByRef(err_un_ty)) {
|
||||
const result_ptr = self.buildAlloca(err_un_llvm_ty);
|
||||
const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
|
||||
_ = self.builder.buildStore(operand, err_ptr);
|
||||
const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, "");
|
||||
const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
|
||||
var ptr_ty_payload: Type.Payload.ElemType = .{
|
||||
.base = .{ .tag = .single_mut_pointer },
|
||||
.data = payload_ty,
|
||||
|
@ -644,3 +644,21 @@ test "coerce error set to the current inferred error set" {
|
||||
};
|
||||
S.foo() catch {};
|
||||
}
|
||||
|
||||
test "error union payload is properly aligned" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
a: u128,
|
||||
b: u128,
|
||||
c: u128,
|
||||
fn foo() error{}!@This() {
|
||||
return @This(){ .a = 1, .b = 2, .c = 3 };
|
||||
}
|
||||
};
|
||||
const blk = S.foo() catch unreachable;
|
||||
if (blk.a != 1) unreachable;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user