Skip to content

[CIR] Correctly handle annotate attribute on C++ constructors/destructors #1699

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

Open
wants to merge 2,563 commits into
base: main
Choose a base branch
from

Conversation

Sharp0802
Copy link

This PR fixes an issue where the [[clang::annotate]] attribute on C++ constructors (CXXConstructorDecl) was not correctly lowered, and resolves a subsequent crash in the cir-to-llvm pipeline caused by the initial fix.

1. The Problem

There were two distinct problems:

  • Initial Bug: The [[clang::annotate]] attribute was completely ignored when applied to a C++ constructor. While it worked for regular functions, the specific code path for handling CXXConstructorDecl in CIRGenModule did not process this attribute.

  • Downstream Crash: After fixing the initial bug to generate the correct annotations and cir.global_annotations in the CIR dialect, the cir-translate tool would crash with a "redefinition of symbol" error for the annotation string (e.g., .str.annotation).

2. Analysis and Root Cause

  • Cause of Initial Bug: In CIRGenModule::emitGlobalDefinition, the code path for constructors and destructors branches to ABI->emitCXXStructor. This path was missing the logic to check for an AnnotateAttr and add it to the deferredAnnotations map, which is correctly handled for regular FunctionDecls.

  • Cause of Downstream Crash: The cir-to-llvm lowering pipeline has two mechanisms for handling annotations:

    1. The LoweringPrepare pass processes the cir.global_annotations attribute on the ModuleOp and generates the corresponding @llvm.global.annotations array and its associated global string constants.
    2. A later stage in the cir-translate binary also attempts to process the same cir.global_annotations attribute.

    The issue was that LoweringPreparePass did not consume (remove) the cir.global_annotations attribute after processing it. This left the attribute on the module, causing the later stage in cir-translate to re-process it, leading to the symbol redefinition crash.

3. Implementation

This PR addresses both issues with two key changes:

  1. In CIRGenModule.cpp:

    • The logic to handle AnnotateAttr has been added to the CXXConstructorDecl / CXXDestructorDecl path within emitGlobalDefinition. This ensures that constructor annotations are correctly identified and deferred for processing, just like regular functions.
  2. In LoweringPreparePass:

    • After the buildGlobalAnnotationValues() function successfully processes the cir.global_annotations attribute and generates the necessary LLVM globals, the pass now removes the cir.global_annotations attribute from the ModuleOp. This "consumes" the attribute, preventing any subsequent pass from redundantly processing it.

4. Verification

With these changes, a C++ constructor with a [[clang::annotate]] attribute is now correctly lowered through the entire pipeline:

  • The ClangIR (cir dialect) correctly contains both the local annotations on the cir.func and the module-level cir.global_annotations.
  • The cir-opt -cir-to-llvm pass successfully lowers this to the LLVM dialect.
  • The cir-translate tool successfully converts the LLVM dialect to LLVM IR text without crashing.
  • The final LLVM IR contains the expected @llvm.global.annotations metadata for the constructor.

This fix ensures that annotation metadata is preserved correctly and robustly for C++ constructors.

AmrDeveloper and others added 30 commits April 9, 2025 13:58
This PR adds support for LLVM lowering of pointers to member functions.
The lowering is ABI-specific and this patch only considers Itanium ABI.

Itanium ABI lowers pointers to member functions to a struct with two
fields of type `ptrdiff_t`. To extract fields from such aggregate
values, this PR includes a new operation `cir.extract_member` to
accomplish this.
This PR adds CIRGen and LLVM lowering support for the
`__builtin_bitreverse` family of builtin functions.
This deals with some x86 aggregate types for CallConvLowering pass.

