amaranth-lang / amaranth

A modern hardware definition language and toolchain based on Python
https://amaranth-lang.org/docs/amaranth/
BSD 2-Clause "Simplified" License
1.56k stars 174 forks source link

Code duplication when using a Value multiple times #787

Open tilk opened 1 year ago

tilk commented 1 year ago

Take the following Amaranth code:

class X(Elaboratable):
    def __init__(self):
        self.i = Signal(8)
        self.o = Signal(8)

    def elaborate(self, platform):
        m = Module()

        v = self.i + self.i
        m.d.comb += self.o.eq(v * v)

        return m

It generates the following Verilog (comments removed for readability):

module top(o, i);
  wire [17:0] \$1 ;
  wire [8:0] \$2 ;
  wire [8:0] \$4 ;
  wire [17:0] \$6 ;
  input [7:0] i;
  wire [7:0] i;
  output [7:0] o;
  wire [7:0] o;
  assign \$2  = i + i;
  assign \$4  = i + i;
  assign \$6  = \$2  * \$4 ;
  assign \$1  = \$6 ;
  assign o = \$6 [7:0];
endmodule

Notice that the single assignment v = self.i + self.i translated to two Verilog assign statements assign \$2 = i + i; and assign \$4 = i + i;.

I understand that this is the consequence of treating Amaranth ASTs as trees (as opposed to DAGs, directed acyclic graphs). But this behavior might be unexpected for many Amaranth users, and lead to unexpected performance loss in some situations. (Here, Yosys is able to de-duplicate the expression; this might not work in general). Is this the intended behavior, or a bug?

whitequark commented 1 year ago

It was the intended behavior originally. However, I have some plans for a new Verilog/RTLIL backend, which would reuse identical subexpressions. There is no ETA on that.

whitequark commented 4 months ago

We have implemented the new IR. However, due to various compatibility reasons, the duplication still happens. It will likely be deduplicated by Amaranth 0.7.