@@ -945,13 +945,45 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
945945 memoryEffects, noUnwind, willReturn);
946946
947947 mlir::LLVM::LLVMFunctionType llvmFnTy;
948+
949+ // Temporary to handle the case where we need to prepend an operand if the
950+ // callee is an alias.
951+ SmallVector<mlir::Value> adjustedCallOperands;
952+
948953 if (calleeAttr) { // direct call
949- mlir::FunctionOpInterface fn =
950- mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(
951- op, calleeAttr);
952- assert (fn && " Did not find function for call" );
953- llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
954- converter->convertType (fn.getFunctionType ()));
954+ mlir::Operation *callee =
955+ mlir::SymbolTable::lookupNearestSymbolFrom (op, calleeAttr);
956+ if (auto fn = mlir::dyn_cast<mlir::FunctionOpInterface>(callee)) {
957+ llvmFnTy = converter->convertType <mlir::LLVM::LLVMFunctionType>(
958+ fn.getFunctionType ());
959+ assert (llvmFnTy && " Failed to convert function type" );
960+ } else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) {
961+ // If the callee was an alias. In that case,
962+ // we need to prepend the address of the alias to the operands. The
963+ // way aliases work in the LLVM dialect is a little counter-intuitive.
964+ // The AliasOp itself is a pseudo-function that returns the address of
965+ // the global value being aliased, but when we generate the call we
966+ // need to insert an operation that gets the address of the AliasOp.
967+ // This all gets sorted out when the LLVM dialect is lowered to LLVM IR.
968+ auto symAttr = mlir::cast<mlir::FlatSymbolRefAttr>(calleeAttr);
969+ auto addrOfAlias =
970+ mlir::LLVM::AddressOfOp::create (
971+ rewriter, op->getLoc (),
972+ mlir::LLVM::LLVMPointerType::get (rewriter.getContext ()), symAttr)
973+ .getResult ();
974+ adjustedCallOperands.push_back (addrOfAlias);
975+
976+ // Now add the regular operands and assign this to the range value.
977+ llvm::append_range (adjustedCallOperands, callOperands);
978+ callOperands = adjustedCallOperands;
979+
980+ // Clear the callee attribute because we're calling an alias.
981+ calleeAttr = {};
982+ llvmFnTy = mlir::cast<mlir::LLVM::LLVMFunctionType>(alias.getType ());
983+ } else {
984+ // Was this an ifunc?
985+ return op->emitError (" Unexpected callee type!" );
986+ }
955987 } else { // indirect call
956988 assert (!op->getOperands ().empty () &&
957989 " operands list must no be empty for the indirect call" );
@@ -1198,6 +1230,30 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
11981230 }
11991231}
12001232
1233+ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias (
1234+ cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty, OpAdaptor adaptor,
1235+ mlir::ConversionPatternRewriter &rewriter) const {
1236+ SmallVector<mlir::NamedAttribute, 4 > attributes;
1237+ lowerFuncAttributes (op, /* filterArgAndResAttrs=*/ false , attributes);
1238+
1239+ mlir::Location loc = op.getLoc ();
1240+ auto aliasOp = rewriter.replaceOpWithNewOp <mlir::LLVM::AliasOp>(
1241+ op, ty, convertLinkage (op.getLinkage ()), op.getName (), op.getDsoLocal (),
1242+ /* threadLocal=*/ false , attributes);
1243+
1244+ // Create the alias body
1245+ mlir::OpBuilder builder (op.getContext ());
1246+ mlir::Block *block = builder.createBlock (&aliasOp.getInitializerRegion ());
1247+ builder.setInsertionPointToStart (block);
1248+ // The type of AddressOfOp is always a pointer.
1249+ assert (!cir::MissingFeatures::addressSpace ());
1250+ mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get (ty.getContext ());
1251+ auto addrOp = mlir::LLVM::AddressOfOp::create (builder, loc, ptrTy, aliasee);
1252+ mlir::LLVM::ReturnOp::create (builder, loc, addrOp);
1253+
1254+ return mlir::success ();
1255+ }
1256+
12011257mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite (
12021258 cir::FuncOp op, OpAdaptor adaptor,
12031259 mlir::ConversionPatternRewriter &rewriter) const {
@@ -1222,6 +1278,11 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
12221278 resultType ? resultType : mlir::LLVM::LLVMVoidType::get (getContext ()),
12231279 signatureConversion.getConvertedTypes (),
12241280 /* isVarArg=*/ fnType.isVarArg ());
1281+
1282+ // If this is an alias, it needs to be lowered to llvm::AliasOp.
1283+ if (std::optional<llvm::StringRef> aliasee = op.getAliasee ())
1284+ return matchAndRewriteAlias (op, *aliasee, llvmFnTy, adaptor, rewriter);
1285+
12251286 // LLVMFuncOp expects a single FileLine Location instead of a fused
12261287 // location.
12271288 mlir::Location loc = op.getLoc ();
0 commit comments