mirror of https://github.com/llvm/circt.git
[HWArith][HWArithToHW] Implement ICmp (#3637)
This commit is contained in:
parent
25314edcec
commit
d4dbdb1fd7
|
@ -192,7 +192,7 @@ operand's width.
|
||||||
We know that `a + 1 > b`, and derive from (S) that the result type must be
|
We know that `a + 1 > b`, and derive from (S) that the result type must be
|
||||||
`si<(a+1) + 1>` = `si<a+2>`.
|
`si<(a+1) + 1>` = `si<a+2>`.
|
||||||
|
|
||||||
* `a < b`, i.e. the unsigned operand's width is stricly less than the signed
|
* `a < b`, i.e. the unsigned operand's width is strictly less than the signed
|
||||||
operand's width.
|
operand's width.
|
||||||
|
|
||||||
As `a + 1 ≤ b`, the result via (S) is `si<b+1>`.
|
As `a + 1 ≤ b`, the result via (S) is `si<b+1>`.
|
||||||
|
@ -233,7 +233,7 @@ Example:
|
||||||
|
|
||||||
Result value range: `[SI_MIN<a> - SI_MAX<b>, SI_MAX<a> - SI_MIN<b>]`
|
Result value range: `[SI_MIN<a> - SI_MAX<b>, SI_MAX<a> - SI_MIN<b>]`
|
||||||
|
|
||||||
We rewrite the value range and then appy the same reasoning as for the
|
We rewrite the value range and then apply the same reasoning as for the
|
||||||
[signed addition](#signed-addition-S):
|
[signed addition](#signed-addition-S):
|
||||||
```
|
```
|
||||||
[SI_MIN<a> - SI_MAX<b>, SI_MAX<a> - SI_MIN<b>]
|
[SI_MIN<a> - SI_MAX<b>, SI_MAX<a> - SI_MIN<b>]
|
||||||
|
@ -370,7 +370,7 @@ Example:
|
||||||
|
|
||||||
Result value range: `[SI_MIN<a> / 1, SI_MIN<a> / -1]`
|
Result value range: `[SI_MIN<a> / 1, SI_MIN<a> / -1]`
|
||||||
|
|
||||||
`- SI_MIN<a>` is not convered by `si<a>`, so we have to widen the result type to
|
`- SI_MIN<a>` is not covered by `si<a>`, so we have to widen the result type to
|
||||||
`si<a+1>`.
|
`si<a+1>`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -465,6 +465,45 @@ required.
|
||||||
%3 = hwarith.cast %13 : (si14) -> i4 // (S)
|
%3 = hwarith.cast %13 : (si14) -> i4 // (S)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Comparison
|
||||||
|
|
||||||
|
In order to compare two sign-aware operands, a common type must first be found
|
||||||
|
that is able to preserve the values of the two operands. Once determined, the
|
||||||
|
operands are casted to this comparison type as specified in the
|
||||||
|
[casting section](#casting). To simplify the use as well as the IR generation
|
||||||
|
of the dialect, the necessary casting steps are hidden from the user and
|
||||||
|
applied during the lowering. Thus, the following code:
|
||||||
|
```mlir
|
||||||
|
%2 = hwarith.cast %0 : (si3) -> si6
|
||||||
|
%3 = hwarith.cast %1 : (ui5) -> si6
|
||||||
|
%4 = hwarith.icmp lt %2, %3 : si6, si6
|
||||||
|
```
|
||||||
|
can be simplified to:
|
||||||
|
```mlir
|
||||||
|
%4 = hwarith.icmp lt %0, %1 : si3, ui5
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the result of the comparison is *always* of type `ui1`, regardless of
|
||||||
|
the operands. So if the `i1` type is needed, the result must be cast
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
#### Overview
|
||||||
|
|
||||||
|
| | LHS type | RHS type | Comparison type | Result type |
|
||||||
|
| - | :------- | :------- | :--------------------------------------- | :---------- |
|
||||||
|
|(U)| `ui<a>` | `ui<b>` | `ui<r>`, *r* = max(*a*, *b*) | `ui1` |
|
||||||
|
|(S)| `si<a>` | `si<b>` | `si<r>`, *r* = max(*a*, *b*) | `ui1` |
|
||||||
|
|(M)| `ui<a>` | `si<b>` | `si<r>`, *r* = *a* + 1 **if** *a* ≥ *b* | `ui1` |
|
||||||
|
| | | | `si<r>`, *r* = *b* **if** *a* < *b* | `ui1` |
|
||||||
|
|(M)| `si<a>` | `ui<b>` | Same as `ui<b> si<a>` | `ui1` |
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
```mlir
|
||||||
|
%0 = hwarith.icmp lt %10, %11 : ui5, ui6 // (U)
|
||||||
|
%1 = hwarith.icmp lt %12, %13 : si3, si4 // (S)
|
||||||
|
%2 = hwarith.icmp lt %12, %11 : si3, ui6 // (M)
|
||||||
|
```
|
||||||
|
|
||||||
### Additional operators
|
### Additional operators
|
||||||
**TODO**: elaborate once operators are provided.
|
**TODO**: elaborate once operators are provided.
|
||||||
* `hwarith.mod %0, %1 : (#l0, #l1) -> (#l2)`:
|
* `hwarith.mod %0, %1 : (#l0, #l1) -> (#l2)`:
|
||||||
|
|
|
@ -2,3 +2,6 @@ add_circt_dialect(HWArith hwarith)
|
||||||
add_circt_dialect_doc(HWArith hwarith)
|
add_circt_dialect_doc(HWArith hwarith)
|
||||||
|
|
||||||
set(LLVM_TARGET_DEFINITIONS HWArith.td)
|
set(LLVM_TARGET_DEFINITIONS HWArith.td)
|
||||||
|
mlir_tablegen(HWArithEnums.h.inc -gen-enum-decls)
|
||||||
|
mlir_tablegen(HWArithEnums.cpp.inc -gen-enum-defs)
|
||||||
|
add_public_tablegen_target(MLIRHWArithEnumsIncGen)
|
||||||
|
|
|
@ -19,4 +19,7 @@
|
||||||
// Pull in the Dialect definition.
|
// Pull in the Dialect definition.
|
||||||
#include "circt/Dialect/HWArith/HWArithDialect.h.inc"
|
#include "circt/Dialect/HWArith/HWArithDialect.h.inc"
|
||||||
|
|
||||||
|
// Pull in all enum type definitions and utility function declarations.
|
||||||
|
#include "circt/Dialect/HWArith/HWArithEnums.h.inc"
|
||||||
|
|
||||||
#endif // CIRCT_DIALECT_HWARITH_HWARITHDIALECT_H
|
#endif // CIRCT_DIALECT_HWARITH_HWARITHDIALECT_H
|
||||||
|
|
|
@ -22,4 +22,15 @@
|
||||||
#define GET_OP_CLASSES
|
#define GET_OP_CLASSES
|
||||||
#include "circt/Dialect/HWArith/HWArith.h.inc"
|
#include "circt/Dialect/HWArith/HWArith.h.inc"
|
||||||
|
|
||||||
|
namespace circt {
|
||||||
|
namespace hwarith {
|
||||||
|
|
||||||
|
// Infer the bitwidth as well as the signedness that is required to store the
|
||||||
|
// sum of two given integer types without over- or underflowing.
|
||||||
|
unsigned inferAddResultType(IntegerType::SignednessSemantics &signedness,
|
||||||
|
IntegerType lhs, IntegerType rhs);
|
||||||
|
|
||||||
|
} // namespace hwarith
|
||||||
|
} // namespace circt
|
||||||
|
|
||||||
#endif // CIRCT_DIALECT_HWARITH_OPS_H
|
#endif // CIRCT_DIALECT_HWARITH_OPS_H
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifndef CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
#ifndef CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
||||||
#define CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
#define CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
||||||
|
|
||||||
|
include "mlir/IR/EnumAttr.td"
|
||||||
include "mlir/IR/OpAsmInterface.td"
|
include "mlir/IR/OpAsmInterface.td"
|
||||||
include "mlir/Interfaces/InferTypeOpInterface.td"
|
include "mlir/Interfaces/InferTypeOpInterface.td"
|
||||||
include "mlir/Interfaces/SideEffectInterfaces.td"
|
include "mlir/Interfaces/SideEffectInterfaces.td"
|
||||||
|
@ -201,4 +202,53 @@ def HWArith_CastOp : HWArithOp<"cast", [NoSideEffect]> {
|
||||||
let hasVerifier = 1;
|
let hasVerifier = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comparison predicates
|
||||||
|
// `==` and `!=`
|
||||||
|
def ICmpPredicateEQ : I64EnumAttrCase<"eq", 0b000>;
|
||||||
|
def ICmpPredicateNE : I64EnumAttrCase<"ne", 0b001>;
|
||||||
|
// `<` and `>=`
|
||||||
|
def ICmpPredicateLT : I64EnumAttrCase<"lt", 0b010>;
|
||||||
|
def ICmpPredicateGE : I64EnumAttrCase<"ge", 0b011>;
|
||||||
|
// `<=` and `>`
|
||||||
|
def ICmpPredicateLE : I64EnumAttrCase<"le", 0b100>;
|
||||||
|
def ICmpPredicateGT : I64EnumAttrCase<"gt", 0b101>;
|
||||||
|
|
||||||
|
let cppNamespace = "circt::hwarith" in
|
||||||
|
def ICmpPredicate : I64EnumAttr<
|
||||||
|
"ICmpPredicate",
|
||||||
|
"hwarith.icmp comparison predicate",
|
||||||
|
[ICmpPredicateEQ, ICmpPredicateNE, ICmpPredicateLT,
|
||||||
|
ICmpPredicateGE, ICmpPredicateLE, ICmpPredicateGT]>;
|
||||||
|
|
||||||
|
def ICmpOp : HWArithOp<"icmp", [NoSideEffect]> {
|
||||||
|
let summary = "Sign- and bitwidth-aware integer comparison.";
|
||||||
|
let description = [{
|
||||||
|
The `icmp` operation compares two integers using a predicate. If the
|
||||||
|
predicate is true, returns 1, otherwise returns 0. This operation always
|
||||||
|
returns a one bit wide result of type `ui1`. Both operand types may be
|
||||||
|
signed or unsigned scalar integer types of arbitrary bitwidth.
|
||||||
|
|
||||||
|
| LHS type | RHS type | Comparison type | Result type |
|
||||||
|
| :------- | :------- | :--------------------------------------- | :---------- |
|
||||||
|
| `ui<a>` | `ui<b>` | `ui<r>`, *r* = max(*a*, *b*) | `ui1` |
|
||||||
|
| `si<a>` | `si<b>` | `si<r>`, *r* = max(*a*, *b*) | `ui1` |
|
||||||
|
| `ui<a>` | `si<b>` | `si<r>`, *r* = *a* + 1 **if** *a* ≥ *b* | `ui1` |
|
||||||
|
| | | `si<r>`, *r* = *b* **if** *a* < *b* | `ui1` |
|
||||||
|
| `si<a>` | `ui<b>` | Same as `ui<b> si<a>` | `ui1` |
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```mlir
|
||||||
|
%0 = hwarith.icmp lt %10, %11 : ui5, ui6
|
||||||
|
%1 = hwarith.icmp lt %12, %13 : si3, si4
|
||||||
|
%2 = hwarith.icmp lt %12, %11 : si3, ui6
|
||||||
|
```
|
||||||
|
}];
|
||||||
|
|
||||||
|
let arguments = (ins ICmpPredicate:$predicate,
|
||||||
|
HWArithIntegerType:$lhs, HWArithIntegerType:$rhs);
|
||||||
|
let results = (outs UI1:$result);
|
||||||
|
|
||||||
|
let assemblyFormat = "$predicate $lhs `,` $rhs attr-dict `:` type($lhs) `,` type($rhs)";
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
#endif // CIRCT_DIALECT_HWARITH_HWARITHOPS_TD
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
namespace circt {
|
namespace circt {
|
||||||
namespace hwarith {
|
namespace hwarith {
|
||||||
|
|
||||||
|
// Check whether a specified type satisfies the constraints for the
|
||||||
|
// HWArithIntegerType
|
||||||
bool isHWArithIntegerType(::mlir::Type type);
|
bool isHWArithIntegerType(::mlir::Type type);
|
||||||
|
|
||||||
} // namespace hwarith
|
} // namespace hwarith
|
||||||
|
|
|
@ -167,6 +167,65 @@ struct CastOpLowering : public OpConversionPattern<CastOp> {
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Utility lowering function that maps a hwarith::ICmpPredicate predicate and
|
||||||
|
// the information whether the comparison contains signed values to the
|
||||||
|
// corresponding comb::ICmpPredicate.
|
||||||
|
static comb::ICmpPredicate lowerPredicate(ICmpPredicate pred, bool isSigned) {
|
||||||
|
#define _CREATE_HWARITH_ICMP_CASE(x) \
|
||||||
|
case ICmpPredicate::x: \
|
||||||
|
return isSigned ? comb::ICmpPredicate::s##x : comb::ICmpPredicate::u##x
|
||||||
|
|
||||||
|
switch (pred) {
|
||||||
|
case ICmpPredicate::eq:
|
||||||
|
return comb::ICmpPredicate::eq;
|
||||||
|
|
||||||
|
case ICmpPredicate::ne:
|
||||||
|
return comb::ICmpPredicate::ne;
|
||||||
|
|
||||||
|
_CREATE_HWARITH_ICMP_CASE(lt);
|
||||||
|
_CREATE_HWARITH_ICMP_CASE(ge);
|
||||||
|
_CREATE_HWARITH_ICMP_CASE(le);
|
||||||
|
_CREATE_HWARITH_ICMP_CASE(gt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _CREATE_HWARITH_ICMP_CASE
|
||||||
|
|
||||||
|
llvm_unreachable(
|
||||||
|
"Missing hwarith::ICmpPredicate to comb::ICmpPredicate lowering");
|
||||||
|
return comb::ICmpPredicate::eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ICmpOpLowering : public OpConversionPattern<ICmpOp> {
|
||||||
|
using OpConversionPattern<ICmpOp>::OpConversionPattern;
|
||||||
|
|
||||||
|
LogicalResult
|
||||||
|
matchAndRewrite(ICmpOp op, OpAdaptor adaptor,
|
||||||
|
ConversionPatternRewriter &rewriter) const override {
|
||||||
|
auto lhsType = op.lhs().getType().cast<IntegerType>();
|
||||||
|
auto rhsType = op.rhs().getType().cast<IntegerType>();
|
||||||
|
IntegerType::SignednessSemantics cmpSignedness;
|
||||||
|
const unsigned cmpWidth =
|
||||||
|
inferAddResultType(cmpSignedness, lhsType, rhsType) - 1;
|
||||||
|
|
||||||
|
ICmpPredicate pred = op.predicate();
|
||||||
|
comb::ICmpPredicate combPred = lowerPredicate(
|
||||||
|
pred, cmpSignedness == IntegerType::SignednessSemantics::Signed);
|
||||||
|
|
||||||
|
const auto loc = op.getLoc();
|
||||||
|
Value lhsValue = extendTypeWidth(rewriter, loc, adaptor.lhs(), cmpWidth,
|
||||||
|
lhsType.isSigned());
|
||||||
|
Value rhsValue = extendTypeWidth(rewriter, loc, adaptor.rhs(), cmpWidth,
|
||||||
|
rhsType.isSigned());
|
||||||
|
|
||||||
|
rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, combPred, lhsValue, rhsValue);
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Templated patterns
|
// Templated patterns
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -212,7 +271,7 @@ public:
|
||||||
target.addIllegalDialect<HWArithDialect>();
|
target.addIllegalDialect<HWArithDialect>();
|
||||||
target.addLegalDialect<comb::CombDialect, hw::HWDialect>();
|
target.addLegalDialect<comb::CombDialect, hw::HWDialect>();
|
||||||
|
|
||||||
patterns.add<ConstantOpLowering, CastOpLowering,
|
patterns.add<ConstantOpLowering, CastOpLowering, ICmpOpLowering,
|
||||||
BinaryOpLowering<AddOp, comb::AddOp>,
|
BinaryOpLowering<AddOp, comb::AddOp>,
|
||||||
BinaryOpLowering<SubOp, comb::SubOp>,
|
BinaryOpLowering<SubOp, comb::SubOp>,
|
||||||
BinaryOpLowering<MulOp, comb::MulOp>, DivOpLowering>(
|
BinaryOpLowering<MulOp, comb::MulOp>, DivOpLowering>(
|
||||||
|
|
|
@ -15,6 +15,7 @@ add_circt_dialect_library(CIRCTHWArith
|
||||||
|
|
||||||
DEPENDS
|
DEPENDS
|
||||||
MLIRHWArithIncGen
|
MLIRHWArithIncGen
|
||||||
|
MLIRHWArithEnumsIncGen
|
||||||
MLIRIR
|
MLIRIR
|
||||||
|
|
||||||
LINK_COMPONENTS
|
LINK_COMPONENTS
|
||||||
|
|
|
@ -29,4 +29,7 @@ void HWArithDialect::initialize() {
|
||||||
>();
|
>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provide implementations for the enums we use.
|
||||||
|
#include "circt/Dialect/HWArith/HWArithEnums.cpp.inc"
|
||||||
|
|
||||||
#include "circt/Dialect/HWArith/HWArithDialect.cpp.inc"
|
#include "circt/Dialect/HWArith/HWArithDialect.cpp.inc"
|
||||||
|
|
|
@ -75,32 +75,6 @@ ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
|
||||||
// AddOp
|
// AddOp
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static unsigned inferAddResultType(IntegerType::SignednessSemantics &signedness,
|
|
||||||
IntegerType lhs, IntegerType rhs) {
|
|
||||||
// the result width is never less than max(w1, w2) + 1
|
|
||||||
unsigned resultWidth = std::max(lhs.getWidth(), rhs.getWidth()) + 1;
|
|
||||||
|
|
||||||
if (lhs.getSignedness() == rhs.getSignedness()) {
|
|
||||||
// max(w1, w2) + 1 in case both operands use the same signedness
|
|
||||||
// the signedness is also identical to the operands
|
|
||||||
signedness = lhs.getSignedness();
|
|
||||||
} else {
|
|
||||||
// For mixed signedness the result is always signed
|
|
||||||
signedness = IntegerType::Signed;
|
|
||||||
|
|
||||||
// Regarding the result width two case need to be considered:
|
|
||||||
if ((lhs.isUnsigned() && lhs.getWidth() >= rhs.getWidth()) ||
|
|
||||||
(rhs.isUnsigned() && rhs.getWidth() >= lhs.getWidth())) {
|
|
||||||
// 1. the unsigned width is >= the signed width,
|
|
||||||
// then the width needs to be increased by 1
|
|
||||||
++resultWidth;
|
|
||||||
}
|
|
||||||
// 2. the unsigned width is < the signed width,
|
|
||||||
// then no further adjustment is needed
|
|
||||||
}
|
|
||||||
return resultWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogicalResult AddOp::inferReturnTypes(MLIRContext *context,
|
LogicalResult AddOp::inferReturnTypes(MLIRContext *context,
|
||||||
Optional<Location> loc,
|
Optional<Location> loc,
|
||||||
ValueRange operands, DictionaryAttr attrs,
|
ValueRange operands, DictionaryAttr attrs,
|
||||||
|
@ -200,6 +174,32 @@ LogicalResult DivOp::inferReturnTypes(MLIRContext *context,
|
||||||
namespace circt {
|
namespace circt {
|
||||||
namespace hwarith {
|
namespace hwarith {
|
||||||
|
|
||||||
|
unsigned inferAddResultType(IntegerType::SignednessSemantics &signedness,
|
||||||
|
IntegerType lhs, IntegerType rhs) {
|
||||||
|
// the result width is never less than max(w1, w2) + 1
|
||||||
|
unsigned resultWidth = std::max(lhs.getWidth(), rhs.getWidth()) + 1;
|
||||||
|
|
||||||
|
if (lhs.getSignedness() == rhs.getSignedness()) {
|
||||||
|
// max(w1, w2) + 1 in case both operands use the same signedness
|
||||||
|
// the signedness is also identical to the operands
|
||||||
|
signedness = lhs.getSignedness();
|
||||||
|
} else {
|
||||||
|
// For mixed signedness the result is always signed
|
||||||
|
signedness = IntegerType::Signed;
|
||||||
|
|
||||||
|
// Regarding the result width two case need to be considered:
|
||||||
|
if ((lhs.isUnsigned() && lhs.getWidth() >= rhs.getWidth()) ||
|
||||||
|
(rhs.isUnsigned() && rhs.getWidth() >= lhs.getWidth())) {
|
||||||
|
// 1. the unsigned width is >= the signed width,
|
||||||
|
// then the width needs to be increased by 1
|
||||||
|
++resultWidth;
|
||||||
|
}
|
||||||
|
// 2. the unsigned width is < the signed width,
|
||||||
|
// then no further adjustment is needed
|
||||||
|
}
|
||||||
|
return resultWidth;
|
||||||
|
}
|
||||||
|
|
||||||
static LogicalResult verifyBinOp(Operation *binOp) {
|
static LogicalResult verifyBinOp(Operation *binOp) {
|
||||||
auto ops = binOp->getOperands();
|
auto ops = binOp->getOperands();
|
||||||
if (ops.size() != 2)
|
if (ops.size() != 2)
|
||||||
|
|
|
@ -179,14 +179,14 @@ hw.module @div(%op0: i32, %op1: i32) -> (sisi: i32, siui: i32, uisi: i32, uiui:
|
||||||
%op1Unsigned = hwarith.cast %op1 : (i32) -> ui32
|
%op1Unsigned = hwarith.cast %op1 : (i32) -> ui32
|
||||||
|
|
||||||
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 31 : (i32) -> i1
|
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 31 : (i32) -> i1
|
||||||
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %0, %op0 : i1, i32
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP0]], %op0 : i1, i32
|
||||||
// CHECK: %[[SIGN_BIT_OP1:.*]] = comb.extract %op1 from 31 : (i32) -> i1
|
// CHECK: %[[SIGN_BIT_OP1:.*]] = comb.extract %op1 from 31 : (i32) -> i1
|
||||||
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %2, %op1 : i1, i32
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP1]], %op1 : i1, i32
|
||||||
// CHECK: %[[SISI_RES:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
// CHECK: %[[SISI_RES:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
||||||
%sisi = hwarith.div %op0Signed, %op1Signed : (si32, si32) -> si33
|
%sisi = hwarith.div %op0Signed, %op1Signed : (si32, si32) -> si33
|
||||||
|
|
||||||
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 31 : (i32) -> i1
|
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 31 : (i32) -> i1
|
||||||
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %5, %op0 : i1, i32
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP0]], %op0 : i1, i32
|
||||||
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
||||||
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op1 : i1, i32
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op1 : i1, i32
|
||||||
// CHECK: %[[SIUI_RES_IMM:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
// CHECK: %[[SIUI_RES_IMM:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
||||||
|
@ -196,7 +196,7 @@ hw.module @div(%op0: i32, %op1: i32) -> (sisi: i32, siui: i32, uisi: i32, uiui:
|
||||||
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
||||||
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op0 : i1, i32
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op0 : i1, i32
|
||||||
// CHECK: %[[SIGN_BIT_OP1:.*]] = comb.extract %op1 from 31 : (i32) -> i1
|
// CHECK: %[[SIGN_BIT_OP1:.*]] = comb.extract %op1 from 31 : (i32) -> i1
|
||||||
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %11, %op1 : i1, i32
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP1]], %op1 : i1, i32
|
||||||
// CHECK: %[[UISI_RES:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
// CHECK: %[[UISI_RES:.*]] = comb.divs %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
||||||
%uisi = hwarith.div %op0Unsigned, %op1Signed : (ui32, si32) -> si33
|
%uisi = hwarith.div %op0Unsigned, %op1Signed : (ui32, si32) -> si33
|
||||||
|
|
||||||
|
@ -213,3 +213,83 @@ hw.module @div(%op0: i32, %op1: i32) -> (sisi: i32, siui: i32, uisi: i32, uiui:
|
||||||
// CHECK: hw.output %[[SISI_OUT]], %[[SIUI_RES]], %[[UISI_OUT]], %[[UIUI_RES]] : i32, i32, i32, i32
|
// CHECK: hw.output %[[SISI_OUT]], %[[SIUI_RES]], %[[UISI_OUT]], %[[UIUI_RES]] : i32, i32, i32, i32
|
||||||
hw.output %sisiOut, %siuiOut, %uisiOut, %uiuiOut : i32, i32, i32, i32
|
hw.output %sisiOut, %siuiOut, %uisiOut, %uiuiOut : i32, i32, i32, i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
// CHECK: hw.module @icmp(%op0: i32, %op1: i32) -> (sisi: i1, siui: i1, uisi: i1, uiui: i1) {
|
||||||
|
hw.module @icmp(%op0: i32, %op1: i32) -> (sisi: i1, siui: i1, uisi: i1, uiui: i1) {
|
||||||
|
%op0Signed = hwarith.cast %op0 : (i32) -> si32
|
||||||
|
%op0Unsigned = hwarith.cast %op0 : (i32) -> ui32
|
||||||
|
%op1Signed = hwarith.cast %op1 : (i32) -> si32
|
||||||
|
%op1Unsigned = hwarith.cast %op1 : (i32) -> ui32
|
||||||
|
|
||||||
|
// CHECK: %[[SISI_OUT:.*]] = comb.icmp slt %op0, %op1 : i32
|
||||||
|
%sisi = hwarith.icmp lt %op0Signed, %op1Signed : si32, si32
|
||||||
|
|
||||||
|
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 31 : (i32) -> i1
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP0]], %op0 : i1, i32
|
||||||
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
||||||
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op1 : i1, i32
|
||||||
|
// CHECK: %[[SIUI_OUT:.*]] = comb.icmp slt %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
||||||
|
%siui = hwarith.icmp lt %op0Signed, %op1Unsigned : si32, ui32
|
||||||
|
|
||||||
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op0 : i1, i32
|
||||||
|
// CHECK: %[[SIGN_BIT_OP1:.*]] = comb.extract %op1 from 31 : (i32) -> i1
|
||||||
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[SIGN_BIT_OP1]], %op1 : i1, i32
|
||||||
|
// CHECK: %[[UISI_OUT:.*]] = comb.icmp slt %[[OP0_PADDED]], %[[OP1_PADDED]] : i33
|
||||||
|
%uisi = hwarith.icmp lt %op0Unsigned, %op1Signed : ui32, si32
|
||||||
|
|
||||||
|
// CHECK: %[[UIUI_OUT:.*]] = comb.icmp ult %op0, %op1 : i32
|
||||||
|
%uiui = hwarith.icmp lt %op0Unsigned, %op1Unsigned : ui32, ui32
|
||||||
|
|
||||||
|
%sisiOut = hwarith.cast %sisi : (ui1) -> i1
|
||||||
|
%siuiOut = hwarith.cast %siui : (ui1) -> i1
|
||||||
|
%uisiOut = hwarith.cast %uisi : (ui1) -> i1
|
||||||
|
%uiuiOut = hwarith.cast %uiui : (ui1) -> i1
|
||||||
|
|
||||||
|
// CHECK: hw.output %[[SISI_OUT]], %[[SIUI_OUT]], %[[UISI_OUT]], %[[UIUI_OUT]] : i1, i1, i1, i1
|
||||||
|
hw.output %sisiOut, %siuiOut, %uisiOut, %uiuiOut : i1, i1, i1, i1
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----
|
||||||
|
|
||||||
|
// CHECK: hw.module @icmp_mixed_width(%op0: i5, %op1: i7) -> (sisi: i1, siui: i1, uisi: i1, uiui: i1) {
|
||||||
|
hw.module @icmp_mixed_width(%op0: i5, %op1: i7) -> (sisi: i1, siui: i1, uisi: i1, uiui: i1) {
|
||||||
|
%op0Signed = hwarith.cast %op0 : (i5) -> si5
|
||||||
|
%op0Unsigned = hwarith.cast %op0 : (i5) -> ui5
|
||||||
|
%op1Signed = hwarith.cast %op1 : (i7) -> si7
|
||||||
|
%op1Unsigned = hwarith.cast %op1 : (i7) -> ui7
|
||||||
|
|
||||||
|
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 4 : (i5) -> i1
|
||||||
|
// CHECK: %[[SIGN_EXTEND:.*]] = comb.replicate %[[SIGN_BIT_OP0]] : (i1) -> i2
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[SIGN_EXTEND]], %op0 : i2, i5
|
||||||
|
// CHECK: %[[SISI_OUT:.*]] = comb.icmp slt %[[OP0_PADDED]], %op1 : i7
|
||||||
|
%sisi = hwarith.icmp lt %op0Signed, %op1Signed : si5, si7
|
||||||
|
|
||||||
|
// CHECK: %[[SIGN_BIT_OP0:.*]] = comb.extract %op0 from 4 : (i5) -> i1
|
||||||
|
// CHECK: %[[SIGN_EXTEND:.*]] = comb.replicate %[[SIGN_BIT_OP0]] : (i1) -> i3
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[SIGN_EXTEND]], %op0 : i3, i5
|
||||||
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant false
|
||||||
|
// CHECK: %[[OP1_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op1 : i1, i7
|
||||||
|
// CHECK: %[[SIUI_OUT:.*]] = comb.icmp slt %[[OP0_PADDED]], %[[OP1_PADDED]] : i8
|
||||||
|
%siui = hwarith.icmp lt %op0Signed, %op1Unsigned : si5, ui7
|
||||||
|
|
||||||
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant 0 : i2
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op0 : i2, i5
|
||||||
|
// CHECK: %[[UISI_OUT:.*]] = comb.icmp slt %[[OP0_PADDED]], %op1 : i7
|
||||||
|
%uisi = hwarith.icmp lt %op0Unsigned, %op1Signed : ui5, si7
|
||||||
|
|
||||||
|
// CHECK: %[[ZERO_EXTEND:.*]] = hw.constant 0 : i2
|
||||||
|
// CHECK: %[[OP0_PADDED:.*]] = comb.concat %[[ZERO_EXTEND]], %op0 : i2, i5
|
||||||
|
// CHECK: %[[UIUI_OUT:.*]] = comb.icmp ult %[[OP0_PADDED]], %op1 : i7
|
||||||
|
%uiui = hwarith.icmp lt %op0Unsigned, %op1Unsigned : ui5, ui7
|
||||||
|
|
||||||
|
%sisiOut = hwarith.cast %sisi : (ui1) -> i1
|
||||||
|
%siuiOut = hwarith.cast %siui : (ui1) -> i1
|
||||||
|
%uisiOut = hwarith.cast %uisi : (ui1) -> i1
|
||||||
|
%uiuiOut = hwarith.cast %uiui : (ui1) -> i1
|
||||||
|
|
||||||
|
// CHECK: hw.output %[[SISI_OUT]], %[[SIUI_OUT]], %[[UISI_OUT]], %[[UIUI_OUT]] : i1, i1, i1, i1
|
||||||
|
hw.output %sisiOut, %siuiOut, %uisiOut, %uiuiOut : i1, i1, i1, i1
|
||||||
|
}
|
||||||
|
|
|
@ -31,4 +31,8 @@ hw.module @test1() {
|
||||||
%11 = hwarith.add %10, %6 : (si9, ui3) -> si10
|
%11 = hwarith.add %10, %6 : (si9, ui3) -> si10
|
||||||
// CHECK: %12 = hwarith.cast %11 : (si10) -> i9
|
// CHECK: %12 = hwarith.cast %11 : (si10) -> i9
|
||||||
%12 = hwarith.cast %11 : (si10) -> i9
|
%12 = hwarith.cast %11 : (si10) -> i9
|
||||||
|
// CHECK: %13 = hwarith.icmp eq %5, %10 : ui2, si9
|
||||||
|
%13 = hwarith.icmp eq %5, %10 : ui2, si9
|
||||||
|
// CHECK: %14 = hwarith.cast %13 : (ui1) -> i1
|
||||||
|
%14 = hwarith.cast %13 : (ui1) -> i1
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue