Skip to content

[LLHD] Canonicalizer for processes produced by always @(*) #8013

@maerhart

Description

@maerhart

Lowering the following with circt-verilog

module combo (  input   a, b, c, d, e,  output  reg z);

        always @ (*) begin
                z = ((a & b) | (c ^ d) & ~e);
        end

endmodule

results in this MLIR:

  hw.module @combo(in %a : i1, in %b : i1, in %c : i1, in %d : i1, in %e : i1, out z : i1) {
    %0 = llhd.constant_time <0ns, 0d, 1e>
    %true = hw.constant true
    %false = hw.constant false
    %a_0 = llhd.sig name "a" %false : i1
    %1 = llhd.prb %a_0 : !hw.inout<i1>
    %b_1 = llhd.sig name "b" %false : i1
    %2 = llhd.prb %b_1 : !hw.inout<i1>
    %c_2 = llhd.sig name "c" %false : i1
    %3 = llhd.prb %c_2 : !hw.inout<i1>
    %d_3 = llhd.sig name "d" %false : i1
    %4 = llhd.prb %d_3 : !hw.inout<i1>
    %e_4 = llhd.sig name "e" %false : i1
    %5 = llhd.prb %e_4 : !hw.inout<i1>
    %z = llhd.sig %false : i1
    llhd.process {
      cf.br ^bb1
    ^bb1:  // 3 preds: ^bb0, ^bb2, ^bb3
      %7 = llhd.prb %a_0 : !hw.inout<i1>
      %8 = llhd.prb %b_1 : !hw.inout<i1>
      %9 = llhd.prb %c_2 : !hw.inout<i1>
      %10 = llhd.prb %d_3 : !hw.inout<i1>
      %11 = llhd.prb %e_4 : !hw.inout<i1>
      llhd.wait (%1, %2, %3, %4, %5 : i1, i1, i1, i1, i1), ^bb2
    ^bb2:  // pred: ^bb1
      %12 = llhd.prb %a_0 : !hw.inout<i1>
      %13 = comb.icmp bin ne %7, %12 : i1
      %14 = llhd.prb %b_1 : !hw.inout<i1>
      %15 = comb.icmp bin ne %8, %14 : i1
      %16 = llhd.prb %c_2 : !hw.inout<i1>
      %17 = comb.icmp bin ne %9, %16 : i1
      %18 = llhd.prb %d_3 : !hw.inout<i1>
      %19 = comb.icmp bin ne %10, %18 : i1
      %20 = llhd.prb %e_4 : !hw.inout<i1>
      %21 = comb.icmp bin ne %11, %20 : i1
      %22 = comb.or bin %13, %15, %17, %19, %21 : i1
      cf.cond_br %22, ^bb3, ^bb1
    ^bb3:  // pred: ^bb2
      %23 = llhd.prb %a_0 : !hw.inout<i1>
      %24 = llhd.prb %b_1 : !hw.inout<i1>
      %25 = comb.and %23, %24 : i1
      %26 = llhd.prb %c_2 : !hw.inout<i1>
      %27 = llhd.prb %d_3 : !hw.inout<i1>
      %28 = comb.xor %26, %27 : i1
      %29 = llhd.prb %e_4 : !hw.inout<i1>
      %30 = comb.xor %29, %true : i1
      %31 = comb.and %28, %30 : i1
      %32 = comb.or %25, %31 : i1
      llhd.drv %z, %32 after %0 : !hw.inout<i1>
      cf.br ^bb1
    }
    llhd.drv %a_0, %a after %0 : !hw.inout<i1>
    llhd.drv %b_1, %b after %0 : !hw.inout<i1>
    llhd.drv %c_2, %c after %0 : !hw.inout<i1>
    llhd.drv %d_3, %d after %0 : !hw.inout<i1>
    llhd.drv %e_4, %e after %0 : !hw.inout<i1>
    %6 = llhd.prb %z : !hw.inout<i1>
    hw.output %6 : i1
  }

%22 will always evaluate to true because the wait operation will only branch if one of its sensitivity values changes. We should add a folder/canonicalizer that performs this simplification.

The code responsible for generating this pattern is in MooreToCore in the WaitEventOp lowering pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions