From e389ffa60501eb4bb8b2d59994465b3b34e7fc1f Mon Sep 17 00:00:00 2001 From: uenoku Date: Tue, 18 Jan 2022 15:03:34 +0900 Subject: [PATCH] Revert "[FIRRTL] Add multibit_mux op and lowerings (#2392)" (#2472) This reverts commit 2eea30198f9799c48a6fbad23a909384c8bd6080 because it is causing assertion failure in an internal design. --- .../circt/Dialect/FIRRTL/FIRRTLExpressions.td | 20 ------- include/circt/Dialect/FIRRTL/FIRRTLVisitors.h | 3 +- lib/Conversion/FIRRTLToHW/LowerToHW.cpp | 22 -------- lib/Dialect/FIRRTL/FIRRTLFolds.cpp | 39 -------------- lib/Dialect/FIRRTL/FIRRTLOps.cpp | 49 ----------------- lib/Dialect/FIRRTL/Transforms/LowerTypes.cpp | 36 +++++-------- test/Conversion/FIRRTLToHW/lower-to-hw.mlir | 9 +--- test/Dialect/FIRRTL/canonicalization.mlir | 16 ------ test/Dialect/FIRRTL/lower-types.mlir | 52 +++++++++++++------ 9 files changed, 53 insertions(+), 193 deletions(-) diff --git a/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td b/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td index d8b0febe83..2dd84f861e 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td +++ b/include/circt/Dialect/FIRRTL/FIRRTLExpressions.td @@ -242,26 +242,6 @@ def SubaccessOp : FIRRTLExprOp<"subaccess", [ let hasCanonicalizeMethod = true; } -def MultibitMuxOp : FIRRTLExprOp<"multibit_mux"> { - let summary = "Multibit multiplexer"; - let description = [{ - The multibit mux expression dynamically selects operands. The - index must be an expression with an unsigned integer type. - ``` - %result = firrtl.multibit_mux %index, %0, %1, %2, ... : t1, t2 - ``` - }]; - - let arguments = (ins FIRRTLType:$index, Variadic:$inputs); - let results = (outs FIRRTLType:$result); - - // Need a custom parser/printer to emit operands type only once. - let parser = "return parse$cppClass(parser, result);"; - let printer = "print$cppClass(p, *this);"; - let hasFolder = true; - let hasCanonicalizeMethod = true; -} - //===----------------------------------------------------------------------===// // Primitive Operations //===----------------------------------------------------------------------===// diff --git a/include/circt/Dialect/FIRRTL/FIRRTLVisitors.h b/include/circt/Dialect/FIRRTL/FIRRTLVisitors.h index 5295f0f0c7..2e06626570 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLVisitors.h +++ b/include/circt/Dialect/FIRRTL/FIRRTLVisitors.h @@ -31,7 +31,7 @@ public: // Basic Expressions .template Case< ConstantOp, SpecialConstantOp, InvalidValueOp, SubfieldOp, - SubindexOp, SubaccessOp, MultibitMuxOp, + SubindexOp, SubaccessOp, // Arithmetic and Logical Binary Primitives. AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp, OrPrimOp, XorPrimOp, @@ -89,7 +89,6 @@ public: HANDLE(SubfieldOp, Unhandled); HANDLE(SubindexOp, Unhandled); HANDLE(SubaccessOp, Unhandled); - HANDLE(MultibitMuxOp, Unhandled); // Arithmetic and Logical Binary Primitives. HANDLE(AddPrimOp, Binary); diff --git a/lib/Conversion/FIRRTLToHW/LowerToHW.cpp b/lib/Conversion/FIRRTLToHW/LowerToHW.cpp index a134870a25..64137ce1b3 100644 --- a/lib/Conversion/FIRRTLToHW/LowerToHW.cpp +++ b/lib/Conversion/FIRRTLToHW/LowerToHW.cpp @@ -1400,7 +1400,6 @@ struct FIRRTLLowering : public FIRRTLVisitor { } LogicalResult visitExpr(TailPrimOp op); LogicalResult visitExpr(MuxPrimOp op); - LogicalResult visitExpr(MultibitMuxOp op); LogicalResult visitExpr(VerbatimExprOp op); // Statements @@ -3158,27 +3157,6 @@ LogicalResult FIRRTLLowering::visitExpr(MuxPrimOp op) { ifFalse); } -LogicalResult FIRRTLLowering::visitExpr(MultibitMuxOp op) { - // Lower and resize to the index width. - auto index = getLoweredAndExtOrTruncValue( - op.index(), UIntType::get(op.getContext(), - getBitWidthFromVectorSize(op.inputs().size()))); - - if (!index) - return failure(); - SmallVector loweredInputs; - loweredInputs.reserve(op.inputs().size()); - - for (auto input : op.inputs()) { - auto lowered = getLoweredAndExtendedValue(input, op.getType()); - if (!lowered) - return failure(); - loweredInputs.push_back(lowered); - } - Value array = builder.create(loweredInputs); - return setLoweringTo(op, array, index); -} - LogicalResult FIRRTLLowering::visitExpr(VerbatimExprOp op) { auto resultTy = lowerType(op.getType()); if (!resultTy) diff --git a/lib/Dialect/FIRRTL/FIRRTLFolds.cpp b/lib/Dialect/FIRRTL/FIRRTLFolds.cpp index 5072e8b98d..2d554a531e 100644 --- a/lib/Dialect/FIRRTL/FIRRTLFolds.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLFolds.cpp @@ -1360,45 +1360,6 @@ LogicalResult SubaccessOp::canonicalize(SubaccessOp op, }); } -OpFoldResult MultibitMuxOp::fold(ArrayRef operands) { - // If there is only one input, just return it. - if (operands.size() == 2) - return getOperand(1); - - if (auto constIndex = getConstant(operands[0])) { - auto index = constIndex->getExtValue(); - // operands[0] is index so (index + 1) is the index we want. - if (index >= 0 && index + 1 < static_cast(operands.size())) - return getOperand(index + 1); - } - - return {}; -} - -LogicalResult MultibitMuxOp::canonicalize(MultibitMuxOp op, - PatternRewriter &rewriter) { - // If all operands are equal, just canonicalize to it. We can add this - // canonicalization as a folder but it costly to look through all inputs so it - // is added here. - if (llvm::all_of(op.inputs().drop_front(), - [&](auto input) { return input == op.inputs().front(); })) { - rewriter.replaceOp(op, op.inputs().front()); - return success(); - } - - // If the size is 2, canonicalize into a normal mux to introduce more folds. - if (op.inputs().size() != 2) - return failure(); - - // multibit_mux(index, {lhs, rhs}) -> mux(index==0, lhs, rhs) - Value zero = rewriter.create( - op.getLoc(), op.index().getType().cast(), APInt(1, 0)); - Value cond = rewriter.createOrFold(op.getLoc(), op.index(), zero); - rewriter.replaceOpWithNewOp(op, cond, op.inputs()[0], - op.inputs()[1]); - return success(); -} - //===----------------------------------------------------------------------===// // Declarations //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/FIRRTL/FIRRTLOps.cpp b/lib/Dialect/FIRRTL/FIRRTLOps.cpp index 79b6b02ab5..39cb3bbe35 100644 --- a/lib/Dialect/FIRRTL/FIRRTLOps.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLOps.cpp @@ -2189,55 +2189,6 @@ FIRRTLType SubaccessOp::inferReturnType(ValueRange operands, return {}; } -static ParseResult parseMultibitMuxOp(OpAsmParser &parser, - OperationState &result) { - OpAsmParser::OperandType index; - llvm::SmallVector inputs; - Type indexType, elemType; - - if (parser.parseOperand(index) || parser.parseComma() || - parser.parseOperandList(inputs) || - parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || - parser.parseType(indexType) || parser.parseComma() || - parser.parseType(elemType)) - return failure(); - - if (parser.resolveOperand(index, indexType, result.operands)) - return failure(); - - result.addTypes(elemType); - - return parser.resolveOperands(inputs, elemType, result.operands); -} - -static void printMultibitMuxOp(OpAsmPrinter &p, MultibitMuxOp op) { - p << " " << op.index() << ", "; - p.printOperands(op.inputs()); - p.printOptionalAttrDict(op->getAttrs()); - p << " : " << op.index().getType() << ", " << op.getType(); -} - -FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands, - ArrayRef attrs, - Optional loc) { - if (operands.size() < 2) { - if (loc) - mlir::emitError(*loc, "at least one input is required"); - return FIRRTLType(); - } - - // Check all mux inputs have the same type. - if (!llvm::all_of(operands.drop_front(2), [&](auto op) { - return operands[1].getType() == op.getType(); - })) { - if (loc) - mlir::emitError(*loc, "all inputs must have the same type"); - return FIRRTLType(); - } - - return operands[1].getType().cast(); -} - //===----------------------------------------------------------------------===// // Binary Primitives //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/FIRRTL/Transforms/LowerTypes.cpp b/lib/Dialect/FIRRTL/Transforms/LowerTypes.cpp index c74ea827a7..433948a365 100644 --- a/lib/Dialect/FIRRTL/Transforms/LowerTypes.cpp +++ b/lib/Dialect/FIRRTL/Transforms/LowerTypes.cpp @@ -339,7 +339,6 @@ struct TypeLoweringVisitor : public FIRRTLVisitor { bool visitDecl(RegResetOp op); bool visitExpr(InvalidValueOp op); bool visitExpr(SubaccessOp op); - bool visitExpr(MultibitMuxOp op); bool visitExpr(MuxPrimOp op); bool visitExpr(mlir::UnrealizedConversionCastOp op); bool visitExpr(BitCastOp op); @@ -1276,31 +1275,24 @@ bool TypeLoweringVisitor::visitExpr(SubaccessOp op) { return true; } - // Construct a multibit mux - SmallVector inputs; - inputs.reserve(vType.getNumElements()); - for (unsigned index : llvm::seq(0u, vType.getNumElements())) - inputs.push_back(builder->create(input, index)); + // Reads. All writes have been eliminated before now + auto selectWidth = llvm::Log2_64_Ceil(vType.getNumElements()); - Value multibitMux = builder->create(op.index(), inputs); - op.replaceAllUsesWith(multibitMux); + // We have at least one element + Value mux = builder->create(input, 0); + // Build up the mux + for (size_t index = 1, e = vType.getNumElements(); index < e; ++index) { + auto cond = builder->create( + op.index(), builder->createOrFold( + UIntType::get(op.getContext(), selectWidth), + APInt(selectWidth, index))); + auto access = builder->create(input, index); + mux = builder->create(cond, access, mux); + } + op.replaceAllUsesWith(mux); return true; } -bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) { - auto clone = [&](FlatBundleFieldEntry field, StringRef name, - ArrayAttr attrs) -> Operation * { - SmallVector newInputs; - newInputs.reserve(op.inputs().size()); - for (auto input : op.inputs()) { - auto inputSub = getSubWhatever(input, field.index); - newInputs.push_back(inputSub); - } - return builder->create(op.index(), newInputs); - }; - return lowerProducer(op, clone); -} - //===----------------------------------------------------------------------===// // Pass Infrastructure //===----------------------------------------------------------------------===// diff --git a/test/Conversion/FIRRTLToHW/lower-to-hw.mlir b/test/Conversion/FIRRTLToHW/lower-to-hw.mlir index ff04860c7b..8d193f4bd3 100644 --- a/test/Conversion/FIRRTLToHW/lower-to-hw.mlir +++ b/test/Conversion/FIRRTLToHW/lower-to-hw.mlir @@ -315,15 +315,10 @@ firrtl.circuit "Simple" attributes {annotations = [{class = // CHECK: [[SEXT:%.+]] = comb.concat {{.*}}, %in3 : i1, i8 // CHECK: = comb.sub %c0_i9, [[SEXT]] : i9 %54 = firrtl.neg %in3 : (!firrtl.sint<8>) -> !firrtl.sint<9> + // CHECK: hw.output %false, %false : i1, i1 firrtl.connect %out1, %53 : !firrtl.sint<1>, !firrtl.sint<1> %55 = firrtl.neg %in5 : (!firrtl.sint<0>) -> !firrtl.sint<1> - - %61 = firrtl.multibit_mux %17, %55, %55, %55 : !firrtl.uint<1>, !firrtl.sint<1> - // CHECK: %[[ZEXT_INDEX:.+]] = comb.concat %false, {{.*}} : i1, i1 - // CHECK-NEXT: %[[ARRAY:.+]] = hw.array_create %false, %false, %false - // CHECK-NEXT: %[[ARRAY_GET:.+]] = hw.array_get %[[ARRAY]][%[[ZEXT_INDEX]]] - // CHECK: hw.output %false, %[[ARRAY_GET]] : i1, i1 - firrtl.connect %out2, %61 : !firrtl.sint<1>, !firrtl.sint<1> + firrtl.connect %out2, %55 : !firrtl.sint<1>, !firrtl.sint<1> } // module Print : diff --git a/test/Dialect/FIRRTL/canonicalization.mlir b/test/Dialect/FIRRTL/canonicalization.mlir index 72b05ff1d9..7f9a493428 100644 --- a/test/Dialect/FIRRTL/canonicalization.mlir +++ b/test/Dialect/FIRRTL/canonicalization.mlir @@ -440,8 +440,6 @@ firrtl.module @Head(in %in4u: !firrtl.uint<4>, // CHECK-LABEL: firrtl.module @Mux firrtl.module @Mux(in %in: !firrtl.uint<4>, in %cond: !firrtl.uint<1>, - in %val1: !firrtl.uint<1>, - in %val2: !firrtl.uint<1>, out %out: !firrtl.uint<4>, out %out1: !firrtl.uint<1>) { // CHECK: firrtl.connect %out, %in @@ -468,20 +466,6 @@ firrtl.module @Mux(in %in: !firrtl.uint<4>, %invalid_ui1 = firrtl.invalidvalue : !firrtl.uint<1> %8 = firrtl.mux (%invalid_ui1, %in, %c7_ui4) : (!firrtl.uint<1>, !firrtl.uint<4>, !firrtl.uint<4>) -> !firrtl.uint<4> firrtl.connect %out, %8 : !firrtl.uint<4>, !firrtl.uint<4> - - %9 = firrtl.multibit_mux %c1_ui1, %c0_ui1, %cond : !firrtl.uint<1>, !firrtl.uint<1> - // CHECK-NEXT: firrtl.connect %out1, %cond - firrtl.connect %out1, %9 : !firrtl.uint<1>, !firrtl.uint<1> - - %10 = firrtl.multibit_mux %cond, %val1, %val2 : !firrtl.uint<1>, !firrtl.uint<1> - // CHECK-NEXT: %[[NOT_COND:.+]] = firrtl.not %cond - // CHECK-NEXT: %[[MUX:.+]] = firrtl.mux(%0, %val1, %val2) - // CHECK-NEXT: firrtl.connect %out1, %[[MUX]] - firrtl.connect %out1, %10 : !firrtl.uint<1>, !firrtl.uint<1> - - %11 = firrtl.multibit_mux %cond, %val1, %val1, %val1 : !firrtl.uint<1>, !firrtl.uint<1> - // CHECK-NEXT: firrtl.connect %out1, %val1 - firrtl.connect %out1, %11 : !firrtl.uint<1>, !firrtl.uint<1> } // CHECK-LABEL: firrtl.module @Pad diff --git a/test/Dialect/FIRRTL/lower-types.mlir b/test/Dialect/FIRRTL/lower-types.mlir index 2180ebc24b..5d3d54e9bd 100644 --- a/test/Dialect/FIRRTL/lower-types.mlir +++ b/test/Dialect/FIRRTL/lower-types.mlir @@ -1026,10 +1026,14 @@ firrtl.circuit "TopLevel" { } // CHECK-LABEL: firrtl.module @multidimRead(in %a_0_0: !firrtl.uint<2>, in %a_0_1: !firrtl.uint<2>, in %a_1_0: !firrtl.uint<2>, in %a_1_1: !firrtl.uint<2>, in %sel: !firrtl.uint<2>, out %b: !firrtl.uint<2>) { -// CHECK-NEXT: %0 = firrtl.multibit_mux %sel, %a_0_0, %a_1_0 : !firrtl.uint<2>, !firrtl.uint<2> -// CHECK-NEXT: %1 = firrtl.multibit_mux %sel, %a_0_1, %a_1_1 : !firrtl.uint<2>, !firrtl.uint<2> -// CHECK-NEXT: %2 = firrtl.multibit_mux %sel, %0, %1 : !firrtl.uint<2>, !firrtl.uint<2> -// CHECK-NEXT: firrtl.connect %b, %2 : !firrtl.uint<2>, !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %0 = firrtl.eq %sel, %c1_ui1 : (!firrtl.uint<2>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %1 = firrtl.mux(%0, %a_1_0, %a_0_0) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %2 = firrtl.mux(%0, %a_1_1, %a_0_1) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1_0 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %3 = firrtl.eq %sel, %c1_ui1_0 : (!firrtl.uint<2>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %4 = firrtl.mux(%3, %2, %1) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: firrtl.connect %b, %4 : !firrtl.uint<2>, !firrtl.uint<2> // CHECK-NEXT: } // module Foo: @@ -1160,14 +1164,22 @@ firrtl.circuit "TopLevel" { } // CHECK-LABEL: firrtl.module @multiSubaccess(in %a_0_0: !firrtl.uint<2>, in %a_0_1: !firrtl.uint<2>, in %a_1_0: !firrtl.uint<2>, in %a_1_1: !firrtl.uint<2>, in %sel1: !firrtl.uint<1>, in %sel2: !firrtl.uint<1>, out %b: !firrtl.uint<2>, out %c: !firrtl.uint<2>) { -// CHECK-NEXT: %0 = firrtl.multibit_mux %sel1, %a_0_0, %a_1_0 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: %1 = firrtl.multibit_mux %sel1, %a_0_1, %a_1_1 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: %2 = firrtl.multibit_mux %sel1, %0, %1 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: firrtl.connect %b, %2 : !firrtl.uint<2>, !firrtl.uint<2> -// CHECK-NEXT: %3 = firrtl.multibit_mux %sel1, %a_0_0, %a_1_0 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: %4 = firrtl.multibit_mux %sel1, %a_0_1, %a_1_1 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: %5 = firrtl.multibit_mux %sel2, %3, %4 : !firrtl.uint<1>, !firrtl.uint<2> -// CHECK-NEXT: firrtl.connect %c, %5 : !firrtl.uint<2>, !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %0 = firrtl.eq %sel1, %c1_ui1 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %1 = firrtl.mux(%0, %a_1_0, %a_0_0) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %2 = firrtl.mux(%0, %a_1_1, %a_0_1) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1_0 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %3 = firrtl.eq %sel1, %c1_ui1_0 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %4 = firrtl.mux(%3, %2, %1) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: firrtl.connect %b, %4 : !firrtl.uint<2>, !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1_1 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %5 = firrtl.eq %sel1, %c1_ui1_1 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %6 = firrtl.mux(%5, %a_1_0, %a_0_0) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %7 = firrtl.mux(%5, %a_1_1, %a_0_1) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: %c1_ui1_2 = firrtl.constant 1 : !firrtl.uint<1> +// CHECK-NEXT: %8 = firrtl.eq %sel2, %c1_ui1_2 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> +// CHECK-NEXT: %9 = firrtl.mux(%8, %7, %6) : (!firrtl.uint<1>, !firrtl.uint<2>, !firrtl.uint<2>) -> !firrtl.uint<2> +// CHECK-NEXT: firrtl.connect %c, %9 : !firrtl.uint<2>, !firrtl.uint<2> // CHECK-NEXT: } @@ -1406,10 +1418,18 @@ firrtl.module @is1436_FOO() { firrtl.module @Issue2315(in %x: !firrtl.vector, 5>, in %source: !firrtl.uint<2>, out %z: !firrtl.uint<10>) { %0 = firrtl.subaccess %x[%source] : !firrtl.vector, 5>, !firrtl.uint<2> firrtl.connect %z, %0 : !firrtl.uint<10>, !firrtl.uint<10> - // The width of multibit mux index will be converted at LowerToHW, - // so it is ok that the type of `%source` is uint<2> here. - // CHECK: %0 = firrtl.multibit_mux %source, %x_0, %x_1, %x_2, %x_3, %x_4 : !firrtl.uint<2>, !firrtl.uint<10> - // CHECK-NEXT: firrtl.connect %z, %0 : !firrtl.uint<10>, !firrtl.uint<10> + // CHECK-NEXT: [[IDX:%.+]] = firrtl.constant 1 + // CHECK-NEXT: [[EQ:%.+]] = firrtl.eq %source, [[IDX]] + // CHECK-NEXT: firrtl.mux([[EQ]], %x_1, %x_0) + // CHECK-NEXT: [[IDX:%.+]] = firrtl.constant 2 + // CHECK-NEXT: [[EQ:%.+]] = firrtl.eq %source, [[IDX]] + // CHECK-NEXT: firrtl.mux([[EQ]], %x_2, + // CHECK-NEXT: [[IDX:%.+]] = firrtl.constant 3 + // CHECK-NEXT: [[EQ:%.+]] = firrtl.eq %source, [[IDX]] + // CHECK-NEXT: firrtl.mux([[EQ]], %x_3, + // CHECK-NEXT: [[IDX:%.+]] = firrtl.constant 4 + // CHECK-NEXT: [[EQ:%.+]] = firrtl.eq %source, [[IDX]] + // CHECK-NEXT: firrtl.mux([[EQ]], %x_4, } } // CIRCUIT