@@ -701,6 +701,13 @@ mlir::Value CirAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) {
701
701
sourceType = converter->convertType (fun.getFunctionType ());
702
702
symName = fun.getSymName ();
703
703
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 ;
704
711
} else {
705
712
llvm_unreachable (" Unexpected GlobalOp type" );
706
713
}
@@ -1434,13 +1441,46 @@ rewriteToCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
1434
1441
willReturn);
1435
1442
1436
1443
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
+
1437
1449
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
+ }
1444
1484
} else { // indirect call
1445
1485
assert (op->getOperands ().size () &&
1446
1486
" operands list must no be empty for the indirect call" );
@@ -1449,6 +1489,7 @@ rewriteToCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
1449
1489
auto ptyp = dyn_cast<cir::PointerType>(typ);
1450
1490
auto ftyp = dyn_cast<cir::FuncType>(ptyp.getPointee ());
1451
1491
assert (ftyp && " expected a pointer to a function as the first operand" );
1492
+ llvm::append_range (adjustedCallOperands, callOperands);
1452
1493
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(converter->convertType (ftyp));
1453
1494
}
1454
1495
@@ -2187,10 +2228,34 @@ void CIRToLLVMFuncOpLowering::lowerFuncOpenCLKernelMetadata(
2187
2228
newExtraAttrs.getDictionary (getContext ())));
2188
2229
}
2189
2230
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
+
2190
2256
mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite (
2191
2257
cir::FuncOp op, OpAdaptor adaptor,
2192
2258
mlir::ConversionPatternRewriter &rewriter) const {
2193
-
2194
2259
auto fnType = op.getFunctionType ();
2195
2260
auto isDsoLocal = op.getDsoLocal ();
2196
2261
mlir::TypeConverter::SignatureConversion signatureConversion (
@@ -2211,6 +2276,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
2211
2276
resultType ? resultType : mlir::LLVM::LLVMVoidType::get (getContext ()),
2212
2277
signatureConversion.getConvertedTypes (),
2213
2278
/* 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
+
2214
2285
// LLVMFuncOp expects a single FileLine Location instead of a fused
2215
2286
// location.
2216
2287
auto Loc = op.getLoc ();
0 commit comments