mirror of https://github.com/llvm/circt.git
[Deseq] Add bin flag to enable mux (#8686)
Set the `bin` flag on the `comb.mux` that we insert for enable flip-flops in LLHD's Deseq pass. This allows circt-verilog to preserve the difference between `if (en) q <= d` and `q <= en ? d : q` enables. In the future we'll probably want to have more explicit ops to describe these differences. But adding the `bin` flag causes the pipeline to preserve the property we're interested in for now.
This commit is contained in:
parent
752ccb5218
commit
c43ec9809f
|
@ -1110,11 +1110,14 @@ void Deseq::implementRegister(DriveInfo &drive) {
|
|||
/*isAsync=*/reset != Value{});
|
||||
|
||||
// If the register has an enable, insert a self-mux in front of the register.
|
||||
// Set the `bin` flag on the mux specifically to make up for a subtle
|
||||
// difference between a `if (en) q <= d` enable on a register, and a `q <= en
|
||||
// ? d : q` enable.
|
||||
if (enable) {
|
||||
OpBuilder::InsertionGuard guard(builder);
|
||||
builder.setInsertionPoint(reg);
|
||||
reg.getNextMutable().assign(builder.create<comb::MuxOp>(
|
||||
loc, enable, reg.getNext(), reg.getResult()));
|
||||
loc, enable, reg.getNext(), reg.getResult(), true));
|
||||
}
|
||||
|
||||
// Make the original `llhd.drv` drive the register value unconditionally.
|
||||
|
|
|
@ -132,7 +132,7 @@ hw.module @ClockWithEnable(in %clock: i1, in %d: i42, in %en: i1) {
|
|||
}
|
||||
%3 = llhd.sig %c0_i42 : i42
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clock
|
||||
// CHECK: [[MUX:%.+]] = comb.mux [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[MUX:%.+]] = comb.mux bin [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[REG]] = seq.firreg [[MUX]] clock [[CLK]] : i42
|
||||
// CHECK: llhd.drv {{%.+}}, [[REG]] after {{%.+}} :
|
||||
llhd.drv %3, %1 after %0 if %2 : !hw.inout<i42>
|
||||
|
@ -169,7 +169,7 @@ hw.module @ClockWithEnableAndReset(in %clock: i1, in %reset: i1, in %d: i42, in
|
|||
}
|
||||
%3 = llhd.sig %c0_i42 : i42
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clock
|
||||
// CHECK: [[MUX:%.+]] = comb.mux [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[MUX:%.+]] = comb.mux bin [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[REG]] = seq.firreg [[MUX]] clock [[CLK]] reset async %reset, %c42_i42 : i42
|
||||
// CHECK: llhd.drv {{%.+}}, [[REG]] after {{%.+}} :
|
||||
llhd.drv %3, %1 after %0 if %2 : !hw.inout<i42>
|
||||
|
@ -422,7 +422,7 @@ hw.module @ComplexControlFlow(in %clock: i1, in %d: i42) {
|
|||
}
|
||||
%3 = llhd.sig %c0_i42 : i42
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clock
|
||||
// CHECK: [[MUX:%.+]] = comb.mux [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[MUX:%.+]] = comb.mux bin [[ER]]#1, [[ER]]#0, [[REG:%.+]] : i42
|
||||
// CHECK: [[REG]] = seq.firreg [[MUX]] clock [[CLK]] : i42
|
||||
// CHECK: llhd.drv {{%.+}}, [[REG]] after {{%.+}} :
|
||||
llhd.drv %3, %1 after %0 if %2 : !hw.inout<i42>
|
||||
|
@ -824,75 +824,75 @@ hw.module @LargeControlFlowRegression(in %clk: i1, in %rstn: i1, in %a: i6, in %
|
|||
}
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clk
|
||||
// CHECK: [[RST:%.+]] = comb.xor %rstn, %true
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#1, [[ER]]#0, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#1, [[ER]]#0, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#3, [[ER]]#2, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#3, [[ER]]#2, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#5, [[ER]]#4, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#5, [[ER]]#4, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#7, [[ER]]#6, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#7, [[ER]]#6, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#9, [[ER]]#8, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#9, [[ER]]#8, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#11, [[ER]]#10, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#11, [[ER]]#10, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#13, [[ER]]#12, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#13, [[ER]]#12, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#15, [[ER]]#14, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#15, [[ER]]#14, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#17, [[ER]]#16, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#17, [[ER]]#16, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#19, [[ER]]#18, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#19, [[ER]]#18, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#21, [[ER]]#20, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#21, [[ER]]#20, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#23, [[ER]]#22, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#23, [[ER]]#22, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#25, [[ER]]#24, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#25, [[ER]]#24, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#27, [[ER]]#26, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#27, [[ER]]#26, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#29, [[ER]]#28, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#29, [[ER]]#28, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#31, [[ER]]#30, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#31, [[ER]]#30, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#33, [[ER]]#32, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#33, [[ER]]#32, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#35, [[ER]]#34, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#35, [[ER]]#34, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#37, [[ER]]#36, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#37, [[ER]]#36, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#39, [[ER]]#38, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#39, [[ER]]#38, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#41, [[ER]]#40, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#41, [[ER]]#40, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#43, [[ER]]#42, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#43, [[ER]]#42, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#45, [[ER]]#44, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#45, [[ER]]#44, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#47, [[ER]]#46, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#47, [[ER]]#46, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#49, [[ER]]#48, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#49, [[ER]]#48, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#51, [[ER]]#50, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#51, [[ER]]#50, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#53, [[ER]]#52, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#53, [[ER]]#52, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#55, [[ER]]#54, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#55, [[ER]]#54, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#57, [[ER]]#56, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#57, [[ER]]#56, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#59, [[ER]]#58, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#59, [[ER]]#58, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#61, [[ER]]#60, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#61, [[ER]]#60, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#63, [[ER]]#62, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#63, [[ER]]#62, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#65, [[ER]]#64, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#65, [[ER]]#64, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#67, [[ER]]#66, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#67, [[ER]]#66, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
// CHECK: [[TMP:%.+]] = comb.mux [[ER]]#69, [[ER]]#68, {{%.+}}
|
||||
// CHECK: [[TMP:%.+]] = comb.mux bin [[ER]]#69, [[ER]]#68, {{%.+}}
|
||||
// CHECK: seq.firreg [[TMP]] clock [[CLK]] reset async [[RST]], %c0_i15
|
||||
llhd.drv %mem0, %1#0 after %0 if %1#1 : !hw.inout<i15>
|
||||
llhd.drv %mem1, %1#2 after %0 if %1#3 : !hw.inout<i15>
|
||||
|
|
|
@ -52,7 +52,7 @@ endmodule
|
|||
// CHECK-LABEL: hw.module @Enable(
|
||||
module Enable(input logic clock, input logic enable, input int d, output int q);
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clock
|
||||
// CHECK: [[MUX:%.+]] = comb.mux %enable, %d, [[REG:%.+]] : i32
|
||||
// CHECK: [[MUX:%.+]] = comb.mux bin %enable, %d, [[REG:%.+]] : i32
|
||||
// CHECK: [[REG]] = seq.firreg [[MUX]] clock [[CLK]] : i32
|
||||
// CHECK: hw.output [[REG]]
|
||||
always @(posedge clock) if (enable) q <= d;
|
||||
|
@ -61,7 +61,7 @@ endmodule
|
|||
// CHECK-LABEL: hw.module @ResetAndEnable(
|
||||
module ResetAndEnable(input logic clock, input logic reset, input logic enable, input int d, output int q);
|
||||
// CHECK: [[CLK:%.+]] = seq.to_clock %clock
|
||||
// CHECK: [[MUX:%.+]] = comb.mux %enable, %d, [[REG:%.+]] : i32
|
||||
// CHECK: [[MUX:%.+]] = comb.mux bin %enable, %d, [[REG:%.+]] : i32
|
||||
// CHECK: [[REG]] = seq.firreg [[MUX]] clock [[CLK]] reset async %reset, %c42_i32 : i32
|
||||
// CHECK: hw.output [[REG]]
|
||||
always @(posedge clock, posedge reset) if (reset) q <= 42; else if (enable) q <= d;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// RUN: circt-verilog %s | circt-opt --lower-seq-to-sv --export-verilog | FileCheck %s
|
||||
// REQUIRES: slang
|
||||
// Internal issue in Slang v3 about jump depending on uninitialised value.
|
||||
// UNSUPPORTED: valgrind
|
||||
|
||||
// Ensure we can round-trip the following two different flavors of enables on a
|
||||
// register and have them come out unchanged. These have subtly different
|
||||
// semantics when `en` is X, which must be preserved in order to satisfy logical
|
||||
// equivalence checks.
|
||||
|
||||
// CHECK-LABEL: module Foo
|
||||
module Foo (input logic clk, en, d, output logic qa, qb);
|
||||
// CHECK: always @(posedge clk)
|
||||
always @(posedge clk) begin
|
||||
// CHECK: if (en)
|
||||
// CHECK: [[QA:qa.*]] <= d;
|
||||
if (en)
|
||||
qa <= d;
|
||||
|
||||
// CHECK: [[QB:qb.*]] <= en ? d : [[QB]];
|
||||
qb <= en ? d : qb;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue