@@ -701,6 +701,13 @@ mlir::Value CirAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) {
701701 sourceType = converter->convertType (fun.getFunctionType ());
702702 symName = fun.getSymName ();
703703 sourceAddrSpace = 0 ;
704+ } else if (auto alias = dyn_cast<mlir::LLVM::AliasOp>(sourceSymbol)) {
705+ // FIXME: It seems unusual that we need to handle an LLVM dialect op here,
706+ // but that's the way it happens. Should we be doing something somewhere
707+ // else to lower the GlobalViewAttr sooner?
708+ sourceType = alias.getType ();
709+ symName = alias.getSymName ();
710+ sourceAddrSpace = 0 ;
704711 } else {
705712 llvm_unreachable (" Unexpected GlobalOp type" );
706713 }
@@ -1434,13 +1441,46 @@ rewriteToCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
14341441 willReturn);
14351442
14361443 mlir::LLVM::LLVMFunctionType llvmFnTy;
1444+
1445+ // Temporary to handle the case where we need to prepend an operand if the
1446+ // callee is an alias.
1447+ SmallVector<mlir::Value> adjustedCallOperands;
1448+
14371449 if (calleeAttr) { // direct call
1438- auto fn =
1439- mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(
1440- op, calleeAttr);
1441- assert (fn && " Did not find function for call" );
1442- llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
1443- converter->convertType (fn.getFunctionType ()));
1450+ mlir::Operation *callee =
1451+ mlir::SymbolTable::lookupNearestSymbolFrom (op, calleeAttr);
1452+ if (auto fn = dyn_cast<mlir::FunctionOpInterface>(callee)) {
1453+ llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
1454+ converter->convertType (fn.getFunctionType ()));
1455+ } else if (auto alias = cast<mlir::LLVM::AliasOp>(callee)) {
1456+ // If the callee wasan alias. In that case,
1457+ // we need to prepend the address of the alias to the operands. The
1458+ // way aliases work in the LLVM dialect is a little counter-intuitive.
1459+ // The AliasOp itself is a pseudo-function that returns the address of
1460+ // the global value being aliased, but when we generate the call we
1461+ // need to insert an operation that gets the address of the AliasOp.
1462+ // This all gets sorted out when the LLVM dialect is lowered to LLVM IR.
1463+ auto symAttr = cast<mlir::FlatSymbolRefAttr>(calleeAttr);
1464+ auto addrOfAlias =
1465+ rewriter
1466+ .create <mlir::LLVM::AddressOfOp>(
1467+ op->getLoc (),
1468+ mlir::LLVM::LLVMPointerType::get (rewriter.getContext ()),
1469+ symAttr)
1470+ .getResult ();
1471+ adjustedCallOperands.push_back (addrOfAlias);
1472+
1473+ // Now add the regular operands and assign this to the range value.
1474+ llvm::append_range (adjustedCallOperands, callOperands);
1475+ callOperands = adjustedCallOperands;
1476+
1477+ // Clear the callee attribute because we're calling an alias.
1478+ calleeAttr = {};
1479+ llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(alias.getType ());
1480+ } else {
1481+ // Was this an ifunc?
1482+ return op->emitError (" Unexpected callee type!" );
1483+ }
14441484 } else { // indirect call
14451485 assert (op->getOperands ().size () &&
14461486 " operands list must no be empty for the indirect call" );
@@ -1449,6 +1489,7 @@ rewriteToCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
14491489 auto ptyp = dyn_cast<cir::PointerType>(typ);
14501490 auto ftyp = dyn_cast<cir::FuncType>(ptyp.getPointee ());
14511491 assert (ftyp && " expected a pointer to a function as the first operand" );
1492+ llvm::append_range (adjustedCallOperands, callOperands);
14521493 llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(converter->convertType (ftyp));
14531494 }
14541495
@@ -2187,10 +2228,34 @@ void CIRToLLVMFuncOpLowering::lowerFuncOpenCLKernelMetadata(
21872228 newExtraAttrs.getDictionary (getContext ())));
21882229}
21892230
2231+ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias (
2232+ cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, mlir::Type ty,
2233+ OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {
2234+ SmallVector<mlir::NamedAttribute, 4 > attributes;
2235+ lowerFuncAttributes (op, /* filterArgAndResAttrs=*/ false , attributes);
2236+
2237+ auto loc = op.getLoc ();
2238+ auto aliasOp = rewriter.replaceOpWithNewOp <mlir::LLVM::AliasOp>(
2239+ op, ty, convertLinkage (op.getLinkage ()), op.getName (), op.getDsoLocal (),
2240+ /* threadLocal=*/ false , attributes);
2241+
2242+ // Create the alias body
2243+ mlir::OpBuilder builder (op.getContext ());
2244+ mlir::Block *block = builder.createBlock (&aliasOp.getInitializerRegion ());
2245+ builder.setInsertionPointToStart (block);
2246+ // The type of AddressOfOp is always a pointer.
2247+ assert (!cir::MissingFeatures::addressSpace ());
2248+ mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get (ty.getContext ());
2249+ auto addrOp =
2250+ builder.create <mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue ());
2251+ builder.create <mlir::LLVM::ReturnOp>(loc, addrOp);
2252+
2253+ return mlir::success ();
2254+ }
2255+
21902256mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite (
21912257 cir::FuncOp op, OpAdaptor adaptor,
21922258 mlir::ConversionPatternRewriter &rewriter) const {
2193-
21942259 auto fnType = op.getFunctionType ();
21952260 auto isDsoLocal = op.getDsoLocal ();
21962261 mlir::TypeConverter::SignatureConversion signatureConversion (
@@ -2211,6 +2276,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
22112276 resultType ? resultType : mlir::LLVM::LLVMVoidType::get (getContext ()),
22122277 signatureConversion.getConvertedTypes (),
22132278 /* isVarArg=*/ fnType.isVarArg ());
2279+
2280+ // If this is an alias, it needs to be lowered to llvm::AliasOp.
2281+ std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr ();
2282+ if (aliasee && *aliasee)
2283+ return matchAndRewriteAlias (op, *aliasee, llvmFnTy, adaptor, rewriter);
2284+
22142285 // LLVMFuncOp expects a single FileLine Location instead of a fused
22152286 // location.
22162287 auto Loc = op.getLoc ();
0 commit comments