[Moore] Move signedness from types into ops

Instead of annotating types as signed or unsigned, make Moore dialect
types signless and move the signedness into operations. This affects
division, modulus/remainder, and comparison operations. These now come
in a signed and unsigned flavor. ImportVerilog consults the Slang AST
type to determine signedness when creating Moore dialect ops. The Moore
types themselves now no longer carry any sign information. This
significantly simplifies the dialect and takes the type system one step
closer towards having just a basic two- and four-valued bit vector type.
This commit is contained in:
Fabian Schuiki 2024-05-08 15:43:58 -07:00
parent 54ace0c344
commit 63c794f24e
No known key found for this signature in database
GPG Key ID: C42F5825FC5275E6
14 changed files with 229 additions and 499 deletions

View File

@ -444,7 +444,7 @@ def MulOp : BinaryOpBase<"mul", [Commutative]> {
}];
}
def DivOp : BinaryOpBase<"div"> {
class DivOpBase<string mnemonic> : BinaryOpBase<mnemonic> {
let summary = "Division";
let description = [{
Divide the left-hand side by the right-hand side operand. Any fractional
@ -456,7 +456,10 @@ def DivOp : BinaryOpBase<"div"> {
}];
}
def ModOp : BinaryOpBase<"mod"> {
def DivUOp : DivOpBase<"divu">;
def DivSOp : DivOpBase<"divs">;
class ModOpBase<string mnemonic> : BinaryOpBase<mnemonic> {
let summary = "Remainder";
let description = [{
Compute the remainder of the left-hand side divided by the right-hand side
@ -477,6 +480,9 @@ def ModOp : BinaryOpBase<"mod"> {
}];
}
def ModUOp : ModOpBase<"modu">;
def ModSOp : ModOpBase<"mods">;
def AndOp : BinaryOpBase<"and", [Commutative]> {
let summary = "Bitwise AND operation";
let description = [{
@ -667,10 +673,11 @@ class RelationalOpBase<string mnemonic> : MooreOp<mnemonic, [
let description = [{
Compares the left- and right-hand side operand and returns a single bit 0,
1, or X result. If any bit in the two operands is Z or X, returns X.
Otherwise, if all bits are 0 or 1, `lt`, `le`, `gt`, and `ge` return whether
the left-hand side is less than, less than or equal to, greater than, or
greater than or equal to the right-hand side, respectively. `lt` corresponds
to the `<` operator, `le` to `<=`, `gt` to `>`, and `ge` to `>=`.
Otherwise, if all bits are 0 or 1, `ult/slt`, `ule/sle`, `ugt/sgt`, and
`uge/sge` return whether the left-hand side is less than, less than or equal
to, greater than, or greater than or equal to the right-hand side,
respectively. `ult/slt` corresponds to the `<` operator, `ule/sle` to `<=`,
`ugt/sgt` to `>`, and `uge/sge` to `>=`.
See IEEE 1800-2017 § 11.4.4 "Relational operators".
}];
@ -681,10 +688,31 @@ class RelationalOpBase<string mnemonic> : MooreOp<mnemonic, [
}];
}
def LtOp : RelationalOpBase<"lt"> { let summary = "Less than"; }
def LeOp : RelationalOpBase<"le"> { let summary = "Less than or equal"; }
def GtOp : RelationalOpBase<"gt"> { let summary = "Greater than"; }
def GeOp : RelationalOpBase<"ge"> { let summary = "Greater than or equal"; }
def UltOp : RelationalOpBase<"ult"> {
let summary = "Unsigned less than comparison";
}
def UleOp : RelationalOpBase<"ule"> {
let summary = "Unsigned less than or equal comparison";
}
def UgtOp : RelationalOpBase<"ugt"> {
let summary = "Unsigned greater than comparison";
}
def UgeOp : RelationalOpBase<"uge"> {
let summary = "Unsigned greater than or equal comparison";
}
def SltOp : RelationalOpBase<"slt"> {
let summary = "Signed less than comparison";
}
def SleOp : RelationalOpBase<"sle"> {
let summary = "Signed less than or equal comparison";
}
def SgtOp : RelationalOpBase<"sgt"> {
let summary = "Signed greater than comparison";
}
def SgeOp : RelationalOpBase<"sge"> {
let summary = "Signed greater than or equal comparison";
}
def ConcatOp : MooreOp<"concat", [
Pure, DeclareOpInterfaceMethods<InferTypeOpInterface>

View File

@ -135,101 +135,39 @@ struct SimpleBitVectorType {
/// Create a null SBVT.
SimpleBitVectorType() {}
/// Create a new SBVT with the given domain, sign, and size. The resulting
/// type will expand exactly to `bit signed? [size-1:0]`.
SimpleBitVectorType(Domain domain, Sign sign, unsigned size,
bool usedAtom = false, bool explicitSign = false,
bool explicitSize = true)
: size(size), domain(domain), sign(sign), usedAtom(usedAtom),
explicitSign(explicitSign), explicitSize(explicitSize) {
/// Create a new SBVT with the given domain and size.
SimpleBitVectorType(Domain domain, unsigned size)
: size(size), domain(domain) {
assert(size > 0 && "SBVT requires non-zero size");
}
/// Convert this SBVT to an actual type.
PackedType getType(MLIRContext *context) const;
/// Check whether the type is unsigned.
bool isUnsigned() const { return sign == Sign::Unsigned; }
/// Check whether the type is signed.
bool isSigned() const { return sign == Sign::Signed; }
/// Get the range of the type.
Range getRange() const { return Range(size, RangeDir::Down, 0); }
/// Get a single bit version of this type by setting its size to 1.
SimpleBitVectorType toSingleBit() const {
auto type = *this;
type.size = 1;
type.explicitSize = false;
type.usedAtom = false;
return type;
}
/// Check whether this type is equivalent to another.
bool isEquivalent(const SimpleBitVectorType &other) const {
return domain == other.domain && sign == other.sign && size == other.size;
}
bool operator==(const SimpleBitVectorType &other) const {
if (size == 0 || other.size == 0)
return size == other.size; // if either is null, the other has to be null
return isEquivalent(other) && usedAtom == other.usedAtom &&
explicitSign == other.explicitSign &&
explicitSize == other.explicitSize;
return domain == other.domain && size == other.size;
}
/// Check whether this is a null type.
operator bool() const { return size > 0; }
/// Format this simple bit vector type as a string.
std::string toString() const {
std::string buffer;
llvm::raw_string_ostream(buffer) << *this;
return buffer;
}
/// The size of the vector.
unsigned size = 0;
/// The domain, which dictates whether this is a `bit` or `logic` vector.
Domain domain : 8;
/// The sign.
Sign sign : 8;
// The following flags ensure that converting a `PackedType` to an SBVT and
// then back to a `PackedType` will yield exactly the original type. For
// example, the packed type `int` maps to an SBVT `{32, TwoValued, Signed}`,
// which should be converted back to `int` instead of `bit signed [31:0]`.
/// Whether the type used an integer atom like `int` in the source text.
bool usedAtom : 1;
/// Whether the sign was explicit in the source text.
bool explicitSign : 1;
/// Whether the single-bit vector had an explicit range in the source text.
/// Essentially whether it was `bit` or `bit[a:a]`.
bool explicitSize : 1;
};
// NOLINTNEXTLINE(readability-identifier-naming)
inline llvm::hash_code hash_value(const SimpleBitVectorType &x) {
if (x)
return llvm::hash_combine(x.size, x.domain, x.sign, x.usedAtom,
x.explicitSign, x.explicitSize);
return {};
}
template <typename Os>
Os &operator<<(Os &os, const SimpleBitVectorType &type) {
if (!type) {
os << "<<<NULL SBVT>>>";
return os;
}
os << (type.domain == Domain::TwoValued ? "bit" : "logic");
if (type.sign != Sign::Unsigned || type.explicitSign)
os << " " << type.sign;
if (type.size > 1 || type.explicitSize)
os << " [" << type.getRange() << "]";
return os;
return llvm::hash_combine(x.size, x.domain);
}
namespace detail {
@ -297,9 +235,6 @@ public:
/// Get the value domain of this type.
Domain getDomain() const;
/// Get the sign for this type.
Sign getSign() const;
/// Get the size of this type in bits.
///
/// Returns `None` if any of the type's dimensions is unsized, associative, or
@ -384,9 +319,6 @@ public:
/// Get the value domain of this type.
Domain getDomain() const;
/// Get the sign for this type.
Sign getSign() const;
/// Get the size of this type in bits.
///
/// Returns `None` if any of the type's dimensions is unsized.
@ -432,8 +364,6 @@ public:
static std::optional<Kind> getKindFromKeyword(StringRef keyword);
/// Get the keyword (like `bit`) for one of the integer types.
static StringRef getKeyword(Kind kind);
/// Get the default sign for one of the integer types.
static Sign getDefaultSign(Kind kind);
/// Get the value domain for one of the integer types.
static Domain getDomain(Kind kind);
/// Get the size of one of the integer types.
@ -445,8 +375,7 @@ public:
static std::optional<Kind> getKindFromDomainAndSize(Domain domain,
unsigned size);
static IntType get(MLIRContext *context, Kind kind,
std::optional<Sign> sign = {});
static IntType get(MLIRContext *context, Kind kind);
/// Create a `logic` type.
static IntType getLogic(MLIRContext *context) { return get(context, Logic); }
@ -459,16 +388,9 @@ public:
/// Get the concrete integer vector or atom type.
Kind getKind() const;
/// Get the sign of this type.
Sign getSign() const;
/// Whether the sign of the type was specified explicitly. This allows us to
/// distinguish `bit unsigned` from `bit`.
bool isSignExplicit() const;
/// Get the keyword (like `bit`) for this type.
StringRef getKeyword() const { return getKeyword(getKind()); }
/// Get the default sign for this type.
Sign getDefaultSign() const { return getDefaultSign(getKind()); }
/// Get the value domain for this type.
Domain getDomain() const { return getDomain(getKind()); }
/// Get the size of this type.
@ -797,17 +719,11 @@ class PackedStructType : public Type::TypeBase<PackedStructType, PackedType,
::mlir::TypeTrait::IsMutable> {
public:
static PackedStructType get(MLIRContext *context, StructKind kind,
ArrayRef<StructMember> members,
std::optional<Sign> sign = {});
static PackedStructType get(MLIRContext *context, const Struct &strukt,
std::optional<Sign> sign = {}) {
return get(context, strukt.kind, strukt.members, sign);
ArrayRef<StructMember> members);
static PackedStructType get(MLIRContext *context, const Struct &strukt) {
return get(context, strukt.kind, strukt.members);
}
/// Get the sign of this struct.
Sign getSign() const;
/// Returns whether the sign was explicitly mentioned by the user.
bool isSignExplicit() const;
/// Get the struct definition.
const Struct &getStruct() const;

View File

@ -218,9 +218,15 @@ struct ExprVisitor {
case BinaryOperator::Multiply:
return createBinary<moore::MulOp>(lhs, rhs);
case BinaryOperator::Divide:
return createBinary<moore::DivOp>(lhs, rhs);
if (expr.type->isSigned())
return createBinary<moore::DivSOp>(lhs, rhs);
else
return createBinary<moore::DivUOp>(lhs, rhs);
case BinaryOperator::Mod:
return createBinary<moore::ModOp>(lhs, rhs);
if (expr.type->isSigned())
return createBinary<moore::ModSOp>(lhs, rhs);
else
return createBinary<moore::ModUOp>(lhs, rhs);
case BinaryOperator::BinaryAnd:
return createBinary<moore::AndOp>(lhs, rhs);
@ -249,13 +255,25 @@ struct ExprVisitor {
return createBinary<moore::WildcardNeOp>(lhs, rhs);
case BinaryOperator::GreaterThanEqual:
return createBinary<moore::GeOp>(lhs, rhs);
if (expr.left().type->isSigned())
return createBinary<moore::SgeOp>(lhs, rhs);
else
return createBinary<moore::UgeOp>(lhs, rhs);
case BinaryOperator::GreaterThan:
return createBinary<moore::GtOp>(lhs, rhs);
if (expr.left().type->isSigned())
return createBinary<moore::SgtOp>(lhs, rhs);
else
return createBinary<moore::UgtOp>(lhs, rhs);
case BinaryOperator::LessThanEqual:
return createBinary<moore::LeOp>(lhs, rhs);
if (expr.left().type->isSigned())
return createBinary<moore::SleOp>(lhs, rhs);
else
return createBinary<moore::UleOp>(lhs, rhs);
case BinaryOperator::LessThan:
return createBinary<moore::LtOp>(lhs, rhs);
if (expr.left().type->isSigned())
return createBinary<moore::SltOp>(lhs, rhs);
else
return createBinary<moore::UltOp>(lhs, rhs);
// See IEEE 1800-2017 § 11.4.7 "Logical operators".
case BinaryOperator::LogicalAnd: {
@ -309,9 +327,7 @@ struct ExprVisitor {
rhs = convertToSimpleBitVector(rhs);
if (!lhs || !rhs)
return {};
if (cast<moore::PackedType>(lhs.getType())
.getSimpleBitVector()
.isSigned())
if (expr.type->isSigned())
return builder.create<moore::AShrOp>(loc, lhs, rhs);
return builder.create<moore::ShrOp>(loc, lhs, rhs);
}

View File

@ -33,12 +33,7 @@ struct TypeVisitor {
break;
}
std::optional<moore::Sign> sign =
type.isSigned ? moore::Sign::Signed : moore::Sign::Unsigned;
if (sign == moore::IntType::getDefaultSign(kind))
sign = {};
return moore::IntType::get(context.getContext(), kind, sign);
return moore::IntType::get(context.getContext(), kind);
}
Type visit(const slang::ast::FloatingType &type) {
@ -81,12 +76,7 @@ struct TypeVisitor {
break;
}
std::optional<moore::Sign> sign =
type.isSigned ? moore::Sign::Signed : moore::Sign::Unsigned;
if (sign == moore::IntType::getDefaultSign(kind))
sign = {};
return moore::IntType::get(context.getContext(), kind, sign);
return moore::IntType::get(context.getContext(), kind);
}
Type visit(const slang::ast::PackedArrayType &type) {

View File

@ -26,6 +26,8 @@ using namespace mlir;
using namespace circt;
using namespace moore;
using comb::ICmpPredicate;
namespace {
/// Returns the passed value if the integer width is already correct.
@ -56,51 +58,6 @@ static Value adjustIntegerWidth(OpBuilder &builder, Value value,
return builder.create<comb::MuxOp>(loc, isZero, lo, max, false);
}
/// Due to the result type of the `lt`, or `le`, or `gt`, or `ge` ops are
/// always unsigned, estimating their operands type.
static bool isSignedType(Operation *op) {
return TypeSwitch<Operation *, bool>(op)
.template Case<LtOp, LeOp, GtOp, GeOp>([&](auto op) -> bool {
return cast<UnpackedType>(op->getOperand(0).getType())
.castToSimpleBitVector()
.isSigned() &&
cast<UnpackedType>(op->getOperand(1).getType())
.castToSimpleBitVector()
.isSigned();
})
.Default([&](auto op) -> bool {
return cast<UnpackedType>(op->getResult(0).getType())
.castToSimpleBitVector()
.isSigned();
});
}
/// Not define the predicate for `relation` and `equality` operations in the
/// MooreDialect, but comb needs it. Return a correct `comb::ICmpPredicate`
/// corresponding to different moore `relation` and `equality` operations.
static comb::ICmpPredicate getCombPredicate(Operation *op) {
using comb::ICmpPredicate;
return TypeSwitch<Operation *, ICmpPredicate>(op)
.Case<LtOp>([&](auto op) {
return isSignedType(op) ? ICmpPredicate::slt : ICmpPredicate::ult;
})
.Case<LeOp>([&](auto op) {
return isSignedType(op) ? ICmpPredicate::sle : ICmpPredicate::ule;
})
.Case<GtOp>([&](auto op) {
return isSignedType(op) ? ICmpPredicate::sgt : ICmpPredicate::ugt;
})
.Case<GeOp>([&](auto op) {
return isSignedType(op) ? ICmpPredicate::sge : ICmpPredicate::uge;
})
.Case<EqOp>([&](auto op) { return ICmpPredicate::eq; })
.Case<NeOp>([&](auto op) { return ICmpPredicate::ne; })
.Case<CaseEqOp>([&](auto op) { return ICmpPredicate::ceq; })
.Case<CaseNeOp>([&](auto op) { return ICmpPredicate::cne; })
.Case<WildcardEqOp>([&](auto op) { return ICmpPredicate::weq; })
.Case<WildcardNeOp>([&](auto op) { return ICmpPredicate::wne; });
}
//===----------------------------------------------------------------------===//
// Expression Conversion
//===----------------------------------------------------------------------===//
@ -231,8 +188,7 @@ struct NotOpConversion : public OpConversionPattern<NotOp> {
}
};
template <typename SourceOp, typename UnsignedOp,
typename SignedOp = UnsignedOp>
template <typename SourceOp, typename TargetOp>
struct BinaryOpConversion : public OpConversionPattern<SourceOp> {
using OpConversionPattern<SourceOp>::OpConversionPattern;
using OpAdaptor = typename SourceOp::Adaptor;
@ -240,17 +196,13 @@ struct BinaryOpConversion : public OpConversionPattern<SourceOp> {
LogicalResult
matchAndRewrite(SourceOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
isSignedType(op)
? rewriter.replaceOpWithNewOp<SignedOp>(op, adaptor.getLhs(),
adaptor.getRhs(), false)
: rewriter.replaceOpWithNewOp<UnsignedOp>(op, adaptor.getLhs(),
adaptor.getRhs(), false);
rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
adaptor.getRhs(), false);
return success();
}
};
template <typename SourceOp>
template <typename SourceOp, ICmpPredicate pred>
struct ICmpOpConversion : public OpConversionPattern<SourceOp> {
using OpConversionPattern<SourceOp>::OpConversionPattern;
using OpAdaptor = typename SourceOp::Adaptor;
@ -260,7 +212,6 @@ struct ICmpOpConversion : public OpConversionPattern<SourceOp> {
ConversionPatternRewriter &rewriter) const override {
Type resultType =
ConversionPattern::typeConverter->convertType(op.getResult().getType());
comb::ICmpPredicate pred = getCombPredicate(op);
rewriter.replaceOpWithNewOp<comb::ICmpOp>(
op, resultType, pred, adapter.getLhs(), adapter.getRhs());
@ -494,23 +445,35 @@ static void populateOpConversion(RewritePatternSet &patterns,
// Patterns of unary operations.
ReduceAndOpConversion, ReduceOrOpConversion, ReduceXorOpConversion,
BoolCastOpConversion, NotOpConversion,
BoolCastOpConversion, NotOpConversion,
// Patterns of binary operations.
BinaryOpConversion<AddOp, comb::AddOp>,
BinaryOpConversion<SubOp, comb::SubOp>,
BinaryOpConversion<MulOp, comb::MulOp>,
BinaryOpConversion<DivOp, comb::DivUOp, comb::DivSOp>,
BinaryOpConversion<ModOp, comb::ModUOp, comb::ModSOp>,
BinaryOpConversion<DivUOp, comb::DivUOp>,
BinaryOpConversion<DivSOp, comb::DivSOp>,
BinaryOpConversion<ModUOp, comb::ModUOp>,
BinaryOpConversion<ModSOp, comb::ModSOp>,
BinaryOpConversion<AndOp, comb::AndOp>,
BinaryOpConversion<OrOp, comb::OrOp>,
BinaryOpConversion<XorOp, comb::XorOp>,
// Patterns of relational operations.
ICmpOpConversion<LtOp>, ICmpOpConversion<LeOp>, ICmpOpConversion<GtOp>,
ICmpOpConversion<GeOp>, ICmpOpConversion<EqOp>, ICmpOpConversion<NeOp>,
ICmpOpConversion<CaseEqOp>, ICmpOpConversion<CaseNeOp>,
ICmpOpConversion<WildcardEqOp>, ICmpOpConversion<WildcardNeOp>,
ICmpOpConversion<UltOp, ICmpPredicate::ult>,
ICmpOpConversion<SltOp, ICmpPredicate::slt>,
ICmpOpConversion<UleOp, ICmpPredicate::ule>,
ICmpOpConversion<SleOp, ICmpPredicate::sle>,
ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
ICmpOpConversion<EqOp, ICmpPredicate::eq>,
ICmpOpConversion<NeOp, ICmpPredicate::ne>,
ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
// Patterns of shifting operations.
ShrOpConversion, ShlOpConversion, AShrOpConversion,

View File

@ -157,8 +157,7 @@ LogicalResult ConcatOp::inferReturnTypes(
domain = Domain::FourValued;
size += type.size;
}
results.push_back(
SimpleBitVectorType(domain, Sign::Unsigned, size).getType(context));
results.push_back(SimpleBitVectorType(domain, size).getType(context));
return success();
}

View File

@ -59,13 +59,6 @@ StringRef moore::getKeywordFromSign(const Sign &sign) {
llvm_unreachable("all signs should be handled");
}
std::optional<Sign> moore::getSignFromKeyword(StringRef keyword) {
return StringSwitch<std::optional<Sign>>(keyword)
.Case("unsigned", Sign::Unsigned)
.Case("signed", Sign::Signed)
.Default({});
}
//===----------------------------------------------------------------------===//
// Simple Bit Vector Type
//===----------------------------------------------------------------------===//
@ -73,22 +66,14 @@ std::optional<Sign> moore::getSignFromKeyword(StringRef keyword) {
PackedType SimpleBitVectorType::getType(MLIRContext *context) const {
if (!*this)
return {};
std::optional<Sign> maybeSign;
if (explicitSign)
maybeSign = sign;
// If the type originally used an integer atom, try to reconstruct that.
if (usedAtom)
if (auto kind = IntType::getKindFromDomainAndSize(domain, size))
return IntType::get(context, *kind, maybeSign);
// Build the core integer bit type.
auto kind = domain == Domain::TwoValued ? IntType::Bit : IntType::Logic;
auto intType = IntType::get(context, kind, maybeSign);
auto intType = IntType::get(context, kind);
// If the vector is wider than a single bit, or the dimension was explicit in
// the original type, add a dimension around the bit type.
if (size > 1 || explicitSize)
if (size > 1)
return PackedRangeDim::get(intType, size);
return intType;
}
@ -106,13 +91,6 @@ Domain UnpackedType::getDomain() const {
.Default([](auto) { return Domain::TwoValued; });
}
Sign UnpackedType::getSign() const {
return TypeSwitch<UnpackedType, Sign>(*this)
.Case<PackedType>([](auto type) { return type.getSign(); })
.Case<UnpackedDim>([&](auto type) { return type.getInner().getSign(); })
.Default([](auto) { return Sign::Unsigned; });
}
std::optional<unsigned> UnpackedType::getBitSize() const {
return TypeSwitch<UnpackedType, std::optional<unsigned>>(*this)
.Case<PackedType, RealType>([](auto type) { return type.getBitSize(); })
@ -134,10 +112,7 @@ std::optional<unsigned> UnpackedType::getBitSize() const {
/// Map an `IntType` to the corresponding SBVT. Never returns a null type.
static SimpleBitVectorType getSimpleBitVectorFromIntType(IntType type) {
auto bitSize = type.getBitSize();
bool usedAtom = bitSize > 1;
return SimpleBitVectorType(type.getDomain(), type.getSign(), bitSize,
usedAtom, type.isSignExplicit(), false);
return SimpleBitVectorType(type.getDomain(), type.getBitSize());
}
SimpleBitVectorType UnpackedType::getSimpleBitVectorOrNull() const {
@ -154,15 +129,14 @@ SimpleBitVectorType UnpackedType::getSimpleBitVectorOrNull() const {
// Inner type must be a single-bit integer. Cannot have integer atom
// vectors like `int [31:0]`.
auto sbv = getSimpleBitVectorFromIntType(innerType);
if (sbv.usedAtom)
if (innerType.getBitSize() > 1)
return SimpleBitVectorType{};
// Range must be have non-zero size, and go downwards to zero.
auto range = rangeType.getRange();
if (range.size == 0 || range.offset != 0 || range.dir != RangeDir::Down)
return SimpleBitVectorType{};
sbv.explicitSize = true;
auto sbv = getSimpleBitVectorFromIntType(innerType);
sbv.size = range.size;
return sbv;
})
@ -184,9 +158,7 @@ SimpleBitVectorType UnpackedType::castToSimpleBitVectorOrNull() const {
if (!bitSize || *bitSize == 0)
return {};
return SimpleBitVectorType(packed.getDomain(), packed.getSign(), *bitSize,
/*usedAtom=*/false, /*explicitSign=*/false,
/*explicitSize=*/false);
return SimpleBitVectorType(packed.getDomain(), *bitSize);
}
//===----------------------------------------------------------------------===//
@ -202,14 +174,6 @@ Domain PackedType::getDomain() const {
[](auto type) { return type.getStruct().domain; });
}
Sign PackedType::getSign() const {
return TypeSwitch<PackedType, Sign>(*this)
.Case<VoidType>([](auto) { return Sign::Unsigned; })
.Case<IntType, PackedStructType>(
[&](auto type) { return type.getSign(); })
.Case<PackedDim>([&](auto type) { return type.getInner().getSign(); });
}
std::optional<unsigned> PackedType::getBitSize() const {
return TypeSwitch<PackedType, std::optional<unsigned>>(*this)
.Case<VoidType>([](auto) { return 0; })
@ -235,24 +199,15 @@ struct IntTypeStorage : TypeStorage {
using KeyTy = unsigned;
using Kind = IntType::Kind;
IntTypeStorage(KeyTy key)
: kind(static_cast<Kind>((key >> 16) & 0xFF)),
sign(static_cast<Sign>((key >> 8) & 0xFF)), explicitSign(key & 1) {}
static KeyTy pack(Kind kind, Sign sign, bool explicitSign) {
return static_cast<unsigned>(kind) << 16 |
static_cast<unsigned>(sign) << 8 | explicitSign;
}
bool operator==(const KeyTy &key) const {
return pack(kind, sign, explicitSign) == key;
}
IntTypeStorage(KeyTy key) : kind(static_cast<Kind>(key)) {}
static KeyTy pack(Kind kind) { return static_cast<unsigned>(kind); }
bool operator==(const KeyTy &key) const { return pack(kind) == key; }
static IntTypeStorage *construct(TypeStorageAllocator &allocator,
const KeyTy &key) {
return new (allocator.allocate<IntTypeStorage>()) IntTypeStorage(key);
}
Kind kind;
Sign sign;
bool explicitSign;
};
} // namespace detail
} // namespace moore
@ -296,23 +251,6 @@ StringRef IntType::getKeyword(Kind kind) {
llvm_unreachable("all kinds should be handled");
}
Sign IntType::getDefaultSign(Kind kind) {
switch (kind) {
case IntType::Bit:
case IntType::Logic:
case IntType::Reg:
case IntType::Time:
return Sign::Unsigned;
case IntType::Byte:
case IntType::ShortInt:
case IntType::Int:
case IntType::LongInt:
case IntType::Integer:
return Sign::Signed;
}
llvm_unreachable("all kinds should be handled");
}
Domain IntType::getDomain(Kind kind) {
switch (kind) {
case IntType::Bit:
@ -391,19 +329,12 @@ std::optional<IntType::Kind> IntType::getKindFromDomainAndSize(Domain domain,
llvm_unreachable("all domains should be handled");
}
IntType IntType::get(MLIRContext *context, Kind kind,
std::optional<Sign> sign) {
return Base::get(context, detail::IntTypeStorage::pack(
kind, sign.value_or(getDefaultSign(kind)),
sign.has_value()));
IntType IntType::get(MLIRContext *context, Kind kind) {
return Base::get(context, detail::IntTypeStorage::pack(kind));
}
IntType::Kind IntType::getKind() const { return getImpl()->kind; }
Sign IntType::getSign() const { return getImpl()->sign; }
bool IntType::isSignExplicit() const { return getImpl()->explicitSign; }
//===----------------------------------------------------------------------===//
// Unpacked Reals
//===----------------------------------------------------------------------===//
@ -685,16 +616,9 @@ struct StructTypeStorage : TypeStorage {
using KeyTy = std::tuple<unsigned, ArrayRef<StructMember>>;
StructTypeStorage(KeyTy key)
: strukt(static_cast<StructKind>((std::get<0>(key) >> 16) & 0xFF),
std::get<1>(key)),
sign(static_cast<Sign>((std::get<0>(key) >> 8) & 0xFF)),
explicitSign((std::get<0>(key) >> 0) & 1) {}
static unsigned pack(StructKind kind, Sign sign, bool explicitSign) {
return static_cast<unsigned>(kind) << 16 |
static_cast<unsigned>(sign) << 8 | explicitSign;
}
: strukt(static_cast<StructKind>(std::get<0>(key)), std::get<1>(key)) {}
bool operator==(const KeyTy &key) const {
return std::get<0>(key) == pack(strukt.kind, sign, explicitSign) &&
return std::get<0>(key) == static_cast<unsigned>(strukt.kind) &&
std::get<1>(key) == ArrayRef<StructMember>(strukt.members);
}
static StructTypeStorage *construct(TypeStorageAllocator &allocator,
@ -703,8 +627,6 @@ struct StructTypeStorage : TypeStorage {
}
Struct strukt;
Sign sign;
bool explicitSign;
};
} // namespace detail
@ -712,23 +634,13 @@ struct StructTypeStorage : TypeStorage {
} // namespace circt
PackedStructType PackedStructType::get(MLIRContext *context, StructKind kind,
ArrayRef<StructMember> members,
std::optional<Sign> sign) {
ArrayRef<StructMember> members) {
assert(llvm::all_of(members,
[](const StructMember &member) {
return llvm::isa<PackedType>(member.type);
}) &&
"packed struct members must be packed");
return Base::get(context,
detail::StructTypeStorage::pack(
kind, sign.value_or(Sign::Unsigned), sign.has_value()),
members);
}
Sign PackedStructType::getSign() const { return getImpl()->sign; }
bool PackedStructType::isSignExplicit() const {
return getImpl()->explicitSign;
return Base::get(context, static_cast<unsigned>(kind), members);
}
const Struct &PackedStructType::getStruct() const { return getImpl()->strukt; }
@ -736,9 +648,7 @@ const Struct &PackedStructType::getStruct() const { return getImpl()->strukt; }
UnpackedStructType UnpackedStructType::get(MLIRContext *context,
StructKind kind,
ArrayRef<StructMember> members) {
return Base::get(context,
detail::StructTypeStorage::pack(kind, Sign::Unsigned, false),
members);
return Base::get(context, static_cast<unsigned>(kind), members);
}
const Struct &UnpackedStructType::getStruct() const {
@ -811,19 +721,7 @@ static OptionalParseResult customTypeParser(DialectAsmParser &parser,
// Packed primary types.
if (auto kind = IntType::getKindFromKeyword(mnemonic)) {
std::optional<Sign> sign;
if (succeeded(parser.parseOptionalLess())) {
StringRef signKeyword;
if (parser.parseKeyword(&signKeyword) || parser.parseGreater())
return failure();
sign = getSignFromKeyword(signKeyword);
if (!sign) {
parser.emitError(parser.getCurrentLocation())
<< "expected keyword `unsigned` or `signed`";
return failure();
}
}
return yieldPacked(IntType::get(context, *kind, sign));
return yieldPacked(IntType::get(context, *kind));
}
// Unpacked primary types.
@ -904,22 +802,7 @@ static OptionalParseResult customTypeParser(DialectAsmParser &parser,
if (parser.parseLess())
return failure();
std::optional<Sign> sign;
StringRef keyword;
if (succeeded(parser.parseOptionalKeyword(&keyword))) {
sign = getSignFromKeyword(keyword);
if (!sign) {
parser.emitError(loc) << "expected keyword `unsigned` or `signed`";
return failure();
}
if (subset.implied == Subset::Unpacked) {
parser.emitError(loc) << "unpacked struct cannot have a sign";
return failure();
}
if (parser.parseComma())
return failure();
}
SmallVector<StructMember> members;
auto result2 =
parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Braces, [&]() {
@ -937,8 +820,7 @@ static OptionalParseResult customTypeParser(DialectAsmParser &parser,
return yieldImplied(
[&]() {
return PackedStructType::get(parser.getContext(), *kind, members,
sign);
return PackedStructType::get(parser.getContext(), *kind, members);
},
[&]() {
return UnpackedStructType::get(parser.getContext(), *kind, members);
@ -971,9 +853,6 @@ static LogicalResult customTypePrinter(Type type, DialectAsmPrinter &printer,
// Integers and reals
.Case<IntType>([&](auto type) {
printer << type.getKeyword();
auto sign = type.getSign();
if (type.isSignExplicit())
printer << "<" << getKeywordFromSign(sign) << ">";
return success();
})
.Case<RealType>(
@ -1020,11 +899,7 @@ static LogicalResult customTypePrinter(Type type, DialectAsmPrinter &printer,
// Structs
.Case<PackedStructType, UnpackedStructType>([&](auto type) {
const auto &strukt = type.getStruct();
printer << getMnemonicFromStructKind(strukt.kind) << "<";
auto packed = llvm::dyn_cast<PackedStructType>(type);
if (packed && packed.isSignExplicit())
printer << packed.getSign() << ", ";
printer << "{";
printer << getMnemonicFromStructKind(strukt.kind) << "<{";
llvm::interleaveComma(strukt.members, printer, [&](const auto &member) {
printer << member.name.getValue() << ": ";
printMooreType(member.type, printer, subset);

View File

@ -56,7 +56,7 @@ module Basic;
tri w3 = w0;
// CHECK: %w4 = moore.net triand %w0 : !moore.logic
triand w4 = w0;
// CHECK: %w5 = moore.net trior %w0 : !moore.logic
// CHECK: %w5 = moore.net trior %w0 : !moore.logic
trior w5 = w0;
// CHECK: %w6 = moore.net wand %w0 : !moore.logic
wand w6 = w0;
@ -66,11 +66,11 @@ module Basic;
trireg w8 = w0;
// CHECK: %w9 = moore.net tri0 %w0 : !moore.logic
tri0 w9 = w0;
// CHECK: %w10 = moore.net tri1 %w0 : !moore.logic
// CHECK: %w10 = moore.net tri1 %w0 : !moore.logic
tri1 w10 = w0;
// CHECK: %w11 = moore.net supply0 : !moore.logic
// CHECK: %w11 = moore.net supply0 : !moore.logic
supply0 w11;
// CHECK: %w12 = moore.net supply1 : !moore.logic
// CHECK: %w12 = moore.net supply1 : !moore.logic
supply1 w12;
// CHECK: %b1 = moore.variable : !moore.packed<range<bit, 0:0>>
@ -119,11 +119,10 @@ module Statements;
bit x, y, z;
int i;
initial begin
//===------------------------------------------------------------------===//
// local variables
// CHECK: %a = moore.variable : !moore.int
automatic int a;
// CHECK moore.blocking_assign %i, %a : !moore.int
i = a;
//===------------------------------------------------------------------===//
// Conditional statements
@ -294,9 +293,10 @@ module Expressions;
// CHECK: %b = moore.variable : !moore.int
// CHECK: %c = moore.variable : !moore.int
int a, b, c;
int unsigned u;
int unsigned u, w;
bit [1:0][3:0] v;
integer d, e, f;
integer unsigned g, h, k;
bit x;
logic y;
logic [31:0] vec_1;
@ -313,15 +313,15 @@ module Expressions;
c = 42;
// CHECK: moore.constant 42 : !moore.packed<range<bit, 18:0>>
c = 19'd42;
// CHECK: moore.constant 42 : !moore.packed<range<bit<signed>, 18:0>>
// CHECK: moore.constant 42 : !moore.packed<range<bit, 18:0>>
c = 19'sd42;
// CHECK: moore.concat %a, %b, %c : (!moore.int, !moore.int, !moore.int) -> !moore.packed<range<bit, 95:0>>
a = {a, b, c};
// CHECK: moore.concat %d, %e : (!moore.integer, !moore.integer) -> !moore.packed<range<logic, 63:0>>
d = {d, e};
// CHECK: %[[VAL_1:.*]] = moore.constant false : !moore.packed<range<bit, 0:0>>
// CHECK: %[[VAL_2:.*]] = moore.concat %[[VAL_1]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 0:0>>
// CHECK: %[[VAL_3:.*]] = moore.replicate %[[VAL_2]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 31:0>>
// CHECK: %[[VAL_2:.*]] = moore.concat %[[VAL_1]] : (!moore.packed<range<bit, 0:0>>) -> !moore.bit
// CHECK: %[[VAL_3:.*]] = moore.replicate %[[VAL_2]] : (!moore.bit) -> !moore.packed<range<bit, 31:0>>
a = {32{1'b0}};
// CHECK: %[[VAL:.*]] = moore.constant 1 : !moore.int
// CHECK: moore.extract %vec_1 from %[[VAL]] : !moore.packed<range<logic, 31:0>>, !moore.int -> !moore.packed<range<logic, 3:1>>
@ -432,9 +432,13 @@ module Expressions;
c = a - b;
// CHECK: moore.mul %a, %b : !moore.int
c = a * b;
// CHECK: moore.div %d, %e : !moore.integer
// CHECK: moore.divu %h, %k : !moore.integer
g = h / k;
// CHECK: moore.divs %d, %e : !moore.integer
f = d / e;
// CHECK: moore.mod %d, %e : !moore.integer
// CHECK: moore.modu %h, %k : !moore.integer
g = h % k;
// CHECK: moore.mods %d, %e : !moore.integer
f = d % e;
// CHECK: moore.and %a, %b : !moore.int
@ -473,13 +477,21 @@ module Expressions;
// CHECK: moore.wildcard_ne %a, %b : !moore.int -> !moore.bit
x = a !=? b;
// CHECK: moore.ge %a, %b : !moore.int -> !moore.bit
// CHECK: moore.uge %u, %w : !moore.int -> !moore.bit
c = u >= w;
// CHECK: moore.ugt %u, %w : !moore.int -> !moore.bit
c = u > w;
// CHECK: moore.ule %u, %w : !moore.int -> !moore.bit
c = u <= w;
// CHECK: moore.ult %u, %w : !moore.int -> !moore.bit
c = u < w;
// CHECK: moore.sge %a, %b : !moore.int -> !moore.bit
c = a >= b;
// CHECK: moore.gt %a, %b : !moore.int -> !moore.bit
// CHECK: moore.sgt %a, %b : !moore.int -> !moore.bit
c = a > b;
// CHECK: moore.le %a, %b : !moore.int -> !moore.bit
// CHECK: moore.sle %a, %b : !moore.int -> !moore.bit
c = a <= b;
// CHECK: moore.lt %a, %b : !moore.int -> !moore.bit
// CHECK: moore.slt %a, %b : !moore.int -> !moore.bit
c = a < b;
// CHECK: [[A:%.+]] = moore.bool_cast %a : !moore.int -> !moore.bit
@ -512,7 +524,7 @@ module Expressions;
c = a <<< b;
// CHECK: moore.ashr %a, %b : !moore.int, !moore.int
c = a >>> b;
// CHECK: moore.shr %u, %b : !moore.int<unsigned>, !moore.int
// CHECK: moore.shr %u, %b : !moore.int, !moore.int
c = u >>> b;
//===------------------------------------------------------------------===//
@ -531,13 +543,21 @@ module Expressions;
// CHECK: moore.blocking_assign %a, [[TMP2]]
a *= b;
// CHECK: [[TMP1:%.+]] = moore.read_lvalue %f
// CHECK: [[TMP2:%.+]] = moore.div [[TMP1]], %d
// CHECK: [[TMP2:%.+]] = moore.divs [[TMP1]], %d
// CHECK: moore.blocking_assign %f, [[TMP2]]
f /= d;
// CHECK: [[TMP1:%.+]] = moore.read_lvalue %g
// CHECK: [[TMP2:%.+]] = moore.divu [[TMP1]], %h
// CHECK: moore.blocking_assign %g, [[TMP2]]
g /= h;
// CHECK: [[TMP1:%.+]] = moore.read_lvalue %f
// CHECK: [[TMP2:%.+]] = moore.mod [[TMP1]], %d
// CHECK: [[TMP2:%.+]] = moore.mods [[TMP1]], %d
// CHECK: moore.blocking_assign %f, [[TMP2]]
f %= d;
// CHECK: [[TMP1:%.+]] = moore.read_lvalue %g
// CHECK: [[TMP2:%.+]] = moore.modu [[TMP1]], %h
// CHECK: moore.blocking_assign %g, [[TMP2]]
g %= h;
// CHECK: [[TMP1:%.+]] = moore.read_lvalue %a
// CHECK: [[TMP2:%.+]] = moore.and [[TMP1]], %b
// CHECK: moore.blocking_assign %a, [[TMP2]]
@ -597,7 +617,7 @@ module Conversion;
int c = byte'(a);
// Sign conversion.
// CHECK: [[TMP:%.+]] = moore.conversion %b : !moore.int -> !moore.packed<range<bit<signed>, 31:0>>
// CHECK: [[TMP:%.+]] = moore.conversion %b : !moore.int -> !moore.packed<range<bit, 31:0>>
// CHECK: %d1 = moore.variable [[TMP]]
// CHECK: [[TMP:%.+]] = moore.conversion %b : !moore.int -> !moore.packed<range<bit, 31:0>>
// CHECK: %d2 = moore.variable [[TMP]]
@ -605,7 +625,7 @@ module Conversion;
bit [31:0] d2 = unsigned'(b);
// Width conversion.
// CHECK: [[TMP:%.+]] = moore.conversion %b : !moore.int -> !moore.packed<range<bit<signed>, 18:0>>
// CHECK: [[TMP:%.+]] = moore.conversion %b : !moore.int -> !moore.packed<range<bit, 18:0>>
// CHECK: %e = moore.variable [[TMP]]
bit signed [18:0] e = 19'(b);
endmodule

View File

@ -40,11 +40,11 @@ module IntAtoms;
// CHECK-NEXT: %u0 = moore.variable : !moore.logic
// CHECK-NEXT: %u1 = moore.variable : !moore.bit
// CHECK-NEXT: %u2 = moore.variable : !moore.reg
// CHECK-NEXT: %u3 = moore.variable : !moore.int<unsigned>
// CHECK-NEXT: %u4 = moore.variable : !moore.shortint<unsigned>
// CHECK-NEXT: %u5 = moore.variable : !moore.longint<unsigned>
// CHECK-NEXT: %u6 = moore.variable : !moore.integer<unsigned>
// CHECK-NEXT: %u7 = moore.variable : !moore.byte<unsigned>
// CHECK-NEXT: %u3 = moore.variable : !moore.int
// CHECK-NEXT: %u4 = moore.variable : !moore.shortint
// CHECK-NEXT: %u5 = moore.variable : !moore.longint
// CHECK-NEXT: %u6 = moore.variable : !moore.integer
// CHECK-NEXT: %u7 = moore.variable : !moore.byte
// CHECK-NEXT: %u8 = moore.variable : !moore.time
logic unsigned u0;
bit unsigned u1;
@ -56,15 +56,15 @@ module IntAtoms;
byte unsigned u7;
time unsigned u8;
// CHECK-NEXT: %s0 = moore.variable : !moore.logic<signed>
// CHECK-NEXT: %s1 = moore.variable : !moore.bit<signed>
// CHECK-NEXT: %s2 = moore.variable : !moore.reg<signed>
// CHECK-NEXT: %s0 = moore.variable : !moore.logic
// CHECK-NEXT: %s1 = moore.variable : !moore.bit
// CHECK-NEXT: %s2 = moore.variable : !moore.reg
// CHECK-NEXT: %s3 = moore.variable : !moore.int
// CHECK-NEXT: %s4 = moore.variable : !moore.shortint
// CHECK-NEXT: %s5 = moore.variable : !moore.longint
// CHECK-NEXT: %s6 = moore.variable : !moore.integer
// CHECK-NEXT: %s7 = moore.variable : !moore.byte
// CHECK-NEXT: %s8 = moore.variable : !moore.time<signed>
// CHECK-NEXT: %s8 = moore.variable : !moore.time
logic signed s0;
bit signed s1;
reg signed s2;

View File

@ -46,7 +46,7 @@ func.func @UnrealizedConversionCast(%arg0: !moore.byte) -> !moore.shortint {
}
// CHECK-LABEL: func @Expressions
func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.packed<range<bit, 5:0>>, %arg3: !moore.packed<range<bit<signed>, 4:0>>, %arg4: !moore.bit<signed>) {
func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.packed<range<bit, 5:0>>, %arg3: !moore.packed<range<bit, 4:0>>, %arg4: !moore.bit) {
// CHECK-NEXT: %0 = comb.concat %arg0, %arg0 : i1, i1
// CHECK-NEXT: %1 = comb.concat %arg1, %arg1 : i1, i1
moore.concat %arg0, %arg0 : (!moore.bit, !moore.bit) -> !moore.packed<range<bit, 1:0>>
@ -77,7 +77,7 @@ func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.pac
// CHECK-NEXT: [[V6:%.+]] = hw.constant -1 : i5
// CHECK-NEXT: [[V7:%.+]] = comb.mux [[V4]], [[V5]], [[V6]] : i5
// CHECK-NEXT: comb.shl %arg3, [[V7]] : i5
moore.shl %arg3, %arg2 : !moore.packed<range<bit<signed>, 4:0>>, !moore.packed<range<bit, 5:0>>
moore.shl %arg3, %arg2 : !moore.packed<range<bit, 4:0>>, !moore.packed<range<bit, 5:0>>
// CHECK-NEXT: [[V8:%.+]] = hw.constant 0 : i5
// CHECK-NEXT: [[V9:%.+]] = comb.concat [[V8]], %arg0 : i5, i1
@ -94,7 +94,7 @@ func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.pac
// CHECK-NEXT: [[V14:%.+]] = hw.constant -1 : i5
// CHECK-NEXT: [[V15:%.+]] = comb.mux [[V12]], [[V13]], [[V14]] : i5
// CHECK-NEXT: comb.shrs %arg3, [[V15]] : i5
moore.ashr %arg3, %arg2 : !moore.packed<range<bit<signed>, 4:0>>, !moore.packed<range<bit, 5:0>>
moore.ashr %arg3, %arg2 : !moore.packed<range<bit, 4:0>>, !moore.packed<range<bit, 5:0>>
// CHECK-NEXT: %c2_i32 = hw.constant 2 : i32
%2 = moore.constant 2 : !moore.int
@ -151,10 +151,10 @@ func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.pac
moore.add %arg1, %arg1 : !moore.logic
moore.sub %arg1, %arg1 : !moore.logic
moore.mul %arg1, %arg1 : !moore.logic
moore.div %arg0, %arg0 : !moore.bit
moore.div %arg4, %arg4 : !moore.bit<signed>
moore.mod %arg0, %arg0 : !moore.bit
moore.mod %arg4, %arg4 : !moore.bit<signed>
moore.divu %arg0, %arg0 : !moore.bit
moore.divs %arg4, %arg4 : !moore.bit
moore.modu %arg0, %arg0 : !moore.bit
moore.mods %arg4, %arg4 : !moore.bit
moore.and %arg0, %arg0 : !moore.bit
moore.or %arg0, %arg0 : !moore.bit
moore.xor %arg0, %arg0 : !moore.bit
@ -163,19 +163,19 @@ func.func @Expressions(%arg0: !moore.bit, %arg1: !moore.logic, %arg2: !moore.pac
// CHECK-NEXT: comb.icmp ule %arg0, %arg0 : i1
// CHECK-NEXT: comb.icmp ugt %arg0, %arg0 : i1
// CHECK-NEXT: comb.icmp uge %arg0, %arg0 : i1
moore.lt %arg1, %arg1 : !moore.logic -> !moore.logic
moore.le %arg0, %arg0 : !moore.bit -> !moore.bit
moore.gt %arg0, %arg0 : !moore.bit -> !moore.bit
moore.ge %arg0, %arg0 : !moore.bit -> !moore.bit
moore.ult %arg1, %arg1 : !moore.logic -> !moore.logic
moore.ule %arg0, %arg0 : !moore.bit -> !moore.bit
moore.ugt %arg0, %arg0 : !moore.bit -> !moore.bit
moore.uge %arg0, %arg0 : !moore.bit -> !moore.bit
// CHECK-NEXT: comb.icmp slt %arg4, %arg4 : i1
// CHECK-NEXT: comb.icmp sle %arg4, %arg4 : i1
// CHECK-NEXT: comb.icmp sgt %arg4, %arg4 : i1
// CHECK-NEXT: comb.icmp sge %arg4, %arg4 : i1
moore.lt %arg4, %arg4 : !moore.bit<signed> -> !moore.bit
moore.le %arg4, %arg4 : !moore.bit<signed> -> !moore.bit
moore.gt %arg4, %arg4 : !moore.bit<signed> -> !moore.bit
moore.ge %arg4, %arg4 : !moore.bit<signed> -> !moore.bit
moore.slt %arg4, %arg4 : !moore.bit -> !moore.bit
moore.sle %arg4, %arg4 : !moore.bit -> !moore.bit
moore.sgt %arg4, %arg4 : !moore.bit -> !moore.bit
moore.sge %arg4, %arg4 : !moore.bit -> !moore.bit
// CHECK-NEXT: comb.icmp eq %arg1, %arg1 : i1
// CHECK-NEXT: comb.icmp ne %arg0, %arg0 : i1

View File

@ -35,7 +35,7 @@ moore.module @Foo {
// CHECK: %w11 = moore.net supply0 : !moore.logic
%w11 = moore.net supply0 : !moore.logic
// CHECK: %w12 = moore.net supply1 : !moore.logic
%w12 = moore.net supply1 : !moore.logic
%w12 = moore.net supply1 : !moore.logic
// CHECK: moore.procedure initial {
// CHECK: moore.procedure final {
@ -82,8 +82,8 @@ moore.module @Expressions {
moore.constant 0 : !moore.int
// CHECK: moore.constant -2 : !moore.packed<range<bit, 1:0>>
moore.constant 2 : !moore.packed<range<bit, 1:0>>
// CHECK: moore.constant -2 : !moore.packed<range<bit<signed>, 1:0>>
moore.constant -2 : !moore.packed<range<bit<signed>, 1:0>>
// CHECK: moore.constant -2 : !moore.packed<range<bit, 1:0>>
moore.constant -2 : !moore.packed<range<bit, 1:0>>
// CHECK: moore.conversion %b5 : !moore.packed<range<bit, 4:0>> -> !moore.packed<range<logic, 4:0>>
moore.conversion %b5 : !moore.packed<range<bit, 4:0>> -> !moore.packed<range<logic, 4:0>>
@ -113,17 +113,14 @@ moore.module @Expressions {
moore.sub %int, %int2 : !moore.int
// CHECK: moore.mul %int, %int2 : !moore.int
moore.mul %int, %int2 : !moore.int
// CHECK: moore.div %int, %int2 : !moore.int
moore.div %int, %int2 : !moore.int
// CHECK: moore.mod %int, %int2 : !moore.int
moore.mod %int, %int2 : !moore.int
// CHECK: moore.and %int, %int2 : !moore.int
moore.and %int, %int2 : !moore.int
// CHECK: moore.or %int, %int2 : !moore.int
moore.or %int, %int2 : !moore.int
// CHECK: moore.xor %int, %int2 : !moore.int
moore.xor %int, %int2 : !moore.int
// CHECK: moore.divu %int, %int2 : !moore.int
moore.divu %int, %int2 : !moore.int
// CHECK: moore.divs %int, %int2 : !moore.int
moore.divs %int, %int2 : !moore.int
// CHECK: moore.modu %int, %int2 : !moore.int
moore.modu %int, %int2 : !moore.int
// CHECK: moore.mods %int, %int2 : !moore.int
moore.mods %int, %int2 : !moore.int
// CHECK: moore.shl %l1, %b1 : !moore.logic, !moore.bit
moore.shl %l1, %b1 : !moore.logic, !moore.bit
@ -149,27 +146,33 @@ moore.module @Expressions {
// CHECK: moore.wildcard_ne %integer, %integer2 : !moore.integer -> !moore.logic
moore.wildcard_ne %integer, %integer2 : !moore.integer -> !moore.logic
// CHECK: moore.lt %int, %int2 : !moore.int -> !moore.bit
moore.lt %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.le %int, %int2 : !moore.int -> !moore.bit
moore.le %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.gt %int, %int2 : !moore.int -> !moore.bit
moore.gt %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.ge %int, %int2 : !moore.int -> !moore.bit
moore.ge %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.ge %integer, %integer2 : !moore.integer -> !moore.logic
moore.ge %integer, %integer2 : !moore.integer -> !moore.logic
// CHECK: moore.ult %int, %int2 : !moore.int -> !moore.bit
moore.ult %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.ule %int, %int2 : !moore.int -> !moore.bit
moore.ule %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.ugt %int, %int2 : !moore.int -> !moore.bit
moore.ugt %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.uge %int, %int2 : !moore.int -> !moore.bit
moore.uge %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.slt %int, %int2 : !moore.int -> !moore.bit
moore.slt %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.sle %int, %int2 : !moore.int -> !moore.bit
moore.sle %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.sgt %int, %int2 : !moore.int -> !moore.bit
moore.sgt %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.sge %int, %int2 : !moore.int -> !moore.bit
moore.sge %int, %int2 : !moore.int -> !moore.bit
// CHECK: moore.uge %integer, %integer2 : !moore.integer -> !moore.logic
moore.uge %integer, %integer2 : !moore.integer -> !moore.logic
// CHECK: moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
// CHECK: moore.concat %b1 : (!moore.bit) -> !moore.bit
moore.concat %b1 : (!moore.bit) -> !moore.bit
// CHECK: moore.concat %b5, %b1 : (!moore.packed<range<bit, 4:0>>, !moore.bit) -> !moore.packed<range<bit, 5:0>>
moore.concat %b5, %b1 : (!moore.packed<range<bit, 4:0>>, !moore.bit) -> !moore.packed<range<bit, 5:0>>
// CHECK: moore.concat %l1, %l1, %l1 : (!moore.logic, !moore.logic, !moore.logic) -> !moore.packed<range<logic, 2:0>>
moore.concat %l1, %l1, %l1 : (!moore.logic, !moore.logic, !moore.logic) -> !moore.packed<range<logic, 2:0>>
// CHECK: [[VAL:%.*]] = moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
// CHECK: moore.replicate [[VAL]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 3:0>>
%0 = moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
moore.replicate %0 : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 3:0>>
// CHECK: moore.replicate %b1 : (!moore.bit) -> !moore.packed<range<bit, 3:0>>
moore.replicate %b1 : (!moore.bit) -> !moore.packed<range<bit, 3:0>>
// CHECK: moore.extract %b5 from %b1 : !moore.packed<range<bit, 4:0>>, !moore.bit -> !moore.bit
moore.extract %b5 from %b1 : !moore.packed<range<bit, 4:0>>, !moore.bit -> !moore.bit

View File

@ -10,8 +10,3 @@ func.func @Foo(%arg0: !moore.range<bit, 3:0>) { return }
// -----
// expected-error @+1 {{ambiguous packing; wrap `struct` in `packed<...>` or `unpacked<...>` to disambiguate}}
func.func @Foo(%arg0: !moore.struct<{}, loc(unknown)>) { return }
// -----
// expected-error @+1 {{unpacked struct cannot have a sign}}
func.func @Foo(%arg0: !moore.unpacked<struct<unsigned, {}, loc(unknown)>>) { return }
func.func @Bar(%arg0: !moore.packed<struct<unsigned, {}, loc(unknown)>>) { return }

View File

@ -31,43 +31,7 @@ func.func @IntTypes(
%arg5: !moore.int,
%arg6: !moore.longint,
%arg7: !moore.integer,
%arg8: !moore.time,
// CHECK-SAME: %arg9: !moore.bit<unsigned>
// CHECK-SAME: %arg10: !moore.logic<unsigned>
// CHECK-SAME: %arg11: !moore.reg<unsigned>
// CHECK-SAME: %arg12: !moore.byte<unsigned>
// CHECK-SAME: %arg13: !moore.shortint<unsigned>
// CHECK-SAME: %arg14: !moore.int<unsigned>
// CHECK-SAME: %arg15: !moore.longint<unsigned>
// CHECK-SAME: %arg16: !moore.integer<unsigned>
// CHECK-SAME: %arg17: !moore.time<unsigned>
%arg9: !moore.bit<unsigned>,
%arg10: !moore.logic<unsigned>,
%arg11: !moore.reg<unsigned>,
%arg12: !moore.byte<unsigned>,
%arg13: !moore.shortint<unsigned>,
%arg14: !moore.int<unsigned>,
%arg15: !moore.longint<unsigned>,
%arg16: !moore.integer<unsigned>,
%arg17: !moore.time<unsigned>,
// CHECK-SAME: %arg18: !moore.bit<signed>
// CHECK-SAME: %arg19: !moore.logic<signed>
// CHECK-SAME: %arg20: !moore.reg<signed>
// CHECK-SAME: %arg21: !moore.byte<signed>
// CHECK-SAME: %arg22: !moore.shortint<signed>
// CHECK-SAME: %arg23: !moore.int<signed>
// CHECK-SAME: %arg24: !moore.longint<signed>
// CHECK-SAME: %arg25: !moore.integer<signed>
// CHECK-SAME: %arg26: !moore.time<signed>
%arg18: !moore.bit<signed>,
%arg19: !moore.logic<signed>,
%arg20: !moore.reg<signed>,
%arg21: !moore.byte<signed>,
%arg22: !moore.shortint<signed>,
%arg23: !moore.int<signed>,
%arg24: !moore.longint<signed>,
%arg25: !moore.integer<signed>,
%arg26: !moore.time<signed>
%arg8: !moore.time
) { return }
// CHECK-LABEL: func @RealTypes(
@ -107,15 +71,11 @@ func.func @DimTypes(
// CHECK-LABEL: func @StructTypes(
func.func @StructTypes(
// CHECK-SAME: %arg0: !moore.packed<struct<{}>>
// CHECK-SAME: %arg1: !moore.packed<struct<unsigned, {}>>
// CHECK-SAME: %arg2: !moore.packed<struct<signed, {}>>
// CHECK-SAME: %arg3: !moore.packed<struct<{foo: bit, bar: int}>>
// CHECK-SAME: %arg1: !moore.packed<struct<{foo: bit, bar: int}>>
%arg0: !moore.packed<struct<{}>>,
%arg1: !moore.packed<struct<unsigned, {}>>,
%arg2: !moore.packed<struct<signed, {}>>,
%arg3: !moore.packed<struct<{foo: bit, bar: int}>>,
// CHECK-SAME: %arg4: !moore.unpacked<struct<{}>>
// CHECK-SAME: %arg5: !moore.unpacked<struct<{foo: string, bar: event}>>
%arg4: !moore.unpacked<struct<{}>>,
%arg5: !moore.unpacked<struct<{foo: string, bar: event}>>
%arg1: !moore.packed<struct<{foo: bit, bar: int}>>,
// CHECK-SAME: %arg2: !moore.unpacked<struct<{}>>
// CHECK-SAME: %arg3: !moore.unpacked<struct<{foo: string, bar: event}>>
%arg2: !moore.unpacked<struct<{}>>,
%arg3: !moore.unpacked<struct<{foo: string, bar: event}>>
) { return }

View File

@ -34,11 +34,6 @@ TEST(TypesTest, UnitTypes) {
ASSERT_EQ(stringType.getDomain(), Domain::TwoValued);
ASSERT_EQ(chandleType.getDomain(), Domain::TwoValued);
ASSERT_EQ(eventType.getDomain(), Domain::TwoValued);
ASSERT_EQ(voidType.getSign(), Sign::Unsigned);
ASSERT_EQ(stringType.getSign(), Sign::Unsigned);
ASSERT_EQ(chandleType.getSign(), Sign::Unsigned);
ASSERT_EQ(eventType.getSign(), Sign::Unsigned);
}
TEST(TypesTest, Ranges) {
@ -88,21 +83,7 @@ TEST(TypesTest, PackedInt) {
for (auto pair : pairs) {
auto kind = std::get<0>(pair);
auto type = IntType::get(&context, kind);
auto unsignedType = IntType::get(&context, kind, Sign::Unsigned);
auto signedType = IntType::get(&context, kind, Sign::Signed);
// Check the domain.
ASSERT_EQ(type.getDomain(), std::get<2>(pair));
ASSERT_EQ(unsignedType.getDomain(), std::get<2>(pair));
ASSERT_EQ(signedType.getDomain(), std::get<2>(pair));
// Check the sign.
ASSERT_EQ(type.getSign(), std::get<3>(pair));
ASSERT_EQ(unsignedType.getSign(), Sign::Unsigned);
ASSERT_EQ(signedType.getSign(), Sign::Signed);
ASSERT_FALSE(type.isSignExplicit());
ASSERT_TRUE(unsignedType.isSignExplicit());
ASSERT_TRUE(signedType.isSignExplicit());
}
}
@ -121,10 +102,6 @@ TEST(TypesTest, Reals) {
ASSERT_EQ(t0.getBitSize(), 32u);
ASSERT_EQ(t1.getBitSize(), 64u);
ASSERT_EQ(t2.getBitSize(), 64u);
ASSERT_EQ(t0.getSign(), Sign::Unsigned);
ASSERT_EQ(t1.getSign(), Sign::Unsigned);
ASSERT_EQ(t2.getSign(), Sign::Unsigned);
}
TEST(TypesTest, PackedDim) {
@ -212,25 +189,13 @@ TEST(TypesTest, SimpleBitVectorTypes) {
ASSERT_FALSE(voidType.isSimpleBitVector());
ASSERT_FALSE(voidType.isCastableToSimpleBitVector());
// SBVTs preserve whether the sign was explicitly mentioned.
auto bit1 = IntType::get(&context, IntType::Bit);
auto ubit1 = IntType::get(&context, IntType::Bit, Sign::Unsigned);
auto sbit1 = IntType::get(&context, IntType::Bit, Sign::Signed);
ASSERT_EQ(bit1.getSimpleBitVector().toString(), "bit");
ASSERT_EQ(ubit1.getSimpleBitVector().toString(), "bit unsigned");
ASSERT_EQ(sbit1.getSimpleBitVector().toString(), "bit signed");
// SBVTs preserve whether the original type was an integer atom.
auto intTy = IntType::get(&context, IntType::Int);
auto byteTy = IntType::get(&context, IntType::Byte);
ASSERT_EQ(intTy.getSimpleBitVector().getType(&context), intTy);
ASSERT_EQ(byteTy.getSimpleBitVector().getType(&context), byteTy);
// Integer atoms with a dimension are no SBVT, but can be cast to one.
auto intTy = IntType::get(&context, IntType::Int);
auto intArray = PackedRangeDim::get(intTy, 8);
ASSERT_FALSE(intArray.isSimpleBitVector());
ASSERT_TRUE(intArray.isCastableToSimpleBitVector());
ASSERT_EQ(intArray.castToSimpleBitVector().toString(), "bit signed [255:0]");
ASSERT_EQ(intArray.castToSimpleBitVector(),
SimpleBitVectorType(Domain::TwoValued, 256));
}
} // namespace