Skip to content

[StaticLogicToCalyx] Incorrect bound count in dot product. #3311

Open
@cgyurgyik

Description

// Original dot product.

// RUN: circt-opt %s -lower-static-logic-to-calyx

func.func @main() {
  %c0_i32 = arith.constant 0 : i32
  %lhs = memref.alloc() : memref<4xi32>
  %rhs = memref.alloc() : memref<4xi32>
  %result = memref.alloc() : memref<1xi32>
  %c0 = arith.constant 0 : index
  %c1 = arith.constant 1 : index
  %c4 = arith.constant 4 : index
  %0 = staticlogic.pipeline.while II =  1 trip_count = 5 iter_args(%i = %c0, %acc = %c0_i32) : (index, i32) -> i32 {
    %1 = arith.cmpi ult, %i, %c4 : index
    staticlogic.pipeline.register %1 : i1
  } do {
    %left, %right, %incr = staticlogic.pipeline.stage start = 0  {
      %4 = memref.load %lhs[%i] : memref<4xi32>
      %5 = memref.load %rhs[%i] : memref<4xi32>
      %6 = arith.addi %i, %c1 : index
      staticlogic.pipeline.register %4, %5, %6 : i32, i32, index
    } : i32, i32, index
    %2 = staticlogic.pipeline.stage start = 1  {
      %4 = arith.muli %left, %right : i32
      staticlogic.pipeline.register %4 : i32
    } : i32
    %3 = staticlogic.pipeline.stage start = 4  {
      %4 = arith.addi %acc, %2 : i32
      staticlogic.pipeline.register %4 : i32
    } : i32
    staticlogic.pipeline.terminator iter_args(%incr, %3), results(%3) : (index, i32) -> i32
  }

  memref.store %0, %result[%c0] : memref<1xi32>
  return
}
//  ./bin/circt-opt <file-name.mlir>  -lower-static-logic-to-calyx | ./bin/circt-translate -export-calyx 

import "primitives/core.futil";
import "primitives/binary_operators.futil";
component main<"toplevel"=1>(@clk clk: 1, @reset reset: 1, @go go: 1) -> (@done done: 1) {
  cells {
    std_slice_2 = std_slice(32, 2);
    std_slice_1 = std_slice(32, 2);
    std_slice_0 = std_slice(32, 1);
    std_add_1 = std_add(32);
    std_mult_pipe_0 = std_mult_pipe(32);
    std_add_0 = std_add(32);
    std_lt_0 = std_lt(32);
    @external(1) mem_2 = std_mem_d1(32, 1, 1);
    @external(1) mem_1 = std_mem_d1(32, 4, 2);
    @external(1) mem_0 = std_mem_d1(32, 4, 2);
    stage_1_register_0_reg = std_reg(32);
    stage_0_register_1_reg = std_reg(32);
    stage_0_register_0_reg = std_reg(32);
    while_0_arg1_reg = std_reg(32);
    while_0_arg0_reg = std_reg(32);
  }
  wires {
    group assign_while_0_init_0 {
      while_0_arg0_reg.in = 32'd0;
      while_0_arg0_reg.write_en = 1'd1;
      assign_while_0_init_0[done] = while_0_arg0_reg.done;
    }
    group assign_while_0_init_1 {
      while_0_arg1_reg.in = 32'd0;
      while_0_arg1_reg.write_en = 1'd1;
      assign_while_0_init_1[done] = while_0_arg1_reg.done;
    }
    comb group bb0_0 {
      std_lt_0.left = while_0_arg0_reg.out;
      std_lt_0.right = 32'd4;
    }
    group bb0_1 {
      std_slice_2.in = while_0_arg0_reg.out;
      mem_0.addr0 = std_slice_2.out;
      stage_0_register_0_reg.in = mem_0.read_data;
      stage_0_register_0_reg.write_en = 1'd1;
      bb0_1[done] = stage_0_register_0_reg.done;
    }
    group bb0_2 {
      std_slice_1.in = while_0_arg0_reg.out;
      mem_1.addr0 = std_slice_1.out;
      stage_0_register_1_reg.in = mem_1.read_data;
      stage_0_register_1_reg.write_en = 1'd1;
      bb0_2[done] = stage_0_register_1_reg.done;
    }
    group bb0_3 {
      std_add_0.left = while_0_arg0_reg.out;
      std_add_0.right = 32'd1;
      while_0_arg0_reg.in = std_add_0.out;
      while_0_arg0_reg.write_en = 1'd1;
      bb0_3[done] = while_0_arg0_reg.done;
    }
    group bb0_4 {
      std_mult_pipe_0.left = stage_0_register_0_reg.out;
      std_mult_pipe_0.right = stage_0_register_1_reg.out;
      stage_1_register_0_reg.in = std_mult_pipe_0.out;
      stage_1_register_0_reg.write_en = std_mult_pipe_0.done;
      std_mult_pipe_0.go = 1'd1;
      bb0_4[done] = stage_1_register_0_reg.done;
    }
    group bb0_5 {
      std_add_1.left = while_0_arg1_reg.out;
      std_add_1.right = stage_1_register_0_reg.out;
      while_0_arg1_reg.in = std_add_1.out;
      while_0_arg1_reg.write_en = 1'd1;
      bb0_5[done] = while_0_arg1_reg.done;
    }
    group bb0_6 {
      std_slice_0.in = 32'd0;
      mem_2.addr0 = std_slice_0.out;
      mem_2.write_data = while_0_arg1_reg.out;
      mem_2.write_en = 1'd1;
      bb0_6[done] = mem_2.done;
    }
  }
  control {
    seq {
      seq {
        par {
          assign_while_0_init_0;
          assign_while_0_init_1;
        }
        par {
          bb0_1;
          bb0_2;
          bb0_3;
        }
        par {
          bb0_1;
          bb0_2;
          bb0_3;
          bb0_4;
        }
        @bound(5) while std_lt_0.out with bb0_0 {
          par {
            bb0_1;
            bb0_2;
            bb0_3;
            bb0_4;
            bb0_5;
          }
        }
        par {
          bb0_4;
          bb0_5;
        }
        par {
          bb0_5;
        }
        bb0_6;
      }
    }
  }
}

{
    "mem_0": {
      "data": [
        1, 2, 3, 4
      ],
      "format": {
        "numeric_type": "bitnum",
        "is_signed": true,
        "width": 32
      }
    },
    "mem_1": {
      "data": [
        1, 2, 3, 4
      ],
      "format": {
        "numeric_type": "bitnum",
        "is_signed": true,
        "width": 32
      }
    },
    "mem_2": {
      "data": [
        0
      ],
      "format": {
        "numeric_type": "bitnum",
        "is_signed": true,
        "width": 32
      }
    }
}
// fud e mlir.futil --to debugger -s verilog.data mlir.data -q

 > watch bb0_3
 > continue
Hit breakpoint: main::bb0_3
 > continue
Hit breakpoint: main::bb0_3
 > continue
Hit breakpoint: main::bb0_3
 > continue
Jun 09 03:41:04.457 WARN While loop has violated its bounds. The annotation suggests that the body should execute 5 times, but it exited after 2 iterations. 
     147 |        @bound(5) while std_lt_0.out with bb0_0 {
, source: main

Looking at the generated Calyx IR, this does appear to be true. I'm going to guess it is related to this:

  %0 = staticlogic.pipeline.while II =  1 trip_count = 5 iter_args(%i = %c0, %acc = %c0_i32) : (index, i32) -> i32 {
    %1 = arith.cmpi ult, %i, %c4 : index
    ...

The trip count is 5, but the while loop comparison ends after 4 intervals.

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