Open ChuanqiXu9 opened 1 day ago
Hi! Thanks for looking into this again. For the case below the current implementation still fails to lower to LLVM, but works fine without InactiveUnionFieldAttr
typedef struct {
int a, b, c, d;
} T;
typedef union {
struct {
int a;
long b;
};
T c;
} S;
S s = {.c = {1, 2, 3, 4}};
Is this expected?
then the type of the initializer is not considered to be an union, so the computed size is not correct, which is the reason for the crash.
Have you considered making isLayoutIdentical
more robust? It's possible we might need to use layoutInfo
for taking some of the decisions (it's lazily computed and can be augmented to do more work), etc. It's probably best if we can hide this extra logic and keep some more similarity to OG skeleton to the extend we can.
Hi! Thanks for looking into this again. For the case below the current implementation still fails to lower to LLVM, but works fine without
InactiveUnionFieldAttr
typedef struct { int a, b, c, d; } T; typedef union { struct { int a; long b; }; T c; } S; S s = {.c = {1, 2, 3, 4}};
Is this expected?
Yes, this is more or less "expected". I took a quick look and find it is due to the incorrect result from isLayoutIdentical
too
then the type of the initializer is not considered to be an union, so the computed size is not correct, which is the reason for the crash.
Have you considered making
isLayoutIdentical
more robust? It's possible we might need to uselayoutInfo
for taking some of the decisions (it's lazily computed and can be augmented to do more work), etc. It's probably best if we can hide this extra logic and keep some more similarity to OG skeleton to the extend we can.
It may not solve the root problem. I spent some time to think about this and my conclusion is:
Here is the story:
i64
in this example) and we have members like i32
and paddings (array i8 4). And now we have problems for how to initialize i64
with i32
and a array of i8
4.Previously, it just works because the type of the initializer is not considered to be an union type. It makes sense in LLVM since union type is not a thing in LLVM. But it causes problem in the previous PR.
Close https://github.com/llvm/clangir/issues/1131
I took more time than I thought on this. The problem seems to be more complex than I thought. And the patch itself is a workaround to stop the regression.
Following off are some details that we can look back future:
InactiveUnionFieldAttr
, the line to compare the synthesized type and desired type (the union type) fails. https://github.com/llvm/clangir/blob/3aed38cf52e72cb51a907fad9dd53802f6505b81/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp#L456-L458then the type of the initializer is not considered to be an union, so the computed size is not correct, which is the reason for the crash.
It is worth to note that, before we introduce
InactiveUnionFieldAttr
, the comparison between the synthesized type and the desired type would fail too. But we can have the right size after all. So the reproducer in https://github.com/llvm/clangir/issues/1131 works.It doesn't work if we don't add these padding bits if we used
InactiveUnionFieldAttr
. It can avoid the crash. But then when lowering the code, we have to adding these padding bits by our selves. The problem is the type mismatch.In such manner, in https://github.com/llvm/clangir/blob/3aed38cf52e72cb51a907fad9dd53802f6505b81/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp#L433, the generated llvm type for the initializer of the union is
struct { i64 }
. But the generated type for the init value (in https://github.com/llvm/clangir/blob/3aed38cf52e72cb51a907fad9dd53802f6505b81/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp#L447) isi32
. Then we have to consider how to instantiate astruct { i64 }
with ani32
. The specific example is easy by usingzext
instruction. But how about the generic case? Especially the type of the struct can be not compatible with the init type. This may not be super hard but I'd like to not fix it in the patch.