Skip to content
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

[CIR][Lowering] Add the concept of simple lowering and use it to implement FP intrincis #434

Open
wants to merge 1,362 commits into
base: main
Choose a base branch
from

Conversation

philnik777
Copy link
Contributor

No description provided.

sitio-couto and others added 30 commits January 28, 2024 20:44
Lowers the particular case where an array of structs is constant-initialized.

ghstack-source-id: f8389d899e07f73485658d86469d7595a4373901
Pull Request resolved: llvm#202
Updates the lowering of cir.const to support #cir.const_struct as a
initializer, allowing the initialization of local structs with said
attribute.

ghstack-source-id: cc6c1378775bd2239c821c357e281bbc8cc3b0a7
Pull Request resolved: llvm#203
Global addresses are constant, so we can initialize them at compile time
using CIR's global_view attribute. This patch adds codegen support for
the initialization of variables with constant global addresses.

Since a builder method was added for global_view, the patch also updates
the codegen of global variables to use it wherever possible.

ghstack-source-id: 513365c52ac1ca603a81fcf3ff124b5da39f6f14
Pull Request resolved: llvm#204
Adds lowering logic for CIR's global_view attributes with no indexes.
This is done by converting the global to a region-initialized LLVM
global operation, where the region returns the address of the global
used in the gloval_view initializer attribute.

ghstack-source-id: a9452eddbd516553273461a8187afcebc211e4d3
Pull Request resolved: llvm#205
Constant initialization of static local arrays would fail due to a
mismatch between the variable and the initializer type size. This patch
fixes the data layout interface implementation for the cir.array type.

A complete array in C/C++ should have its type size in bits equal to
the size of the array times the size of the element type.

ghstack-source-id: 56f3f2918b23309210ad026017bafa37ca03b2d4
Pull Request resolved: llvm#206
ghstack-source-id: 1f793b2abcb144ab10b1ddbd99f12d1dcc6c8707
Pull Request resolved: llvm#207
PR llvm#200 broke the vtableAttr usage, as it was not properly refactored
to use ArrayAttr instead of ConstStructAttr to store its members.
This change does the CIR generation for globals initialized by a
constructor call. It currently only covers C++ to CIR generation. The
corresponding LLVM lowering will be in a follow-up commit.

A motivating example is

```
class Init {
  friend class ios_base;

public:
  Init(bool);
  ~Init();

private:
  static bool _S_synced_with_stdio;
};

static Init ioinit(true);
```

Unlike what the default Clang codegen generates LLVM that detaches the
initialization code from the global var definition (like below), we are
taking a different approach that keeps them together, which we think
will make the later dataflow analysis/transform easier.

```
@_ZL8ioinit = internal global %class.Init zeroinitializer, align 1, !dbg !0

define internal void @cxx_global_var_init() #0 section ".text.startup" !dbg !23 {
entry:
  call void @_ZN4InitC2Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZL8ioinit), !dbg !27
  %0 = call i32 @cxa_atexit(ptr @_ZN4InitD1Ev, ptr @_ZL8ioinit, ptr @dso_handle) llvm#3, !dbg !29
  ret void, !dbg !27
}
```

