Skip to content

Commit 30c8465

Browse files
authored
[CIR] Implement support for OffsetOfExpr (llvm#167726)
Implement support for the OffsetOfExpr
1 parent 29e3c2e commit 30c8465

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
203203
return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
204204
}
205205

206+
mlir::Value VisitOffsetOfExpr(OffsetOfExpr *e);
207+
206208
mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
207209
if (e->isGLValue())
208210
return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e),
@@ -2209,6 +2211,21 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
22092211
return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));
22102212
}
22112213

2214+
mlir::Value ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *e) {
2215+
// Try folding the offsetof to a constant.
2216+
Expr::EvalResult evalResult;
2217+
if (e->EvaluateAsInt(evalResult, cgf.getContext())) {
2218+
mlir::Type type = cgf.convertType(e->getType());
2219+
llvm::APSInt value = evalResult.Val.getInt();
2220+
return builder.getConstAPInt(cgf.getLoc(e->getExprLoc()), type, value);
2221+
}
2222+
2223+
cgf.getCIRGenModule().errorNYI(
2224+
e->getSourceRange(),
2225+
"ScalarExprEmitter::VisitOffsetOfExpr Can't eval expr as int");
2226+
return {};
2227+
}
2228+
22122229
mlir::Value ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *e) {
22132230
QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
22142231
mlir::Value result = VisitRealImag(e, promotionTy);
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
7+
8+
struct Struct {
9+
int a;
10+
float b;
11+
double c;
12+
bool d;
13+
};
14+
15+
void offset_of_builtin() {
16+
unsigned long a = __builtin_offsetof(Struct, a);
17+
unsigned long b = __builtin_offsetof(Struct, b);
18+
unsigned long c = __builtin_offsetof(Struct, c);
19+
unsigned long d = __builtin_offsetof(Struct, d);
20+
}
21+
22+
// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init]
23+
// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init]
24+
// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init]
25+
// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init]
26+
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i
27+
// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i>
28+
// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i
29+
// CIR: cir.store {{.*}} %[[CONST_4]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i>
30+
// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !u64i
31+
// CIR: cir.store {{.*}} %[[CONST_8]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i>
32+
// CIR: %[[CONST_16:.*]] = cir.const #cir.int<16> : !u64i
33+
// CIR: cir.store {{.*}} %[[CONST_16]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i>
34+
35+
// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8
36+
// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8
37+
// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8
38+
// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8
39+
// LLVM: store i64 0, ptr %[[A_ADDR]], align 8
40+
// LLVM: store i64 4, ptr %[[B_ADDR]], align 8
41+
// LLVM: store i64 8, ptr %[[C_ADDR]], align 8
42+
// LLVM: store i64 16, ptr %[[D_ADDR]], align 8
43+
44+
// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8
45+
// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8
46+
// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8
47+
// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8
48+
// OGCG: store i64 0, ptr %[[A_ADDR]], align 8
49+
// OGCG: store i64 4, ptr %[[B_ADDR]], align 8
50+
// OGCG: store i64 8, ptr %[[C_ADDR]], align 8
51+
// OGCG: store i64 16, ptr %[[D_ADDR]], align 8
52+
53+
struct StructWithArray {
54+
Struct array[4][4];
55+
};
56+
57+
void offset_of_builtin_from_array_element() {
58+
unsigned long a = __builtin_offsetof(StructWithArray, array[0][0].a);
59+
unsigned long b = __builtin_offsetof(StructWithArray, array[1][1].b);
60+
unsigned long c = __builtin_offsetof(StructWithArray, array[2][2].c);
61+
unsigned long d = __builtin_offsetof(StructWithArray, array[3][3].d);
62+
}
63+
64+
// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init]
65+
// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init]
66+
// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init]
67+
// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init]
68+
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i
69+
// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i>
70+
// CIR: %[[CONST_124:.*]] = cir.const #cir.int<124> : !u64i
71+
// CIR: cir.store {{.*}} %[[CONST_124]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i>
72+
// CIR: %[[CONST_248:.*]] = cir.const #cir.int<248> : !u64i
73+
// CIR: cir.store {{.*}} %[[CONST_248]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i>
74+
// CIR: %[[CONST_376:.*]] = cir.const #cir.int<376> : !u64i
75+
// CIR: cir.store {{.*}} %[[CONST_376]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i>
76+
77+
// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8
78+
// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8
79+
// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8
80+
// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8
81+
// LLVM: store i64 0, ptr %[[A_ADDR]], align 8
82+
// LLVM: store i64 124, ptr %[[B_ADDR]], align 8
83+
// LLVM: store i64 248, ptr %[[C_ADDR]], align 8
84+
// LLVM: store i64 376, ptr %[[D_ADDR]], align 8
85+
86+
// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8
87+
// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8
88+
// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8
89+
// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8
90+
// OGCG: store i64 0, ptr %[[A_ADDR]], align 8
91+
// OGCG: store i64 124, ptr %[[B_ADDR]], align 8
92+
// OGCG: store i64 248, ptr %[[C_ADDR]], align 8
93+
// OGCG: store i64 376, ptr %[[D_ADDR]], align 8

0 commit comments

Comments
 (0)