Skip to content

Commit 8a1b252

Browse files
authored
[CIR] Upstream proper function alias lowering (#150520)
This change implements correct lowering of function aliases to the LLVM dialect.
1 parent 6184ef1 commit 8a1b252

File tree

4 files changed

+95
-14
lines changed

4 files changed

+95
-14
lines changed

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
12011257
mlir::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();

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> {
267267
cir::FuncOp func, bool filterArgAndResAttrs,
268268
mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
269269

270+
mlir::LogicalResult
271+
matchAndRewriteAlias(cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty,
272+
OpAdaptor adaptor,
273+
mlir::ConversionPatternRewriter &rewriter) const;
274+
270275
public:
271276
using mlir::OpConversionPattern<cir::FuncOp>::OpConversionPattern;
272277

clang/test/CIR/CodeGen/ctor-alias.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ struct B {
1111
B::B() {
1212
}
1313

14+
// LLVM: @_ZN1BC1Ev = alias void (ptr), ptr @_ZN1BC2Ev
15+
1416
// OGCG: @_ZN1BC1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BC2Ev
1517

1618
// CHECK: cir.func{{.*}} @_ZN1BC2Ev(%arg0: !cir.ptr<!rec_B>
@@ -25,15 +27,30 @@ B::B() {
2527
// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
2628
// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
2729

28-
// This should be an alias, like the similar OGCG alias above, but that's not
29-
// implemented yet.
30-
// LLVM: declare dso_local void @_ZN1BC1Ev(ptr)
31-
3230
// OGCG: define{{.*}} @_ZN1BC2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
3331
// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
3432
// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
3533
// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
3634

35+
void bar() {
36+
B b;
37+
}
38+
39+
// CHECK: cir.func{{.*}} @_Z3barv()
40+
// CHECK: %[[B:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["b", init]
41+
// CHECK: cir.call @_ZN1BC1Ev(%[[B]]) : (!cir.ptr<!rec_B>) -> ()
42+
// CHECK: cir.return
43+
44+
// LLVM: define{{.*}} void @_Z3barv()
45+
// LLVM: %[[B:.*]] = alloca %struct.B, i64 1, align 1
46+
// LLVM: call void @_ZN1BC1Ev(ptr %[[B]])
47+
// LLVM: ret void
48+
49+
// OGCG: define{{.*}} void @_Z3barv()
50+
// OGCG: %[[B:.*]] = alloca %struct.B, align 1
51+
// OGCG: call void @_ZN1BC1Ev(ptr{{.*}} %[[B]])
52+
// OGCG: ret void
53+
3754
// The constructor in this cases is handled by RAUW rather than aliasing.
3855
struct Struk {
3956
Struk() {}

clang/test/CIR/CodeGen/dtor-alias.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ struct B {
1111
B::~B() {
1212
}
1313

14+
// LLVM: @_ZN1BD1Ev = alias void (ptr), ptr @_ZN1BD2Ev
15+
1416
// OGCG: @_ZN1BD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BD2Ev
1517

1618
// CHECK: cir.func{{.*}} @_ZN1BD2Ev(%arg0: !cir.ptr<!rec_B>
@@ -25,10 +27,6 @@ B::~B() {
2527
// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
2628
// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
2729

28-
// This should be an alias, like the similar OGCG alias above, but that's not
29-
// implemented yet.
30-
// LLVM: declare dso_local void @_ZN1BD1Ev(ptr)
31-
3230
// OGCG: define{{.*}} @_ZN1BD2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
3331
// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
3432
// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]

0 commit comments

Comments
 (0)