So on CIR, we have something like:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
}
```

The destructor support will also be in a separate change.
This PR fixes lowering for `break/continue`  in loops.
The idea is to replace `cir.yield break` and `cir.yield continue` with
the branch operations to the corresponding blocks. Note, that we need to
ignore nesting loops and don't touch `break` in switch operations. Also,
`yield` from `if` need to be considered only when it's not the loop
`yield` and `continue` in switch is ignored since it's processed in the
loops lowering.

Fixes llvm#160
Essentially emits an LValue for the struct and then passes it as a call
argument.
Enabling IR printing with --mlir-print-ir-after=passName1, passName2.
This requires all CIR passes to be registered at startup time.
Summary:
Setting the Optnone attribute for CIR functions and progating it all the
way down to LLVM IR for those not supposed to be optimized.
…zers (llvm#235)

As a follow up to llvm#197, this change
pre-lowers high-level CIR for global initializers.

High-level CIR:

```
  cir.global "private" internal @_ZL8__ioinit = ctor : !ty_22class2EInit22 {
    %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22> loc(#loc8)
    %1 = cir.const(#true) : !cir.bool loc(#loc5)
    cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> () loc(#loc6)
 }
```

After pre-lowering:

```
   cir.global "private" internal @_ZL8__ioinit =  #cir.zero : !ty_22class2EInit22 {ast = #cir.vardecl.ast}

   cir.func internal private @__cxx_global_var_init() {
     %0 = cir.get_global @_ZL8__ioinit : cir.ptr <!ty_22class2EInit22>
     %1 = cir.const(#true) : !cir.bool
     cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr<!ty_22class2EInit22>, !cir.bool) -> ()
     cir.return
  }

   cir.func private @_GLOBAL__sub_I_static.cpp() {
     cir.call @__cxx_global_var_init() : () -> ()
     cir.return
  }
```


There is still work to be done to fully lower to LLVM. E.g, add
`llvm.global_ctors` global to list all module initializers like
`_GLOBAL__sub_I_static`. This will be handled in a separate change.
cir-tidy has been our custom hack for using clang-tidy. There's no reason it
needs to be that way - add a CIRModule to clang-tidy and make the lifetime
checker its first check. Some of the way this was built was inspired in
CLANG_TIDY_ENABLE_STATIC_ANALYZER

Once we can fully migrate deps from cir-tidy, we should remove it in favor of
this.
…s::options

This unbreaks Linux builds, which points to cycles while using utils::options
from ClangTidy.cpp. We need to find a better way to convey this.
This PR fixes CIR generation for the `switch-case` cases like the
following:
```
case 'a':
default:
 ...
```
or
```
default:
case 'a':
...
```
i.e. when the `default` clause is sub-statement of the `case` one and
vice versa.
Whenever a global array is declared and initialized with fewer elements
than its size, the remaining elements are implicitly initialized with
zero. For aggregates types, such as structs, the initialization is done
through the #cir.zero attribute.

ghstack-source-id: b3d172c8092acf904f9c2204621d900d70d0e819
Pull Request resolved: llvm#216
This small improvement allows for a more compact representation of
structs with zero-initialized fields in the C++ codegen.

ghstack-source-id: a3fe0dc6c0dd89e22cb38167bb9d9cd7b9f43b8f
Pull Request resolved: llvm#217
Due to the lack of zeroinitializer support in LLVM, some cases are
tricky to lower #cir.zero. An example is when an array is only partially
initialize with #cir.zero attributes. Since we can't just zeroinitialize
the whole array, the current #cir.zero attribute amend does not suffice.
To simplify the lowering, this patch introduces a new operation that is
solely used to generate zeroinitialize LLVM IR constants.

ghstack-source-id: a3fd40ec3ce8970ac4e958076cc17d3fac573696
Pull Request resolved: llvm#218
Supports lowering for #cir.zero attributes when it appears in aggregate
attributes such as #const.array and #cir.struct.

ghstack-source-id: d26a506f29b581ed57d838e5281d9abbb2c24820
Pull Request resolved: llvm#219
sitio-couto and others added 17 commits January 29, 2024 15:20
Creates a separate C/C++ operation for do-while loops, while keeping the
LoopOpInterface to generically handle loops. This simplifies the IR
generation and printing/parsing of do-while loops. It also allows us to
define it regions in the order that they are executed, which is useful
for the lifetime analysis.

ghstack-source-id: b4d9517197b8f82ae677dc2684101fe5762b21b7
Pull Request resolved: llvm#407
Creates a separate C/C++ operation for while loops, while keeping the
LoopOpInterface to generically handle loops. This simplifies the IR
generation and printing/parsing of while loops.

ghstack-source-id: 29a6d7530263a4f96dbe6ce3052875831126005d
Pull Request resolved: llvm#408
This patch completes the deprecation of the generic `cir.loop` operation
by adding a new `cir.for` operation and removing the `cir.loop` op. The
new representation removes some bloat and places the regions in order of
execution.

ghstack-source-id: 886e0dacc632e5809015e2212810d690ef3ec294
Pull Request resolved: llvm#409
…rations

More machinery for exceptions.

This time around we finally emit a cir.catch and fix the order of emitting
operations. This allows a testcase to be added. I also added `CatchParamOp`,
which fetches the arguments for the clauses from the !cir.eh_info object.

Work coming next:
- Dtors.
- Use cir.try instead of cir.scope.
- Eesume.
- Documentation.`
This is currently missing and Debug builds are failing without it.
ghstack-source-id: 855519648a4bf2dced501f96e6de1b9b164d85ad
Pull Request resolved: llvm#424
ghstack-source-id: 0706d6bb81b5b8eefb04146719b4443aedb29ab1
Pull Request resolved: llvm#427
One more step towards completing try/catch.
…rface

This is prep work for introducing cir.try_call inside cir.try scopes.
One more incremental step towards try/catch: properly use cir.try_call instead
of regular cir.call when within a cir.try region.
)

This patch adds a new `volatile` tag to the following operations to
distinguish volatile loads and stores from normal loads and stores:

- `cir.load`
- `cir.store`
- `cir.get_bitfield`
- `cir.set_bitfield`

Besides, this patch also updates the CodeGen and LLVMIR lowering code to
start emitting CIR and LLVMIR operations with volatile flag.
This is part 3 of implementing vector types and vector operations in
ClangIR, issue llvm#284.

Create new operation `cir.vec.cmp` which implements the relational
comparison operators (`== != < > <= >=`) on vector types. A new
operation was created rather than reusing `cir.cmp` because the result
is a vector of a signed intergral type, not a `bool`.

Add CodeGen and Lowering tests for vector comparisons.

Fix the floating-point comparison predicate when lowering to LLVM. To
handle NaN values correctly, the comparisons need to be ordered rather
than unordered. (Except for `!=`, which needs to be unordered.) For
example, "ueq" was changed to "oeq".
Compilation of the following test
```
void foo6(A* a1) {
  A a2 = (*a1);
}
```
fails with.
```
NYI
UNREACHABLE executed at /home/huawei/cir/repo/llvm-project/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp:175!
```
Commit adds required visitor and fixes the issue.
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.

This is really nice, yay! Mostly cosmetic changes needed.

@@ -1797,6 +1802,9 @@ def VecInsertOp : CIR_Op<"vec.insert", [Pure,
}];

let hasVerifier = 0;

let SimpleLowering = 1;
let LLVMOpName = "InsertElementOp";
Copy link
Member

Choose a reason for hiding this comment

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

@dkolsen-pgi do you plan to change these ops soon in any way that would invalidate this approach?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't have any plans to change cir.vec.insert or cir.vec.extract. I am fine with simplifying the LLVM lowering.

@@ -36,8 +36,13 @@ include "mlir/IR/SymbolInterfaces.td"
// CIR Ops
//===----------------------------------------------------------------------===//

class LoweringInfo {
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment explaining what's the purpose of this class.

@@ -36,8 +36,13 @@ include "mlir/IR/SymbolInterfaces.td"
// CIR Ops
//===----------------------------------------------------------------------===//

class LoweringInfo {
Copy link
Member

Choose a reason for hiding this comment

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

Do you plan to use this for things other than facilitating LLVM lowering? If not, I suggest you rename this to LLVMLoweringInfo for now.

@@ -36,8 +36,13 @@ include "mlir/IR/SymbolInterfaces.td"
// CIR Ops
//===----------------------------------------------------------------------===//

class LoweringInfo {
bit SimpleLowering = 0;
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 SimpleLowering as opposed to which other types of lowering? My suggestion is to tie it up for now with the only implemented thing, which is builtins: bit builtinLowering = 0;

@@ -36,8 +36,13 @@ include "mlir/IR/SymbolInterfaces.td"
// CIR Ops
//===----------------------------------------------------------------------===//

class LoweringInfo {
bit SimpleLowering = 0;
string LLVMOpName;
Copy link
Member

Choose a reason for hiding this comment

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

Let's lowercase all member to be a closer match to MLIR, so this one would be llvmOpName;

@philnik777 philnik777 changed the title [CIR][Lowering] Add the concept of simple lowering and useit to implement FP intrincis [CIR][Lowering] Add the concept of simple lowering and use it to implement FP intrincis Feb 20, 2024
@Lancern
Copy link
Collaborator

Lancern commented Mar 6, 2024

This is an awesome feature! This is not a blocker for the PR, just some ideas for further development. This feature may be generalized in the future to declare lowering rules more flexibly. Consider the cir.bit family of operations, which has an LLVMIR lowering scheme like the following:

%1 = cir.bit.clz(%0 : !u32i) : !s32i
// %1 = llvm.call_intrinsic "llvm.ctlz.i32"(%0 : i32) : i32 -> i32

%2 = cir.bit.ctz(%0 : !u32i) : !s32i
// %2 = llvm.call_intrinsic "llvm.cttz.i32"(%0 : i32) : i32 -> i32

%3 = cir.bit.popcount(%0 : !u32i) : !s32i
// %3 = llvm.call_intrinsic "llvm.ctpop.i32"(%0 : i32) : i32 -> i32

Basically all cir.bit.* operation will be lowered to an llvm.call_intrinsic operation whose intrin parameter is determined by the CIR operation type.

Stuff in this PR cannot be used to achieve the lowering scheme above because we cannot specify the parameters to the LLVMIR operations. It would be nice if this is added in the future; it would be very useful for lowering compiler intrinsics as shown above.

@bcardosolopes
Copy link
Member

Good point @Lancern, we can definitely extend the mechanism later to also support things that get lowered to llvm.call_intrinsic.

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.

None yet