llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)

<details>
<summary>Changes</summary>

This 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:

- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+70-6) 
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+5) 
- (modified) clang/test/CIR/CodeGen/ctor-alias.cpp (+21-4) 
- (modified) clang/test/CIR/CodeGen/dtor-alias.cpp (+2-4) 


``````````diff
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]]

``````````

</details>


https://github.com/llvm/llvm-project/pull/150520
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to