Skip to content

Commit 961b05f

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 0e26c61 commit 961b05f

File tree

1 file changed

+82
-13
lines changed

1 file changed

+82
-13
lines changed

src/codegen/llvm.zig

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

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

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

58005800
fn airErrUnionPayload(
@@ -7345,10 +7345,8 @@ pub const FuncGen = struct {
73457345
return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
73467346
}
73477347

7348-
const optional_llvm_ty = try self.dg.lowerType(optional_ty);
73497348
const non_null_bit = self.builder.buildNot(success_bit, "");
7350-
const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
7351-
return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
7349+
return buildOptional(self, optional_ty, payload, non_null_bit);
73527350
}
73537351

73547352
fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -7512,11 +7510,13 @@ pub const FuncGen = struct {
75127510
const union_ptr = try self.resolveInst(bin_op.lhs);
75137511
const new_tag = try self.resolveInst(bin_op.rhs);
75147512
if (layout.payload_size == 0) {
7513+
// TODO alignment on this store
75157514
_ = self.builder.buildStore(new_tag, union_ptr);
75167515
return null;
75177516
}
75187517
const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
75197518
const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, "");
7519+
// TODO alignment on this store
75207520
_ = self.builder.buildStore(new_tag, tag_field_ptr);
75217521
return null;
75227522
}
@@ -8347,18 +8347,76 @@ pub const FuncGen = struct {
83478347
}
83488348

83498349
/// Assumes the optional is not pointer-like and payload has bits.
8350-
fn optPayloadHandle(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
8351-
if (is_by_ref) {
8350+
fn optPayloadHandle(
8351+
fg: *FuncGen,
8352+
opt_handle: *const llvm.Value,
8353+
opt_ty: Type,
8354+
) *const llvm.Value {
8355+
var buf: Type.Payload.ElemType = undefined;
8356+
const payload_ty = opt_ty.optionalChild(&buf);
8357+
8358+
if (isByRef(opt_ty)) {
83528359
// We have a pointer and we need to return a pointer to the first field.
8353-
const index_type = self.context.intType(32);
8360+
const index_type = fg.context.intType(32);
83548361
const indices: [2]*const llvm.Value = .{
83558362
index_type.constNull(), // dereference the pointer
83568363
index_type.constNull(), // first field is the payload
83578364
};
8358-
return self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, "");
8365+
const payload_ptr = fg.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, "");
8366+
8367+
if (isByRef(payload_ty)) {
8368+
return payload_ptr;
8369+
}
8370+
const target = fg.dg.module.getTarget();
8371+
const payload_alignment = payload_ty.abiAlignment(target);
8372+
const load_inst = fg.builder.buildLoad(payload_ptr, "");
8373+
load_inst.setAlignment(payload_alignment);
8374+
return load_inst;
8375+
}
8376+
8377+
assert(!isByRef(payload_ty));
8378+
return fg.builder.buildExtractValue(opt_handle, 0, "");
8379+
}
8380+
8381+
fn buildOptional(
8382+
self: *FuncGen,
8383+
optional_ty: Type,
8384+
payload: *const llvm.Value,
8385+
non_null_bit: *const llvm.Value,
8386+
) !?*const llvm.Value {
8387+
const optional_llvm_ty = try self.dg.lowerType(optional_ty);
8388+
8389+
if (isByRef(optional_ty)) {
8390+
const target = self.dg.module.getTarget();
8391+
const alloca_inst = self.buildAlloca(optional_llvm_ty);
8392+
const payload_alignment = optional_ty.abiAlignment(target);
8393+
alloca_inst.setAlignment(payload_alignment);
8394+
8395+
const index_type = self.context.intType(32);
8396+
{
8397+
const indices: [2]*const llvm.Value = .{
8398+
index_type.constNull(), // dereference the pointer
8399+
index_type.constNull(), // first field is the payload
8400+
};
8401+
const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
8402+
const store_inst = self.builder.buildStore(payload, field_ptr);
8403+
store_inst.setAlignment(payload_alignment);
8404+
}
8405+
{
8406+
const indices: [2]*const llvm.Value = .{
8407+
index_type.constNull(), // dereference the pointer
8408+
index_type.constInt(1, .False), // second field is the non-null bit
8409+
};
8410+
const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
8411+
const store_inst = self.builder.buildStore(non_null_bit, field_ptr);
8412+
store_inst.setAlignment(1);
8413+
}
8414+
8415+
return alloca_inst;
83598416
}
83608417

8361-
return self.builder.buildExtractValue(opt_handle, 0, "");
8418+
const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
8419+
return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
83628420
}
83638421

83648422
fn fieldPtr(
@@ -9327,7 +9385,18 @@ fn isByRef(ty: Type) bool {
93279385
.ErrorUnion => return isByRef(ty.errorUnionPayload()),
93289386
.Optional => {
93299387
var buf: Type.Payload.ElemType = undefined;
9330-
return isByRef(ty.optionalChild(&buf));
9388+
const payload_ty = ty.optionalChild(&buf);
9389+
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
9390+
return false;
9391+
}
9392+
if (ty.optionalReprIsPayload()) {
9393+
return false;
9394+
}
9395+
return true;
9396+
// TODO we actually want this logic:
9397+
// however it is tripping an LLVM 14 regression:
9398+
// https://github.com/llvm/llvm-project/issues/56585
9399+
//return isByRef(payload_ty);
93319400
},
93329401
}
93339402
}

0 commit comments

Comments
 (0)