authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-18 19:55:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 11:22:48-07:00
log65bc4d915daf33255f16a1586e69040fd9148e87
tree88d1e068ffdb2b210e5e9fa224c670bea21c0139
parentc26d9f6287154774bea6dcea1cea4d1cafaed45c

LLVM: lower optional types as byref=true

This is a possible workaround for https://github.com/llvm/llvm-project/issues/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 files changed, 84 insertions(+), 14 deletions(-)

src/codegen/llvm.zig+84-14
...@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {...@@ -4539,7 +4539,7 @@ pub const FuncGen = struct {
4539 }4539 }
4540 // We need to emit instructions to check for equality/inequality4540 // We need to emit instructions to check for equality/inequality
4541 // of optionals that are not pointers.4541 // of optionals that are not pointers.
4542 const is_by_ref = isByRef(operand_ty);4542 const is_by_ref = isByRef(scalar_ty);
4543 const lhs_non_null = self.optIsNonNull(lhs, is_by_ref);4543 const lhs_non_null = self.optIsNonNull(lhs, is_by_ref);
4544 const rhs_non_null = self.optIsNonNull(rhs, is_by_ref);4544 const rhs_non_null = self.optIsNonNull(rhs, is_by_ref);
4545 const llvm_i2 = self.context.intType(2);4545 const llvm_i2 = self.context.intType(2);
...@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {...@@ -4564,8 +4564,8 @@ pub const FuncGen = struct {
4564 _ = self.builder.buildBr(end_block);4564 _ = self.builder.buildBr(end_block);
45654565
4566 self.builder.positionBuilderAtEnd(both_pl_block);4566 self.builder.positionBuilderAtEnd(both_pl_block);
4567 const lhs_payload = self.optPayloadHandle(lhs, is_by_ref);4567 const lhs_payload = self.optPayloadHandle(lhs, scalar_ty);
4568 const rhs_payload = self.optPayloadHandle(rhs, is_by_ref);4568 const rhs_payload = self.optPayloadHandle(rhs, scalar_ty);
4569 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);4569 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
4570 _ = self.builder.buildBr(end_block);4570 _ = self.builder.buildBr(end_block);
4571 const both_pl_block_end = self.builder.getInsertBlock();4571 const both_pl_block_end = self.builder.getInsertBlock();
...@@ -5795,7 +5795,7 @@ pub const FuncGen = struct {...@@ -5795,7 +5795,7 @@ pub const FuncGen = struct {
5795 return operand;5795 return operand;
5796 }5796 }
57975797
5798 return self.optPayloadHandle(operand, isByRef(payload_ty));5798 return self.optPayloadHandle(operand, optional_ty);
5799 }5799 }
58005800
5801 fn airErrUnionPayload(5801 fn airErrUnionPayload(
...@@ -7347,11 +7347,9 @@ pub const FuncGen = struct {...@@ -7347,11 +7347,9 @@ pub const FuncGen = struct {
7347 }7347 }
73487348
7349 comptime assert(optional_layout_version == 3);7349 comptime assert(optional_layout_version == 3);
7350 const optional_llvm_ty = try self.dg.lowerType(optional_ty);7350
7351 const non_null_bit = self.builder.buildNot(success_bit, "");7351 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), "");7352 return buildOptional(self, optional_ty, payload, non_null_bit);
7353 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
7354 return self.builder.buildInsertValue(partial, non_null_field, 1, "");
7355 }7353 }
73567354
7357 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {7355 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -7515,11 +7513,13 @@ pub const FuncGen = struct {...@@ -7515,11 +7513,13 @@ pub const FuncGen = struct {
7515 const union_ptr = try self.resolveInst(bin_op.lhs);7513 const union_ptr = try self.resolveInst(bin_op.lhs);
7516 const new_tag = try self.resolveInst(bin_op.rhs);7514 const new_tag = try self.resolveInst(bin_op.rhs);
7517 if (layout.payload_size == 0) {7515 if (layout.payload_size == 0) {
7516 // TODO alignment on this store
7518 _ = self.builder.buildStore(new_tag, union_ptr);7517 _ = self.builder.buildStore(new_tag, union_ptr);
7519 return null;7518 return null;
7520 }7519 }
7521 const tag_index = @boolToInt(layout.tag_align < layout.payload_align);7520 const tag_index = @boolToInt(layout.tag_align < layout.payload_align);
7522 const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, "");7521 const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, "");
7522 // TODO alignment on this store
7523 _ = self.builder.buildStore(new_tag, tag_field_ptr);7523 _ = self.builder.buildStore(new_tag, tag_field_ptr);
7524 return null;7524 return null;
7525 }7525 }
...@@ -8355,18 +8355,77 @@ pub const FuncGen = struct {...@@ -8355,18 +8355,77 @@ pub const FuncGen = struct {
8355 }8355 }
83568356
8357 /// Assumes the optional is not pointer-like and payload has bits.8357 /// 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 {8358 fn optPayloadHandle(
8359 if (is_by_ref) {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)) {
8360 // We have a pointer and we need to return a pointer to the first field.8367 // 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);
8362 const indices: [2]*const llvm.Value = .{8369 const indices: [2]*const llvm.Value = .{
8363 index_type.constNull(), // dereference the pointer8370 index_type.constNull(), // dereference the pointer
8364 index_type.constNull(), // first field is the payload8371 index_type.constNull(), // first field is the payload
8365 };8372 };
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;
8367 }8425 }
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, "");
8370 }8429 }
83718430
8372 fn fieldPtr(8431 fn fieldPtr(
...@@ -9335,7 +9394,18 @@ fn isByRef(ty: Type) bool {...@@ -9335,7 +9394,18 @@ fn isByRef(ty: Type) bool {
9335 .ErrorUnion => return isByRef(ty.errorUnionPayload()),9394 .ErrorUnion => return isByRef(ty.errorUnionPayload()),
9336 .Optional => {9395 .Optional => {
9337 var buf: Type.Payload.ElemType = undefined;9396 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);
9339 },9409 },
9340 }9410 }
9341}9411}