| ... | ... | @@ -4568,14 +4568,14 @@ pub const FuncGen = struct { |
| 4568 | 4568 | .ret_addr => try self.airRetAddr(inst), |
| 4569 | 4569 | .frame_addr => try self.airFrameAddress(inst), |
| 4570 | 4570 | .cond_br => try self.airCondBr(inst), |
| 4571 | | .@"try" => try self.airTry(inst), |
| 4571 | .@"try" => try self.airTry(body[i..]), |
| 4572 | 4572 | .try_ptr => try self.airTryPtr(inst), |
| 4573 | 4573 | .intcast => try self.airIntCast(inst), |
| 4574 | 4574 | .trunc => try self.airTrunc(inst), |
| 4575 | 4575 | .fptrunc => try self.airFptrunc(inst), |
| 4576 | 4576 | .fpext => try self.airFpext(inst), |
| 4577 | 4577 | .ptrtoint => try self.airPtrToInt(inst), |
| 4578 | | .load => try self.airLoad(inst, body, i + 1), |
| 4578 | .load => try self.airLoad(body[i..]), |
| 4579 | 4579 | .loop => try self.airLoop(inst), |
| 4580 | 4580 | .not => try self.airNot(inst), |
| 4581 | 4581 | .ret => try self.airRet(inst), |
| ... | ... | @@ -4634,7 +4634,7 @@ pub const FuncGen = struct { |
| 4634 | 4634 | .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent), |
| 4635 | 4635 | |
| 4636 | 4636 | .struct_field_ptr => try self.airStructFieldPtr(inst), |
| 4637 | | .struct_field_val => try self.airStructFieldVal(inst), |
| 4637 | .struct_field_val => try self.airStructFieldVal(body[i..]), |
| 4638 | 4638 | |
| 4639 | 4639 | .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0), |
| 4640 | 4640 | .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1), |
| ... | ... | @@ -4643,18 +4643,18 @@ pub const FuncGen = struct { |
| 4643 | 4643 | |
| 4644 | 4644 | .field_parent_ptr => try self.airFieldParentPtr(inst), |
| 4645 | 4645 | |
| 4646 | | .array_elem_val => try self.airArrayElemVal(inst), |
| 4647 | | .slice_elem_val => try self.airSliceElemVal(inst), |
| 4646 | .array_elem_val => try self.airArrayElemVal(body[i..]), |
| 4647 | .slice_elem_val => try self.airSliceElemVal(body[i..]), |
| 4648 | 4648 | .slice_elem_ptr => try self.airSliceElemPtr(inst), |
| 4649 | | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 4649 | .ptr_elem_val => try self.airPtrElemVal(body[i..]), |
| 4650 | 4650 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 4651 | 4651 | |
| 4652 | | .optional_payload => try self.airOptionalPayload(inst), |
| 4652 | .optional_payload => try self.airOptionalPayload(body[i..]), |
| 4653 | 4653 | .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), |
| 4654 | 4654 | .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), |
| 4655 | 4655 | |
| 4656 | | .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false), |
| 4657 | | .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true), |
| 4656 | .unwrap_errunion_payload => try self.airErrUnionPayload(body[i..], false), |
| 4657 | .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(body[i..], true), |
| 4658 | 4658 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), |
| 4659 | 4659 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), |
| 4660 | 4660 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), |
| ... | ... | @@ -5159,8 +5159,8 @@ pub const FuncGen = struct { |
| 5159 | 5159 | _ = self.builder.buildBr(end_block); |
| 5160 | 5160 | |
| 5161 | 5161 | self.builder.positionBuilderAtEnd(both_pl_block); |
| 5162 | | const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty); |
| 5163 | | const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty); |
| 5162 | const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true); |
| 5163 | const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true); |
| 5164 | 5164 | const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op); |
| 5165 | 5165 | _ = self.builder.buildBr(end_block); |
| 5166 | 5166 | const both_pl_block_end = self.builder.getInsertBlock(); |
| ... | ... | @@ -5305,14 +5305,16 @@ pub const FuncGen = struct { |
| 5305 | 5305 | return null; |
| 5306 | 5306 | } |
| 5307 | 5307 | |
| 5308 | | fn airTry(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5308 | fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5309 | const inst = body_tail[0]; |
| 5309 | 5310 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5310 | 5311 | const err_union = try self.resolveInst(pl_op.operand); |
| 5311 | 5312 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 5312 | 5313 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5313 | 5314 | const err_union_ty = self.air.typeOf(pl_op.operand); |
| 5314 | | const result_ty = self.air.typeOfIndex(inst); |
| 5315 | | return lowerTry(self, err_union, body, err_union_ty, false, result_ty); |
| 5315 | const payload_ty = self.air.typeOfIndex(inst); |
| 5316 | const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false; |
| 5317 | return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, payload_ty); |
| 5316 | 5318 | } |
| 5317 | 5319 | |
| 5318 | 5320 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -5321,8 +5323,8 @@ pub const FuncGen = struct { |
| 5321 | 5323 | const err_union_ptr = try self.resolveInst(extra.data.ptr); |
| 5322 | 5324 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5323 | 5325 | const err_union_ty = self.air.typeOf(extra.data.ptr).childType(); |
| 5324 | | const result_ty = self.air.typeOfIndex(inst); |
| 5325 | | return lowerTry(self, err_union_ptr, body, err_union_ty, true, result_ty); |
| 5326 | const payload_ty = self.air.typeOfIndex(inst); |
| 5327 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, payload_ty); |
| 5326 | 5328 | } |
| 5327 | 5329 | |
| 5328 | 5330 | fn lowerTry( |
| ... | ... | @@ -5331,6 +5333,7 @@ pub const FuncGen = struct { |
| 5331 | 5333 | body: []const Air.Inst.Index, |
| 5332 | 5334 | err_union_ty: Type, |
| 5333 | 5335 | operand_is_ptr: bool, |
| 5336 | can_elide_load: bool, |
| 5334 | 5337 | result_ty: Type, |
| 5335 | 5338 | ) !?*llvm.Value { |
| 5336 | 5339 | const payload_ty = err_union_ty.errorUnionPayload(); |
| ... | ... | @@ -5379,12 +5382,15 @@ pub const FuncGen = struct { |
| 5379 | 5382 | return fg.builder.buildBitCast(err_union, res_ptr_ty, ""); |
| 5380 | 5383 | } |
| 5381 | 5384 | const offset = errUnionPayloadOffset(payload_ty, target); |
| 5382 | | if (operand_is_ptr or isByRef(payload_ty)) { |
| 5385 | if (operand_is_ptr) { |
| 5383 | 5386 | return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); |
| 5384 | 5387 | } else if (isByRef(err_union_ty)) { |
| 5385 | 5388 | const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); |
| 5386 | 5389 | if (isByRef(payload_ty)) { |
| 5387 | | return payload_ptr; |
| 5390 | if (can_elide_load) |
| 5391 | return payload_ptr; |
| 5392 | |
| 5393 | return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false); |
| 5388 | 5394 | } |
| 5389 | 5395 | const load_inst = fg.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, ""); |
| 5390 | 5396 | load_inst.setAlignment(payload_ty.abiAlignment(target)); |
| ... | ... | @@ -5625,14 +5631,16 @@ pub const FuncGen = struct { |
| 5625 | 5631 | return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, ""); |
| 5626 | 5632 | } |
| 5627 | 5633 | |
| 5628 | | fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5634 | fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5635 | const inst = body_tail[0]; |
| 5629 | 5636 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5630 | 5637 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 5631 | 5638 | if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; |
| 5632 | 5639 | |
| 5633 | 5640 | const slice = try self.resolveInst(bin_op.lhs); |
| 5634 | 5641 | const index = try self.resolveInst(bin_op.rhs); |
| 5635 | | const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType()); |
| 5642 | const elem_ty = slice_ty.childType(); |
| 5643 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5636 | 5644 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); |
| 5637 | 5645 | const indices: [1]*llvm.Value = .{index}; |
| 5638 | 5646 | const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| ... | ... | @@ -5653,7 +5661,8 @@ pub const FuncGen = struct { |
| 5653 | 5661 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 5654 | 5662 | } |
| 5655 | 5663 | |
| 5656 | | fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5664 | fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5665 | const inst = body_tail[0]; |
| 5657 | 5666 | if (self.liveness.isUnused(inst)) return null; |
| 5658 | 5667 | |
| 5659 | 5668 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| ... | ... | @@ -5666,7 +5675,11 @@ pub const FuncGen = struct { |
| 5666 | 5675 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); |
| 5667 | 5676 | const elem_ty = array_ty.childType(); |
| 5668 | 5677 | if (isByRef(elem_ty)) { |
| 5669 | | return elem_ptr; |
| 5678 | if (canElideLoad(self, body_tail)) |
| 5679 | return elem_ptr; |
| 5680 | |
| 5681 | const target = self.dg.module.getTarget(); |
| 5682 | return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(target), false); |
| 5670 | 5683 | } else { |
| 5671 | 5684 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| 5672 | 5685 | return self.builder.buildLoad(elem_llvm_ty, elem_ptr, ""); |
| ... | ... | @@ -5677,12 +5690,14 @@ pub const FuncGen = struct { |
| 5677 | 5690 | return self.builder.buildExtractElement(array_llvm_val, rhs, ""); |
| 5678 | 5691 | } |
| 5679 | 5692 | |
| 5680 | | fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5693 | fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5694 | const inst = body_tail[0]; |
| 5681 | 5695 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5682 | 5696 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 5683 | 5697 | if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; |
| 5684 | 5698 | |
| 5685 | | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); |
| 5699 | const elem_ty = ptr_ty.childType(); |
| 5700 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5686 | 5701 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5687 | 5702 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5688 | 5703 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch |
| ... | ... | @@ -5743,7 +5758,8 @@ pub const FuncGen = struct { |
| 5743 | 5758 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); |
| 5744 | 5759 | } |
| 5745 | 5760 | |
| 5746 | | fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5761 | fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5762 | const inst = body_tail[0]; |
| 5747 | 5763 | if (self.liveness.isUnused(inst)) return null; |
| 5748 | 5764 | |
| 5749 | 5765 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| ... | ... | @@ -5826,7 +5842,10 @@ pub const FuncGen = struct { |
| 5826 | 5842 | const llvm_field_ty = try self.dg.lowerType(field_ty); |
| 5827 | 5843 | const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), ""); |
| 5828 | 5844 | if (isByRef(field_ty)) { |
| 5829 | | return field_ptr; |
| 5845 | if (canElideLoad(self, body_tail)) |
| 5846 | return field_ptr; |
| 5847 | |
| 5848 | return self.loadByRef(field_ptr, field_ty, layout.payload_align, false); |
| 5830 | 5849 | } else { |
| 5831 | 5850 | return self.builder.buildLoad(llvm_field_ty, field_ptr, ""); |
| 5832 | 5851 | } |
| ... | ... | @@ -6516,7 +6535,8 @@ pub const FuncGen = struct { |
| 6516 | 6535 | return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, ""); |
| 6517 | 6536 | } |
| 6518 | 6537 | |
| 6519 | | fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6538 | fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 6539 | const inst = body_tail[0]; |
| 6520 | 6540 | if (self.liveness.isUnused(inst)) return null; |
| 6521 | 6541 | |
| 6522 | 6542 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| ... | ... | @@ -6531,14 +6551,16 @@ pub const FuncGen = struct { |
| 6531 | 6551 | } |
| 6532 | 6552 | |
| 6533 | 6553 | const opt_llvm_ty = try self.dg.lowerType(optional_ty); |
| 6534 | | return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty); |
| 6554 | const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false; |
| 6555 | return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load); |
| 6535 | 6556 | } |
| 6536 | 6557 | |
| 6537 | 6558 | fn airErrUnionPayload( |
| 6538 | 6559 | self: *FuncGen, |
| 6539 | | inst: Air.Inst.Index, |
| 6560 | body_tail: []const Air.Inst.Index, |
| 6540 | 6561 | operand_is_ptr: bool, |
| 6541 | 6562 | ) !?*llvm.Value { |
| 6563 | const inst = body_tail[0]; |
| 6542 | 6564 | if (self.liveness.isUnused(inst)) return null; |
| 6543 | 6565 | |
| 6544 | 6566 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| ... | ... | @@ -6558,12 +6580,15 @@ pub const FuncGen = struct { |
| 6558 | 6580 | } |
| 6559 | 6581 | const offset = errUnionPayloadOffset(payload_ty, target); |
| 6560 | 6582 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6561 | | if (operand_is_ptr or isByRef(payload_ty)) { |
| 6583 | if (operand_is_ptr) { |
| 6562 | 6584 | return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6563 | 6585 | } else if (isByRef(err_union_ty)) { |
| 6564 | 6586 | const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6565 | 6587 | if (isByRef(payload_ty)) { |
| 6566 | | return payload_ptr; |
| 6588 | if (self.canElideLoad(body_tail)) |
| 6589 | return payload_ptr; |
| 6590 | |
| 6591 | return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false); |
| 6567 | 6592 | } |
| 6568 | 6593 | const load_inst = self.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, ""); |
| 6569 | 6594 | load_inst.setAlignment(payload_ty.abiAlignment(target)); |
| ... | ... | @@ -8064,35 +8089,37 @@ pub const FuncGen = struct { |
| 8064 | 8089 | return null; |
| 8065 | 8090 | } |
| 8066 | 8091 | |
| 8067 | | fn airLoad( |
| 8068 | | self: *FuncGen, |
| 8069 | | inst: Air.Inst.Index, |
| 8070 | | body: []const Air.Inst.Index, |
| 8071 | | body_i: usize, |
| 8072 | | ) !?*llvm.Value { |
| 8073 | | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8074 | | const ptr_ty = self.air.typeOf(ty_op.operand); |
| 8092 | /// As an optimization, we want to avoid unnecessary copies of isByRef=true |
| 8093 | /// types. Here, we scan forward in the current block, looking to see if |
| 8094 | /// this load dies before any side effects occur. In such case, we can |
| 8095 | /// safely return the operand without making a copy. |
| 8096 | /// |
| 8097 | /// The first instruction of `body_tail` is the one whose copy we want to elide. |
| 8098 | fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool { |
| 8099 | for (body_tail[1..]) |body_inst| { |
| 8100 | switch (fg.liveness.categorizeOperand(fg.air, body_inst, body_tail[0])) { |
| 8101 | .none => continue, |
| 8102 | .write, .noret, .complex => return false, |
| 8103 | .tomb => return true, |
| 8104 | } |
| 8105 | } else unreachable; |
| 8106 | } |
| 8107 | |
| 8108 | fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 8109 | const inst = body_tail[0]; |
| 8110 | const ty_op = fg.air.instructions.items(.data)[inst].ty_op; |
| 8111 | const ptr_ty = fg.air.typeOf(ty_op.operand); |
| 8112 | const ptr_info = ptr_ty.ptrInfo().data; |
| 8113 | const ptr = try fg.resolveInst(ty_op.operand); |
| 8114 | |
| 8075 | 8115 | elide: { |
| 8076 | | const ptr_info = ptr_ty.ptrInfo().data; |
| 8077 | 8116 | if (ptr_info.@"volatile") break :elide; |
| 8078 | | if (self.liveness.isUnused(inst)) return null; |
| 8117 | if (fg.liveness.isUnused(inst)) return null; |
| 8079 | 8118 | if (!isByRef(ptr_info.pointee_type)) break :elide; |
| 8080 | | |
| 8081 | | // It would be valid to fall back to the code below here that simply calls |
| 8082 | | // load(). However, as an optimization, we want to avoid unnecessary copies |
| 8083 | | // of isByRef=true types. Here, we scan forward in the current block, |
| 8084 | | // looking to see if this load dies before any side effects occur. |
| 8085 | | // In such case, we can safely return the operand without making a copy. |
| 8086 | | for (body[body_i..]) |body_inst| { |
| 8087 | | switch (self.liveness.categorizeOperand(self.air, body_inst, inst)) { |
| 8088 | | .none => continue, |
| 8089 | | .write, .noret, .complex => break :elide, |
| 8090 | | .tomb => return try self.resolveInst(ty_op.operand), |
| 8091 | | } |
| 8092 | | } else unreachable; |
| 8119 | if (!canElideLoad(fg, body_tail)) break :elide; |
| 8120 | return ptr; |
| 8093 | 8121 | } |
| 8094 | | const ptr = try self.resolveInst(ty_op.operand); |
| 8095 | | return self.load(ptr, ptr_ty); |
| 8122 | return fg.load(ptr, ptr_ty); |
| 8096 | 8123 | } |
| 8097 | 8124 | |
| 8098 | 8125 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -9412,6 +9439,7 @@ pub const FuncGen = struct { |
| 9412 | 9439 | opt_llvm_ty: *llvm.Type, |
| 9413 | 9440 | opt_handle: *llvm.Value, |
| 9414 | 9441 | opt_ty: Type, |
| 9442 | can_elide_load: bool, |
| 9415 | 9443 | ) !*llvm.Value { |
| 9416 | 9444 | var buf: Type.Payload.ElemType = undefined; |
| 9417 | 9445 | const payload_ty = opt_ty.optionalChild(&buf); |
| ... | ... | @@ -9420,11 +9448,14 @@ pub const FuncGen = struct { |
| 9420 | 9448 | // We have a pointer and we need to return a pointer to the first field. |
| 9421 | 9449 | const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, ""); |
| 9422 | 9450 | |
| 9423 | | if (isByRef(payload_ty)) { |
| 9424 | | return payload_ptr; |
| 9425 | | } |
| 9426 | 9451 | const target = fg.dg.module.getTarget(); |
| 9427 | 9452 | const payload_alignment = payload_ty.abiAlignment(target); |
| 9453 | if (isByRef(payload_ty)) { |
| 9454 | if (can_elide_load) |
| 9455 | return payload_ptr; |
| 9456 | |
| 9457 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false); |
| 9458 | } |
| 9428 | 9459 | const payload_llvm_ty = try fg.dg.lowerType(payload_ty); |
| 9429 | 9460 | const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, ""); |
| 9430 | 9461 | load_inst.setAlignment(payload_alignment); |
| ... | ... | @@ -9559,6 +9590,32 @@ pub const FuncGen = struct { |
| 9559 | 9590 | return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len); |
| 9560 | 9591 | } |
| 9561 | 9592 | |
| 9593 | /// Load a by-ref type by constructing a new alloca and performing a memcpy. |
| 9594 | fn loadByRef( |
| 9595 | fg: *FuncGen, |
| 9596 | ptr: *llvm.Value, |
| 9597 | pointee_type: Type, |
| 9598 | ptr_alignment: u32, |
| 9599 | is_volatile: bool, |
| 9600 | ) !*llvm.Value { |
| 9601 | const pointee_llvm_ty = try fg.dg.lowerType(pointee_type); |
| 9602 | const target = fg.dg.module.getTarget(); |
| 9603 | const result_align = @max(ptr_alignment, pointee_type.abiAlignment(target)); |
| 9604 | const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align); |
| 9605 | const llvm_ptr_u8 = fg.context.intType(8).pointerType(0); |
| 9606 | const llvm_usize = fg.context.intType(Type.usize.intInfo(target).bits); |
| 9607 | const size_bytes = pointee_type.abiSize(target); |
| 9608 | _ = fg.builder.buildMemCpy( |
| 9609 | fg.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""), |
| 9610 | result_align, |
| 9611 | fg.builder.buildBitCast(ptr, llvm_ptr_u8, ""), |
| 9612 | ptr_alignment, |
| 9613 | llvm_usize.constInt(size_bytes, .False), |
| 9614 | is_volatile, |
| 9615 | ); |
| 9616 | return result_ptr; |
| 9617 | } |
| 9618 | |
| 9562 | 9619 | /// This function always performs a copy. For isByRef=true types, it creates a new |
| 9563 | 9620 | /// alloca and copies the value into it, then returns the alloca instruction. |
| 9564 | 9621 | /// For isByRef=false types, it creates a load instruction and returns it. |
| ... | ... | @@ -9570,24 +9627,10 @@ pub const FuncGen = struct { |
| 9570 | 9627 | const ptr_alignment = info.alignment(target); |
| 9571 | 9628 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); |
| 9572 | 9629 | if (info.host_size == 0) { |
| 9573 | | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| 9574 | 9630 | if (isByRef(info.pointee_type)) { |
| 9575 | | const result_align = info.pointee_type.abiAlignment(target); |
| 9576 | | const max_align = @max(result_align, ptr_alignment); |
| 9577 | | const result_ptr = self.buildAlloca(elem_llvm_ty, max_align); |
| 9578 | | const llvm_ptr_u8 = self.context.intType(8).pointerType(0); |
| 9579 | | const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits); |
| 9580 | | const size_bytes = info.pointee_type.abiSize(target); |
| 9581 | | _ = self.builder.buildMemCpy( |
| 9582 | | self.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""), |
| 9583 | | max_align, |
| 9584 | | self.builder.buildBitCast(ptr, llvm_ptr_u8, ""), |
| 9585 | | max_align, |
| 9586 | | llvm_usize.constInt(size_bytes, .False), |
| 9587 | | info.@"volatile", |
| 9588 | | ); |
| 9589 | | return result_ptr; |
| 9631 | return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile"); |
| 9590 | 9632 | } |
| 9633 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| 9591 | 9634 | const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, ""); |
| 9592 | 9635 | llvm_inst.setAlignment(ptr_alignment); |
| 9593 | 9636 | llvm_inst.setVolatile(ptr_volatile); |