-
Notifications
You must be signed in to change notification settings - Fork 140
[CIR][CIRGen] CIR generation for bitfields. Fixes #13 #233
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
Yay, this is awesome! Thanks for putting up a PR, I'm gonna take a look tomorrow and get you some feedback! |
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.
The overall direction is good. The design I'm looking for here is a bit more higher level, but I'm fine with the more lower level as a start point. Next step (in a follow up PR) one could create more higher level abstractions to wrap some of the binop/shift details (for example, struct_element_addr
could receive an additional bit offset argument), and the logic you add in this PR can then move to LoweringPrepare
pass.
Did you had any thoughts on other higher level approaches?
This PR introduces bitfelds support. I explicitly marked the PR as a draft, since I foresee some discussion here. There are no tests so far - and I will add them once we agree on everything else (or won't do it if we disagree at all :) )
I encourage you to add tests as early as possible because it makes it easier for reviews (we can look at the generated code to think about whether things make sense). I'm sure we can always collaborate on a direction that will work for everyone :)
Probably, the key design decision is an extra pointer to CIRGenBitFieldInfo in the Value class. Unfortunately, it can not be done - at least from my point of view - in the same way, as it is done in the original CodeGen/CGValue.h. The rest of the code is a revision of the code generation in CodeGen .
The overall approach is good, one general principle is that we don't add support for paths that we don't write tests for, so the lack of tests makes it harder to judge whether some of it also makes sense (feel free to add asserts and start simple).
Also, there are some changes due to clang-format application. Just noticed it(
It's easier when that it's done already in the first PR, because if patch is already good we just need to merge it.
Basically, the next toy example works.
Doesn't build for me, when I try to build a more reduced version of the example from the description, it fails with Assertion failed: (Dst.isSimple() && "only implemented simple")
, also another good use of a testcase in the PR.
Seems like this is leading to several failures (ninja check-clang-cir
):
Failed Tests (11):
Clang :: CIR/CodeGen/basic.cpp
Clang :: CIR/CodeGen/binop.cpp
Clang :: CIR/CodeGen/cast.cpp
Clang :: CIR/CodeGen/derived-to-base.cpp
Clang :: CIR/CodeGen/loop.cpp
Clang :: CIR/CodeGen/types.c
Clang :: CIR/Transforms/lifetime-check-agg.cpp
Clang :: CIR/Transforms/lifetime-check-remarks.cpp
Clang :: CIR/Transforms/lifetime-check.cpp
Clang :: CIR/Transforms/lifetime-loop-valid.cpp
Clang :: CIR/Transforms/lifetime-loop.cpp
So the plan is the following: I add tests, maybe refactor the code a little, and then will cal you for the next review.
Not really. As I said, I took the code in
that's strange, nothing similar on my side. Will try to reproduce.
Well, that's bad( there is an idea though why did this happen |
Reproduced. If the code is in in |
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.
@gitoleg pretty neat!
I just had some minor suggestions and questions.
Sounds good!
Gotcha, please add testcases both for c and c++ then! |
@bcardosolopes @sitio-couto I addressed almost every issue, but still we lack of tests. The idea for you is to take a look at the code and tests, and may be add more ideas for the latter. Speaking about the tests were failing - there is a function |
Thanks for addressing the issues and for your patience! Can you also change the tests to use substitution blocks? There are other examples in the test directories. It's currently not easy to spot the relationship of the generated CIR with the source code in the tests.
Sweet! Can you rebase? @sitio-couto landed bunch of changes to structs. Do all tests pass? I'm gonna give it a try then. I've had second thoughts, and since you are here this might be a good opportunity to introduce a higher level operation already, by embed more information in
You're talking about the call from |
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.
Some inline comments too!
Also, as you fix things, can you mark relevant comments as resolved? That helps the reviewers a bunch, thanks! |
@bcardosolopes The first solution is to add at least a couple of integer attributes to the operations that will define the bitfield: an offset in the storage and the size. The problem is that load from and store to bitfield differ one from another (have different shift operations). So when we will pre-lower the Another solution is to introduce two new operations, for example So, what do you think? |
@bcardosolopes @gitoleg a few of my thoughts on the discussion:
Sounds like a lot of work for a single PR. Maybe we could break this into 3 separate PRs: this one, the creation and lowering of the higher-level ops, and updating the codegen to favor higher-level ops. There might be some wasted work in-between these PRs, but changing the current PR to use higher-level ops will likely be just as wasteful.
The idea of
I would suggest we start like this as well. There will likely be a large intersection between these and |
@gitoleg @sitio-couto thanks for the feedback. You're both right, |
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.
Marking this as needing changes because rebase and latest comments, but this almost ready to ship per latest discussion - raising representation will come into followup PRs. Thanks again for working on this @gitoleg
As we discussed in llvm#233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
This is an updated PR for [PR #233](#233) with some fixes explained in [PR #261](#261) which now can be safely closed. First of all, let me introduce how do the bitfields looks like in CIR. For the struct `S` defined as following: ``` typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; unsigned f; } S; ``` the CIR type is `!ty_22S22 = !cir.struct<struct "S" {!u32i, !u32i, !u16i, !u32i} #cir.record.decl.ast>` where all the bitfields are packed in the first three storages. Also, the next bugs was fixed: - type mismatch - index out of bounds - single bitfield of size < 8 The cases covered with tests.
As we discussed in #233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](llvm/clangir#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
…lvm#268) This is an updated PR for [PR llvm#233](llvm/clangir#233) with some fixes explained in [PR llvm#261](llvm/clangir#261) which now can be safely closed. First of all, let me introduce how do the bitfields looks like in CIR. For the struct `S` defined as following: ``` typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; unsigned f; } S; ``` the CIR type is `!ty_22S22 = !cir.struct<struct "S" {!u32i, !u32i, !u16i, !u32i} #cir.record.decl.ast>` where all the bitfields are packed in the first three storages. Also, the next bugs was fixed: - type mismatch - index out of bounds - single bitfield of size < 8 The cases covered with tests.
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
As we discussed in llvm#233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](llvm#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
…lvm#268) This is an updated PR for [PR llvm#233](llvm#233) with some fixes explained in [PR llvm#261](llvm#261) which now can be safely closed. First of all, let me introduce how do the bitfields looks like in CIR. For the struct `S` defined as following: ``` typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; unsigned f; } S; ``` the CIR type is `!ty_22S22 = !cir.struct<struct "S" {!u32i, !u32i, !u16i, !u32i} #cir.record.decl.ast>` where all the bitfields are packed in the first three storages. Also, the next bugs was fixed: - type mismatch - index out of bounds - single bitfield of size < 8 The cases covered with tests.
As we discussed in llvm#233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](llvm#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
…lvm#268) This is an updated PR for [PR llvm#233](llvm#233) with some fixes explained in [PR llvm#261](llvm#261) which now can be safely closed. First of all, let me introduce how do the bitfields looks like in CIR. For the struct `S` defined as following: ``` typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; unsigned f; } S; ``` the CIR type is `!ty_22S22 = !cir.struct<struct "S" {!u32i, !u32i, !u16i, !u32i} #cir.record.decl.ast>` where all the bitfields are packed in the first three storages. Also, the next bugs was fixed: - type mismatch - index out of bounds - single bitfield of size < 8 The cases covered with tests.
As we discussed in llvm#233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
This is an updated PR for [PR #233](#233) with some fixes explained in [PR #261](#261) which now can be safely closed. First of all, let me introduce how do the bitfields looks like in CIR. For the struct `S` defined as following: ``` typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; unsigned f; } S; ``` the CIR type is `!ty_22S22 = !cir.struct<struct "S" {!u32i, !u32i, !u16i, !u32i} #cir.record.decl.ast>` where all the bitfields are packed in the first three storages. Also, the next bugs was fixed: - type mismatch - index out of bounds - single bitfield of size < 8 The cases covered with tests.
As we discussed in #233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR removes the method `hasBooleanRepresentation` as was discussed in [PR#233](#233) Briefly, the `cir.bool` has the same representation in memory and after load. The LLVM IR differs, that's why the check is there, in the origin `CodeGen`. Also, in order to trigger the path and make the implementation to be conform with the original `CodeGen`, there are changes in the `CIRGenExprScalar`: call the common `buildFromLValue` instead of manaul `load` creation. Also, a couple of tests for the bool load/store added
This PR introduces bitfelds support. This now works: ``` typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
As we discussed in #233, there is a desire to have CIR operations for bit fields set/get access and do all the stuff in the `LoweringPrepare`. There is one thing I want to discuss, that's why the PR is marked as a draft now. Looks like I have to introduce some redundant helpers for all these `or` and `shift` operations: while we were in the `CodeGen` area, we used `CIRGenBuilder` and we could easily extend it. I bet we don't want to depend from `CodeGen` in the `LoweringPrepare`. Once it's true. what is a good place for all this common things? As an idea, we could introduce one more layer for builder, with no state involved - just helpers and nothing else. But again, what is a good place for it from your point of view?
This PR introduces bitfelds support. I explicitly marked the PR as a draft, since I foresee some discussion here.
There are no tests so far - and I will add them once we agree on everything else (or won't do it if we disagree at all :) )
Probably, the key design decision is an extra pointer to
CIRGenBitFieldInfo
in theValue
class. Unfortunately, it can not be done - at least from my point of view - in the same way, as it is done in the originalCodeGen/CGValue.h
. The rest of the code is a revision of the code generation inCodeGen
.Also, there are some changes due to
clang-format
application. Just noticed it(Basically, the next toy example works.
the output is:
1 321 15 -2 -123 1234