Skip to content

Commit 5204776

Browse files
committed
[CIR][CIRGen] Add const attribute to alloca operations
This patch adds a new attribute `const` to the alloca operation to indicate that the corresponding local variable declaration is `const`-qualified. Future optimizations may find this new attribute useful.
1 parent 4c44bf1 commit 5204776

15 files changed

+84
-25
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

+5
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ def AllocaOp : CIR_Op<"alloca", [
469469
cases, the first use contains the initialization (a cir.store, a cir.call
470470
to a ctor, etc).
471471

472+
The presence of the `const` attribute indicates that the local variable is
473+
declared with C/C++ `const` keyword.
474+
472475
The `dynAllocSize` specifies the size to dynamically allocate on the stack
473476
and ignores the allocation size based on the original type. This is useful
474477
when handling VLAs and is omitted when declaring regular local variables.
@@ -492,6 +495,7 @@ def AllocaOp : CIR_Op<"alloca", [
492495
TypeAttr:$allocaType,
493496
StrAttr:$name,
494497
UnitAttr:$init,
498+
UnitAttr:$constant,
495499
ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$alignment,
496500
OptionalAttr<ASTVarDeclInterface>:$ast
497501
);
@@ -529,6 +533,7 @@ def AllocaOp : CIR_Op<"alloca", [
529533
($dynAllocSize^ `:` type($dynAllocSize) `,`)?
530534
`[` $name
531535
(`,` `init` $init^)?
536+
(`,` `const` $constant^)?
532537
`]`
533538
(`ast` $ast^)? attr-dict
534539
}];

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,11 @@ mlir::LogicalResult CIRGenFunction::declare(const Decl *var, QualType ty,
305305
assert(!symbolTable.count(var) && "not supposed to be available just yet");
306306

307307
addr = buildAlloca(namedVar->getName(), ty, loc, alignment);
308-
if (isParam) {
309-
auto allocaOp = cast<mlir::cir::AllocaOp>(addr.getDefiningOp());
308+
auto allocaOp = cast<mlir::cir::AllocaOp>(addr.getDefiningOp());
309+
if (isParam)
310310
allocaOp.setInitAttr(mlir::UnitAttr::get(builder.getContext()));
311-
}
311+
if (ty->isReferenceType() || ty.isConstQualified())
312+
allocaOp.setConstantAttr(mlir::UnitAttr::get(builder.getContext()));
312313

313314
symbolTable.insert(var, addr);
314315
return mlir::success();
@@ -324,10 +325,11 @@ mlir::LogicalResult CIRGenFunction::declare(Address addr, const Decl *var,
324325
assert(!symbolTable.count(var) && "not supposed to be available just yet");
325326

326327
addrVal = addr.getPointer();
327-
if (isParam) {
328-
auto allocaOp = cast<mlir::cir::AllocaOp>(addrVal.getDefiningOp());
328+
auto allocaOp = cast<mlir::cir::AllocaOp>(addrVal.getDefiningOp());
329+
if (isParam)
329330
allocaOp.setInitAttr(mlir::UnitAttr::get(builder.getContext()));
330-
}
331+
if (ty->isReferenceType() || ty.isConstQualified())
332+
allocaOp.setConstantAttr(mlir::UnitAttr::get(builder.getContext()));
331333

332334
symbolTable.insert(var, addrVal);
333335
return mlir::success();

clang/test/CIR/CodeGen/assign-operator.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct String {
1616
//
1717
// CHECK: cir.func linkonce_odr @_ZN10StringViewC2ERK6String
1818
// CHECK: %0 = cir.alloca !cir.ptr<!ty_StringView>, !cir.ptr<!cir.ptr<!ty_StringView>>, ["this", init] {alignment = 8 : i64}
19-
// CHECK: %1 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["s", init] {alignment = 8 : i64}
19+
// CHECK: %1 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["s", init, const] {alignment = 8 : i64}
2020
// CHECK: cir.store %arg0, %0 : !cir.ptr<!ty_StringView>
2121
// CHECK: cir.store %arg1, %1 : !cir.ptr<!ty_String>
2222
// CHECK: %2 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_StringView>>
@@ -47,7 +47,7 @@ struct String {
4747
//
4848
// CHECK: cir.func linkonce_odr @_ZN10StringViewaSEOS_
4949
// CHECK: %0 = cir.alloca !cir.ptr<!ty_StringView>, !cir.ptr<!cir.ptr<!ty_StringView>>, ["this", init] {alignment = 8 : i64}
50-
// CHECK: %1 = cir.alloca !cir.ptr<!ty_StringView>, !cir.ptr<!cir.ptr<!ty_StringView>>, ["", init] {alignment = 8 : i64}
50+
// CHECK: %1 = cir.alloca !cir.ptr<!ty_StringView>, !cir.ptr<!cir.ptr<!ty_StringView>>, ["", init, const] {alignment = 8 : i64}
5151
// CHECK: %2 = cir.alloca !cir.ptr<!ty_StringView>, !cir.ptr<!cir.ptr<!ty_StringView>>, ["__retval"] {alignment = 8 : i64}
5252
// CHECK: cir.store %arg0, %0 : !cir.ptr<!ty_StringView>
5353
// CHECK: cir.store %arg1, %1 : !cir.ptr<!ty_StringView>

clang/test/CIR/CodeGen/basic.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ void x() {
155155
}
156156

157157
// CHECK: cir.func @_Z1xv()
158-
// CHECK: %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b0", init] {alignment = 1 : i64}
159-
// CHECK: %1 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b1", init] {alignment = 1 : i64}
158+
// CHECK: %0 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b0", init, const] {alignment = 1 : i64}
159+
// CHECK: %1 = cir.alloca !cir.bool, !cir.ptr<!cir.bool>, ["b1", init, const] {alignment = 1 : i64}
160160
// CHECK: %2 = cir.const #true
161161
// CHECK: cir.store %2, %0 : !cir.bool, !cir.ptr<!cir.bool>
162162
// CHECK: %3 = cir.const #false

clang/test/CIR/CodeGen/bitfields.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void store_field() {
4343
}
4444

4545
// CHECK: cir.func @_Z10load_field
46-
// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr<!ty_S>, !cir.ptr<!cir.ptr<!ty_S>>, ["s", init]
46+
// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr<!ty_S>, !cir.ptr<!cir.ptr<!ty_S>>, ["s", init, const]
4747
// CHECK: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.ptr<!ty_S>>, !cir.ptr<!ty_S>
4848
// CHECK: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr<!ty_S> -> !cir.ptr<!cir.array<!u8i x 3>>
4949
// CHECK: [[TMP3:%.*]] = cir.get_bitfield(#bfi_d, [[TMP2]] : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i

clang/test/CIR/CodeGen/cond.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ min(const unsigned long& __a, const unsigned long& __b) {
1111
}
1212

1313
// CHECK: cir.func @_Z3minRKmS0_(%arg0: !cir.ptr<!u64i>
14-
// CHECK: %0 = cir.alloca !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>, ["__a", init] {alignment = 8 : i64}
15-
// CHECK: %1 = cir.alloca !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>, ["__b", init] {alignment = 8 : i64}
14+
// CHECK: %0 = cir.alloca !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>, ["__a", init, const] {alignment = 8 : i64}
15+
// CHECK: %1 = cir.alloca !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>, ["__b", init, const] {alignment = 8 : i64}
1616
// CHECK: %2 = cir.alloca !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>, ["__retval"] {alignment = 8 : i64}
1717
// CHECK: cir.store %arg0, %0 : !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>
1818
// CHECK: cir.store %arg1, %1 : !cir.ptr<!u64i>, !cir.ptr<!cir.ptr<!u64i>>
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
int produce_int();
5+
void blackbox(const int &);
6+
7+
void local_const_int() {
8+
const int x = produce_int();
9+
}
10+
11+
// CHECK-LABEL: @_Z15local_const_intv
12+
// CHECK: %{{.+}} = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init, const]
13+
// CHECK: }
14+
15+
void param_const_int(const int x) {}
16+
17+
// CHECK-LABEL: @_Z15param_const_inti
18+
// CHECK: %{{.+}} = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init, const]
19+
// CHECK: }
20+
21+
void local_constexpr_int() {
22+
constexpr int x = 42;
23+
blackbox(x);
24+
}
25+
26+
// CHECK-LABEL: @_Z19local_constexpr_intv
27+
// CHECK: %{{.+}} = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init, const]
28+
// CHECK: }
29+
30+
void local_reference() {
31+
int x = 0;
32+
int &r = x;
33+
}
34+
35+
// CHECK-LABEL: @_Z15local_referencev
36+
// CHECK: %{{.+}} = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["r", init, const]
37+
// CHECK: }
38+
39+
struct Foo {
40+
int a;
41+
int b;
42+
};
43+
44+
Foo produce_foo();
45+
46+
void local_const_struct() {
47+
const Foo x = produce_foo();
48+
}
49+
50+
// CHECK-LABEL: @_Z18local_const_structv
51+
// CHECK: %{{.+}} = cir.alloca !ty_Foo, !cir.ptr<!ty_Foo>, ["x", init, const]
52+
// CHECK: }

clang/test/CIR/CodeGen/coro-task.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ folly::coro::Task<int> byRef(const std::string& s) {
275275

276276
// FIXME: this could be less redundant than two allocas + reloads
277277
// CHECK: cir.func coroutine @_Z5byRefRKSt6string(%arg0: !cir.ptr<![[StdString]]> {{.*}} ![[IntTask]] extra{{.*}}{
278-
// CHECK: %[[#AllocaParam:]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}} ["s", init]
279-
// CHECK: %[[#AllocaFnUse:]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}} ["s", init]
278+
// CHECK: %[[#AllocaParam:]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}} ["s", init, const]
279+
// CHECK: %[[#AllocaFnUse:]] = cir.alloca !cir.ptr<![[StdString]]>, {{.*}} ["s", init, const]
280280

281281
folly::coro::Task<void> silly_coro() {
282282
std::optional<folly::coro::Task<int>> task;

clang/test/CIR/CodeGen/ctor-member-lvalue-to-rvalue.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct String {
77
String(const String &s) : size{s.size} {}
88
// CHECK: cir.func linkonce_odr @_ZN6StringC2ERKS_
99
// CHECK: %0 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["this", init] {alignment = 8 : i64}
10-
// CHECK: %1 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["s", init] {alignment = 8 : i64}
10+
// CHECK: %1 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["s", init, const] {alignment = 8 : i64}
1111
// CHECK: cir.store %arg0, %0
1212
// CHECK: cir.store %arg1, %1
1313
// CHECK: %2 = cir.load %0

clang/test/CIR/CodeGen/derived-to-base.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void vcall(C1 &c1) {
109109
}
110110

111111
// CHECK: cir.func @_Z5vcallR2C1(%arg0: !cir.ptr<!ty_C1_>
112-
// CHECK: %0 = cir.alloca !cir.ptr<!ty_C1_>, !cir.ptr<!cir.ptr<!ty_C1_>>, ["c1", init] {alignment = 8 : i64}
112+
// CHECK: %0 = cir.alloca !cir.ptr<!ty_C1_>, !cir.ptr<!cir.ptr<!ty_C1_>>, ["c1", init, const] {alignment = 8 : i64}
113113
// CHECK: %1 = cir.alloca !ty_buffy, !cir.ptr<!ty_buffy>, ["b"] {alignment = 8 : i64}
114114
// CHECK: %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["e"] {alignment = 4 : i64}
115115
// CHECK: %3 = cir.alloca !ty_buffy, !cir.ptr<!ty_buffy>, ["agg.tmp0"] {alignment = 8 : i64}

clang/test/CIR/CodeGen/lvalue-refs.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct String {
77
void split(String &S) {}
88

99
// CHECK: cir.func @_Z5splitR6String(%arg0: !cir.ptr<!ty_String>
10-
// CHECK: %0 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["S", init]
10+
// CHECK: %0 = cir.alloca !cir.ptr<!ty_String>, !cir.ptr<!cir.ptr<!ty_String>>, ["S", init, const]
1111

1212
void foo() {
1313
String s;

clang/test/CIR/CodeGen/new.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ void m(int a, int b) {
1212
}
1313

1414
// CHECK: cir.func linkonce_odr @_ZSt11make_sharedI1SJRiS1_EESt10shared_ptrIT_EDpOT0_(
15-
// CHECK: %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["args", init] {alignment = 8 : i64}
16-
// CHECK: %1 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["args", init] {alignment = 8 : i64}
15+
// CHECK: %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["args", init, const] {alignment = 8 : i64}
16+
// CHECK: %1 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["args", init, const] {alignment = 8 : i64}
1717
// CHECK: %2 = cir.alloca !ty_std3A3Ashared_ptr3CS3E, !cir.ptr<!ty_std3A3Ashared_ptr3CS3E>, ["__retval"] {alignment = 1 : i64}
1818
// CHECK: cir.store %arg0, %0 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
1919
// CHECK: cir.store %arg1, %1 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>

clang/test/CIR/CodeGen/rangefor.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ void init(unsigned numImages) {
3333
// CHECK: %3 = cir.cast(integral, %2 : !u32i), !u64i
3434
// CHECK: cir.call @_ZNSt6vectorI6tripleEC1Em(%1, %3) : (!cir.ptr<![[VEC]]>, !u64i) -> ()
3535
// CHECK: cir.scope {
36-
// CHECK: %4 = cir.alloca !cir.ptr<![[VEC]]>, !cir.ptr<!cir.ptr<![[VEC]]>>, ["__range1", init] {alignment = 8 : i64}
36+
// CHECK: %4 = cir.alloca !cir.ptr<![[VEC]]>, !cir.ptr<!cir.ptr<![[VEC]]>>, ["__range1", init, const] {alignment = 8 : i64}
3737
// CHECK: %5 = cir.alloca ![[VEC_IT]], !cir.ptr<![[VEC_IT]]>, ["__begin1", init] {alignment = 8 : i64}
3838
// CHECK: %6 = cir.alloca ![[VEC_IT]], !cir.ptr<![[VEC_IT]]>, ["__end1", init] {alignment = 8 : i64}
39-
// CHECK: %7 = cir.alloca !cir.ptr<!ty_triple>, !cir.ptr<!cir.ptr<!ty_triple>>, ["image", init] {alignment = 8 : i64}
39+
// CHECK: %7 = cir.alloca !cir.ptr<!ty_triple>, !cir.ptr<!cir.ptr<!ty_triple>>, ["image", init, const] {alignment = 8 : i64}
4040
// CHECK: cir.store %1, %4 : !cir.ptr<![[VEC]]>, !cir.ptr<!cir.ptr<![[VEC]]>>
4141
// CHECK: %8 = cir.load %4 : !cir.ptr<!cir.ptr<![[VEC]]>>, !cir.ptr<![[VEC]]>
4242
// CHECK: %9 = cir.call @_ZNSt6vectorI6tripleE5beginEv(%8) : (!cir.ptr<![[VEC]]>) -> ![[VEC_IT]]

clang/test/CIR/CodeGen/return.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ int &ret0(int &x) {
55
}
66

77
// CHECK: cir.func @_Z4ret0Ri
8-
// CHECK: %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init] {alignment = 8 : i64}
8+
// CHECK: %0 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init, const] {alignment = 8 : i64}
99
// CHECK: %1 = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["__retval"] {alignment = 8 : i64}
1010
// CHECK: cir.store %arg0, %0 : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
1111
// CHECK: %2 = cir.load %0 : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>

clang/test/CIR/CodeGen/temporary-materialization.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ int test() {
1111
// CHECK: cir.func @_Z4testv()
1212
// CHECK-NEXT: %{{.+}} = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
1313
// CHECK-NEXT: %[[#TEMP_SLOT:]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp0", init] {alignment = 4 : i64}
14-
// CHECK-NEXT: %[[#x:]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init] {alignment = 8 : i64}
14+
// CHECK-NEXT: %[[#x:]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["x", init, const] {alignment = 8 : i64}
1515
// CHECK-NEXT: cir.scope {
1616
// CHECK-NEXT: %[[#TEMP_VALUE:]] = cir.call @_Z8make_intv() : () -> !s32i
1717
// CHECK-NEXT: cir.store %[[#TEMP_VALUE]], %[[#TEMP_SLOT]] : !s32i, !cir.ptr<!s32i>
@@ -33,7 +33,7 @@ int test_scoped() {
3333
// CHECK-NEXT: %{{.+}} = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
3434
// CHECK: cir.scope {
3535
// CHECK-NEXT: %[[#TEMP_SLOT:]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp0", init] {alignment = 4 : i64}
36-
// CHECK-NEXT: %[[#y:]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["y", init] {alignment = 8 : i64}
36+
// CHECK-NEXT: %[[#y:]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["y", init, const] {alignment = 8 : i64}
3737
// CHECK-NEXT: cir.scope {
3838
// CHECK-NEXT: %[[#TEMP_VALUE:]] = cir.call @_Z8make_intv() : () -> !s32i
3939
// CHECK-NEXT: cir.store %[[#TEMP_VALUE]], %[[#TEMP_SLOT]] : !s32i, !cir.ptr<!s32i>

0 commit comments

Comments
 (0)