This simplifies a lot of handling of BoolAttr/IntegerAttr. For example, a lot of places currently have to handle both IntegerAttr and BoolAttr. In other places, a decision is made to pick one which can lead to surprising results for users. For example, DenseElementsAttr currently uses BoolAttr for i1 even if the user initialized it with an Array of i1 IntegerAttrs.
Differential Revision: https://reviews.llvm.org/D81047
struct AffineMapAttributeStorage;
struct ArrayAttributeStorage;
-struct BoolAttributeStorage;
struct DictionaryAttributeStorage;
struct IntegerAttributeStorage;
struct IntegerSetAttributeStorage;
enum Kind {
AffineMap = Attribute::FIRST_STANDARD_ATTR,
Array,
- Bool,
Dictionary,
Float,
Integer,
};
//===----------------------------------------------------------------------===//
-// BoolAttr
-//===----------------------------------------------------------------------===//
-
-class BoolAttr : public Attribute::AttrBase<BoolAttr, Attribute,
- detail::BoolAttributeStorage> {
-public:
- using Base::Base;
- using ValueType = bool;
-
- static BoolAttr get(bool value, MLIRContext *context);
-
- bool getValue() const;
-
- /// Methods for support type inquiry through isa, cast, and dyn_cast.
- static bool kindof(unsigned kind) { return kind == StandardAttributes::Bool; }
-};
-
-//===----------------------------------------------------------------------===//
// DictionaryAttr
//===----------------------------------------------------------------------===//
};
//===----------------------------------------------------------------------===//
+// BoolAttr
+
+/// Special case of IntegerAttr to represent boolean integers, i.e., signless i1
+/// integers.
+class BoolAttr : public Attribute {
+public:
+ using Attribute::Attribute;
+ using ValueType = bool;
+
+ static BoolAttr get(bool value, MLIRContext *context);
+
+ /// Enable conversion to IntegerAttr. This uses conversion vs. inheritance to
+ /// avoid bringing in all of IntegerAttrs methods.
+ operator IntegerAttr() const { return IntegerAttr(impl); }
+
+ /// Return the boolean value of this attribute.
+ bool getValue() const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast.
+ static bool classof(Attribute attr);
+};
+
+//===----------------------------------------------------------------------===//
// IntegerSetAttr
//===----------------------------------------------------------------------===//
bool condition;
if (auto condAttr = operands.front().dyn_cast_or_null<IntegerAttr>()) {
condition = condAttr.getValue().isOneValue();
- } else if (auto condAttr = operands.front().dyn_cast_or_null<BoolAttr>()) {
- condition = condAttr.getValue();
} else {
// If the condition isn't constant, both regions may be executed.
regions.push_back(RegionSuccessor(&thenRegion()));
// need to additionally check that the value's attribute type is consistent
// with the result type.
switch (value.getKind()) {
- case StandardAttributes::Bool:
case StandardAttributes::Integer:
case StandardAttributes::Float: {
if (valueType != opType)
auto value = constOp.default_value();
switch (value.getKind()) {
- case StandardAttributes::Bool:
case StandardAttributes::Integer:
case StandardAttributes::Float: {
// Make sure bitwidth is allowed.
if (auto floatAttr = valueAttr.dyn_cast<FloatAttr>()) {
return prepareConstantFp(loc, floatAttr, isSpec);
}
- if (auto intAttr = valueAttr.dyn_cast<IntegerAttr>()) {
- return prepareConstantInt(loc, intAttr, isSpec);
- }
if (auto boolAttr = valueAttr.dyn_cast<BoolAttr>()) {
return prepareConstantBool(loc, boolAttr, isSpec);
}
+ if (auto intAttr = valueAttr.dyn_cast<IntegerAttr>()) {
+ return prepareConstantInt(loc, intAttr, isSpec);
+ }
return 0;
}
}
Block *CondBranchOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
- if (BoolAttr condAttr = operands.front().dyn_cast_or_null<BoolAttr>())
- return condAttr.getValue() ? trueDest() : falseDest();
if (IntegerAttr condAttr = operands.front().dyn_cast_or_null<IntegerAttr>())
return condAttr.getValue().isOneValue() ? trueDest() : falseDest();
return nullptr;
if (value.getType() != type)
return false;
// Finally, check that the attribute kind is handled.
- return value.isa<BoolAttr>() || value.isa<IntegerAttr>() ||
- value.isa<FloatAttr>() || value.isa<ElementsAttr>() ||
- value.isa<UnitAttr>();
+ return value.isa<IntegerAttr>() || value.isa<FloatAttr>() ||
+ value.isa<ElementsAttr>() || value.isa<UnitAttr>();
}
void ConstantFloatOp::build(OpBuilder &builder, OperationState &result,
case StandardAttributes::Unit:
os << "unit";
break;
- case StandardAttributes::Bool:
- os << (attr.cast<BoolAttr>().getValue() ? "true" : "false");
-
- // BoolAttr always elides the type.
- return;
case StandardAttributes::Dictionary:
os << '{';
interleaveComma(attr.cast<DictionaryAttr>().getValue(),
break;
case StandardAttributes::Integer: {
auto intAttr = attr.cast<IntegerAttr>();
+ if (attrType.isSignlessInteger(1)) {
+ os << (intAttr.getValue().getBoolValue() ? "true" : "false");
+
+ // Boolean integer attributes always elides the type.
+ return;
+ }
+
// Only print attributes as unsigned if they are explicitly unsigned or are
// signless 1-bit values. Indexes, signed values, and multi-bit signless
// values print as signed.
ArrayRef<Attribute> value;
};
-/// An attribute representing a boolean value.
-struct BoolAttributeStorage : public AttributeStorage {
- using KeyTy = std::pair<MLIRContext *, bool>;
-
- BoolAttributeStorage(Type type, bool value)
- : AttributeStorage(type), value(value) {}
-
- /// We only check equality for and hash with the boolean key parameter.
- bool operator==(const KeyTy &key) const { return key.second == value; }
- static unsigned hashKey(const KeyTy &key) {
- return llvm::hash_value(key.second);
- }
-
- static BoolAttributeStorage *construct(AttributeStorageAllocator &allocator,
- const KeyTy &key) {
- return new (allocator.allocate<BoolAttributeStorage>())
- BoolAttributeStorage(IntegerType::get(1, key.first), key.second);
- }
-
- bool value;
-};
-
/// An attribute representing a dictionary of sorted named attributes.
struct DictionaryAttributeStorage final
: public AttributeStorage,
}
//===----------------------------------------------------------------------===//
-// BoolAttr
-//===----------------------------------------------------------------------===//
-
-bool BoolAttr::getValue() const { return getImpl()->value; }
-
-//===----------------------------------------------------------------------===//
// DictionaryAttr
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
IntegerAttr IntegerAttr::get(Type type, const APInt &value) {
+ if (type.isSignlessInteger(1))
+ return BoolAttr::get(value.getBoolValue(), type.getContext());
return Base::get(type.getContext(), StandardAttributes::Integer, type, value);
}
}
//===----------------------------------------------------------------------===//
+// BoolAttr
+
+bool BoolAttr::getValue() const {
+ auto *storage = reinterpret_cast<IntegerAttributeStorage *>(impl);
+ return storage->getValue().getBoolValue();
+}
+
+bool BoolAttr::classof(Attribute attr) {
+ IntegerAttr intAttr = attr.dyn_cast<IntegerAttr>();
+ return intAttr && intAttr.getType().isSignlessInteger(1);
+}
+
+//===----------------------------------------------------------------------===//
// IntegerSetAttr
//===----------------------------------------------------------------------===//
Attribute DenseElementsAttr::AttributeElementIterator::operator*() const {
auto owner = getFromOpaquePointer(base).cast<DenseElementsAttr>();
Type eltTy = owner.getType().getElementType();
- if (auto intEltTy = eltTy.dyn_cast<IntegerType>()) {
- if (intEltTy.getWidth() == 1)
- return BoolAttr::get((*IntElementIterator(owner, index)).isOneValue(),
- owner.getContext());
+ if (auto intEltTy = eltTy.dyn_cast<IntegerType>())
return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
- }
if (eltTy.isa<IndexType>())
return IntegerAttr::get(eltTy, *IntElementIterator(owner, index));
if (auto floatEltTy = eltTy.dyn_cast<FloatType>()) {
break;
case StandardTypes::Integer:
case StandardTypes::Index:
- intVal = values[i].isa<BoolAttr>()
- ? APInt(1, values[i].cast<BoolAttr>().getValue() ? 1 : 0)
- : values[i].cast<IntegerAttr>().getValue();
+ intVal = values[i].cast<IntegerAttr>().getValue();
break;
default:
llvm_unreachable("unexpected element type");
return FloatAttr::get(eltType, 0);
// Otherwise, this is an integer.
- auto intEltTy = eltType.cast<IntegerType>();
- if (intEltTy.getWidth() == 1)
- return BoolAttr::get(false, eltType.getContext());
+ // TODO: Handle StringAttr here.
return IntegerAttr::get(eltType, 0);
}
case StandardTypes::F32:
case StandardTypes::F64:
return getFloatAttr(type, 0.0);
- case StandardTypes::Integer: {
- auto width = type.cast<IntegerType>().getWidth();
- if (width == 1)
- return getBoolAttr(false);
- return getIntegerAttr(type, APInt(width, 0));
- }
+ case StandardTypes::Integer:
+ return getIntegerAttr(type, APInt(type.cast<IntegerType>().getWidth(), 0));
case StandardTypes::Vector:
case StandardTypes::RankedTensor: {
auto vtType = type.cast<ShapedType>();
/// the IR.
struct BuiltinDialect : public Dialect {
BuiltinDialect(MLIRContext *context) : Dialect(/*name=*/"", context) {
- addAttributes<AffineMapAttr, ArrayAttr, BoolAttr, DenseIntOrFPElementsAttr,
+ addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
DenseStringElementsAttr, DictionaryAttr, FloatAttr,
SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
//// Note: These must be registered after the types as they may generate one
//// of the above types internally.
/// Bool Attributes.
- // Note: The context is also used within the BoolAttrStorage.
- impl->falseAttr = AttributeUniquer::get<BoolAttr>(
- this, StandardAttributes::Bool, this, false);
- impl->trueAttr = AttributeUniquer::get<BoolAttr>(
- this, StandardAttributes::Bool, this, true);
+ impl->falseAttr = AttributeUniquer::get<IntegerAttr>(
+ this, StandardAttributes::Integer, impl->int1Ty,
+ APInt(/*numBits=*/1, false))
+ .cast<BoolAttr>();
+ impl->trueAttr = AttributeUniquer::get<IntegerAttr>(
+ this, StandardAttributes::Integer, impl->int1Ty,
+ APInt(/*numBits=*/1, true))
+ .cast<BoolAttr>();
/// Unit Attribute.
impl->unitAttr =
AttributeUniquer::get<UnitAttr>(this, StandardAttributes::Unit);
return llvm::ConstantInt::get(
llvmType,
intAttr.getValue().sextOrTrunc(llvmType->getIntegerBitWidth()));
- if (auto boolAttr = attr.dyn_cast<BoolAttr>())
- return llvm::ConstantInt::get(llvmType, boolAttr.getValue());
if (auto floatAttr = attr.dyn_cast<FloatAttr>())
return llvm::ConstantFP::get(llvmType, floatAttr.getValue());
if (auto funcAttr = attr.dyn_cast<FlatSymbolRefAttr>())
// CHECK: cond_br %{{.*}}, ^[[then:.*]], ^[[else:.*]]
%0:2 = scf.if %arg0 -> (i1, i1) {
// CHECK: ^[[then]]:
-// CHECK: %[[v0:.*]] = constant 0
-// CHECK: %[[v1:.*]] = constant 1
+// CHECK: %[[v0:.*]] = constant false
+// CHECK: %[[v1:.*]] = constant true
// CHECK: br ^[[dom:.*]](%[[v0]], %[[v1]] : i1, i1)
- %c0 = constant 0 : i1
- %c1 = constant 1 : i1
+ %c0 = constant false
+ %c1 = constant true
scf.yield %c0, %c1 : i1, i1
} else {
// CHECK: ^[[else]]:
-// CHECK: %[[v2:.*]] = constant 0
-// CHECK: %[[v3:.*]] = constant 1
+// CHECK: %[[v2:.*]] = constant false
+// CHECK: %[[v3:.*]] = constant true
// CHECK: br ^[[dom]](%[[v3]], %[[v2]] : i1, i1)
- %c0 = constant 0 : i1
- %c1 = constant 1 : i1
+ %c0 = constant false
+ %c1 = constant true
scf.yield %c1, %c0 : i1, i1
}
// CHECK: ^[[dom]](%[[arg1:.*]]: i1, %[[arg2:.*]]: i1):
// CHECK: cond_br %{{.*}}, ^[[first_then:.*]], ^[[first_else:.*]]
%0 = scf.if %arg0 -> i1 {
// CHECK: ^[[first_then]]:
- %1 = constant 1 : i1
+ %1 = constant true
// CHECK: br ^[[first_dom:.*]]({{.*}})
scf.yield %1 : i1
} else {
// CHECK: ^[[first_else]]:
- %2 = constant 0 : i1
+ %2 = constant false
// CHECK: br ^[[first_dom]]({{.*}})
scf.yield %2 : i1
}
// CHECK: spv.constant false
- %9 = constant 0 : i1
+ %9 = constant false
// CHECK: spv.constant true
- %10 = constant 1 : i1
+ %10 = constant true
return
}
return %0 : vector<8xi1>
}
// CHECK-LABEL: func @genbool_1d
-// CHECK: %[[T0:.*]] = llvm.mlir.constant(1 : i1) : !llvm.i1
+// CHECK: %[[T0:.*]] = llvm.mlir.constant(true) : !llvm.i1
// CHECK: %[[T1:.*]] = llvm.mlir.constant(dense<false> : vector<8xi1>) : !llvm<"<8 x i1>">
// CHECK: %[[T2:.*]] = llvm.mlir.constant(0 : i64) : !llvm.i64
// CHECK: %[[T3:.*]] = llvm.insertelement %[[T0]], %[[T1]][%[[T2]] : !llvm.i64] : !llvm<"<8 x i1>">
func @cond_br_folding(%cond : i1, %a : i32) {
// CHECK-NEXT: return
- %false_cond = constant 0 : i1
- %true_cond = constant 1 : i1
+ %false_cond = constant false
+ %true_cond = constant true
cond_br %cond, ^bb1, ^bb2(%a : i32)
^bb1:
func @cond_br_and_br_folding(%a : i32) {
// CHECK-NEXT: return
- %false_cond = constant 0 : i1
- %true_cond = constant 1 : i1
+ %false_cond = constant false
+ %true_cond = constant true
cond_br %true_cond, ^bb2, ^bb1(%a : i32)
^bb1(%x : i32):
}
// CHECK-LABEL: func @genbool_1d
-// CHECK: %[[TT:.*]] = constant 1 : i1
+// CHECK: %[[TT:.*]] = constant true
// CHECK: %[[C1:.*]] = constant dense<false> : vector<8xi1>
// CHECK: %[[T0.*]] = vector.insert %[[TT]], %[[C1]] [0] : i1 into vector<8xi1>
// CHECK: %[[T1.*]] = vector.insert %[[TT]], %[[T0]] [1] : i1 into vector<8xi1>
}
// CHECK-LABEL: func @genbool_2d
-// CHECK: %[[TT:.*]] = constant 1 : i1
+// CHECK: %[[TT:.*]] = constant true
// CHECK: %[[C1:.*]] = constant dense<false> : vector<4xi1>
// CHECK: %[[C2:.*]] = constant dense<false> : vector<4x4xi1>
// CHECK: %[[T0:.*]] = vector.insert %[[TT]], %[[C1]] [0] : i1 into vector<4xi1>
}
// CHECK-LABEL: func @genbool_3d
-// CHECK: %[[Tt:.*]] = constant 1 : i1
+// CHECK: %[[Tt:.*]] = constant true
// CHECK: %[[C1:.*]] = constant dense<false> : vector<4xi1>
// CHECK: %[[C2:.*]] = constant dense<false> : vector<3x4xi1>
// CHECK: %[[C3:.*]] = constant dense<false> : vector<2x3x4xi1>
// CHECK-LABEL: @operator_and
// CHECK: [[ARG0:%.*]]: i1, [[ARG1:%.*]]: i1
// CHECK: [[AND:%.*]] = and [[ARG0]], [[ARG1]]
- // CHECK: [[TRUE:%.*]] = constant 1 : i1
+ // CHECK: [[TRUE:%.*]] = constant true
// CHECK: subi [[TRUE]], [[AND]] : i1
f.print(llvm::outs());
f.erase();
// -----
func @dominance_error_in_unreachable_op() -> i1 {
- %c = constant 0 : i1
+ %c = constant false
return %c : i1
^bb0:
"dummy" () ({ // unreachable
"std.cond_br"(%x, %y, %x, %y) [^bb2, ^bb3] {operand_segment_sizes = dense<[1, 1, 2]>: vector<3xi32>} : (i1, i17, i1, i17) -> ()
^bb2(%a : i17):
- %true = constant 1 : i1
+ %true = constant true
// CHECK: return %{{.*}}, %{{.*}} : i1, i17
"std.return"(%true, %a) : (i1, i17) -> ()
// CHECK: %{{.*}} = constant 17 : i23
%z = constant 17 : i23
- // CHECK: %{{.*}} = constant 1 : i1
- %t = constant 1 : i1
- // CHECK: %{{.*}} = constant 0 : i1
- %f = constant 0 : i1
+ // CHECK: %{{.*}} = constant true
+ %t = constant true
+ // CHECK: %{{.*}} = constant false
+ %f = constant false
// The trick to parse type declarations should not interfere with hex
// literals.
}
func @unreachable_dominance_violation_ok() -> i1 {
- %c = constant 0 : i1 // CHECK: [[VAL:%.*]] = constant 0 : i1
+ %c = constant false // CHECK: [[VAL:%.*]] = constant false
return %c : i1 // CHECK: return [[VAL]] : i1
^bb1: // CHECK: ^bb1: // no predecessors
// %1 is not dominated by it's definition, but block is not reachable.
; CHECK-LABEL: llvm.func @f1(%arg0: !llvm.i64) -> !llvm.i32 {
; CHECK-DAG: %[[c2:[0-9]+]] = llvm.mlir.constant(2 : i32) : !llvm.i32
; CHECK-DAG: %[[c42:[0-9]+]] = llvm.mlir.constant(42 : i32) : !llvm.i32
-; CHECK-DAG: %[[c1:[0-9]+]] = llvm.mlir.constant(1 : i1) : !llvm.i1
+; CHECK-DAG: %[[c1:[0-9]+]] = llvm.mlir.constant(true) : !llvm.i1
; CHECK-DAG: %[[c43:[0-9]+]] = llvm.mlir.constant(43 : i32) : !llvm.i32
define internal dso_local i32 @f1(i64 %a) norecurse {
entry:
func @cmpi() -> (i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) {
%c42 = constant 42 : i32
%cm1 = constant -1 : i32
- // CHECK-DAG: [[F:%.+]] = constant 0 : i1
- // CHECK-DAG: [[T:%.+]] = constant 1 : i1
+ // CHECK-DAG: [[F:%.+]] = constant false
+ // CHECK-DAG: [[T:%.+]] = constant true
// CHECK-NEXT: return [[F]],
%0 = cmpi "eq", %c42, %cm1 : i32
// CHECK-SAME: [[T]],
func @cmpf_normal_numbers() -> (i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) {
%c42 = constant 42. : f32
%cm1 = constant -1. : f32
- // CHECK-DAG: [[F:%.+]] = constant 0 : i1
- // CHECK-DAG: [[T:%.+]] = constant 1 : i1
+ // CHECK-DAG: [[F:%.+]] = constant false
+ // CHECK-DAG: [[T:%.+]] = constant true
// CHECK-NEXT: return [[F]],
%0 = cmpf "false", %c42, %cm1 : f32
// CHECK-SAME: [[F]],
func @cmpf_nan() -> (i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) {
%c42 = constant 42. : f32
%cqnan = constant 0xFFFFFFFF : f32
- // CHECK-DAG: [[F:%.+]] = constant 0 : i1
- // CHECK-DAG: [[T:%.+]] = constant 1 : i1
+ // CHECK-DAG: [[F:%.+]] = constant false
+ // CHECK-DAG: [[T:%.+]] = constant true
// CHECK-NEXT: return [[F]],
%0 = cmpf "false", %c42, %cqnan : f32
// CHECK-SAME: [[F]]
func @cmpf_inf() -> (i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1) {
%c42 = constant 42. : f32
%cpinf = constant 0x7F800000 : f32
- // CHECK-DAG: [[F:%.+]] = constant 0 : i1
- // CHECK-DAG: [[T:%.+]] = constant 1 : i1
+ // CHECK-DAG: [[F:%.+]] = constant false
+ // CHECK-DAG: [[T:%.+]] = constant true
// CHECK-NEXT: return [[F]],
%0 = cmpf "false", %c42, %cpinf: f32
// CHECK-SAME: [[F]]
// CHECK-NEXT: %c1_i32 = constant 1 : i32
%0 = constant 1 : i32
- // CHECK-NEXT: %true = constant 1 : i1
- %cond = constant 1 : i1
+ // CHECK-NEXT: %true = constant true
+ %cond = constant true
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c1_i32 : i32)
cond_br %cond, ^bb1, ^bb2(%0 : i32)
// CHECK-NEXT: %c0_i32 = constant 0 : i32
%0 = constant 0 : i32
- // CHECK-NEXT: %true = constant 1 : i1
- %cond = constant 1 : i1
+ // CHECK-NEXT: %true = constant true
+ %cond = constant true
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c0_i32 : i32)
cond_br %cond, ^bb1, ^bb2(%0 : i32)
// CHECK-NEXT: %0 = "foo.region"
%0 = "foo.region"() ({
// CHECK-NEXT: %c0_i32 = constant 0 : i32
- // CHECK-NEXT: %true = constant 1 : i1
+ // CHECK-NEXT: %true = constant true
// CHECK-NEXT: cond_br
%1 = constant 0 : i32
- %true = constant 1 : i1
+ %true = constant true
cond_br %true, ^bb1, ^bb2(%1 : i32)
^bb1: // CHECK: ^bb1:
// CHECK-LABEL: func @inline_with_multi_return() -> i32
func @inline_with_multi_return() -> i32 {
-// CHECK-NEXT: [[VAL_7:%.*]] = constant 0 : i1
+// CHECK-NEXT: [[VAL_7:%.*]] = constant false
// CHECK-NEXT: cond_br [[VAL_7]], ^bb1, ^bb2
// CHECK: ^bb1:
// CHECK-NEXT: [[VAL_8:%.*]] = constant 0 : i32
// CHECK: ^bb3([[VAL_10:%.*]]: i32):
// CHECK-NEXT: return [[VAL_10]] : i32
- %false = constant 0 : i1
+ %false = constant false
%x = call @func_with_multi_return(%false) : (i1) -> i32
return %x : i32
}
// CHECK-LABEL: func @complex_inner_if(
func @complex_inner_if(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
- // CHECK-DAG: %[[TRUE:.*]] = constant 1 : i1
+ // CHECK-DAG: %[[TRUE:.*]] = constant true
// CHECK-DAG: %[[CST:.*]] = constant 1 : i32
// CHECK: cond_br %[[TRUE]], ^bb1
// CHECK: %[[CST:.*]] = constant 1 : i32
// CHECK: return %[[CST]] : i32
- %cond = constant 1 : i1
+ %cond = constant true
%cst_1 = constant 1 : i32
%select = select %cond, %cst_1, %arg0 : i32
return %select : i32
// CHECK-LABEL: func @simple_loop_inner_control_flow
func @simple_loop_inner_control_flow(%arg0 : i32) -> i32 {
// CHECK-DAG: %[[CST:.*]] = constant 1 : i32
- // CHECK-DAG: %[[TRUE:.*]] = constant 1 : i1
+ // CHECK-DAG: %[[TRUE:.*]] = constant true
%cst_1 = constant 1 : i32
br ^bb1(%cst_1 : i32)