authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-22 23:35:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-22 23:35:46-07:00
log6aeb6bcc84f48fdc88374fa4a3d5a2b9d0bd147e
treed470bb4aff252454118b418f007c005ac755f14f
parentd97928bf52a217f75c359ae9b1513bd9d42c82d3

stage2: LLVM backend: fix optional_payload instructions

They previously did not respect the optional type layout, but now they do.

1 files changed, 42 insertions(+), 22 deletions(-)

src/codegen/llvm.zig+42-22
...@@ -1770,8 +1770,8 @@ pub const FuncGen = struct {...@@ -1770,8 +1770,8 @@ pub const FuncGen = struct {
1770 .ptr_elem_val => try self.airPtrElemVal(inst),1770 .ptr_elem_val => try self.airPtrElemVal(inst),
1771 .ptr_elem_ptr => try self.airPtrElemPtr(inst),1771 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
17721772
1773 .optional_payload => try self.airOptionalPayload(inst, false),1773 .optional_payload => try self.airOptionalPayload(inst),
1774 .optional_payload_ptr => try self.airOptionalPayload(inst, true),1774 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
17751775
1776 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),1776 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
1777 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),1777 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
...@@ -2520,35 +2520,55 @@ pub const FuncGen = struct {...@@ -2520,35 +2520,55 @@ pub const FuncGen = struct {
2520 return self.builder.buildICmp(op, loaded, zero, "");2520 return self.builder.buildICmp(op, loaded, zero, "");
2521 }2521 }
25222522
2523 fn airOptionalPayload(2523 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2524 self: *FuncGen,2524 if (self.liveness.isUnused(inst)) return null;
2525 inst: Air.Inst.Index,
2526 operand_is_ptr: bool,
2527 ) !?*const llvm.Value {
2528 if (self.liveness.isUnused(inst))
2529 return null;
25302525
2531 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2526 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2532 const operand = try self.resolveInst(ty_op.operand);2527 const operand = try self.resolveInst(ty_op.operand);
2528 const optional_ty = self.air.typeOf(ty_op.operand).childType();
2529 var buf: Type.Payload.ElemType = undefined;
2530 const payload_ty = optional_ty.optionalChild(&buf);
2531 if (!payload_ty.hasCodeGenBits()) {
2532 // We have a pointer to a zero-bit value and we need to return
2533 // a pointer to a zero-bit value.
2534 return operand;
2535 }
2536 if (optional_ty.isPtrLikeOptional()) {
2537 // The payload and the optional are the same value.
2538 return operand;
2539 }
2540 const index_type = self.context.intType(32);
2541 const indices: [2]*const llvm.Value = .{
2542 index_type.constNull(), // dereference the pointer
2543 index_type.constNull(), // first field is the payload
2544 };
2545 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
2546 }
25332547
2534 if (operand_is_ptr) {2548 fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2535 const operand_ty = self.air.typeOf(ty_op.operand).elemType();2549 if (self.liveness.isUnused(inst)) return null;
2536 if (operand_ty.isPtrLikeOptional()) {
2537 return self.builder.buildLoad(operand, "");
2538 }
25392550
2540 const index_type = self.context.intType(32);2551 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2541 var indices: [2]*const llvm.Value = .{2552 const operand = try self.resolveInst(ty_op.operand);
2542 index_type.constNull(), index_type.constNull(),2553 const optional_ty = self.air.typeOf(ty_op.operand);
2543 };2554 const payload_ty = self.air.typeOfIndex(inst);
2544 return self.builder.buildInBoundsGEP(operand, &indices, 2, "");2555 if (!payload_ty.hasCodeGenBits()) return null;
2545 }
25462556
2547 const operand_ty = self.air.typeOf(ty_op.operand);2557 if (optional_ty.isPtrLikeOptional()) {
2548 if (operand_ty.isPtrLikeOptional()) {2558 // Payload value is the same as the optional value.
2549 return operand;2559 return operand;
2550 }2560 }
25512561
2562 if (isByRef(payload_ty)) {
2563 // We have a pointer and we need to return a pointer to the first field.
2564 const index_type = self.context.intType(32);
2565 const indices: [2]*const llvm.Value = .{
2566 index_type.constNull(), // dereference the pointer
2567 index_type.constNull(), // first field is the payload
2568 };
2569 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
2570 }
2571
2552 return self.builder.buildExtractValue(operand, 0, "");2572 return self.builder.buildExtractValue(operand, 0, "");
2553 }2573 }
25542574