90Type computeNewReturnType(Type origRetTy,
const ArgClassification &retInfo,
130 FunctionOpInterface funcOpInterface,
const FunctionClassification &fc,
131 OpBuilder &builder) {
138 cir::FuncOp funcOp = cast<cir::FuncOp>(funcOpInterface);
140 if (!needsRewrite(fc))
145 MLIRContext *ctx = funcOp->getContext();
150 assert(oldResultTypes.size() <= 1 &&
151 "CIR functions return zero or one value");
154 if (failed(buildNewArgTypes(oldArgTypes, fc, newArgTypes,
155 [&]() {
return funcOp.emitOpError(); })))
158 Type voidTy = cir::VoidType::get(ctx);
159 Type origRetTy = oldResultTypes.empty() ? voidTy : oldResultTypes[0];
160 Type newRetTy = computeNewReturnType(origRetTy, fc.returnInfo, ctx,
161 [&]() { return funcOp.emitOpError(); });
166 if (funcOp.isDefinition()) {
167 Region &body = funcOp->getRegion(0);
169 Block &entry = body.front();
177 for (
unsigned blockIdx : llvm::reverse(ignored)) {
178 if (
blockIdx >= entry.getNumArguments())
180 BlockArgument arg = entry.getArgument(
blockIdx);
181 if (!arg.use_empty()) {
182 builder.setInsertionPointToStart(&entry);
184 createIgnoredValue(builder, funcOp.getLoc(), arg.getType());
185 arg.replaceAllUsesWith(poison);
197 if (fc.returnInfo.kind == ArgKind::Ignore && !oldResultTypes.empty()) {
198 assert(isa<cir::VoidType>(newRetTy) &&
199 "Ignore-return path requires the new return type to be void");
201 funcOp.walk([&](cir::ReturnOp r) { returns.push_back(r); });
202 for (cir::ReturnOp r : returns) {
203 if (r.getNumOperands() == 0)
205 builder.setInsertionPoint(r);
206 cir::ReturnOp::create(builder, r.getLoc());
212 Type newFnTy = funcOp.cloneTypeWith(newArgTypes, newResultTypes);
213 funcOp.setFunctionTypeAttr(TypeAttr::get(newFnTy));
220 if (!ignored.empty()) {
221 if (
auto existing = funcOp->getAttrOfType<ArrayAttr>(
"arg_attrs")) {
223 kept.reserve(newArgTypes.size());
224 for (
auto [oldIdx, attr] : llvm::enumerate(existing.getValue())) {
225 if (oldIdx >= fc.argInfos.size() ||
226 fc.argInfos[oldIdx].kind != ArgKind::Ignore)
227 kept.push_back(attr);
229 funcOp->setAttr(
"arg_attrs", ArrayAttr::get(ctx, kept));
237 Operation *callOp,
const FunctionClassification &fc, OpBuilder &builder) {
238 if (!needsRewrite(fc))
241 if (isa<cir::TryCallOp>(callOp))
242 return callOp->emitOpError()
243 <<
"TryCallOp not yet implemented in CallConvLowering";
245 auto call = cast<cir::CallOp>(callOp);
246 if (call.isIndirect())
247 return call.emitOpError()
248 <<
"indirect call not yet implemented in CallConvLowering";
250 for (
auto [idx, ac] : llvm::enumerate(fc.argInfos)) {
252 case ArgKind::Direct:
254 return call.emitOpError()
255 <<
"Direct with coerced type at call-site arg " << idx
256 <<
" not yet implemented in CallConvLowering";
258 case ArgKind::Ignore:
260 case ArgKind::Expand:
261 return call.emitOpError() <<
"Expand at call-site arg " << idx
262 <<
" not yet implemented in CallConvLowering";
263 case ArgKind::Extend:
264 return call.emitOpError() <<
"Extend at call-site arg " << idx
265 <<
" not yet implemented in CallConvLowering";
266 case ArgKind::Indirect:
267 return call.emitOpError() <<
"Indirect at call-site arg " << idx
268 <<
" not yet implemented in CallConvLowering";
273 ValueRange argOperands = call.getArgOperands();
274 newArgs.reserve(argOperands.size());
275 if (argOperands.size() > fc.argInfos.size())
276 return call.emitOpError()
277 <<
"variadic arguments not yet implemented in CallConvLowering";
278 assert(fc.argInfos.size() == argOperands.size() &&
279 "call operand count must match classified arg count");
280 for (
auto [idx, ac] : llvm::enumerate(fc.argInfos)) {
281 if (ac.kind == ArgKind::Ignore)
283 newArgs.push_back(argOperands[idx]);
286 bool hasResult = call.getNumResults() > 0;
287 Type origRetTy = hasResult ? call.getResult().getType()
288 : cir::VoidType::get(callOp->getContext());
289 Type callRetTy = origRetTy;
290 if (fc.returnInfo.kind == ArgKind::Ignore && hasResult)
291 callRetTy = cir::VoidType::get(callOp->getContext());
292 if ((fc.returnInfo.kind == ArgKind::Direct ||
293 fc.returnInfo.kind == ArgKind::Extend) &&
294 fc.returnInfo.coercedType)
295 return call.emitOpError() <<
"Direct/Extend return with coerced type at "
296 <<
"call-site not yet implemented in "
297 <<
"CallConvLowering";
299 builder.setInsertionPoint(call);
300 auto newCall = cir::CallOp::create(builder, call.getLoc(),
301 call.getCalleeAttr(), callRetTy, newArgs);
302 for (NamedAttribute attr : call->getAttrs())
303 if (!newCall->hasAttr(attr.getName()))
304 newCall->setAttr(attr.getName(), attr.getValue());
306 if (hasResult && fc.returnInfo.kind == ArgKind::Ignore) {
311 if (!call.getResult().use_empty()) {
312 builder.setInsertionPointAfter(newCall);
313 Value poison = createIgnoredValue(builder, call.getLoc(), origRetTy);
314 call.getResult().replaceAllUsesWith(poison);
316 }
else if (hasResult) {
317 call.getResult().replaceAllUsesWith(newCall.getResult());
mlir::LogicalResult rewriteFunctionDefinition(mlir::FunctionOpInterface funcOp, const mlir::abi::FunctionClassification &fc, mlir::OpBuilder &builder) override
mlir::LogicalResult rewriteCallSite(mlir::Operation *callOp, const mlir::abi::FunctionClassification &fc, mlir::OpBuilder &builder) override