Skip to content

Commit e2b4ba0

Browse files
authored
[CIR] Add poison attribute (#150760)
This patch adds the `#cir.poison` attribute which represents a poison value. This patch also updates various operation folders to let them propagate poison values from their inputs to their outputs.
1 parent c639475 commit e2b4ba0

File tree

7 files changed

+147
-7
lines changed

7 files changed

+147
-7
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ def UndefAttr : CIR_TypedAttr<"Undef", "undef"> {
146146
}];
147147
}
148148

149+
//===----------------------------------------------------------------------===//
150+
// PoisonAttr
151+
//===----------------------------------------------------------------------===//
152+
153+
def CIR_PoisonAttr : CIR_TypedAttr<"Poison", "poison"> {
154+
let summary = "Represent a typed poison constant";
155+
let description = [{
156+
The PoisonAttr represents a typed poison constant, corresponding to LLVM's
157+
notion of poison.
158+
}];
159+
}
160+
149161
//===----------------------------------------------------------------------===//
150162
// IntegerAttr
151163
//===----------------------------------------------------------------------===//

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ struct MissingFeatures {
287287

288288
// Future CIR attributes
289289
static bool optInfoAttr() { return false; }
290-
static bool poisonAttr() { return false; }
291290
};
292291

293292
} // namespace cir

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
339339
}
340340

341341
if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
342-
cir::ConstComplexAttr>(attrType))
342+
cir::ConstComplexAttr, cir::PoisonAttr>(attrType))
343343
return success();
344344

345345
assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
@@ -629,6 +629,11 @@ static Value tryFoldCastChain(cir::CastOp op) {
629629
}
630630

631631
OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {
632+
if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getSrc())) {
633+
// Propagate poison value
634+
return cir::PoisonAttr::get(getContext(), getType());
635+
}
636+
632637
if (getSrc().getType() == getType()) {
633638
switch (getKind()) {
634639
case cir::CastKind::integral: {
@@ -1783,6 +1788,12 @@ static bool isBoolNot(cir::UnaryOp op) {
17831788
//
17841789
// and the argument of the first one (%0) will be used instead.
17851790
OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) {
1791+
if (auto poison =
1792+
mlir::dyn_cast_if_present<cir::PoisonAttr>(adaptor.getInput())) {
1793+
// Propagate poison values
1794+
return poison;
1795+
}
1796+
17861797
if (isBoolNot(*this))
17871798
if (auto previous = dyn_cast_or_null<UnaryOp>(getInput().getDefiningOp()))
17881799
if (isBoolNot(previous))
@@ -2239,16 +2250,18 @@ static OpFoldResult
22392250
foldUnaryBitOp(mlir::Attribute inputAttr,
22402251
llvm::function_ref<llvm::APInt(const llvm::APInt &)> func,
22412252
bool poisonZero = false) {
2253+
if (mlir::isa_and_present<cir::PoisonAttr>(inputAttr)) {
2254+
// Propagate poison value
2255+
return inputAttr;
2256+
}
2257+
22422258
auto input = mlir::dyn_cast_if_present<IntAttr>(inputAttr);
22432259
if (!input)
22442260
return nullptr;
22452261

22462262
llvm::APInt inputValue = input.getValue();
2247-
if (poisonZero && inputValue.isZero()) {
2248-
// TODO(cir): maybe we should return a poison value here?
2249-
assert(!MissingFeatures::poisonAttr());
2250-
return nullptr;
2251-
}
2263+
if (poisonZero && inputValue.isZero())
2264+
return cir::PoisonAttr::get(input.getType());
22522265

22532266
llvm::APInt resultValue = func(inputValue);
22542267
return IntAttr::get(input.getType(), resultValue);
@@ -2307,6 +2320,12 @@ OpFoldResult ByteSwapOp::fold(FoldAdaptor adaptor) {
23072320
}
23082321

23092322
OpFoldResult RotateOp::fold(FoldAdaptor adaptor) {
2323+
if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getInput()) ||
2324+
mlir::isa_and_present<cir::PoisonAttr>(adaptor.getAmount())) {
2325+
// Propagate poison values
2326+
return cir::PoisonAttr::get(getType());
2327+
}
2328+
23102329
auto input = mlir::dyn_cast_if_present<IntAttr>(adaptor.getInput());
23112330
auto amount = mlir::dyn_cast_if_present<IntAttr>(adaptor.getAmount());
23122331
if (!input && !amount)

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,12 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
10271027
mlir::ConversionPatternRewriter &rewriter) const {
10281028
mlir::Attribute attr = op.getValue();
10291029

1030+
if (mlir::isa<cir::PoisonAttr>(attr)) {
1031+
rewriter.replaceOpWithNewOp<mlir::LLVM::PoisonOp>(
1032+
op, getTypeConverter()->convertType(op.getType()));
1033+
return mlir::success();
1034+
}
1035+
10301036
if (mlir::isa<mlir::IntegerType>(op.getType())) {
10311037
// Verified cir.const operations cannot actually be of these types, but the
10321038
// lowering pass may generate temporary cir.const operations with these

clang/test/CIR/Lowering/poison.cir

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: cir-translate -cir-to-llvmir --disable-cc-lowering -o %t.ll %s
2+
// RUN: FileCheck -check-prefix=LLVM --input-file=%t.ll %s
3+
4+
!s32i = !cir.int<s, 32>
5+
6+
module {
7+
cir.func @lower_poison() -> !s32i {
8+
%0 = cir.const #cir.poison : !s32i
9+
cir.return %0 : !s32i
10+
}
11+
// LLVM-LABEL: @lower_poison
12+
// LLVM-NEXT: ret i32 poison
13+
// LLVM-NEXT: }
14+
}

clang/test/CIR/Transforms/bit.cir

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ module {
2525
// CHECK-NEXT: cir.return %[[R]] : !u32i
2626
// CHECK-NEXT: }
2727

28+
cir.func @fold_clz_zero_poison() -> !u32i {
29+
%0 = cir.const #cir.int<0> : !u32i
30+
%1 = cir.clz %0 poison_zero : !u32i
31+
cir.return %1 : !u32i
32+
}
33+
// CHECK-LABEL: @fold_clz_zero_poison
34+
// CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i
35+
// CHECK-NEXT: cir.return %[[R]] : !u32i
36+
// CHECK-NEXT: }
37+
38+
cir.func @fold_clz_zero_no_poison() -> !u32i {
39+
%0 = cir.const #cir.int<0> : !u32i
40+
%1 = cir.clz %0 : !u32i
41+
cir.return %1 : !u32i
42+
}
43+
// CHECK-LABEL: @fold_clz_zero_no_poison
44+
// CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i
45+
// CHECK-NEXT: cir.return %[[R]] : !u32i
46+
// CHECK-NEXT: }
47+
2848
cir.func @fold_ctz() -> !u32i {
2949
%0 = cir.const #cir.int<2> : !u32i
3050
%1 = cir.ctz %0 : !u32i
@@ -35,6 +55,26 @@ module {
3555
// CHECK-NEXT: cir.return %[[R]] : !u32i
3656
// CHECK-NEXT: }
3757

58+
cir.func @fold_ctz_zero_poison() -> !u32i {
59+
%0 = cir.const #cir.int<0> : !u32i
60+
%1 = cir.ctz %0 poison_zero : !u32i
61+
cir.return %1 : !u32i
62+
}
63+
// CHECK-LABEL: @fold_ctz_zero_poison
64+
// CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i
65+
// CHECK-NEXT: cir.return %[[R]] : !u32i
66+
// CHECK-NEXT: }
67+
68+
cir.func @fold_ctz_zero_no_poison() -> !u32i {
69+
%0 = cir.const #cir.int<0> : !u32i
70+
%1 = cir.ctz %0 : !u32i
71+
cir.return %1 : !u32i
72+
}
73+
// CHECK-LABEL: @fold_ctz_zero_no_poison
74+
// CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i
75+
// CHECK-NEXT: cir.return %[[R]] : !u32i
76+
// CHECK-NEXT: }
77+
3878
cir.func @fold_parity() -> !u32i {
3979
// 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111
4080
// 0xdeadbeef contains 24 ones
@@ -82,6 +122,16 @@ module {
82122
// CHECK-NEXT: cir.return %[[R]] : !u32i
83123
// CHECK-NEXT: }
84124

125+
cir.func @fold_input_poison() -> !s32i {
126+
%0 = cir.const #cir.poison : !s32i
127+
%1 = cir.clrsb %0 : !s32i
128+
cir.return %1 : !s32i
129+
}
130+
// CHECK-LABEL: @fold_input_poison
131+
// CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i
132+
// CHECK-NEXT: cir.return %[[P]] : !s32i
133+
// CHECK-NEXT: }
134+
85135
cir.func @fold_rotate_input_all_zeros(%arg0 : !u32i) -> !u32i {
86136
%0 = cir.const #cir.int<0> : !u32i
87137
%1 = cir.rotate left %0, %arg0 : !u32i
@@ -138,4 +188,24 @@ module {
138188
// CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4024348094> : !u32i
139189
// CHECK-NEXT: cir.return %[[R]] : !u32i
140190
// CHECK-NEXT: }
191+
192+
cir.func @fold_rotate_input_poison(%arg0 : !u32i) -> !u32i {
193+
%0 = cir.const #cir.poison : !u32i
194+
%1 = cir.rotate left %0, %arg0 : !u32i
195+
cir.return %1 : !u32i
196+
}
197+
// CHECK-LABEL: @fold_rotate_input_poison
198+
// CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i
199+
// CHECK-NEXT: cir.return %[[P]] : !u32i
200+
// CHECK-NEXT: }
201+
202+
cir.func @fold_rotate_amount_poison(%arg0 : !u32i) -> !u32i {
203+
%0 = cir.const #cir.poison : !u32i
204+
%1 = cir.rotate left %arg0, %0 : !u32i
205+
cir.return %1 : !u32i
206+
}
207+
// CHECK-LABEL: @fold_rotate_amount_poison
208+
// CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i
209+
// CHECK-NEXT: cir.return %[[P]] : !u32i
210+
// CHECK-NEXT: }
141211
}

clang/test/CIR/Transforms/canonicalize.cir

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ module {
3939
// CHECK: cir.func{{.*}} @unary_not(%arg0: !cir.bool) -> !cir.bool
4040
// CHECK-NEXT: cir.return %arg0 : !cir.bool
4141

42+
cir.func @unary_poison() -> !s32i {
43+
%0 = cir.const #cir.poison : !s32i
44+
%1 = cir.unary(inc, %0) : !s32i, !s32i
45+
cir.return %1 : !s32i
46+
}
47+
// CHECK: @unary_poison
48+
// CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i
49+
// CHECK-NEXT: cir.return %[[P]] : !s32i
50+
// CHECK-NEXT: }
51+
4252
cir.func @cast1(%arg0: !cir.bool) -> !cir.bool {
4353
%0 = cir.cast(bool_to_int, %arg0 : !cir.bool), !s32i
4454
%1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool
@@ -70,4 +80,14 @@ module {
7080
// CHECK-NEXT: %[[CAST3:.*]] = cir.cast(integral, %[[CAST2]] : !s32i), !s64i
7181
// CHECK-NEXT: cir.return %[[CAST3]] : !s64i
7282

83+
cir.func @cast_poison() -> !s64i {
84+
%0 = cir.const #cir.poison : !s32i
85+
%1 = cir.cast(integral, %0 : !s32i), !s64i
86+
cir.return %1 : !s64i
87+
}
88+
// CHECK: @cast_poison
89+
// CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s64i
90+
// CHECK-NEXT: cir.return %[[P]] : !s64i
91+
// CHECK-NEXT: }
92+
7393
}

0 commit comments

Comments
 (0)