Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Calyx backend issue with emitting signed binops #430

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions file-tests/should-futil/emit-signed-op.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import "primitives/core.futil";
import "primitives/memories/seq.futil";
import "primitives/binary_operators.futil";
component main() -> () {
cells {
@external(1) a = seq_mem_d1(10,128,8);
a_read0_0 = std_reg(10);
a_read1_0 = std_reg(10);
add0 = std_sadd(10);
add1 = std_sadd(8);
and0 = std_and(10);
@external(1) b = seq_mem_d1(10,128,8);
b_read0_0 = std_reg(10);
b_read1_0 = std_reg(10);
@external(1) c = seq_mem_d1(10,128,8);
const0 = std_const(8,0);
const1 = std_const(8,1);
@external(1) d = seq_mem_d1(10,128,8);
i0 = std_reg(8);
}
wires {
group let0<"promotable"=1> {
i0.in = const0.out;
i0.write_en = 1'd1;
let0[done] = i0.done;
}
group let1<"promotable"=2> {
a_read0_0.in = a.read_data;
a_read0_0.write_en = a.done;
let1[done] = a_read0_0.done;
a.content_en = 1'd1;
a.addr0 = i0.out;
}
group let2<"promotable"=2> {
b_read0_0.in = b.read_data;
b_read0_0.write_en = b.done;
let2[done] = b_read0_0.done;
b.content_en = 1'd1;
b.addr0 = i0.out;
}
group let3<"promotable"=2> {
a_read1_0.in = a.read_data;
a_read1_0.write_en = a.done;
let3[done] = a_read1_0.done;
a.content_en = 1'd1;
a.addr0 = i0.out;
}
group let4<"promotable"=2> {
b_read1_0.in = b.read_data;
b_read1_0.write_en = b.done;
let4[done] = b_read1_0.done;
b.content_en = 1'd1;
b.addr0 = i0.out;
}
group upd0<"promotable"=1> {
c.content_en = 1'd1;
c.addr0 = i0.out;
c.write_en = 1'd1;
and0.left = a_read0_0.out;
and0.right = b_read0_0.out;
c.write_data = and0.out;
upd0[done] = c.done;
}
group upd1<"promotable"=1> {
d.content_en = 1'd1;
d.addr0 = i0.out;
d.write_en = 1'd1;
add0.left = a_read1_0.out;
add0.right = b_read1_0.out;
d.write_data = add0.out;
upd1[done] = d.done;
}
group upd2<"promotable"=1> {
i0.write_en = 1'd1;
add1.left = i0.out;
add1.right = const1.out;
i0.in = add1.out;
upd2[done] = i0.done;
}
}
control {
seq {
@pos(0) let0;
repeat 128 {
seq {
par {
@pos(1) let1;
@pos(2) let2;
}
par {
@pos(3) upd0;
@pos(4) let3;
@pos(5) let4;
}
@pos(6) upd1;
@pos(0) upd2;
}
}
}
}
}
metadata #{
0: for (let i:bit<8>=0..128) {
1: c[i] := a[i] & b[i]; // This should not be emit signed Calyx primitive
2: c[i] := a[i] & b[i]; // This should not be emit signed Calyx primitive
3: c[i] := a[i] & b[i]; // This should not be emit signed Calyx primitive
4: d[i] := a[i] + b[i]; // This should emit a signed Calyx primitive
5: d[i] := a[i] + b[i]; // This should emit a signed Calyx primitive
6: d[i] := a[i] + b[i]; // This should emit a signed Calyx primitive
}#
9 changes: 9 additions & 0 deletions file-tests/should-futil/emit-signed-op.fuse
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
decl a: bit<10>[128];
decl b: bit<10>[128];
decl c: bit<10>[128];
decl d: bit<10>[128];

for (let i:bit<8>=0..128) {
c[i] := a[i] & b[i]; // This should not be emit signed Calyx primitive
d[i] := a[i] + b[i]; // This should emit a signed Calyx primitive
}
8 changes: 4 additions & 4 deletions src/main/scala/backends/calyx/Backend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ private class CalyxBackendHelper {
/** `emitBinop` is a helper function to generate the structure for `e1 binop
* e2`. The return type is described in `emitExpr`.
*/
def emitBinop(compName: String, e1: Expr, e2: Expr)(implicit
def emitBinop(compName: String, op: BOp, e1: Expr, e2: Expr)(implicit
store: Store
): EmitOutput = {
val e1Out = emitExpr(e1)
Expand Down Expand Up @@ -286,7 +286,7 @@ private class CalyxBackendHelper {

bitsForType(e1.typ, e1.pos) match {
case (e1Bits, None) => {
val isSigned = signed(e1.typ)
val isSigned = signed(e1.typ, op)
val binOp = Stdlib.binop(s"$compName", e1Bits, isSigned)
val comp = Cell(genName(compName), binOp, false, List())
val struct = List(
Expand All @@ -309,7 +309,7 @@ private class CalyxBackendHelper {
val (e2Bits, Some(intBit2)) = bitsForType(e2.typ, e2.pos): @unchecked
val fracBit1 = e1Bits - intBit1
val fracBit2 = e2Bits - intBit2
val isSigned = signed(e1.typ)
val isSigned = signed(e1.typ, op)
assertOrThrow(
fracBit1 == fracBit2 && intBit1 == intBit2,
NotImplemented(
Expand Down Expand Up @@ -487,7 +487,7 @@ private class CalyxBackendHelper {
"out_remainder",
None
)
case _ => emitBinop(compName, e1, e2)
case _ => emitBinop(compName, op, e1, e2)
}
}
case EVar(id) =>
Expand Down
14 changes: 8 additions & 6 deletions src/main/scala/backends/calyx/Helpers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ object Helpers:

/** Returns true if the given int or fixed point is signed
*/
def signed(typ: Option[Type]) =
typ match
case Some(TSizedInt(_, un)) => un == false
case Some(TFixed(_, _, un)) => un == false
case _ => false

def signed(typ: Option[Type], op: BOp) =
op match
case _@NumOp(_, _) =>
typ match
case Some(TSizedInt(_, un)) => un == false
case Some(TFixed(_, _, un)) => un == false
case _ => false
case _ => false // bit
Loading