Suppose we have a simple struct like this.
```cpp
struct dim3 { int x, y, z; };
```
It can be coerced into
```cpp
struct dim3_ { uint64_t xy; int z; };
```
And for a function that receives it as an argument, OG does the
following transformation for x86:
```cpp
void f(dim3 arg) { /* Before */ }
void f(uint64_t xy, int z) { /* After */ }
```
Now this transformation is implemented in the CallConvLowering pass of
CIR.
I checked
https://github.com/llvm/clangir/blob/main/clang/test/CIR/CodeGen/globals.cpp
and thought code works as expected. Although, test results need to be
adjusted a bit.

Resolves: llvm#1252
This PR adds support for returns inside of a TryOp, for example: 

```
void foo() {
  int r = 1;
  try {
    return;
    ++r;
  } catch (...) {
  }
}
```
Currently, it fails during the CodeGen with: 
```
error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for, cir.case'
```
were TryOp's omitted on purpose?
Change the assembly format for `cir::FuncType` from
```
!cir.func<!returnType (!argType)>
```
to
```
!cir.func<(!argType) -> !returnType>
```

This change (1) is easier to parse because it doesn't require lookahead,
(2) is consistent with the format of ClangIR `FuncOp` assembly, and (3)
is consistent with function types in other MLIR dialects.

Change all the tests to use or to expect the new format for function
types.

The contents and the semantics of `cir::FuncType` are unchanged. Only
the assembly format is being changed. Functions that return `void` in C
or C++ are still represented in MLIR as having no return type.

Most of the changes are in `parseFuncType` and `printFuncType` and the
functions they call in `CIRTypes.cpp`.

A `FuncType::verify` function was added to check that an explicit return
type is not `cir::VoidType`.

`FuncType::isVoid()` was renamed to `FuncType::hasVoidReturn()`

Some comments for `FuncType` were improved.

An `llvm_unreachable` was added to `StructType::getKindAsStr` to
suppress a compiler warning and to catch a memory error that corrupts
the `RecordKind` field. (This was a drive-by fix and has nothing to do
with the rest of this change.)
Commit the .clang-tidy files for ClangIR. The biggest different between
these and the Clang files is the capitalization of variable names. Most
ClangIR code follows the MLIR conventions instead of the Clang
conventions.
llvm#1390)

The CIRGen support is already there. This PR adds LLVM lowering support
for comparisons between pointers to member functions. Note that pointers
to member functions could only be compared for equality.
Run clang-tidy on `CIRGenFunction.cpp` and fix all the issues that were
identified. The vast majority of issues were the case of parameter and
variable names. Some of the issues that didn't have to do with names had
to be resolved manually.

There should be no behavior changes.
To give LoweringPrepare type information from `CIRGenTypeCache`, this PR
adds two attributes to ModuleOp:
```mlir
module attributes {
  cir.int_size = #cir.int_size<32>,
  cir.size_type_size = #cir.size_type_size<64>,
  ...
} {}
```
The `CIRDataLayout` class is also extended to have `getPtrDiffTy` and so
on.

Some tests that only expects `cir.lang` and `cir.sob` are also changed
to take this into account.
If type of operand is not integer, it can be handled like what I do in
`__builtin_elementwise_exp`.
This patch adds support for simple cast operations on pointers to member
functions, including: 1) casting pointers to member function values to
boolean values; 2) reinterpret casts between pointers to member
functions.
This uses the assembly format for the optional return type and keeps a
custom printer/parser only for function parameters, which still require
a custom form for ellipses.
…#1412)

for example, lower 
`cir.alloca !cir.array<!s32i x N>, !cir.ptr<!cir.array<!s32i x N>>` 
to `memref.alloca() : memref<Nxi32>`

see llvm#1405
Get rid of the function `FuncOp::verifyType`. The function performed
three checks:

1. Check that `isa<cir::FuncType>(getFunctionType())`. This is a
tautology that is always true, since the return type of
`getFunctionType()` is already `cir::FuncType`.

2. Report an error if `type.isVarArg() && type.getNumInputs() == 0`,
i.e. when a variadic function has no named parameters. That check is
incorrect. In C++, variadic functions don't need to have any named
parameters. `void f(...) { }` is legal in C++ and ClangIR needs to be
able to compile it.

