cornell-zhang / heterocl

HeteroCL: A Multi-Paradigm Programming Infrastructure for Software-Defined Heterogeneous Computing
https://cornell-zhang.github.io/heterocl/
Apache License 2.0
322 stars 92 forks source link

Incorrect FIFO read position #284

Closed chhzh123 closed 3 years ago

chhzh123 commented 4 years ago

See the example below. A FIFO is added between B and C stage. Due to the condition i > 0, only the last 10 elements of C need to be read from FIFO.

def test():
    A = hcl.placeholder((10,), "A")

    def kernel(A):
        B = hcl.compute(A.shape, 
                lambda i: A[i] + 1, "B")
        C = hcl.compute((11,),
                lambda i: hcl.select(i > 0, B[i], 0),"C")
        return C

    target = hcl.platform.zc706
    target.config(compile="vivado_hls", mode="csyn")
    s = hcl.create_schedule([A], kernel)
    s.to([A], target.xcel)
    s.to(kernel.C, target.host)
    s.to(kernel.B, s[kernel.C])
    f = hcl.build(s, target)
    np_A = np.zeros((10,))
    np_C = np.zeros((11,))
    hcl_A = hcl.asarray(np_A)
    hcl_C = hcl.asarray(np_C)
    f(hcl_A, hcl_C)

However, the generated code read the FIFO first, and test the condition, which may cause empty FIFO reading.

void test(bit32 A[10], bit32 C[11]) {
    bit32 B[10];
    bit32 B_pipe_1[10];
    #pragma HLS dataflow
    #pragma HLS stream variable=B_pipe_1 depth=1
    B_i: for (bit32 i = 0; i < 10; ++i) {
      bit32 B_temp;
      B_temp = (A[i] + 1);
      B_pipe_1[i] = B_temp;
    }
    C_i1: for (bit32 i1 = 0; i1 < 11; ++i1) {
      bit32 B_temp1;
      B_temp1 = B_pipe_1[i1];
      C[i1] = ((0 < i1) ? ((bit32)B_temp1) : ((bit32)0));
    }
  }

No need to generate temporal variables, but directly using the original variable is okay.

hecmay commented 4 years ago

The select expression is implemented as a MUX, so the B_pipe_1 will be read unconditionally. To fix this issue, we can let the CodeGen to generate an if-then-else statement for select expression.