[RTL] Signed Math and comparisons (#279)

Add signed comparisons, arithmetic (signed) shift right, and signed math ops
firrtl to rtl should use the fancy new signed ops
match firrtl lowering semantics: had to check with the firrtl expert about the truncate in rem lowering for signed types
This commit is contained in:
Andrew Lenharth 2020-11-25 13:05:49 -06:00 committed by GitHub
parent 1cdeeb783d
commit 86c0be773a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 198 additions and 133 deletions

View File

@ -100,10 +100,13 @@ class UTVariadicRTLOp<string mnemonic, list<OpTrait> traits = []> :
def AddOp : UTVariadicRTLOp<"add", [Commutative]>;
def SubOp : UTBinRTLOp<"sub">;
def MulOp : UTVariadicRTLOp<"mul", [Commutative]>;
def DivOp : UTBinRTLOp<"div">;
def ModOp : UTBinRTLOp<"mod">;
def DivUOp : UTBinRTLOp<"divu">;
def DivSOp : UTBinRTLOp<"divs">;
def ModUOp : UTBinRTLOp<"modu">;
def ModSOp : UTBinRTLOp<"mods">;
def ShlOp : UTBinRTLOp<"shl">;
def ShrOp : UTBinRTLOp<"shr">;
def ShrUOp : UTBinRTLOp<"shru">;
def ShrSOp : UTBinRTLOp<"shrs">;
def AndOp : UTVariadicRTLOp<"and", [Commutative]>;
def OrOp : UTVariadicRTLOp<"or", [Commutative]>;

View File

@ -23,7 +23,8 @@ public:
return TypeSwitch<Operation *, ResultType>(op)
.template Case<ConstantOp,
// Arithmetic and Logical Binary Operations.
AddOp, SubOp, MulOp, DivOp, ModOp, ShlOp, ShrOp,
AddOp, SubOp, MulOp, DivUOp, DivSOp, ModUOp, ModSOp,
ShlOp, ShrUOp, ShrSOp,
// Bitwise operations
AndOp, OrOp, XorOp,
// Comparison operations
@ -73,16 +74,19 @@ public:
}
// Basic nodes.
HANDLE(ConstantOp, Unhandled)
HANDLE(ConstantOp, Unhandled);
// Arithmetic and Logical Binary Operations.
HANDLE(AddOp, Binary);
HANDLE(SubOp, Binary);
HANDLE(MulOp, Binary);
HANDLE(DivOp, Binary);
HANDLE(ModOp, Binary);
HANDLE(DivUOp, Binary);
HANDLE(DivSOp, Binary);
HANDLE(ModUOp, Binary);
HANDLE(ModSOp, Binary);
HANDLE(ShlOp, Binary);
HANDLE(ShrOp, Binary);
HANDLE(ShrUOp, Binary);
HANDLE(ShrSOp, Binary);
HANDLE(AndOp, Variadic);
HANDLE(OrOp, Variadic);

View File

