circt icon indicating copy to clipboard operation
circt copied to clipboard

[Comb] ShlOp canonicalization might lead to less optimal logic

Open uenoku opened this issue 1 year ago • 1 comments

Comb canonicalizes extract(lowBit, 1 << x) -> x == lowBit but it could introduce a lot of comparisons which might be better not to apply:

//> using scala "2.13.10"
//> using lib "org.chipsalliance::chisel::6.0.0-RC1"
//> using plugin "org.chipsalliance:::chisel-plugin::6.0.0-RC1"
//> using options "-unchecked", "-deprecation", "-language:reflectiveCalls", "-feature", "-Xcheckinit", "-Xfatal-warnings", "-Ywarn-dead-code", "-Ywarn-unused", "-Ymacro-annotations"

import chisel3._
import circt.stage.ChiselStage

class Foo(width:Int, disable: Boolean) extends Module {
  assert(width <= 31)
  val depth = 1 << width
  val sel = IO(Input(UInt(width.W)))
  val out = IO(Output(Vec(depth.toInt, UInt(1.W))))
  val shift = 1.asUInt(depth.W) << sel
  if(disable)
    dontTouch(shift)
  for (i <- 0 until depth){
    out(i) := shift(i)
  }
}

object Main extends App {
  println(
    ChiselStage.emitSystemVerilog(
      gen = new Foo(3, false),
      firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
    )
  )
  println(
    ChiselStage.emitSystemVerilog(
      gen = new Foo(3, true),
      firtoolOpts = Array("-disable-all-randomization", "-strip-debug-info")
    )
  )
}

w/ canonicalization:

// Generated by CIRCT firtool-1.62.0
module Foo(
  input        clock,
               reset,
  input  [2:0] sel,
  output       out_0,
               out_1,
               out_2,
               out_3,
               out_4,
               out_5,
               out_6,
               out_7
);

  assign out_0 = sel == 3'h0;
  assign out_1 = sel == 3'h1;
  assign out_2 = sel == 3'h2;
  assign out_3 = sel == 3'h3;
  assign out_4 = sel == 3'h4;
  assign out_5 = sel == 3'h5;
  assign out_6 = sel == 3'h6;
  assign out_7 = &sel;
endmodule

w/o canonicalization:

// Generated by CIRCT firtool-1.62.0
module Foo(
  input        clock,
               reset,
  input  [2:0] sel,
  output       out_0,
               out_1,
               out_2,
               out_3,
               out_4,
               out_5,
               out_6,
               out_7
);

  wire [14:0] shift = 15'h1 << sel;
  assign out_0 = shift[0];
  assign out_1 = shift[1];
  assign out_2 = shift[2];
  assign out_3 = shift[3];
  assign out_4 = shift[4];
  assign out_5 = shift[5];
  assign out_6 = shift[6];
  assign out_7 = shift[7];
endmodule

uenoku avatar Jan 10 '24 17:01 uenoku

PPA results are pretty close from some tests.

darthscsi avatar Jan 23 '24 20:01 darthscsi