================
@@ -1063,14 +1063,147 @@ void rewriteIndirectReturnCall(cir::CallOp call,
} // namespace
-void CIRABIRewriteContext::normalizeParameterSlotAlignments(
+/// Bring \p funcOp's non-byval indirect parameter \p argNo into the shape the
+/// rest of the rewrite assumes. \p claimedSlots carries the slots \p funcOp's
+/// earlier non-byval indirect parameters took. See prepareNonByvalParameters.
+static mlir::LogicalResult
+prepareNonByvalParameter(cir::FuncOp funcOp, unsigned argNo,
+ const ArgClassification &ac,
+ mlir::BlockArgument blockArg, mlir::DominanceInfo
&dom,
+ SmallPtrSetImpl<mlir::Operation *> &claimedSlots) {
+ // The spill is the store that writes the parameter itself. Any other use
+ // consumes the record value. At -O1 and above such a use comes from
+ // cir-simplify: CIRGen marks a const-qualified parameter's slot const, so
+ // the load of it folds to the stored parameter.
+ cir::StoreOp spill;
+ cir::StoreOp extraSpill;
+ mlir::Operation *otherUse = nullptr;
+ SmallVector<mlir::OpOperand *> callArgs;
+ for (mlir::OpOperand &use : blockArg.getUses()) {
+ auto store = dyn_cast<cir::StoreOp>(use.getOwner());
+ if (store && store.getValue() == blockArg) {
+ // Which of two stores is the spill decides which slot stands in for the
+ // parameter, and the use list is in no particular order, so there is
+ // nothing to prefer between them.
+ if (spill)
+ extraSpill = store;
+ else
+ spill = store;
+ continue;
+ }
+ // Only an argument is served by a load of the slot. Any other consumer
+ // belongs to a rewrite that reads the parameter its own way: a returned
+ // record, for one, is rewritten through the sret slot, which assumes the
+ // returned load names the return slot and not this one.
+ auto call = dyn_cast<cir::CIRCallOpInterface>(use.getOwner());
+ if (call && llvm::is_contained(call.getArgOperands(), blockArg))
+ callArgs.push_back(&use);
+ else if (!otherUse)
+ otherUse = use.getOwner();
+ }
+
+ if (extraSpill)
+ return extraSpill->emitOpError()
+ << "non-byval parameter " << argNo
+ << " spilled more than once is not yet implemented in "
+ "CallConvLowering";
+
+ if (otherUse)
+ return otherUse->emitOpError()
+ << "non-byval parameter " << argNo
+ << " consumed other than as a call argument is not yet implemented "
+ "in CallConvLowering";
+
+ if (!spill) {
+ // Every other kind of use was reported above, so the parameter has no
+ // uses at all and needs neither a slot nor a read.
+ if (callArgs.empty())
+ return mlir::success();
+
+ // Without a spill the parameter becomes the incoming pointer directly,
+ // which is the storage an argument taken from it has to name. Giving it
+ // the spill it lacks lets the checks and the read below apply unchanged,
+ // and neither survives the pass: insertArgCoercion erases the store and
+ // finalizeParameterSlots replaces the slot.
+ mlir::OpBuilder builder(funcOp.getContext());
+ builder.setInsertionPointToStart(blockArg.getOwner());
+ auto synthesized = cir::AllocaOp::create(
----------------
andykaylor wrote:
Should we be marking this as `const`. Can we have gotten here if it isn't?
https://github.com/llvm/llvm-project/pull/225010
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits