Skip to content

Commit 65bc4d9

Browse files
committed
LLVM: lower optional types as byref=true
This is a possible workaround for llvm/llvm-project#56585 On my computer it makes stage3-release go from false positive compilation errors on the behavior tests to "segmentation fault". Is this forwards progress or backwards progress? I have no idea. See #11450
1 parent c26d9f6 commit 65bc4d9

File tree

1 file changed

+84
-14
lines changed

1 file changed

+84
-14
lines changed

src/codegen/llvm.zig

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {
45394539
}
45404540
// We need to emit instructions to check for equality/inequality
45414541
// of optionals that are not pointers.
4542-
const is_by_ref = isByRef(operand_ty);
4542+
const is_by_ref = isByRef(scalar_ty);
45434543
const lhs_non_null = self.optIsNonNull(lhs, is_by_ref);
45444544
const rhs_non_null = self.optIsNonNull(rhs, is_by_ref);
45454545
const llvm_i2 = self.context.intType(2);
@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {
45644564
_ = self.builder.buildBr(end_block);
45654565

45664566
self.builder.positionBuilderAtEnd(both_pl_block);
4567-
const lhs_payload = self.optPayloadHandle(lhs, is_by_ref);
4568-
const rhs_payload = self.optPayloadHandle(rhs, is_by_ref);
4567+
const lhs_payload = self.optPayloadHandle(lhs, scalar_ty);
4568+
const rhs_payload = self.optPayloadHandle(rhs, scalar_ty);
45694569
const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
45704570
_ = self.builder.buildBr(end_block);
45714571
const both_pl_block_end = self.builder.getInsertBlock();
@@ -5795,7 +5795,7 @@ pub const FuncGen = struct {
57955795
return operand;
57965796
}
57975797

5798-
return self.optPayloadHandle(operand, isByRef(payload_ty));
5798+
return self.optPayloadHandle(operand, optional_ty);
57995799
}
58005800

58015801
fn airErrUnionPayload(
@@ -7347,11 +7347,9 @@ pub const FuncGen = struct {
73477347
}
73487348

73497349
comptime assert(optional_layout_version == 3);
7350-
const optional_llvm_ty = try self.dg.lowerType(optional_ty);
7350+
73517351
const non_null_bit = self.builder.buildNot(success_bit, "");
7352-
const non_null_field = self.builder.buildZExt(non_null_bit, self.dg.context.intType(8), "");
7353-
const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
7354-
return self.builder.buildInsertValue(partial, non_null_field, 1, "");
7352+
return buildOptional(self, optional_ty, payload, non_null_bit);
73557353
}
73567354

73577355
fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -7515,11 +7513,13 @@ pub const FuncGen = struct {
75157513
const union_ptr = try self.resolveInst(bin_op.lhs);
75167514
const new_tag = try self.resolveInst(bin_op.rhs);
75177515
if (layout.payload_size == 0) {
7516+
// TODO alignment on this store
75187517
_ = self.builder.buildStore(new_tag, union_ptr);
75197518
return null;
75207519
}
75217520
const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
75227521
const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, "");
7522+
// TODO alignment on this store
75237523
_ = self.builder.buildStore(new_tag, tag_field_ptr);
75247524
return null;
75257525
}
@@ -8355,18 +8355,77 @@ pub const FuncGen = struct {
83558355
}
83568356

83578357
/// Assumes the optional is not pointer-like and payload has bits.
8358-
fn optPayloadHandle(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
8359-
if (is_by_ref) {
8358+
fn optPayloadHandle(
8359+
fg: *FuncGen,
8360+
opt_handle: *const llvm.Value,
8361+
opt_ty: Type,
8362+
) *const llvm.Value {
8363+
var buf: Type.Payload.ElemType = undefined;
8364+
const payload_ty = opt_ty.optionalChild(&buf);
8365+
8366+
if (isByRef(opt_ty)) {
83608367
// We have a pointer and we need to return a pointer to the first field.
8361-
const index_type = self.context.intType(32);
8368+
const index_type = fg.context.intType(32);
83628369
const indices: [2]*const llvm.Value = .{
83638370
index_type.constNull(), // dereference the pointer
83648371
index_type.constNull(), // first field is the payload
83658372
};
8366-
return self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, "");
8373+
const payload_ptr = fg.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, "");
8374+
8375+
if (isByRef(payload_ty)) {
8376+
return payload_ptr;
8377+
}
8378+
const target = fg.dg.module.getTarget();
8379+
const payload_alignment = payload_ty.abiAlignment(target);
8380+
const load_inst = fg.builder.buildLoad(payload_ptr, "");
8381+
load_inst.setAlignment(payload_alignment);
8382+
return load_inst;
8383+
}
8384+
8385+
assert(!isByRef(payload_ty));
8386+
return fg.builder.buildExtractValue(opt_handle, 0, "");
8387+
}
8388+
8389+
fn buildOptional(
8390+
self: *FuncGen,
8391+
optional_ty: Type,
8392+
payload: *const llvm.Value,
8393+
non_null_bit: *const llvm.Value,
8394+
) !?*const llvm.Value {
8395+
const optional_llvm_ty = try self.dg.lowerType(optional_ty);
8396+
const non_null_field = self.builder.buildZExt(non_null_bit, self.dg.context.intType(8), "");
8397+
8398+
if (isByRef(optional_ty)) {
8399+
const target = self.dg.module.getTarget();
8400+
const alloca_inst = self.buildAlloca(optional_llvm_ty);
8401+
const payload_alignment = optional_ty.abiAlignment(target);
8402+
alloca_inst.setAlignment(payload_alignment);
8403+
8404+
const index_type = self.context.intType(32);
8405+
{
8406+
const indices: [2]*const llvm.Value = .{
8407+
index_type.constNull(), // dereference the pointer
8408+
index_type.constNull(), // first field is the payload
8409+
};
8410+
const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
8411+
const store_inst = self.builder.buildStore(payload, field_ptr);
8412+
store_inst.setAlignment(payload_alignment);
8413+
}
8414+
{
8415+
const indices: [2]*const llvm.Value = .{
8416+
index_type.constNull(), // dereference the pointer
8417+
index_type.constInt(1, .False), // second field is the non-null bit
8418+
};
8419+
const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
8420+
const store_inst = self.builder.buildStore(non_null_field, field_ptr);
8421+
store_inst.setAlignment(1);
8422+
}
8423+
8424+
return alloca_inst;
83678425
}
83688426

8369-
return self.builder.buildExtractValue(opt_handle, 0, "");
8427+
const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
8428+
return self.builder.buildInsertValue(partial, non_null_field, 1, "");
83708429
}
83718430

83728431
fn fieldPtr(
@@ -9335,7 +9394,18 @@ fn isByRef(ty: Type) bool {
93359394
.ErrorUnion => return isByRef(ty.errorUnionPayload()),
93369395
.Optional => {
93379396
var buf: Type.Payload.ElemType = undefined;
9338-
return isByRef(ty.optionalChild(&buf));
9397+
const payload_ty = ty.optionalChild(&buf);
9398+
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
9399+
return false;
9400+
}
9401+
if (ty.optionalReprIsPayload()) {
9402+
return false;
9403+
}
9404+
return true;
9405+
// TODO we actually want this logic:
9406+
// however it is tripping an LLVM 14 regression:
9407+
// https://github.com/llvm/llvm-project/issues/56585
9408+
//return isByRef(payload_ty);
93399409
},
93409410
}
93419411
}

0 commit comments

Comments
 (0)