authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-14 20:05:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-14 22:26:11-07:00
log9c136be78fcc44d4dd4902605de6af14358c67a3
tree5861223079650e79cd5015fc1f616b86be2b763f
parent070e3ea37dd51c2a2080941a056c455f70232148

LLVM: add padding to optional types when lowering

If the LLVM ABI size does not agree with the Zig ABI size.

1 files changed, 31 insertions(+), 11 deletions(-)

src/codegen/llvm.zig+31-11
...@@ -2537,10 +2537,22 @@ pub const DeclGen = struct {...@@ -2537,10 +2537,22 @@ pub const DeclGen = struct {
2537 return payload_llvm_ty;2537 return payload_llvm_ty;
2538 }2538 }
25392539
2540 comptime assert(optional_layout_version == 1);
2540 const fields: [2]*const llvm.Type = .{2541 const fields: [2]*const llvm.Type = .{
2541 payload_llvm_ty, dg.context.intType(1),2542 payload_llvm_ty,
2543 dg.context.intType(1),
2542 };2544 };
2543 return dg.context.structType(&fields, fields.len, .False);2545 const llvm_ty = dg.context.structType(&fields, fields.len, .False);
2546 const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty);
2547 const zig_size = t.abiSize(target);
2548 const padding = @intCast(c_uint, zig_size - llvm_size);
2549 if (padding == 0) return llvm_ty;
2550 const padded_fields: [3]*const llvm.Type = .{
2551 payload_llvm_ty,
2552 dg.context.intType(1),
2553 dg.context.intType(8).arrayType(padding),
2554 };
2555 return dg.context.structType(&padded_fields, padded_fields.len, .False);
2544 },2556 },
2545 .ErrorUnion => {2557 .ErrorUnion => {
2546 const payload_ty = t.errorUnionPayload();2558 const payload_ty = t.errorUnionPayload();
...@@ -3101,6 +3113,7 @@ pub const DeclGen = struct {...@@ -3101,6 +3113,7 @@ pub const DeclGen = struct {
3101 else => unreachable,3113 else => unreachable,
3102 },3114 },
3103 .Optional => {3115 .Optional => {
3116 comptime assert(optional_layout_version == 1);
3104 var buf: Type.Payload.ElemType = undefined;3117 var buf: Type.Payload.ElemType = undefined;
3105 const payload_ty = tv.ty.optionalChild(&buf);3118 const payload_ty = tv.ty.optionalChild(&buf);
3106 const llvm_i1 = dg.context.intType(1);3119 const llvm_i1 = dg.context.intType(1);
...@@ -3109,25 +3122,30 @@ pub const DeclGen = struct {...@@ -3109,25 +3122,30 @@ pub const DeclGen = struct {
3109 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3122 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3110 return non_null_bit;3123 return non_null_bit;
3111 }3124 }
3125 const llvm_ty = try dg.lowerType(tv.ty);
3112 if (tv.ty.optionalReprIsPayload()) {3126 if (tv.ty.optionalReprIsPayload()) {
3113 if (tv.val.castTag(.opt_payload)) |payload| {3127 if (tv.val.castTag(.opt_payload)) |payload| {
3114 return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });3128 return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });
3115 } else if (is_pl) {3129 } else if (is_pl) {
3116 return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });3130 return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });
3117 } else {3131 } else {
3118 const llvm_ty = try dg.lowerType(tv.ty);
3119 return llvm_ty.constNull();3132 return llvm_ty.constNull();
3120 }3133 }
3121 }3134 }
3122 assert(payload_ty.zigTypeTag() != .Fn);3135 assert(payload_ty.zigTypeTag() != .Fn);
3123 const fields: [2]*const llvm.Value = .{3136
3124 try dg.lowerValue(.{3137 const llvm_field_count = llvm_ty.countStructElementTypes();
3125 .ty = payload_ty,3138 var fields_buf: [3]*const llvm.Value = undefined;
3126 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),3139 fields_buf[0] = try dg.lowerValue(.{
3127 }),3140 .ty = payload_ty,
3128 non_null_bit,3141 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
3129 };3142 });
3130 return dg.context.constStruct(&fields, fields.len, .False);3143 fields_buf[1] = non_null_bit;
3144 if (llvm_field_count > 2) {
3145 assert(llvm_field_count == 3);
3146 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
3147 }
3148 return dg.context.constStruct(&fields_buf, llvm_field_count, .False);
3131 },3149 },
3132 .Fn => {3150 .Fn => {
3133 const fn_decl_index = switch (tv.val.tag()) {3151 const fn_decl_index = switch (tv.val.tag()) {
...@@ -5865,6 +5883,7 @@ pub const FuncGen = struct {...@@ -5865,6 +5883,7 @@ pub const FuncGen = struct {
5865 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5883 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5866 const payload_ty = self.air.typeOf(ty_op.operand);5884 const payload_ty = self.air.typeOf(ty_op.operand);
5867 const non_null_bit = self.context.intType(1).constAllOnes();5885 const non_null_bit = self.context.intType(1).constAllOnes();
5886 comptime assert(optional_layout_version == 1);
5868 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;5887 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;
5869 const operand = try self.resolveInst(ty_op.operand);5888 const operand = try self.resolveInst(ty_op.operand);
5870 const optional_ty = self.air.typeOfIndex(inst);5889 const optional_ty = self.air.typeOfIndex(inst);
...@@ -9318,6 +9337,7 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {...@@ -9318,6 +9337,7 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
9318/// We can do this because for all types, Zig ABI alignment >= LLVM ABI9337/// We can do this because for all types, Zig ABI alignment >= LLVM ABI
9319/// alignment.9338/// alignment.
9320const struct_layout_version = 2;9339const struct_layout_version = 2;
9340const optional_layout_version = 1;
93219341
9322/// We use the least significant bit of the pointer address to tell us9342/// We use the least significant bit of the pointer address to tell us
9323/// whether the type is fully resolved. Types that are only fwd declared9343/// whether the type is fully resolved. Types that are only fwd declared