@ -536,7 +536,8 @@ struct FIRRTLLowering : public LowerFIRRTLToRTLBase<FIRRTLLowering>,
// Binary Ops.
template <typename ResultOpType>
template <typename ResultUnsignedOpType,
typename ResultSignedOpType = ResultUnsignedOpType>
LogicalResult lowerBinOp(Operation *op);
template <typename ResultOpType>
LogicalResult lowerBinOpToVariadic(Operation *op);
@ -580,7 +581,9 @@ struct FIRRTLLowering : public LowerFIRRTLToRTLBase<FIRRTLLowering>,
LogicalResult visitExpr(MulPrimOp op) {
return lowerBinOpToVariadic<rtl::MulOp>(op);
}
LogicalResult visitExpr(DivPrimOp op) { return lowerBinOp<rtl::DivOp>(op); }
LogicalResult visitExpr(DivPrimOp op) {
return lowerBinOp<rtl::DivUOp, rtl::DivSOp>(op);
}
LogicalResult visitExpr(RemPrimOp op);
// Other Operations
@ -956,7 +959,7 @@ LogicalResult FIRRTLLowering::lowerBinOpToVariadic(Operation *op) {
/// lowerBinOp extends each operand to the destination type, then performs the
/// specified binary operator.
template <typename ResultOpType>
template <typename ResultUnsignedOpType, typename ResultSignedOpType>
LogicalResult FIRRTLLowering::lowerBinOp(Operation *op) {
// Extend the two operands to match the destination type.
auto resultType = op->getResult(0).getType();
@ -966,7 +969,9 @@ LogicalResult FIRRTLLowering::lowerBinOp(Operation *op) {
return failure();
// Emit the result operation.
return setLoweringTo<ResultOpType>(op, lhs, rhs);
if (resultType.cast<IntType>().isSigned())
return setLoweringTo<ResultSignedOpType>(op, lhs, rhs);
return setLoweringTo<ResultUnsignedOpType>(op, lhs, rhs);
}
/// lowerCmpOp extends each operand to the longest type, then performs the
@ -1003,10 +1008,17 @@ LogicalResult FIRRTLLowering::visitExpr(CatPrimOp op) {
}
LogicalResult FIRRTLLowering::visitExpr(RemPrimOp op) {
// FIRRTL has the width of (a % b) = Min(W(a), W(b)) so we need to truncate
// operands to the minimum width before doing the mod, not extend them.
auto lhs = getLoweredValue(op.lhs());
auto rhs = getLoweredValue(op.rhs());
// FIRRTL has the width of (a % b) = Min(W(a), W(b)), but the operation is
// done at max(W(a), W(b))) so we need to extend one operand, then truncate
// the result.
auto lhsFirTy = op.lhs().getType().dyn_cast<IntType>();
auto rhsFirTy = op.rhs().getType().dyn_cast<IntType>();
if (!lhsFirTy || !rhsFirTy || !lhsFirTy.hasWidth() || !rhsFirTy.hasWidth())
return failure();
auto opType = lhsFirTy.getWidth() > rhsFirTy.getWidth() ? lhsFirTy : rhsFirTy;
auto lhs = getLoweredAndExtendedValue(op.lhs(), opType);
auto rhs = getLoweredAndExtendedValue(op.rhs(), opType);
if (!lhs || !rhs)
return failure();
@ -1016,13 +1028,13 @@ LogicalResult FIRRTLLowering::visitExpr(RemPrimOp op) {
auto destWidth = unsigned(resultFirType.getWidthOrSentinel());
auto resultType = builder->getIntegerType(destWidth);
// Truncate either operand if required.
if (lhs.getType().cast<IntegerType>().getWidth() != destWidth)
lhs = builder->create<rtl::ExtractOp>(resultType, lhs, 0);
if (rhs.getType().cast<IntegerType>().getWidth() != destWidth)
rhs = builder->create<rtl::ExtractOp>(resultType, rhs, 0);
return setLoweringTo<rtl::ModOp>(op, ValueRange({lhs, rhs}));
Value modInst;
if (resultFirType.isUnsigned()) {
modInst = builder->create<rtl::ModUOp>(ValueRange({lhs, rhs}));
} else {
modInst = builder->create<rtl::ModSOp>(ValueRange({lhs, rhs}));
}
return setLoweringTo<rtl::ExtractOp>(op, resultType, modInst, 0);
}
//===----------------------------------------------------------------------===//
@ -1109,7 +1121,7 @@ LogicalResult FIRRTLLowering::visitExpr(DShrPrimOp op) {
// Zero extend or truncate the shift amount if needed.
rhs = zeroExtendOrTruncate(rhs, lhs.getType(), *builder);
return setLoweringTo<rtl::ShrOp>(op, lhs, rhs);
return setLoweringTo<rtl::ShrUOp>(op, lhs, rhs);
}
LogicalResult FIRRTLLowering::visitExpr(TailPrimOp op) {

View File

@ -711,7 +711,8 @@ public:
private:
/// Emit the specified value as a subexpression to the stream.
SubExprInfo emitSubExpr(Value exp, VerilogPrecedence parenthesizeIfLooserThan,
bool forceExpectedSign = false);
bool forceExpectedSign = false,
bool opForceSign = false);
SubExprInfo visitUnhandledExpr(Operation *op);
SubExprInfo visitInvalidExpr(Operation *op) {
@ -738,10 +739,15 @@ private:
SubExprInfo emitBitSelect(Value operand, unsigned hiBit, unsigned loBit);
SubExprInfo emitBinary(Operation *op, VerilogPrecedence prec,
const char *syntax, bool hasStrictSign = false);
const char *syntax, bool hasStrictSign = false,
bool opForceSign = false);
SubExprInfo emitVariadic(Operation *op, VerilogPrecedence prec,
const char *syntax, bool hasStrictSign = false);
const char *syntax, bool hasStrictSign = false,
bool opForceSign = false);
SubExprInfo emitRTLSignedVariadic(Operation *op, VerilogPrecedence prec,
const char *syntax);
/// Emit the specified subexpression in a context where the sign matters,
/// e.g. for a less than comparison or divide.
@ -749,6 +755,13 @@ private:
const char *syntax) {
return emitBinary(op, prec, syntax, /*hasStrictSign:*/ true);
}
/// Emit the specified subexpression in a context where the sign matters,
/// e.g. for a less than comparison or divide.
SubExprInfo emitRTLSignedBinary(Operation *op, VerilogPrecedence prec,
const char *syntax) {
return emitBinary(op, prec, syntax, /*hasStrictSign:*/ true,
/*opForceSign*/ true);
}
SubExprInfo emitUnary(Operation *op, const char *syntax, bool forceUnsigned) {
os << syntax;
auto signedness = emitSubExpr(op->getOperand(0), Unary).signedness;
@ -856,17 +869,22 @@ private:
SubExprInfo visitComb(rtl::MulOp op) {
return emitVariadic(op, Multiply, "*");
}
SubExprInfo visitComb(rtl::DivOp op) {
return emitSignedBinary(op, Multiply, "/");
SubExprInfo visitComb(rtl::DivUOp op) {
return emitBinary(op, Multiply, "/");
}
SubExprInfo visitComb(rtl::ModOp op) {
return emitSignedBinary(op, Multiply, "%");
SubExprInfo visitComb(rtl::DivSOp op) {
return emitRTLSignedBinary(op, Multiply, "/");
}
SubExprInfo visitComb(rtl::ShlOp op) {
return emitSignedBinary(op, Shift, "<<");
SubExprInfo visitComb(rtl::ModUOp op) {
return emitBinary(op, Multiply, "%");
}
SubExprInfo visitComb(rtl::ShrOp op) {
return emitSignedBinary(op, Shift, ">>>");
SubExprInfo visitComb(rtl::ModSOp op) {
return emitRTLSignedBinary(op, Multiply, "%");
}
SubExprInfo visitComb(rtl::ShlOp op) { return emitBinary(op, Shift, "<<"); }
SubExprInfo visitComb(rtl::ShrUOp op) { return emitBinary(op, Shift, ">>>"); }
SubExprInfo visitComb(rtl::ShrSOp op) {
return emitRTLSignedBinary(op, Shift, ">>>");
}
SubExprInfo visitComb(rtl::AndOp op) { return emitVariadic(op, And, "&"); }
SubExprInfo visitComb(rtl::OrOp op) { return emitVariadic(op, Or, "|"); }
@ -883,10 +901,15 @@ private:
// RTL Comparison Operations
SubExprInfo visitComb(rtl::ICmpOp op) {
std::array<const char *, 10> symop{"==", "!=", "<", "<=", "<",
"<=", ">", ">=", ">", ">="};
return emitSignedBinary(op, Comparison,
symop[static_cast<uint64_t>(op.predicate())]);
std::array<const char *, 10> symop{"==", "!=", "<", "<=", ">",
">=", "<", "<=", ">", ">="};
std::array<bool, 10> signop{false, false, true, true, true,
true, false, false, false, false};
auto pred = static_cast<uint64_t>(op.predicate());
auto symopstr = symop[pred];
if (signop[pred])
return emitRTLSignedBinary(op, Comparison, symopstr);
return emitBinary(op, Comparison, symopstr);
}
private:
@ -918,8 +941,10 @@ std::string ExprEmitter::emitExpressionToString(Value exp,
}
SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
const char *syntax, bool hasStrictSign) {
auto lhsInfo = emitSubExpr(op->getOperand(0), prec, hasStrictSign);
const char *syntax, bool hasStrictSign,
bool opForceSign) {
auto lhsInfo =
emitSubExpr(op->getOperand(0), prec, hasStrictSign, opForceSign);
os << ' ' << syntax << ' ';
// The precedence of the RHS operand must be tighter than this operator if
@ -932,12 +957,15 @@ SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
if (rhsOperandOp && op->getName() == rhsOperandOp->getName())
rhsPrec = prec;
auto rhsInfo = emitSubExpr(op->getOperand(1), rhsPrec, hasStrictSign);
auto rhsInfo =
emitSubExpr(op->getOperand(1), rhsPrec, hasStrictSign, opForceSign);
// If we have a strict sign, then match the firrtl operation sign.
// Otherwise, the result is signed if both operands are signed.
SubExprSignedness signedness;
if (hasStrictSign)
if (opForceSign)
signedness = IsSigned;
else if (hasStrictSign)
signedness = getSignednessOf(op->getResult(0).getType());
else if (lhsInfo.signedness == IsSigned && rhsInfo.signedness == IsSigned)
signedness = IsSigned;
@ -948,19 +976,26 @@ SubExprInfo ExprEmitter::emitBinary(Operation *op, VerilogPrecedence prec,
}
SubExprInfo ExprEmitter::emitVariadic(Operation *op, VerilogPrecedence prec,
const char *syntax, bool hasStrictSign) {
const char *syntax, bool hasStrictSign,
bool opForceSign) {
interleave(
op->getOperands().begin(), op->getOperands().end(),
[&](Value v1) { emitSubExpr(v1, prec, hasStrictSign); },
[&](Value v1) { emitSubExpr(v1, prec, hasStrictSign, opForceSign); },
[&] { os << ' ' << syntax << ' '; });
return {prec, IsUnsigned};
}
SubExprInfo ExprEmitter::emitRTLSignedVariadic(Operation *op,
VerilogPrecedence prec,
const char *syntax) {
return emitVariadic(op, prec, syntax, true, true);
}
/// Emit the specified value as a subexpression to the stream.
SubExprInfo ExprEmitter::emitSubExpr(Value exp,
VerilogPrecedence parenthesizeIfLooserThan,
bool forceExpectedSign) {
bool forceExpectedSign, bool opForceSign) {
auto *op = exp.getDefiningOp();
bool shouldEmitInlineExpr = op && isVerilogExpression(op);
@ -972,7 +1007,8 @@ SubExprInfo ExprEmitter::emitSubExpr(Value exp,
// If this is a non-expr or shouldn't be done inline, just refer to its
// name.
if (!shouldEmitInlineExpr) {
if (forceExpectedSign && getSignednessOf(exp.getType()) != IsUnsigned) {
if ((forceExpectedSign && getSignednessOf(exp.getType()) != IsUnsigned) ||
opForceSign) {
os << "$signed(" << emitter.getName(exp) << ')';
return {Unary, IsSigned};
}

View File

@ -12,7 +12,7 @@ firrtl.circuit "M1" {
firrtl.connect %y, %c : !firrtl.flip<uint<8>>, !firrtl.uint<8>
%d = rtl.mul %z, %z, %z : i8
%e = rtl.mod %d, %c5 : i8
%e = rtl.modu %d, %c5 : i8
%f = rtl.concat %e, %z, %d : (i8, i8, i8) -> i8
%g = firrtl.stdIntCast %f : (i8) -> !firrtl.uint<8>
firrtl.connect %y, %g : !firrtl.flip<uint<8>>, !firrtl.uint<8>

View File

@ -7,87 +7,95 @@ module {
// CHECK-LABEL: // external module E
rtl.module @TESTSIMPLE(%a: i4, %cond: i1) -> (%r0: i4, %r1: i4, %r2: i4, %r3: i4, %r4: i4, %r5: i4, %r6: i4, %r7: i4, %r8: i4, %r9: i4,
%r10: i1, %r11: i1, %r12: i1, %r13: i1, %r14: i1, %r15: i1, %r16: i1, %r17: i1, %r18: i1, %r19: i1,
%r20: i1, %r21: i1, %r22: i1, %r23: i12, %r24: i2, %r25: i9, %r26: i9, %r27: i4
) {
%0 = rtl.add %a, %a : i4
%1 = rtl.sub %a, %a : i4
%2 = rtl.mul %a, %a : i4
%3 = rtl.div %a, %a : i4
%4 = rtl.mod %a, %a : i4
%5 = rtl.shl %a, %a : i4
%6 = rtl.shr %a, %a : i4
%7 = rtl.or %a, %a : i4
%8 = rtl.and %a, %a : i4
%9 = rtl.xor %a, %a : i4
%10 = rtl.icmp "eq" %a, %a : i4
%11 = rtl.icmp "ne" %a, %a : i4
%12 = rtl.icmp "slt" %a, %a : i4
%13 = rtl.icmp "sle" %a, %a : i4
%14 = rtl.icmp "sgt" %a, %a : i4
%15 = rtl.icmp "sge" %a, %a : i4
%16 = rtl.icmp "ult" %a, %a : i4
%17 = rtl.icmp "ule" %a, %a : i4
%18 = rtl.icmp "ugt" %a, %a : i4
%19 = rtl.icmp "uge" %a, %a : i4
%20 = rtl.andr %a : i4
%21 = rtl.orr %a : i4
%22 = rtl.xorr %a : i4
%23 = rtl.concat %a, %a, %a : (i4, i4, i4) -> i12
%24 = rtl.extract %a from 1 : (i4) -> i2
%25 = rtl.sext %a : (i4) -> i9
%26 = rtl.zext %a : (i4) -> i9
%27 = rtl.mux %cond, %a, %a : i4
rtl.module @TESTSIMPLE(%a: i4, %b: i4, %cond: i1) -> (
%r0: i4, %r2: i4, %r4: i4, %r6: i4,
%r7: i4, %r8: i4, %r9: i4, %r10: i4,
%r11: i4, %r12: i4, %r13: i4, %r14: i4,
%r15: i4, %r16: i1,
%r17: i1, %r18: i1, %r19: i1, %r20: i1,
%r21: i1, %r22: i1, %r23: i1, %r24: i1,
%r25: i1, %r26: i1, %r27: i1, %r28: i1,
%r29: i12, %r30: i2, %r31: i9, %r32: i9, %r33: i4
) {
rtl.output %0, %1, %2, %3, %4, %5, %6, %7, %8, %9,
%10, %11, %12, %13, %14, %15, %16, %17, %18, %19,
%20, %21, %22, %23, %24, %25, %26, %27 :
i4, i4, i4, i4, i4,
i4, i4, i4, i4, i4,
i1, i1, i1, i1, i1,
i1, i1, i1, i1, i1,
i1, i1, i1, i12, i2,
i9, i9, i4
%0 = rtl.add %a, %b : i4
%2 = rtl.sub %a, %b : i4
%4 = rtl.mul %a, %b : i4
%6 = rtl.divu %a, %b : i4
%7 = rtl.divs %a, %b : i4
%8 = rtl.modu %a, %b : i4
%9 = rtl.mods %a, %b : i4
%10 = rtl.shl %a, %b : i4
%11 = rtl.shru %a, %b : i4
%12 = rtl.shrs %a, %b : i4
%13 = rtl.or %a, %b : i4
%14 = rtl.and %a, %b : i4
%15 = rtl.xor %a, %b : i4
%16 = rtl.icmp "eq" %a, %b : i4
%17 = rtl.icmp "ne" %a, %b : i4
%18 = rtl.icmp "slt" %a, %b : i4
%19 = rtl.icmp "sle" %a, %b : i4
%20 = rtl.icmp "sgt" %a, %b : i4
%21 = rtl.icmp "sge" %a, %b : i4
%22 = rtl.icmp "ult" %a, %b : i4
%23 = rtl.icmp "ule" %a, %b : i4
%24 = rtl.icmp "ugt" %a, %b : i4
%25 = rtl.icmp "uge" %a, %b : i4
%26 = rtl.andr %a : i4
%27 = rtl.orr %a : i4
%28 = rtl.xorr %a : i4
%29 = rtl.concat %a, %a, %b : (i4, i4, i4) -> i12
%30 = rtl.extract %a from 1 : (i4) -> i2
%31 = rtl.sext %a : (i4) -> i9
%32 = rtl.zext %a : (i4) -> i9
%33 = rtl.mux %cond, %a, %b : i4
rtl.output %0, %2, %4, %6, %7, %8, %9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25, %26, %27, %28, %29, %30, %31, %32, %33:
i4,i4, i4,i4,i4,i4,i4, i4,i4,i4,i4,i4,
i4,i1,i1,i1,i1, i1,i1,i1,i1,i1, i1,i1,i1,i1,
i12, i2,i9,i9,i4
}
// CHECK-LABEL: module TESTSIMPLE(
// CHECK-NEXT: input [3:0] a,
// CHECK-NEXT: input [3:0] a, b
// CHECK-NEXT: input cond,
// CHECK-NEXT: output [3:0] r0, r1, r2, r3, r4, r5, r6, r7, r8, r9,
// CHECK-NEXT: output r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22,
// CHECK-NEXT: output [11:0] r23,
// CHECK-NEXT: output [1:0] r24,
// CHECK-NEXT: output [8:0] r25, r26,
// CHECK-NEXT: output [3:0] r27);
// CHECK-NEXT: output [3:0] r0, r2, r4, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15
// CHECK-NEXT: output r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28
// CHECK-NEXT: output [11:0] r29,
// CHECK-NEXT: output [1:0] r30,
// CHECK-NEXT: output [8:0] r31, r32,
// CHECK-NEXT: output [3:0] r33);
// CHECK-EMPTY:
// CHECK-NEXT: assign r0 = a + a;
// CHECK-NEXT: assign r1 = a - a;
// CHECK-NEXT: assign r2 = a * a;
// CHECK-NEXT: assign r3 = a / a;
// CHECK-NEXT: assign r4 = a % a;
// CHECK-NEXT: assign r5 = a << a;
// CHECK-NEXT: assign r6 = a >>> a;
// CHECK-NEXT: assign r7 = a | a;
// CHECK-NEXT: assign r8 = a & a;
// CHECK-NEXT: assign r9 = a ^ a;
// CHECK-NEXT: assign r10 = a == a;
// CHECK-NEXT: assign r11 = a != a;
// CHECK-NEXT: assign r12 = a < a;
// CHECK-NEXT: assign r13 = a <= a;
// CHECK-NEXT: assign r14 = a < a;
// CHECK-NEXT: assign r15 = a <= a;
// CHECK-NEXT: assign r16 = a > a;
// CHECK-NEXT: assign r17 = a >= a;
// CHECK-NEXT: assign r18 = a > a;
// CHECK-NEXT: assign r19 = a >= a;
// CHECK-NEXT: assign r20 = &a;
// CHECK-NEXT: assign r21 = |a;
// CHECK-NEXT: assign r22 = ^a;
// CHECK-NEXT: assign r23 = {a, a, a};
// CHECK-NEXT: assign r24 = a[2:1];
// CHECK-NEXT: assign r25 = {{[{}][{}]}}5{a[3]}}, a};
// CHECK-NEXT: assign r26 = {{[{}][{}]}}5'd0}, a};
// CHECK-NEXT: assign r27 = cond ? a : a;
// CHECK-NEXT: assign r0 = a + b;
// CHECK-NEXT: assign r2 = a - b;
// CHECK-NEXT: assign r4 = a * b;
// CHECK-NEXT: assign r6 = a / b;
// CHECK-NEXT: assign r7 = $signed(a) / $signed(b);
// CHECK-NEXT: assign r8 = a % b;
// CHECK-NEXT: assign r9 = $signed(a) % $signed(b);
// CHECK-NEXT: assign r10 = a << b;
// CHECK-NEXT: assign r11 = a >>> b;
// CHECK-NEXT: assign r12 = $signed(a) >>> $signed(b);
// CHECK-NEXT: assign r13 = a | b;
// CHECK-NEXT: assign r14 = a & b;
// CHECK-NEXT: assign r15 = a ^ b;
// CHECK-NEXT: assign r16 = a == b;
// CHECK-NEXT: assign r17 = a != b;
// CHECK-NEXT: assign r18 = $signed(a) < $signed(b);
// CHECK-NEXT: assign r19 = $signed(a) <= $signed(b);
// CHECK-NEXT: assign r20 = $signed(a) > $signed(b);
// CHECK-NEXT: assign r21 = $signed(a) >= $signed(b);
// CHECK-NEXT: assign r22 = a < b;
// CHECK-NEXT: assign r23 = a <= b;
// CHECK-NEXT: assign r24 = a > b;
// CHECK-NEXT: assign r25 = a >= b;
// CHECK-NEXT: assign r26 = &a;
// CHECK-NEXT: assign r27 = |a;
// CHECK-NEXT: assign r28 = ^a;
// CHECK-NEXT: assign r29 = {a, a, b};
// CHECK-NEXT: assign r30 = a[2:1];
// CHECK-NEXT: assign r31 = {{[{}][{}]}}5{a[3]}}, a};
// CHECK-NEXT: assign r32 = {{[{}][{}]}}5'd0}, a};
// CHECK-NEXT: assign r33 = cond ? a : b;
// CHECK-NEXT: endmodule
rtl.module @B(%a: i1 { rtl.inout }) -> (%b: i1, %c: i1) {

View File

@ -103,20 +103,22 @@ module attributes {firrtl.mainModule = "Simple"} {
// CHECK-NEXT: [[ZEXTC1:%.+]] = rtl.zext [[CONCAT1]] : (i8) -> i12
// CHECK-NEXT: [[ZEXT2:%.+]] = rtl.zext [[SUB]] : (i4) -> i12
// CHECK-NEXT: [[VAL18:%.+]] = rtl.mul [[ZEXTC1]], [[ZEXT2]] : i12
// CHECK-NEXT: [[VAL18:%.+]] = rtl.mul [[ZEXTC1]], [[ZEXT2]] : i12
%18 = firrtl.mul %6, %2 : (!firrtl.uint<8>, !firrtl.uint<4>) -> !firrtl.uint<12>
// CHECK-NEXT: [[IN3SEXT:%.+]] = rtl.sext %in3 : (i8) -> i9
// CHECK-NEXT: [[PADRESSEXT:%.+]] = rtl.sext [[PADRES]] : (i3) -> i9
// CHECK-NEXT: = rtl.div [[IN3SEXT]], [[PADRESSEXT]] : i9
// CHECK-NEXT: = rtl.divs [[IN3SEXT]], [[PADRESSEXT]] : i9
%19 = firrtl.div %in3c, %3 : (!firrtl.sint<8>, !firrtl.sint<3>) -> !firrtl.sint<9>
// CHECK-NEXT: [[IN3TRUNC:%.+]] = rtl.extract %in3 from 0 : (i8) -> i3
// CHECK-NEXT: = rtl.mod [[IN3TRUNC]], [[PADRES]] : i3
// CHECK-NEXT: [[IN3EX:%.+]] = rtl.sext [[PADRES]] : (i3) -> i8
// CHECK-NEXT: [[MOD1:%.+]] = rtl.mods %in3, [[IN3EX]] : i8
// CHECK-NEXT: = rtl.extract [[MOD1]] from 0 : (i8) -> i3
%20 = firrtl.rem %in3c, %3 : (!firrtl.sint<8>, !firrtl.sint<3>) -> !firrtl.sint<3>
// CHECK-NEXT: [[IN3TRUNC:%.+]] = rtl.extract %in3 from 0 : (i8) -> i3
// CHECK-NEXT: = rtl.mod [[PADRES]], [[IN3TRUNC]] : i3
// CHECK-NEXT: [[IN4EX:%.+]] = rtl.sext [[PADRES]] : (i3) -> i8
// CHECK-NEXT: [[MOD2:%.+]] = rtl.mods [[IN4EX]], %in3 : i8
// CHECK-NEXT: = rtl.extract [[MOD2]] from 0 : (i8) -> i3
%21 = firrtl.rem %3, %in3c : (!firrtl.sint<3>, !firrtl.sint<8>) -> !firrtl.sint<3>
// CHECK-NEXT: [[WIRE:%n1]] = rtl.wire : i2
@ -151,7 +153,7 @@ module attributes {firrtl.mainModule = "Simple"} {
%28 = firrtl.andr %27 : (!firrtl.uint<12>) -> !firrtl.uint<1>
// CHECK-NEXT: = rtl.extract [[VAL18]] from 0 : (i12) -> i3
// CHECK-NEXT: = rtl.shr [[XOR]], {{.*}} : i3
// CHECK-NEXT: = rtl.shru [[XOR]], {{.*}} : i3
%29 = firrtl.dshr %24, %18 : (!firrtl.uint<3>, !firrtl.uint<12>) -> !firrtl.uint<3>
// CHECK-NEXT: = rtl.zext %2 : (i3) -> i8

View File

@ -26,8 +26,8 @@ func @shl_op(%a: i7, %b: i7) -> i7 {
// CHECK-LABEL: func @shr_op(%arg0: i7, %arg1: i7) -> i7 {
func @shr_op(%a: i7, %b: i7) -> i7 {
// CHECK-NEXT: [[RES:%[0-9]+]] = rtl.shr %arg0, %arg1 : i7
%0 = rtl.shr %a, %b : i7
// CHECK-NEXT: [[RES:%[0-9]+]] = rtl.shru %arg0, %arg1 : i7
%0 = rtl.shru %a, %b : i7
// CHECK-NEXT: return [[RES]]
return %0 : i7
}