3. Report an error when the return type is `void`. This check is correct
(`void` return is represented as no return in MLIR), but it is
redundant. This is already checked in `FuncType::verify`.

Since `FuncOp::verifyType` serves no useful purpose, delete it, along
with the test for `int variadic(...)` that was in
`clang/test/CIR/IR/invalid.cir`.
)

Currently, the following code snippet fails during CIR codegen with
exceptions enabled:
```
#include <string>

void foo(const char *path) {
  std::string str = path;
  str = path;
  str = path;
}
```
using `bin/clang++ tmp.cpp -fclangir -Xclang -emit-cir -S`, the error: 
```
error: empty block: expect at least a terminator
```
Relevant part of the CIR before verification looks like: 
```
%118 = "cir.load"(%114) : (!cir.ptr<!cir.ptr<!cir.int<s, 8>>>) -> !cir.ptr<!cir.int<s, 8>>
"cir.try"() <{catch_types = [#cir.unwind], cleanup, synthetic}> ({
    %123 = "cir.call"(%115, %118) <{ast = #cir.call.expr.ast, callee = @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc, calling_conv = 1 : i32, exception, extra_attrs = #cir<extra({})>, side_effect = 1 : i32}> ({
    "cir.call"(%115) <{callee = @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev, calling_conv = 1 : i32, extra_attrs = #cir<extra({nothrow = #cir.nothrow})>, side_effect = 1 : i32}> ({
    }) : (!cir.ptr<!cir.struct<class "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>" {!cir.struct<struct "std::__cxx11::basic_string<char>::_Alloc_hider" {!cir.ptr<!cir.int<s, 8>>} #cir.record.decl.ast>, !cir.int<u, 64>, !cir.struct<union "anon.0" padded {!cir.array<!cir.int<s, 8> x 16>, !cir.int<u, 64>, !cir.array<!cir.int<u, 8> x 8>} #cir.record.decl.ast>} #cir.record.decl.ast>>) -> ()
    "cir.yield"() : () -> ()
    }) : (!cir.ptr<!cir.struct<class "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>" {!cir.struct<struct "std::__cxx11::basic_string<char>::_Alloc_hider" {!cir.ptr<!cir.int<s, 8>>} #cir.record.decl.ast>, !cir.int<u, 64>, !cir.struct<union "anon.0" padded {!cir.array<!cir.int<s, 8> x 16>, !cir.int<u, 64>, !cir.array<!cir.int<u, 8> x 8>} #cir.record.decl.ast>} #cir.record.decl.ast>>, !cir.ptr<!cir.int<s, 8>>) -> !cir.ptr<!cir.struct<class "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>" {!cir.struct<struct "std::__cxx11::basic_string<char>::_Alloc_hider" {!cir.ptr<!cir.int<s, 8>>} #cir.record.decl.ast>, !cir.int<u, 64>, !cir.struct<union "anon.0" padded {!cir.array<!cir.int<s, 8> x 16>, !cir.int<u, 64>, !cir.array<!cir.int<u, 8> x 8>} #cir.record.decl.ast>} #cir.record.decl.ast>>
    "cir.store"(%123, %116) : (!cir.ptr<!cir.struct<class "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>" {!cir.struct<struct "std::__cxx11::basic_string<char>::_Alloc_hider" {!cir.ptr<!cir.int<s, 8>>} #cir.record.decl.ast>, !cir.int<u, 64>, !cir.struct<union "anon.0" padded {!cir.array<!cir.int<s, 8> x 16>, !cir.int<u, 64>, !cir.array<!cir.int<u, 8> x 8>} #cir.record.decl.ast>} #cir.record.decl.ast>>, !cir.ptr<!cir.ptr<!cir.struct<class "std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>" {!cir.struct<struct "std::__cxx11::basic_string<char>::_Alloc_hider" {!cir.ptr<!cir.int<s, 8>>} #cir.record.decl.ast>, !cir.int<u, 64>, !cir.struct<union "anon.0" padded {!cir.array<!cir.int<s, 8> x 16>, !cir.int<u, 64>, !cir.array<!cir.int<u, 8> x 8>} #cir.record.decl.ast>} #cir.record.decl.ast>>>) -> ()
    "cir.yield"() : () -> ()
}, {
^bb0:              <--- EMPTY BLOCK
}) : () -> ()
```
There is an empty block! If you extend the snippet with more `str =
path;`, you get more empty blocks...

