-
Notifications
You must be signed in to change notification settings - Fork 104
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][Transforms] Fix CallConv Function Lowering #979
Conversation
Thanks! This is marked as a draft, be sure to mark it ready for review when you want us to take a look :) |
Yes, there are a few things I want to check. It should be ready for review soon. |
Hey @bruteforceboy!
Since this workaround for type-checking is likely to show up in the future, this is what I had in mind:
This explicitly marks the intent of these kinds of casts, doesn't require much code, and makes it easy to drop the cast.
Looking forward to seeing what you cook up! |
@sitio-couto thanks for the feedback, sounds reasonable.
Maybe call it |
@sitio-couto creating a new cast kind sounds good! Personally, I played around with trying to remove the bitcast, but I didn't make so much progress. I had several problems with mismatched types after removing the bitcasts. I have now updated the PR, with my attempt at making the CIR correct. I have compared the generated LLVM, with the original codegen, and everything seems fine. |
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.
This is great, thanks for working on it
clang/test/CIR/Lowering/struct.c
Outdated
@@ -0,0 +1,89 @@ | |||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -fclangir-call-conv-lowering | |||
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM |
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.
This test should be in clang/test/CIR/Transforms/Target/x86_64/
auto Dest = storeOp.getAddr(); | ||
auto DestPtr = emitPointerBitcast(Dest, SrcTy, *this); | ||
rewriter.replaceOpWithNewOp<StoreOp>(storeOp, Ret, DestPtr); | ||
} |
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.
What happens if this isn't a StoreOp
?
clang/test/CIR/Lowering/struct.c
Outdated
int a, b; | ||
} S; | ||
|
||
// LLVM: @init(i64 %[[#V0:]]) |
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.
This testcase is great, thanks. The test should also show post-lowering in CIR terms, see other tests from clang/test/CIR/Transforms/Target/x86_64/
, most important it should show the casts.
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.
Noted. I will update these next week.
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.
I would advise against these tests.
They are too monolithic as they test multiple areas of the pipeline and are not quite related to the changes in this PR. These usually are extra work to maintain.
The CC lowering test already covers what this PR changes, what comes after is another pass' responsibility.
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.
I'm talking about the location, I think this is the best subdir to use for callconv tests, @sitio-couto do you have an alternative suggestion?
The CC lowering test already covers what this PR changes, what comes after is another pass' responsibility.
It's totally fine if new tests in this subdir test for LLVM output
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.
@bcardosolopes I see what you mean about the location, and I agree that from the options we have, your suggestion is the best. IIUC, these are integration tests that aim to check if ClangIR meets its LLVM IR baseline requirement, do we have a folder for those?
The CC lowering tests already feel a bit too monolithic. Ideally, they should focus on CIR-to-CIR testing, while CIR-to-LLVM is handled by lowering tests. C/C++ to LLVM IR is another suite of tests of its own, I suppose.
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.
I agree with @sitio-couto that we should keep CIR-to-CIR testing under transform tests, and LLVM in lowering tests. For now, I will add the CIR equivalent under the transform tests, and leave the LLVM equivalent under the lowering tests. Let me know what you think.
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.
Ideally, they should focus on CIR-to-CIR testing, while CIR-to-LLVM is handled by lowering tests. C/C++ to LLVM IR is another suite of tests of its own, I suppose.
In an ideal world that would be right, but we need AST for some of the pieces and we don't yet have a mechanism to serialize them, so CIR to CIR is only applicable to a handful of cases. Note that test/clang/CIR/Lowering
is already a mix of testing both LLVM and CIR in the same file AND standalone CIR tests. We should follow this pattern until we have a AST serialization story that will break the monolithic behavior for good.
For now, I will add the CIR equivalent under the transform tests, and leave the LLVM equivalent under the lowering tests. Let me know what you think.
I just moved things around and we now have test/clang/CIR/CallConvLowering/AArch64
, please put struct.c
there and test both CIR and LLVM output in the same file (note that this is a very common pattern in Lowering subdir).
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.
we need AST for some of the pieces [...] so CIR to CIR is only applicable to a handful of cases.
Agreed, and in this case, it applies: the test doesn't rely on AST info. While these tests are necessary, we should minimize them when possible, as you pointed out, it's the "ideal."
test/clang/CIR/Lowering
is already a mix of testing both LLVM and CIR in the same file AND standalone CIR tests. We should follow this pattern until we have a AST serialization story that will break the monolithic behavior for good.
I think we should follow said pattern where it makes sense; otherwise, we'll introduce unnecessary redundancy. Lowering tests are tightly coupled with LLVM Dialect and IR, requiring both cir-opt
and cir-translate
, so it's coherent to include both. This approach is also common in CodeGen, to ensure CIRGen emits the same LLVM IR as CodeGen (AFAIK), which also seems coherent. But for the CC lowering tests, it seems unnecessary.
In any case, I'm fine with your call.
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.
I moved the tests to test/clang/CIR/CallConvLowering/AArch64
.
@@ -899,6 +909,15 @@ Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo, | |||
} | |||
}(); | |||
|
|||
for (auto user : Caller.getOperation()->getUsers()) { |
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.
Seems like updating the users of a transformed call should be a common thing to do in target lowering, I wonder if there's a better place for this or if the logic can be incorporated in a pre-existing place. cc @sitio-couto
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.
This seems hacky. You should not have to handle more bit casts after the return value lambda that does the type coercion, is already concluded. Especially not in a path common to all return types and all store ops. This should be done only to struct return values and their respective stores.
This should be within the createCoercedValue call you left commented above. Please move this logic there.
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.
Was this fixed? Seems like I'm seeing the same code?
@bruteforceboy please allow the reviewers to resolve conversations, easier to make sure things got addressed.
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.
oh, sorry about that. I moved the rewrite for the store operations, so it is only for struct return values.
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.
@bruteforceboy reviewed.
clang/test/CIR/Transforms/Target/x86_64/x86_64-call-conv-lowering-pass.cpp
Outdated
Show resolved
Hide resolved
@@ -899,6 +909,15 @@ Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo, | |||
} | |||
}(); | |||
|
|||
for (auto user : Caller.getOperation()->getUsers()) { |
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.
This seems hacky. You should not have to handle more bit casts after the return value lambda that does the type coercion, is already concluded. Especially not in a path common to all return types and all store ops. This should be done only to struct return values and their respective stores.
This should be within the createCoercedValue call you left commented above. Please move this logic there.
clang/test/CIR/Lowering/struct.c
Outdated
int a, b; | ||
} S; | ||
|
||
// LLVM: @init(i64 %[[#V0:]]) |
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.
I would advise against these tests.
They are too monolithic as they test multiple areas of the pipeline and are not quite related to the changes in this PR. These usually are extra work to maintain.
The CC lowering test already covers what this PR changes, what comes after is another pass' responsibility.
clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp
Outdated
Show resolved
Hide resolved
dc6b5f4
to
e744086
Compare
@sitio-couto any else that needs addressing? |
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.
@bruteforceboy approved! thanks for changes.
Re #958 > Consider the following code snippet `tmp.c`: > ``` > typedef struct { > int a, b; > } S; > > void foo(S s) {} > ``` > Running `bin/clang tmp.c -fclangir -Xclang -emit-llvm -Xclang -fclangir-call-conv-lowering -S -o -`, we get: > ``` > loc(fused["tmp.c":5:1, "tmp.c":5:16]): error: 'llvm.bitcast' op result #0 must be LLVM-compatible non-aggregate type, but got '!llvm.struct<"struct.S", (i32, i32)>' > ``` > We can also produce a similar error from this: > ``` > typedef struct { > int a, b; > } S; > > S init() { S s; return s; } > ``` > gives: > ``` > loc(fused["tmp.c":5:17, "tmp.c":5:24]): error: 'llvm.bitcast' op operand #0 must be LLVM-compatible non-aggregate type, but got '!llvm.struct<"struct.S", (i32, i32)>' > ``` > I've traced the errors back to `lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp` in `LowerFunction::buildAggregateStore`, `castReturnValue`, and `buildAggregateBitcast`. > > `withElementType(SrcTy)` is currently commented out/ignored in `LowerFunction.cpp`, but it is important. > > This PR adds/fixes this and updates one test. I thought [about it](#958 (comment)) and I understand adding `cir.bitcast` to circumvent the CIR checks, but I am not sure how we can ignore/drop the bitcast while lowering. I think we can just make the CIR casts correct. I have added a number of lowering tests to verify that the CIR is lowered properly. cc: @sitio-couto @bcardosolopes.
Re #958
I thought about it and I understand adding
cir.bitcast
to circumvent the CIR checks, but I am not sure how we can ignore/drop the bitcast while lowering. I think we can just make the CIR casts correct.I have added a number of lowering tests to verify that the CIR is lowered properly.
cc: @sitio-couto @bcardosolopes.