-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[CIR] Upstream proper function alias lowering #150520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This change implements correct lowering of function aliases to the LLVM dialect.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis change implements correct lowering of function aliases to the LLVM dialect. Full diff: https://github.com/llvm/llvm-project/pull/150520.diff 4 Files Affected:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 3cd7de0a56bc3..baa0a5e326c4a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -919,13 +919,46 @@ rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
memoryEffects, noUnwind, willReturn);
mlir::LLVM::LLVMFunctionType llvmFnTy;
+
+ // Temporary to handle the case where we need to prepend an operand if the
+ // callee is an alias.
+ SmallVector<mlir::Value> adjustedCallOperands;
+
if (calleeAttr) { // direct call
- mlir::FunctionOpInterface fn =
- mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(
- op, calleeAttr);
- assert(fn && "Did not find function for call");
- llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
- converter->convertType(fn.getFunctionType()));
+ mlir::Operation *callee =
+ mlir::SymbolTable::lookupNearestSymbolFrom(op, calleeAttr);
+ if (auto fn = dyn_cast<mlir::FunctionOpInterface>(callee)) {
+ llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
+ converter->convertType(fn.getFunctionType()));
+ } else if (auto alias = cast<mlir::LLVM::AliasOp>(callee)) {
+ // If the callee wasan alias. In that case,
+ // we need to prepend the address of the alias to the operands. The
+ // way aliases work in the LLVM dialect is a little counter-intuitive.
+ // The AliasOp itself is a pseudo-function that returns the address of
+ // the global value being aliased, but when we generate the call we
+ // need to insert an operation that gets the address of the AliasOp.
+ // This all gets sorted out when the LLVM dialect is lowered to LLVM IR.
+ auto symAttr = cast<mlir::FlatSymbolRefAttr>(calleeAttr);
+ auto addrOfAlias =
+ rewriter
+ .create<mlir::LLVM::AddressOfOp>(
+ op->getLoc(),
+ mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),
+ symAttr)
+ .getResult();
+ adjustedCallOperands.push_back(addrOfAlias);
+
+ // Now add the regular operands and assign this to the range value.
+ llvm::append_range(adjustedCallOperands, callOperands);
+ callOperands = adjustedCallOperands;
+
+ // Clear the callee attribute because we're calling an alias.
+ calleeAttr = {};
+ llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(alias.getType());
+ } else {
+ // Was this an ifunc?
+ return op->emitError("Unexpected callee type!");
+ }
} else { // indirect call
assert(!op->getOperands().empty() &&
"operands list must no be empty for the indirect call");
@@ -1166,6 +1199,31 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
}
}
+mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias(
+ cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, mlir::Type ty,
+ OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {
+ SmallVector<mlir::NamedAttribute, 4> attributes;
+ lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);
+
+ mlir::Location loc = op.getLoc();
+ auto aliasOp = rewriter.replaceOpWithNewOp<mlir::LLVM::AliasOp>(
+ op, ty, convertLinkage(op.getLinkage()), op.getName(), op.getDsoLocal(),
+ /*threadLocal=*/false, attributes);
+
+ // Create the alias body
+ mlir::OpBuilder builder(op.getContext());
+ mlir::Block *block = builder.createBlock(&aliasOp.getInitializerRegion());
+ builder.setInsertionPointToStart(block);
+ // The type of AddressOfOp is always a pointer.
+ assert(!cir::MissingFeatures::addressSpace());
+ mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get(ty.getContext());
+ auto addrOp =
+ builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue());
+ builder.create<mlir::LLVM::ReturnOp>(loc, addrOp);
+
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
cir::FuncOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1190,6 +1248,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),
signatureConversion.getConvertedTypes(),
/*isVarArg=*/fnType.isVarArg());
+
+ // If this is an alias, it needs to be lowered to llvm::AliasOp.
+ std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr();
+ if (aliasee && *aliasee)
+ return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter);
+
// LLVMFuncOp expects a single FileLine Location instead of a fused
// ___location.
mlir::Location loc = op.getLoc();
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 2911ced66e58e..0f003f644d2fa 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -257,6 +257,11 @@ class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> {
cir::FuncOp func, bool filterArgAndResAttrs,
mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const;
+ mlir::LogicalResult
+ matchAndRewriteAlias(cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee,
+ mlir::Type ty, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const;
+
public:
using mlir::OpConversionPattern<cir::FuncOp>::OpConversionPattern;
diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp
index a20e206c6d714..c4bf455e3a09b 100644
--- a/clang/test/CIR/CodeGen/ctor-alias.cpp
+++ b/clang/test/CIR/CodeGen/ctor-alias.cpp
@@ -11,6 +11,8 @@ struct B {
B::B() {
}
+// LLVM: @_ZN1BC1Ev = alias void (ptr), ptr @_ZN1BC2Ev
+
// OGCG: @_ZN1BC1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BC2Ev
// CHECK: cir.func{{.*}} @_ZN1BC2Ev(%arg0: !cir.ptr<!rec_B>
@@ -25,15 +27,30 @@ B::B() {
// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
-// This should be an alias, like the similar OGCG alias above, but that's not
-// implemented yet.
-// LLVM: declare dso_local void @_ZN1BC1Ev(ptr)
-
// OGCG: define{{.*}} @_ZN1BC2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+void bar() {
+ B b;
+}
+
+// CHECK: cir.func{{.*}} @_Z3barv()
+// CHECK: %[[B:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["b", init]
+// CHECK: cir.call @_ZN1BC1Ev(%[[B]]) : (!cir.ptr<!rec_B>) -> ()
+// CHECK: cir.return
+
+// LLVM: define{{.*}} void @_Z3barv()
+// LLVM: %[[B:.*]] = alloca %struct.B, i64 1, align 1
+// LLVM: call void @_ZN1BC1Ev(ptr %[[B]])
+// LLVM: ret void
+
+// OGCG: define{{.*}} void @_Z3barv()
+// OGCG: %[[B:.*]] = alloca %struct.B, align 1
+// OGCG: call void @_ZN1BC1Ev(ptr{{.*}} %[[B]])
+// OGCG: ret void
+
// The constructor in this cases is handled by RAUW rather than aliasing.
struct Struk {
Struk() {}
diff --git a/clang/test/CIR/CodeGen/dtor-alias.cpp b/clang/test/CIR/CodeGen/dtor-alias.cpp
index e37ddabb5b4fd..f4d54dfd7da26 100644
--- a/clang/test/CIR/CodeGen/dtor-alias.cpp
+++ b/clang/test/CIR/CodeGen/dtor-alias.cpp
@@ -11,6 +11,8 @@ struct B {
B::~B() {
}
+// LLVM: @_ZN1BD1Ev = alias void (ptr), ptr @_ZN1BD2Ev
+
// OGCG: @_ZN1BD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BD2Ev
// CHECK: cir.func{{.*}} @_ZN1BD2Ev(%arg0: !cir.ptr<!rec_B>
@@ -25,10 +27,6 @@ B::~B() {
// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
-// This should be an alias, like the similar OGCG alias above, but that's not
-// implemented yet.
-// LLVM: declare dso_local void @_ZN1BD1Ev(ptr)
-
// OGCG: define{{.*}} @_ZN1BD2Ev(ptr{{.*}} %[[THIS_ARG:.*]])
// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
|
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>( | ||
converter->convertType(fn.getFunctionType())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>( | |
converter->convertType(fn.getFunctionType())); | |
llvmFnTy = | |
converter->convertType<mlir::LLVM::LLVMFunctionType>(fn.getFunctionType()); |
if (auto fn = dyn_cast<mlir::FunctionOpInterface>(callee)) { | ||
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>( | ||
converter->convertType(fn.getFunctionType())); | ||
} else if (auto alias = cast<mlir::LLVM::AliasOp>(callee)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} else if (auto alias = cast<mlir::LLVM::AliasOp>(callee)) { | |
} else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) { |
// the global value being aliased, but when we generate the call we | ||
// need to insert an operation that gets the address of the AliasOp. | ||
// This all gets sorted out when the LLVM dialect is lowered to LLVM IR. | ||
auto symAttr = cast<mlir::FlatSymbolRefAttr>(calleeAttr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto symAttr = cast<mlir::FlatSymbolRefAttr>(calleeAttr); | |
auto symAttr = mlir::cast<mlir::FlatSymbolRefAttr>(calleeAttr); |
rewriter | ||
.create<mlir::LLVM::AddressOfOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewriter | |
.create<mlir::LLVM::AddressOfOp>( | |
mlir::LLVM::AddressOfOp::create(rewriter, |
- some formatting
|
||
// Clear the callee attribute because we're calling an alias. | ||
calleeAttr = {}; | ||
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(alias.getType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(alias.getType()); | |
llvmFnTy = mlir::cast<mlir::LLVM::LLVMFunctionType>(alias.getType()); |
auto addrOp = | ||
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue()); | ||
builder.create<mlir::LLVM::ReturnOp>(loc, addrOp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto addrOp = | |
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue()); | |
builder.create<mlir::LLVM::ReturnOp>(loc, addrOp); | |
auto addrOp = | |
mlir::LLVM::AddressOfOp::create(builder, loc, ptrTy, aliasee.getValue()); | |
mlir::LLVM::ReturnOp::(builder, loc, addrOp); |
std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr(); | ||
if (aliasee && *aliasee) | ||
return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr(); | |
if (aliasee && *aliasee) | |
return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter); | |
if (std::optional<llvm::StringRef> aliasee = op.getAliasee()) | |
return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter); |
@@ -1166,6 +1199,31 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes( | |||
} | |||
} | |||
|
|||
mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias( | |||
cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, mlir::Type ty, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, mlir::Type ty, | |
cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty, |
assert(!cir::MissingFeatures::addressSpace()); | ||
mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get(ty.getContext()); | ||
auto addrOp = | ||
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee.getValue()); | |
builder.create<mlir::LLVM::AddressOfOp>(loc, ptrTy, aliasee); |
@@ -257,6 +257,11 @@ class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> { | |||
cir::FuncOp func, bool filterArgAndResAttrs, | |||
mlir::SmallVectorImpl<mlir::NamedAttribute> &result) const; | |||
|
|||
mlir::LogicalResult | |||
matchAndRewriteAlias(cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matchAndRewriteAlias(cir::FuncOp op, mlir::FlatSymbolRefAttr aliasee, | |
matchAndRewriteAlias(cir::FuncOp op, llvm::StringRef aliasee, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, minor nit
fn.getFunctionType()); | ||
assert(llvmFnTy && "Failed to convert function type"); | ||
} else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) { | ||
// If the callee wasan alias. In that case, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasan -> was an
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
This change implements correct lowering of function aliases to the LLVM dialect.