-
Notifications
You must be signed in to change notification settings - Fork 446
[SCF to Calyx] Generates external memory outside top level component #10036
Description
The semantics of Calyx doesn't allow external memory outside top-level component. However, the SCF To calyx pass doesn't seem to abide with this.
func.func @test(%arg0 : memref<3xf32>){
%alloc = memref.alloc() : memref<3xf32>
%c0 = arith.constant 0: index
%c3 = arith.constant 3: index
%step = arith.constant 1: index
%cst_54 = arith.constant 54.5675 : f32
scf.for %i = %c0 to %c3 step %step {
memref.store %cst_54, %alloc[%i] : memref<3xf32>
}
return
}
func.func @main() {
%alloc = memref.alloc() : memref<3xf32>
%c0 = arith.constant 0: index
%c3 = arith.constant 3: index
%step = arith.constant 1: index
%cst_45 = arith.constant 45.5675 : f32
scf.for %i = %c0 to %c3 step %step {
memref.store %cst_45, %alloc[%i] : memref<3xf32>
}
func.call @test(%alloc): (memref<3xf32>) -> ()
return
}If we use --pass-pipeline="builtin.module(lower-scf-to-calyx{top-level-function=main})" with circt-opt. It generates a test component corresponding to the test function with external attribute set to true for the memory:
module attributes {calyx.entrypoint = "main"} {
calyx.component @test(%clk: i1 {clk}, %reset: i1 {reset}, %go: i1 {go}) -> (%done: i1 {done}) {
%c1_i32 = hw.constant 1 : i32
%true = hw.constant true
%c0_i32 = hw.constant 0 : i32
%cst = calyx.constant @cst_0 <5.456750e+01 : f32> : i32
%std_slice_0.in, %std_slice_0.out = calyx.std_slice @std_slice_0 : i32, i2
%std_add_0.left, %std_add_0.right, %std_add_0.out = calyx.std_add @std_add_0 : i32, i32, i32
%mem_0.addr0, %mem_0.clk, %mem_0.reset, %mem_0.content_en, %mem_0.write_en, %mem_0.write_data, %mem_0.read_data, %mem_0.done = calyx.seq_mem @mem_0 <[3] x 32> [2] {external = true} : i2, i1, i1, i1, i1, i32, i32, i1
...
See Complete Output at Compiler Explorer
I checked the code at Conversion/SCFToCalyx/SCFToCalyx.cpp which adds external attribute to every memref.AllocaOp without checking whether it is top level component or not:
memoryOp->setAttr("external", IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));I went on to change the code to add an check for top level component:
if (componentOp.hasAttr("toplevel")){
memoryOp->setAttr("external", IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));
}But I ran into another issue now. It's in the emitter.
There seems to be an assumption that memories in calyx are either of the two - external, ref.
The CalyxEmitter while emitting native calyx checks for the existence of the external attribute in the memory. If it is not external it assumes that it is a ref which it isn't (in this case) because it is just a memory local to the component.
Should we just set external = false (for non top-level component and non ref memory) and in the emitter check if external is set to false ?