[clang] [CIR] Add support for unary operations on bitfield members (PR #148083)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 13 13:05:45 PDT 2025
================
@@ -239,3 +239,51 @@ void set_volatile(V* v) {
// OGCG: [[TMP3:%.*]] = and i64 [[TMP2]], -1095216660481
// OGCG: [[TMP4:%.*]] = or i64 [[TMP3]], 12884901888
// OGCG: store volatile i64 [[TMP4]], ptr [[TMP1]], align 4
+
+void unOp(S* s) {
+ s->d++;
+}
+
+// CIR: cir.func {{.*@unOp}}
+// CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["s", init] {alignment = 8 : i64}
+// CIR: [[TMP1:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR: [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "d"} : !cir.ptr<!rec_S> -> !cir.ptr<!u64i>
+// CIR: [[TMP3:%.*]] = cir.get_bitfield(#bfi_d, [[TMP2]] : !cir.ptr<!u64i>) -> !s32i
+// CIR: [[TMP4:%.*]] = cir.unary(inc, [[TMP3]]) nsw : !s32i, !s32i
+// CIR: cir.set_bitfield(#bfi_d, [[TMP2]] : !cir.ptr<!u64i>, [[TMP4]] : !s32i)
+
+// LLVM: define {{.*@unOp}}
+// LLVM: [[TMP0:%.*]] = getelementptr %struct.S, ptr [[LOAD0:%.*]], i32 0, i32 0
+// LLVM: [[TMP1:%.*]] = load i64, ptr [[TMP0]], align 8
----------------
Andres-Salamanca wrote:
The reason this happens is because during lowering of `get_bitfield`, we call `load` with an alignment of zero here:
https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp#L2630-L2631
When `load` is called with zero alignment, it defaults to the alignment of the type being loaded. In this example, the type is `u64`, since the member `d` is packed inside the following record:
`!rec_S = !cir.record<struct "S" {!u64i, !u16i, !u32i}>`
So the load uses the alignment of u64
https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/llvm/include/llvm/IR/IRBuilder.h#L1879-L1886
In contrast, classic CodeGen passes the alignment of the *struct*. Since the struct in this example only contains `int` members, its alignment is 4, and the load honors that. If we change the struct to include a `long`, classic CodeGen adjusts and uses an alignment of 8 accordingly as shown here:
https://godbolt.org/z/3a3Yhdjzr
[https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/clang/lib/CodeGen/CGExpr.cpp#L2341-L2343](https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/clang/lib/CodeGen/CGExpr.cpp#L2341-L2343)
[https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/clang/lib/CodeGen/CGBuilder.h#L124-L129](https://github.com/llvm/llvm-project/blob/f168175d01247af53e3ab243486065facc18fa49/clang/lib/CodeGen/CGBuilder.h#L124-L129)
The issue is that by the time we reach lowering, we no longer retain the original source-level struct alignment info, so the default alignment ends up coming from the storage type instead.
we could extend `BitFieldInfoAttr` to store the original type of the field.?
https://github.com/llvm/llvm-project/pull/148083
More information about the cfe-commits
mailing list