================
@@ -599,29 +622,209 @@ static mlir::Value emitCopiedCoercedLoad(mlir::OpBuilder
&builder,
"a direct offset must leave the record as the slot's type");
mlir::OpBuilder::InsertionGuard guard(builder);
builder.setInsertionPoint(load);
- mlir::Value recView = emitViewAtOffset(builder, loc, recTy, slot, ignored,
0);
- cir::CopyOp::create(builder, loc, recView, load.getAddr(),
- builder.getI64IntegerAttr(slot.getAlignment()),
- builder.getI64IntegerAttr(srcAlign));
+ mlir::Value recView =
+ emitViewAtOffset(builder, loc, recTy, slot, ignored, /*offset=*/0);
+ auto copy =
+ cir::CopyOp::create(builder, loc, recView, load.getAddr(),
+ builder.getI64IntegerAttr(slot.getAlignment()),
+ builder.getI64IntegerAttr(srcAlign));
+ copy.setIsVolatile(load.getIsVolatile());
+ return slot;
+}
+
+/// Copy the bytes of the record \p load reads into a coercion slot, as
+/// emitCopiedCoercionSlot does, then read \p coercedTy out of the slot at
+/// \p offset. The read takes the slot's alignment at \p offset.
+static mlir::Value emitCopiedCoercedLoad(mlir::OpBuilder &builder,
+ mlir::Location loc, cir::LoadOp load,
+ mlir::Type coercedTy,
+ mlir::Block *slotBlock,
+ const mlir::DataLayout &dl,
+ unsigned offset) {
+ cir::AllocaOp slot = emitCopiedCoercionSlot(builder, loc, load, coercedTy,
+ slotBlock, dl, offset);
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.setInsertionPoint(load);
+ SmallPtrSet<mlir::Operation *, 4> ignored;
mlir::Value coercedView =
emitViewAtOffset(builder, loc, coercedTy, slot, ignored, offset);
auto coerced = cir::LoadOp::create(builder, loc, coercedView);
coerced.setAlignment(llvm::MinAlign(slot.getAlignment(), offset));
return coerced;
}
+/// Read \p coercedTy at \p offset out of the bytes the record load \p load
+/// reads: straight out of its storage if \p load is not volatile and
+/// canReadInPlace accepts it, and otherwise out of a coercion slot at the
start
+/// of \p slotBlock that those bytes are copied into. emitInPlaceCoercedLoad
+/// does not mark its read volatile, so a volatile load is read through the
+/// volatile copy instead. Either way no new load of the record type is
+/// emitted.
+static mlir::Value emitCoercedRecordLoad(
+ mlir::OpBuilder &builder, mlir::Location loc, cir::LoadOp load,
+ mlir::Type coercedTy, mlir::Block *slotBlock, const mlir::DataLayout &dl,
+ const cir::CIRDataLayout &cirDataLayout, unsigned offset) {
+ if (!load.getIsVolatile() &&
+ canReadInPlace(load, coercedTy, cirDataLayout, offset))
+ return emitInPlaceCoercedLoad(builder, loc, load, coercedTy, offset);
+ return emitCopiedCoercedLoad(builder, loc, load, coercedTy, slotBlock, dl,
+ offset);
+}
+
+/// Whether \p ty is a struct that ends in pad members, as CIRGen emits for
tail
+/// padding another object may reuse. It is also true of other structs CIRGen
+/// ends in pad members, such as an over-aligned one.
+static bool hasTailPadding(mlir::Type ty) {
+ auto structTy = mlir::dyn_cast<cir::StructType>(ty);
+ if (!structTy)
+ return false;
+ llvm::ArrayRef<mlir::Type> members = structTy.getMembers();
+ llvm::ArrayRef<cir::RecordMemberKind> kinds = structTy.getMemberKinds();
+ for (auto [member, kind] : llvm::reverse(llvm::zip_equal(members, kinds)))
+ if (cir::memberOwnsBytes(member))
+ return kind == cir::RecordMemberKind::Pad;
+ return false;
+}
+
+/// Whether a cir.copy of \p ty into \p dst that stands in for a store of it
+/// skips tail padding. Unless \p dst is an alloca, which holds a complete
+/// object, it can be a potentially-overlapping subobject, such as a
+/// [[no_unique_address]] member or a base, whose tail padding holds another
+/// object. Classic CodeGen writes only the data size into a destination it is
+/// handed (EmitCall) and into one that may overlap (EmitAggregateCopy).
+/// Copying the whole object into an alloca is equivalent, since nothing else
+/// lives in its tail padding.
+static bool shouldSkipTailPadding(mlir::Value dst, mlir::Type ty) {
+ return !cir::getUnderlyingAlloca(dst) && hasTailPadding(ty);
+}
+
+/// Rewire the uses of the record value \p val, whose bytes sit at \p addr,
+/// which is aligned to \p addrAlign, so that each one finds the record in
+/// memory. \p val may already have been retyped to the type it is passed as,
a
+/// coerced type or a pointer, but its uses still expect the record.
+///
+/// A store of \p val becomes a cir.copy from \p addr at the store, volatile if
+/// the store is and skipping tail padding as shouldSkipTailPadding says. A
+/// store of the record value writes only what its lowered type stores, so
+/// another union member's data past those bytes would be lost. A consumer may
+/// be rewritten before \p val's defining op, and has then already stored \p
val
+/// into a slot of its own. That store becomes a copy here too.
+///
+/// Every other use is pointed at one cir.load of \p addr created at the
+/// builder's insertion point. Only a call argument, a return and a read of a
+/// member that is not itself a record may use it, since those either read
+/// \p addr when they are rewritten or read a field. Uses by an operation in
+/// \p exceptions are left alone. Fails, after reporting it, on an atomic
store
+/// of \p val or a use by anything else, before anything is rewired.
+static mlir::LogicalResult
+rewireRecordUses(mlir::OpBuilder &builder, mlir::Location loc, mlir::Value val,
+ mlir::Value addr, uint64_t addrAlign,
+ const mlir::DataLayout &dl,
+ const SmallPtrSetImpl<mlir::Operation *> &exceptions) {
+ mlir::Type recTy = mlir::cast<cir::PointerType>(addr.getType()).getPointee();
+ assert(mlir::isa<cir::RecordType>(recTy) && "only a record is rewired");
+ SmallVector<cir::StoreOp> stores;
+ SmallVector<mlir::OpOperand *> otherUses;
+ for (mlir::OpOperand &use : val.getUses()) {
+ mlir::Operation *user = use.getOwner();
+ if (exceptions.contains(user))
+ continue;
+ auto store = mlir::dyn_cast<cir::StoreOp>(user);
+ if (!store) {
----------------
adams381 wrote:
Restructured it that way, so the store case comes first and the `dyn_cast` sits
in the `if`. I left off the `else`, since the store branch ends in `continue`
and the coding standard asks us not to follow that with an `else`.
https://github.com/llvm/llvm-project/pull/231663
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits