Skip to content

Commit 88039a4

Browse files
committed
[CIR] Upstream proper function alias lowering
This change implements correct lowering of function aliases to the LLVM dialect.
1 parent c12dfd5 commit 88039a4

File tree

4 files changed

+98
-14
lines changed

4 files changed

+98
-14
lines changed

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

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -919,13 +919,46 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
919919
memoryEffects, noUnwind, willReturn);
920920

921921
mlir::LLVM::LLVMFunctionType llvmFnTy;
922+
923+
// Temporary to handle the case where we need to prepend an operand if the
924+
// callee is an alias.
925+
SmallVector<mlir::Value> adjustedCallOperands;
926+
922927
if (calleeAttr) { // direct call
923-
mlir::FunctionOpInterface fn =
924-
mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(
925-
op, calleeAttr);
926-
assert(fn && "Did not find function for call");
927-
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
928-
converter->convertType(fn.getFunctionType()));
928+
mlir::Operation *callee =
929+
mlir::SymbolTable::lookupNearestSymbolFrom(op, calleeAttr);
930+
if (auto fn = dyn_cast<mlir::FunctionOpInterface>(callee)) {
931+
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
932+
converter->convertType(fn.getFunctionType()));
933+
} else if (auto alias = cast<mlir::LLVM::AliasOp>(callee)) {
934+
// If the callee wasan alias. In that case,
935+
// we need to prepend the address of the alias to the operands. The
936+
// way aliases work in the LLVM dialect is a little counter-intuitive.
937+
// The AliasOp itself is a pseudo-function that returns the address of
938+
// the global value being aliased, but when we generate the call we
939+
// need to insert an operation that gets the address of the AliasOp.
940+
// This all gets sorted out when the LLVM dialect is lowered to LLVM IR.
941+
auto symAttr = cast<mlir::FlatSymbolRefAttr>(calleeAttr);
942+
auto addrOfAlias =
943+
rewriter
944+
.create<mlir::LLVM::AddressOfOp>(
945+
op->getLoc(),
946+
mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),
947+
symAttr)
948+
.getResult();
949+
adjustedCallOperands.push_back(addrOfAlias);
950+
951+
// Now add the regular operands and assign this to the range value.
952+
llvm::append_range(adjustedCallOperands, callOperands);
953+
callOperands = adjustedCallOperands;
954+
955+
// Clear the callee attribute because we're calling an alias.
956+
calleeAttr = {};
957+
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(alias.getType());
958+
} else {
959+
// Was this an ifunc?
960+
return op->emitError("Unexpected callee type!");
961+
}
929962
} else { // indirect call
930963
assert(!op->getOperands().empty() &&
931964
"operands list must no be empty for the indirect call");
@@ -1166,6 +1199,31 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
11661199
}
11671200
}
11681201

1202+
mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias(
1203+
cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, mlir::Type ty,
1204+
OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {
1205+
SmallVector<mlir::NamedAttribute, 4> attributes;
1206+
lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);
1207+
1208+
mlir::Location loc = op.getLoc();
1209+
auto aliasOp = rewriter.replaceOpWithNewOp<mlir::LLVM::AliasOp>(
1210+
op, ty, convertLinkage(op.getLinkage()), op.getName(), op.getDsoLocal(),
1211+
/*threadLocal=*/false, attributes);
1212+
1213+
// Create the alias body
1214+
mlir::OpBuilder builder(op.getContext());
1215+
mlir::Block *block = builder.createBlock(&aliasOp.getInitializerRegion());
1216+
builder.setInsertionPointToStart(block);
1217+
// The type of AddressOfOp is always a pointer.
1218+
assert(!cir::MissingFeatures::addressSpace());
1219+
mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get(ty.getContext());
1220+
auto addrOp =
1221+
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue());
1222+
builder.create<mlir::LLVM::ReturnOp>(loc, addrOp);
1223+
1224+
return mlir::success();
1225+
}
1226+
11691227
mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
11701228
cir::FuncOp op, OpAdaptor adaptor,
11711229
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1190,6 +1248,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
11901248
resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),
11911249
signatureConversion.getConvertedTypes(),
11921250
/*isVarArg=*/fnType.isVarArg());
1251+
1252+
// If this is an alias, it needs to be lowered to llvm::AliasOp.
1253+
std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr();
1254+
if (aliasee && *aliasee)
1255+
return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter);
1256+
11931257
// LLVMFuncOp expects a single FileLine Location instead of a fused
11941258
// location.
11951259
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
@@ -257,6 +257,11 @@ class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> {
257257
cir::FuncOp func, bool filterArgAndResAttrs,
258258
mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
259259

260+
mlir::LogicalResult
261+
matchAndRewriteAlias(cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee,
262+
mlir::Type ty, OpAdaptor adaptor,
263+
mlir::ConversionPatternRewriter &rewriter) const;
264+
260265
public:
261266
using mlir::OpConversionPattern<cir::FuncOp>::OpConversionPattern;
262267

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)