The issue is the `cir.resume` ops which should be in those empty blocks
from synthetic TryOp's aren't linked properly during the cleanup.

My suggestion: We should explicitly add `cir.resume` for synthetic
tryOp's, because we already know they have just an [unwind
handler](https://github.com/llvm/clangir/blob/8746bd4bbe777352c2935e9937449637a8943767/clang/lib/CIR/CodeGen/CIRGenCall.cpp#L506).
So, during
[CIRGenCleanup](https://github.com/llvm/clangir/blob/8746bd4bbe777352c2935e9937449637a8943767/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp#L667)
we don't need to add `cir.resume` for synthetic TryOp's. This PR adds
this and a test.
Run clang-tidy on `clang/lib/CIR/CodeGen/CIRGenModule.cpp`. Accept all
of the recommended fixes, except for one suggestion to use
`std::any_of`. The vast majority of the changes had to do with the case
of identifiers, changing variables and parameters from `VarName` to
`varName`.
I noticed that `AtomicFenceOp` doesn't use `OptionalAttr` like mlir
llvmir. As a result, `getLLVMSyncScope` does't return `std::optional`.
Should I use `Arg` instead?
bruteforceboy and others added 20 commits June 9, 2025 07:04
)

This PR introduces
[`TryMarkNoThrow`](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CodeGen/CodeGenFunction.cpp#L1394).
[`isInterposable`](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CodeGen/CodeGenFunction.cpp#L1397C10-L1397C26)
isn't fully implemented and I'm not quite sure we need it? Anyway, I
have introduced a missing feature `getSemanticInterposition` relevant
for its completion.

I have also updated an old test --
[`foo()`](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/test/CIR/CodeGen/try-catch-dtors.cpp#L313)
should be marked as unwind/nothrow. I have compared with the original
CodeGen and attached the llvm output for verification.

One concern I have is if the cases I have to mimic
[`mayThrow`](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/llvm/lib/IR/Instruction.cpp#L1158)
from the OG are enough, please let me know your thoughts.
This PR adds support for the `-fdump-record-layouts` flag. It enables
printing both the `CIRGenRecordLayout` and the `ASTRecordLayout`,
similar to what is done in CodeGen.
Backport support for Complex value initialization from the empty
InitList.

Backported from llvm/llvm-project#143192
)

Currently we can't handle continues nested under `IfOp`, because if we
replace it with a yield, then it only breaks out of that `if`-statement,
rather than continuing the whole loop.
Perhaps that should be done by changing the whole structure of the while
loop.

Co-authored-by: Yue Huang <[email protected]>
…llvm#1670)

Backport the VecShuffleOp verifier to catch invalid index

Implemented in llvm/llvm-project#143262
…llvm#1673)

When we process a completed Enum type, we were checking to see if the
completed type was in the type cache and clearing the cache if the
completed and converted underlying type for the enum doesn't pass an
`isInteger(32)` check. Unfortunately, this checks to see if the type is
the MLIR builtin 32-bit integer type, whereas it will always be a CIR
integer type, so the check always fails.

I don't believe there can ever be a case where the forward declared type
for the enum doesn't match the completed type, so we should never need
to clear the cache. This change replaces the previous check with an
assert that compares the actual completed type to the cached type.
…vm#1672)

This removes unnecessary parens from the assembly format of
BaseClassAddrOp, DerivedClassAddrOp, BaseDataMemberOp,
DerivedDataMemberOp, BaseMethodOp, and DerivedMethodOp to bring them
into conformance with the CIR ASM Style Guide.

The is no function change beyond the assembly format change.
- Replace std::map with llvm::StringMap and std::vector with
llvm::SmallVector for improved performance.
 - Preserve the behavior
 - Remove unused headers
Backport creating Array type with ComplexType as element type
As the scf dialect does not support early exits, it might be necessary
to change the body of WhileOp to implement the semantics of ContinueOp.
I choose to add a guard `if (!cond)` for everything following the
`continue`.

Co-authored-by: Yue Huang <[email protected]>
This PR is related to llvm#1685 and adds some basic support for the printf
function.

Limitations:
1. It only works if all variadic params are of basic interger/float type
(for more info why memref type operands don't work see llvm#1685)
2. Only works if the format string is definied directly inside the
printf function

The downside of this PR is also that the handling this edge case adds
significant code bloat and reduces readability for the cir.call op
lowering (I tried to insert some meanigful comments to improve the
readability), but I think its worth to do this so we have some basic
printf support (without adding an extra cir operation) until upstream
support for variadic functions is added to the func dialect. Also a few
more test (which use such a basic form of printf) in the llvm Single
Source test suite are working with this PR:

before this PR:

Testing Time: 4.00s

Total Discovered Tests: 1833
Passed : 420 (22.91%)
Failed : 10 (0.55%)
Executable Missing: 1403 (76.54%)

with this PR:

Testing Time: 10.29s

Total Discovered Tests: 1833
  Passed            :  458 (24.99%)
  Failed            :    6 (0.33%)
  Executable Missing: 1369 (74.69%)
This PR addresses the feedback from
llvm/llvm-project#142041 (comment).
Our algorithm for accumulating bitfields has diverged from CodeGen since
Clang 19.

There is one key difference: in CIR, we use the function
`getBitfieldStorageType`, which checks whether the bit width of the
current accumulation run is a valid fundamental width (i.e., a power of
two: 8, 16, 32, 64). If it is, it returns a CIR type of that size
otherwise, it returns an array with the closest alignment.

For example, given the following struct:

```c
struct S {
  int a : 4;
  int b : 27;
  int c : 17;
  int d : 2;
  int e : 15;
  unsigned f;
};
```

The CodeGen output is:

```llvm
%struct.S = type { i64, i16, i32 }
```

Whereas the new CIR algorithm produces:

```mlir
!cir.record<struct "S" {!cir.array<!u8i x 7>, !u16i, !u32i}>
```
In CIR, the algorithm accumulates up to field `d`, resulting in 50
accumulated bits. Since 50 is not a fundamental width, the closest
alignment is 56 bits, which leads to the type `!cir.array<!u8i x 7>`.
The algorithm stops before accumulating field `e` because including it
would exceed the register size (64), which is not ideal.

At this point, it's unclear whether this divergence from CodeGen
represents an improvement. If we wanted to match CodeGen exactly, we
would need to replace the use of `getBitfieldStorageType` with
`getUIntNType`. The difference is that `getUIntNType` always returns the
closest power-of-two integer type instead of falling back to an array
when the size is not a fundamental width.

With this change, CIR would match CodeGen's layout exactly. It would
require the following small code change:
```diff
diff --git a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
index 7c1802b..17538b191738 100644
--- a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
@@ -616,7 +616,7 @@ CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
       if (!InstallBest) {
         // Determine if accumulating the just-seen span will create an expensive
         // access unit or not.
-        mlir::Type Type = getBitfieldStorageType(astContext.toBits(AccessSize));
+        mlir::Type Type = getUIntNType(astContext.toBits(AccessSize));
         if (!astContext.getTargetInfo().hasCheapUnalignedBitFieldAccess())
           llvm_unreachable("NYI");

@@ -674,12 +674,12 @@ CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
         // remain there after a stable sort.
         mlir::Type Type;
         if (BestClipped) {
-          assert(getSize(getBitfieldStorageType(
+          assert(getSize(getUIntNType(
                      astContext.toBits(AccessSize))) > AccessSize &&
                  "Clipped access need not be clipped");
           Type = getByteArrayType(AccessSize);
         } else {
-          Type = getBitfieldStorageType(astContext.toBits(AccessSize));
+          Type = getUIntNType(astContext.toBits(AccessSize));
           assert(getSize(Type) == AccessSize &&
                  "Unclipped access must be clipped");
         }
```
You can see a comparison between the two functions
https://godbolt.org/z/qjx1MaEWG.

I'm currently unsure whether using one function over the other has
performance implications. Regarding the **ARM error I mentioned in the
meeting: it was an `assert` I had forgotten to update. It's now fixed
sorry for the confusion.**
- Create CIR specific EnumAttr bases and prefix enum attributes with `CIR_` that automatically puts enum to `cir` namespace

- Removes unnecessary enum case definitions

- Unifies naming of enum values to use capitals consistently and make enumerations to start from 0

- Remove now unnecessary printers/parsers that gets to be generated automatically
…vm#1683)

No test cases provided for `lzcnt_u16` as presented in the OG codegen
equivalent: `test/CodeGen/X86/lzcnt-builtins.c`.

related: llvm#1404
Implement base-2 exponential intrinsic as part of llvm#1192
…lvm#1671)

Hi, This is my first here! Tried to mirror some of the patterns already
presented in both the codegen lib and its tests

I'm very excited to start contributing and potentially making an impact
in this project! feedback is much appreciated.
convert from codegen
```c++
      assert(!Base.isVirtual() && "should not see vbases here");
      auto *BaseRD = Base.getType()->getAsCXXRecordDecl();
      Address V = CGF.GetAddressOfDirectBaseInCompleteClass(
          Dest.getAddress(), CXXRD, BaseRD,
          /*isBaseVirtual*/ false);
      AggValueSlot AggSlot = AggValueSlot::forAddr(
          V, Qualifiers(),
          AggValueSlot::IsDestructed,
          AggValueSlot::DoesNotNeedGCBarriers,
          AggValueSlot::IsNotAliased,
          CGF.getOverlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
      CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);

      if (QualType::DestructionKind dtorKind =
              Base.getType().isDestructedType())
        CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType());
```
Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 32e3971d31452620eb102f122259b429733b3ef0 67e6ac3525ffff8e95fdefd8d4cc0861a8234c8c --extensions cpp -- clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
View the diff from clang-format here.
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 756416302b..069233d27b 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1610,7 +1610,7 @@ void LoweringPreparePass::runOnOperation() {
   buildCXXGlobalInitFunc();
   buildGlobalCtorDtorList();
   buildGlobalAnnotationValues();
-  
+
   if (theModule && theModule->hasAttr("cir.global_annotations")) {
     theModule->removeAttr("cir.global_annotations");
   }

Copy link
Member

@bcardosolopes bcardosolopes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed explanation, some comments but this mostly ready to go

@@ -1610,6 +1610,10 @@ void LoweringPreparePass::runOnOperation() {
buildCXXGlobalInitFunc();
buildGlobalCtorDtorList();
buildGlobalAnnotationValues();

if (theModule && theModule->hasAttr("cir.global_annotations")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the curly braces!

@@ -2190,6 +2190,11 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
cir::FuncOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {

mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();
if (module->hasAttr("cir.global_annotations")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here!

@@ -2190,6 +2190,11 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
cir::FuncOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {

mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();
if (module->hasAttr("cir.global_annotations")) {
op->removeAttr("annotations");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? If cir.global_annotations have been removed in lowering prepare, how come it might show up here again?

@bcardosolopes
Copy link
Member

Seems like some clang-format is needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.