llvm / circt

Circuit IR Compilers and Tools
https://circt.org
Other
1.67k stars 298 forks source link

Support of IEEE single and double precision floating point operations #2667

Open JuanEsco063 opened 2 years ago

JuanEsco063 commented 2 years ago

Hello everyone,

I just want to confirm the status of supporting IEEE single and double precision floating point operations in CIRCT and if it is on the roadmap.

I was playing around with the handshake integration test and changed the data type to f64 (see attached) and I am getting the following errors:

matmul_std_lin_float.mlir:3:17: error: unsupported data type ''f64''
    %c123_f64 = arith.constant 123.0 : f64
                ^
matmul_std_lin_float.mlir:3:17: error: unsupported data type ''f64''
    %c123_f64 = arith.constant 123.0 : f64
                ^
matmul_std_lin_float.mlir:3:17: error: only memrefs of signless ints are supported
    %c123_f64 = arith.constant 123.0 : f64
                ^
matmul_std_lin_float.mlir:3:17: note: see current operation: %2:4 = "handshake.memory"(%164, %163, %456, %455, %470) {id = 2 : i32, ldCount = 1 : i32, lsq = false, memRefType = memref<64xf64>, stCount = 2 : i32} : (f64, index, f64, index, index) -> (f64, none, none, none)
matmul_std_lin_float.mlir:3:17: error: unsupported operation type
    %c123_f64 = arith.constant 123.0 : f64
                ^
matmul_std_lin_float.mlir:3:17: note: see current operation: %2:4 = "handshake.memory"(%164, %163, %456, %455, %470) {id = 2 : i32, ldCount = 1 : i32, lsq = false, memRefType = memref<64xf64>, stCount = 2 : i32} : (f64, index, f64, index, index) -> (f64, none, none, none)
matmul_std_lin_float.mlir:2:3: error: failed to legalize operation 'handshake.func' that was explicitly marked illegal
  func @top() -> f64 {
  ^
matmul_std_lin_float.mlir:2:3: note: see current operation: "handshake.func"() ({
^bb0(%arg0: none):
}) {argNames = ["inCtrl"], resNames = ["out0", "outCtrl"], sym_name = "top", type = (none) -> (f64, none)} : () -> ()
matmul_std_lin_float.mlir:2:3: error: 'handshake.func' op error during conversion
  func @top() -> f64 {
  ^
matmul_std_lin_float.mlir:2:3: note: see current operation: "handshake.func"() ({
^bb0(%arg0: none):
}) {argNames = ["inCtrl"], resNames = ["out0", "outCtrl"], sym_name = "top", type = (none) -> (f64, none)} : () -> ()

Of course I could just have a syntax error or not be using the arith.constant operator correctly so any feedback would be greatly appreciated.

Best regards, Juan

matmul_std_lin_float.txt

mikeurbach commented 2 years ago

Hey @JuanEsco063 thanks for bringing this up. Indeed, CIRCT dialects generally only work with integral bitwidth signals, and as you've seen, the HLS flow through handshake is explicit about this. I think we absolutely should have a solid library of FP ops in a dialect that workflows can target. To me, it seems like there are already great projects we can borrow implementations from, so this just becomes and engineering effort to package them up in CIRCT and expose them with the right layering.

JuanEsco063 commented 2 years ago

Hey @mikeurbach! I am leaving this issue open for future reference and in case anyone else has the same questions. At this point, do you know any path that could allow someone to integrate an external module (say Xilinx IP) to perform FP operations somewhat straightforwardly?

mikeurbach commented 2 years ago

The support exists within CIRCT, but I don't think there is any transformation/pass that will do exactly what you want out of the box. I think you'd want to emit suitable hw.module.extern (link) ops for all the operations you'd want to target (e.g. Xilinx IP).

For example, if you wanted to use a xilinx dsp for multiplication, you could run a pass on the HW/Comb level of IR that turns every comb.mul into an instance of a hw.module.extern with the appropriate name, ports, parameters, etc to map to a xilinx dsp. Then if you include the Xilinx IP alongside the CIRCT-generated Verilog, the synthesis tools should be able to link it together.

I know others have used external IPs in this manner, and it's just a matter of getting it hooked up at the right layer in whatever CIRCT-based flow you are using.

JuanEsco063 commented 2 years ago

@mikeurbach As always, your insight is always helpful! I will explore this avenue. Seems like a good way to start and hopefully it works. I will update this issue as soon as I have some results.

Thanks!

JuanEsco063 commented 2 years ago

@mikeurbach Do you know anyone who has successfully completed the flow you mentioned I can reach out to?

I am trying to do what you suggested following the path shown on the CIRCT homepage (https://circt.llvm.org/) of STD->HS->FIRRTL-> HW with no luck.

Starting from the example dot.mlir code in the integration_tests/Dialect/Handshake, I can convert it to HS, then I can convert it to FIRRTL and emit Verilog from that using firtool (but we already knew that). However, I am unable to lower from FIRRTL dialect to HW. I am using the pass --lower-firrtl-to-hw but I get errors. Maybe I am misunderstanding something and that pass is from FIRRTL (not the FIRRTL dialect) to HW.

On the other hand, I can convert the HS dialect to HW, but all the modules become external module references and the ports are defined as ESI interfaces. Using the passes --lower-esi-ports and --lower-esi-to-hw seems to get rid of the ESI ports, but using the pass --export-verilog does nothing. Once in (what I assume) is SV dialect, how do you emit Verilog?

mikeurbach commented 2 years ago

Starting from the example dot.mlir code in the integration_tests/Dialect/Handshake, I can convert it to HS, then I can convert it to FIRRTL and emit Verilog from that using firtool (but we already knew that). However, I am unable to lower from FIRRTL dialect to HW. I am using the pass --lower-firrtl-to-hw but I get errors. Maybe I am misunderstanding something and that pass is from FIRRTL (not the FIRRTL dialect) to HW.

I think --lower-firrtl-to-hw should work as a standalone pass, but maybe it works best with firtool. Can you try firtool --format=mlir --ir-hw? That should call --lower-firrtl-to-hw, as well as other prerequisites required to get there.

On the other hand, I can convert the HS dialect to HW, but all the modules become external module references and the ports are defined as ESI interfaces. Using the passes --lower-esi-ports and --lower-esi-to-hw seems to get rid of the ESI ports, but using the pass --export-verilog does nothing. Once in (what I assume) is SV dialect, how do you emit Verilog?

I think this flow is currently work in progress unfortunately.

Do you know anyone who has successfully completed the flow you mentioned I can reach out to?

That would be myself and @teqdruid, but unfortunately that project is closed source. We were using PyCDE to create the CIRCT IRs, and that's how we created the appropriate external modules for the platform. Happy to provide more info about that approach if that's helpful.

JuanEsco063 commented 2 years ago

@mikeurbach Yes, using firtool instead of circt-opt did the trick. I will ping you directly regarding replacing the arith.muli/addi with external IP. Once I get a FP IP working and integrated I will update the issue.