llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Sirui Mu (Lancern) <details> <summary>Changes</summary> 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. --- Full diff: https://github.com/llvm/llvm-project/pull/150760.diff 7 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+14-2) - (modified) clang/include/clang/CIR/MissingFeatures.h (-1) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+24-6) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+6) - (added) clang/test/CIR/Lowering/poison.cir (+14) - (modified) clang/test/CIR/Transforms/bit.cir (+70) - (modified) clang/test/CIR/Transforms/canonicalize.cir (+20) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 29d8aea8d08e7..977fe3178c42c 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -127,7 +127,7 @@ def CIR_BoolAttr : CIR_Attr<"Bool", "bool", [TypedAttrInterface]> { // ZeroAttr //===----------------------------------------------------------------------===// -def ZeroAttr : CIR_TypedAttr<"Zero", "zero"> { +def CIR_ZeroAttr : CIR_TypedAttr<"Zero", "zero"> { let summary = "Attribute to represent zero initialization"; let description = [{ The ZeroAttr is used to indicate zero initialization on structs. @@ -138,7 +138,7 @@ def ZeroAttr : CIR_TypedAttr<"Zero", "zero"> { // UndefAttr //===----------------------------------------------------------------------===// -def UndefAttr : CIR_TypedAttr<"Undef", "undef"> { +def CIR_UndefAttr : CIR_TypedAttr<"Undef", "undef"> { let summary = "Represent an undef constant"; let description = [{ The UndefAttr represents an undef constant, corresponding to LLVM's notion @@ -146,6 +146,18 @@ def UndefAttr : CIR_TypedAttr<"Undef", "undef"> { }]; } +//===----------------------------------------------------------------------===// +// PoisonAttr +//===----------------------------------------------------------------------===// + +def CIR_PoisonAttr : CIR_TypedAttr<"Poison", "poison"> { + let summary = "Represent a typed poison constant"; + let description = [{ + The PoisonAttr represents a typed poison constant, corresponding to LLVM's + notion of poison. + }]; +} + //===----------------------------------------------------------------------===// // IntegerAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index d17c85f89d589..e1a5c3d9ca337 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -287,7 +287,6 @@ struct MissingFeatures { // Future CIR attributes static bool optInfoAttr() { return false; } - static bool poisonAttr() { return false; } }; } // namespace cir diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 9c36a43c663cf..0152fcdcc7e01 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -339,7 +339,7 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType, } if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr, - cir::ConstComplexAttr>(attrType)) + cir::ConstComplexAttr, cir::PoisonAttr>(attrType)) return success(); assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?"); @@ -629,6 +629,11 @@ static Value tryFoldCastChain(cir::CastOp op) { } OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) { + if (mlir::isa_and_present<PoisonAttr>(adaptor.getSrc())) { + // Propagate poison value + return PoisonAttr::get(getContext(), getType()); + } + if (getSrc().getType() == getType()) { switch (getKind()) { case cir::CastKind::integral: { @@ -1783,6 +1788,11 @@ static bool isBoolNot(cir::UnaryOp op) { // // and the argument of the first one (%0) will be used instead. OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) { + if (auto poison = mlir::dyn_cast_if_present<PoisonAttr>(adaptor.getInput())) { + // Propagate poison values + return poison; + } + if (isBoolNot(*this)) if (auto previous = dyn_cast_or_null<UnaryOp>(getInput().getDefiningOp())) if (isBoolNot(previous)) @@ -2239,16 +2249,18 @@ static OpFoldResult foldUnaryBitOp(mlir::Attribute inputAttr, llvm::function_ref<llvm::APInt(const llvm::APInt &)> func, bool poisonZero = false) { + if (mlir::isa_and_present<PoisonAttr>(inputAttr)) { + // Propagate poison value + return inputAttr; + } + auto input = mlir::dyn_cast_if_present<IntAttr>(inputAttr); if (!input) return nullptr; llvm::APInt inputValue = input.getValue(); - if (poisonZero && inputValue.isZero()) { - // TODO(cir): maybe we should return a poison value here? - assert(!MissingFeatures::poisonAttr()); - return nullptr; - } + if (poisonZero && inputValue.isZero()) + return PoisonAttr::get(input.getType()); llvm::APInt resultValue = func(inputValue); return IntAttr::get(input.getType(), resultValue); @@ -2307,6 +2319,12 @@ OpFoldResult ByteSwapOp::fold(FoldAdaptor adaptor) { } OpFoldResult RotateOp::fold(FoldAdaptor adaptor) { + if (mlir::isa_and_present<PoisonAttr>(adaptor.getInput()) || + mlir::isa_and_present<PoisonAttr>(adaptor.getAmount())) { + // Propagate poison values + return PoisonAttr::get(getType()); + } + auto input = mlir::dyn_cast_if_present<IntAttr>(adaptor.getInput()); auto amount = mlir::dyn_cast_if_present<IntAttr>(adaptor.getAmount()); if (!input && !amount) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3cd7de0a56bc3..c27b8899ba596 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1027,6 +1027,12 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { mlir::Attribute attr = op.getValue(); + if (mlir::isa<cir::PoisonAttr>(attr)) { + rewriter.replaceOpWithNewOp<mlir::LLVM::PoisonOp>( + op, getTypeConverter()->convertType(op.getType())); + return mlir::success(); + } + if (mlir::isa<mlir::IntegerType>(op.getType())) { // Verified cir.const operations cannot actually be of these types, but the // lowering pass may generate temporary cir.const operations with these diff --git a/clang/test/CIR/Lowering/poison.cir b/clang/test/CIR/Lowering/poison.cir new file mode 100644 index 0000000000000..6f8b7927e3f8f --- /dev/null +++ b/clang/test/CIR/Lowering/poison.cir @@ -0,0 +1,14 @@ +// RUN: cir-translate -cir-to-llvmir --disable-cc-lowering -o %t.ll %s +// RUN: FileCheck -check-prefix=LLVM --input-file=%t.ll %s + +!s32i = !cir.int<s, 32> + +module { + cir.func @lower_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + cir.return %0 : !s32i + } + // LLVM-LABEL: @lower_poison + // LLVM-NEXT: ret i32 poison + // LLVM-NEXT: } +} diff --git a/clang/test/CIR/Transforms/bit.cir b/clang/test/CIR/Transforms/bit.cir index c85b05de4d9ea..fc27adbc9bb88 100644 --- a/clang/test/CIR/Transforms/bit.cir +++ b/clang/test/CIR/Transforms/bit.cir @@ -25,6 +25,26 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_clz_zero_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.clz %0 poison_zero : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_clz_zero_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_clz_zero_no_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.clz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_clz_zero_no_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + cir.func @fold_ctz() -> !u32i { %0 = cir.const #cir.int<2> : !u32i %1 = cir.ctz %0 : !u32i @@ -35,6 +55,26 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_ctz_zero_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.ctz %0 poison_zero : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_ctz_zero_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_ctz_zero_no_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.ctz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_ctz_zero_no_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + cir.func @fold_parity() -> !u32i { // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111 // 0xdeadbeef contains 24 ones @@ -82,6 +122,16 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_input_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.clrsb %0 : !s32i + cir.return %1 : !s32i + } + // CHECK-LABEL: @fold_input_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i + // CHECK-NEXT: cir.return %[[P]] : !s32i + // CHECK-NEXT: } + cir.func @fold_rotate_input_all_zeros(%arg0 : !u32i) -> !u32i { %0 = cir.const #cir.int<0> : !u32i %1 = cir.rotate left %0, %arg0 : !u32i @@ -138,4 +188,24 @@ module { // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4024348094> : !u32i // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + + cir.func @fold_rotate_input_poison(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.poison : !u32i + %1 = cir.rotate left %0, %arg0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_input_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[P]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_amount_poison(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.poison : !u32i + %1 = cir.rotate left %arg0, %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_amount_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[P]] : !u32i + // CHECK-NEXT: } } diff --git a/clang/test/CIR/Transforms/canonicalize.cir b/clang/test/CIR/Transforms/canonicalize.cir index 7ba163eb30bb1..5daff119a626f 100644 --- a/clang/test/CIR/Transforms/canonicalize.cir +++ b/clang/test/CIR/Transforms/canonicalize.cir @@ -39,6 +39,16 @@ module { // CHECK: cir.func{{.*}} @unary_not(%arg0: !cir.bool) -> !cir.bool // CHECK-NEXT: cir.return %arg0 : !cir.bool + cir.func @unary_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.unary(inc, %0) : !s32i, !s32i + cir.return %1 : !s32i + } + // CHECK: @unary_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i + // CHECK-NEXT: cir.return %[[P]] : !s32i + // CHECK-NEXT: } + cir.func @cast1(%arg0: !cir.bool) -> !cir.bool { %0 = cir.cast(bool_to_int, %arg0 : !cir.bool), !s32i %1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool @@ -70,4 +80,14 @@ module { // CHECK-NEXT: %[[CAST3:.*]] = cir.cast(integral, %[[CAST2]] : !s32i), !s64i // CHECK-NEXT: cir.return %[[CAST3]] : !s64i + cir.func @cast_poison() -> !s64i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.cast(integral, %0 : !s32i), !s64i + cir.return %1 : !s64i + } + // CHECK: @cast_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s64i + // CHECK-NEXT: cir.return %[[P]] : !s64i + // CHECK-NEXT: } + } `````````` </details> https://github.com/llvm/llvm-project/pull/150760 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits