diff --git a/include/circt/Dialect/Moore/MooreOps.td b/include/circt/Dialect/Moore/MooreOps.td index b2375620a5d7..2a043e4881c4 100644 --- a/include/circt/Dialect/Moore/MooreOps.td +++ b/include/circt/Dialect/Moore/MooreOps.td @@ -708,6 +708,8 @@ def SubOp : BinaryOpBase<"sub"> { See IEEE 1800-2017 ยง 11.4.3 "Arithmetic operators". }]; + + let hasFolder = 1; } def MulOp : BinaryOpBase<"mul", [Commutative]> { diff --git a/lib/Conversion/ImportVerilog/Expressions.cpp b/lib/Conversion/ImportVerilog/Expressions.cpp index 8a0d9b41ca43..51588f91d52d 100644 --- a/lib/Conversion/ImportVerilog/Expressions.cpp +++ b/lib/Conversion/ImportVerilog/Expressions.cpp @@ -430,23 +430,54 @@ struct RvalueExprVisitor { return builder.create(loc, type, value); } + Value getSelectIndex(Value index, const slang::ConstantRange &range) const { + auto indexType = cast(index.getType()); + auto bw = std::max(llvm::Log2_32_Ceil(std::abs(range.upper())), + indexType.getBitSize().value()); + auto intType = + moore::IntType::get(index.getContext(), bw, indexType.getDomain()); + + if (range.isLittleEndian()) { + if (range.lower() == 0) + return index; + + Value newIndex = + builder.createOrFold(loc, intType, index); + Value offset = + builder.create(loc, intType, range.lower()); + return builder.createOrFold(loc, newIndex, offset); + } + + if (range.upper() == 0) + return builder.createOrFold(loc, index); + + Value newIndex = + builder.createOrFold(loc, intType, index); + Value offset = + builder.create(loc, intType, range.upper()); + return builder.createOrFold(loc, offset, newIndex); + } + // Handle single bit selections. Value visit(const slang::ast::ElementSelectExpression &expr) { auto type = context.convertType(*expr.type); auto value = context.convertRvalueExpression(expr.value()); if (!type || !value) return {}; + auto range = expr.value().type->getFixedRange(); if (auto *constValue = expr.selector().constant) { assert(!constValue->hasUnknown()); assert(constValue->size() <= 32); auto lowBit = constValue->integer().as().value(); - return builder.create(loc, type, value, lowBit); + return builder.create(loc, type, value, + range.translateIndex(lowBit)); } auto lowBit = context.convertRvalueExpression(expr.selector()); if (!lowBit) return {}; - return builder.create(loc, type, value, lowBit); + return builder.create(loc, type, value, + getSelectIndex(lowBit, range)); } // Handle range bits selections. @@ -509,9 +540,12 @@ struct RvalueExprVisitor { else dynLowBit = context.convertRvalueExpression(expr.left()); } + auto range = expr.value().type->getFixedRange(); if (leftConst && rightConst) - return builder.create(loc, type, value, constLowBit); - return builder.create(loc, type, value, dynLowBit); + return builder.create( + loc, type, value, range.translateIndex(constLowBit)); + return builder.create( + loc, type, value, getSelectIndex(dynLowBit, range)); } Value visit(const slang::ast::MemberAccessExpression &expr) { diff --git a/lib/Dialect/Moore/MooreOps.cpp b/lib/Dialect/Moore/MooreOps.cpp index 5deef56f322d..2e0a5caac075 100644 --- a/lib/Dialect/Moore/MooreOps.cpp +++ b/lib/Dialect/Moore/MooreOps.cpp @@ -1188,6 +1188,18 @@ LogicalResult PowUOp::canonicalize(PowUOp op, PatternRewriter &rewriter) { return failure(); } +//===----------------------------------------------------------------------===// +// SubOp +//===----------------------------------------------------------------------===// + +OpFoldResult SubOp::fold(FoldAdaptor adaptor) { + if (auto intAttr = dyn_cast_or_null(adaptor.getRhs())) + if (intAttr.getValue().isZero()) + return getLhs(); + + return {}; +} + //===----------------------------------------------------------------------===// // TableGen generated logic. //===----------------------------------------------------------------------===// diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index e8ec896ab63a..95d500774518 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -693,6 +693,10 @@ module Expressions; logic y; // CHECK: %vec_1 = moore.variable : logic [31:0] vec_1; + // CHECK: %vec_1a = moore.variable : + logic [31:15] vec_1a; + // CHECK: %vec_1b = moore.variable : + logic [-31:0] vec_1b; // CHECK: %vec_2 = moore.variable : logic [0:31] vec_2; // CHECK: %vec_3 = moore.variable : @@ -890,7 +894,7 @@ module Expressions; // CHECK: moore.extract [[TMP1]] from 1 : l32 -> l3 y = vec_1[3:1]; // CHECK: [[TMP1:%.+]] = moore.read %vec_2 : - // CHECK: moore.extract [[TMP1]] from 2 : l32 -> l2 + // CHECK: moore.extract [[TMP1]] from 29 : l32 -> l2 y = vec_2[2:3]; // CHECK: [[TMP1:%.+]] = moore.read %d : // CHECK: [[TMP2:%.+]] = moore.read %x : @@ -907,8 +911,56 @@ module Expressions; // CHECK: moore.extract [[TMP1]] from 15 : l32 -> l1 y = vec_1[15+:1]; // CHECK: [[TMP1:%.+]] = moore.read %vec_2 : - // CHECK: moore.extract [[TMP1]] from 0 : l32 -> l1 + // CHECK: moore.extract [[TMP1]] from 31 : l32 -> l1 y = vec_2[0+:1]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_2 : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.constant 31 : l32 + // CHECK: [[TMP4:%.+]] = moore.sub [[TMP3]], [[TMP2]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP4]] : l32, l32 -> l2 + y = vec_2[vec_1+:2]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_2 : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.constant 31 : l32 + // CHECK: [[TMP4:%.+]] = moore.sub [[TMP3]], [[TMP2]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP4]] : l32, l32 -> l1 + y = vec_2[vec_1]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1a : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.constant 15 : l32 + // CHECK: [[TMP4:%.+]] = moore.sub [[TMP2]], [[TMP3]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP4]] : l17, l32 -> l2 + y = vec_1a[vec_1+:2]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1a : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.constant 15 : l32 + // CHECK: [[TMP4:%.+]] = moore.sub [[TMP2]], [[TMP3]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP4]] : l17, l32 -> l1 + y = vec_1a[vec_1]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1b : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.neg [[TMP2]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP3]] : l32, l32 -> l2 + y = vec_1b[vec_1+:2]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1b : + // CHECK: [[TMP2:%.+]] = moore.read %vec_1 : + // CHECK: [[TMP3:%.+]] = moore.neg [[TMP2]] : l32 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP3]] : l32, l32 -> l1 + y = vec_1b[vec_1]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1a : + // CHECK: [[TMP2:%.+]] = moore.read %x : + // CHECK: [[TMP3:%.+]] = moore.conversion [[TMP2]] : !moore.i1 -> !moore.i5 + // CHECK: [[TMP4:%.+]] = moore.constant 15 : i5 + // CHECK: [[TMP5:%.+]] = moore.sub [[TMP3]], [[TMP4]] : i5 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP5]] : l17, i5 -> l2 + y = vec_1a[x+:2]; + // CHECK: [[TMP1:%.+]] = moore.read %vec_1a : + // CHECK: [[TMP2:%.+]] = moore.read %x : + // CHECK: [[TMP3:%.+]] = moore.conversion [[TMP2]] : !moore.i1 -> !moore.i5 + // CHECK: [[TMP4:%.+]] = moore.constant 15 : i5 + // CHECK: [[TMP5:%.+]] = moore.sub [[TMP3]], [[TMP4]] : i5 + // CHECK: moore.dyn_extract [[TMP1]] from [[TMP5]] : l17, i5 -> l1 + y = vec_1a[x]; // CHECK: [[TMP1:%.+]] = moore.read %vec_1 // CHECK: [[TMP2:%.+]] = moore.constant 1 : i32 // CHECK: [[TMP3:%.+]] = moore.read %a @@ -918,9 +970,9 @@ module Expressions; // CHECK: moore.dyn_extract [[TMP1]] from [[TMP6]] : l32, i32 -> l1 c = vec_1[1*a-:1]; // CHECK: [[TMP1:%.+]] = moore.read %arr : >> - // CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 3 : uarray<3 x uarray<6 x i4>> -> uarray<6 x i4> - // CHECK: [[TMP5:%.+]] = moore.extract [[TMP3]] from 7 : uarray<6 x i4> -> i4 - // CHECK: moore.extract [[TMP5]] from 3 : i4 -> i2 + // CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 0 : uarray<3 x uarray<6 x i4>> -> uarray<6 x i4> + // CHECK: [[TMP5:%.+]] = moore.extract [[TMP3]] from 0 : uarray<6 x i4> -> i4 + // CHECK: moore.extract [[TMP5]] from 2 : i4 -> i2 c = arr[3][7][4:3]; // CHECK: [[TMP1:%.+]] = moore.read %vec_1 : // CHECK: [[TMP2:%.+]] = moore.read %c : diff --git a/test/Dialect/Moore/canonicalizers.mlir b/test/Dialect/Moore/canonicalizers.mlir index 2754fcef860c..b5c0a30f8f49 100644 --- a/test/Dialect/Moore/canonicalizers.mlir +++ b/test/Dialect/Moore/canonicalizers.mlir @@ -291,3 +291,11 @@ func.func @MoveInitialOutOfSSAVariable() { func.call @useRef(%1) : (!moore.ref) -> () return } + +// CHECK-LABEL: @sub +func.func @sub(%arg0: !moore.i32) -> !moore.i32 { + %0 = moore.constant 0 : !moore.i32 + %1 = moore.sub %arg0, %0 : !moore.i32 + // CHECK: return %arg0 : + return %1 : !moore.i32 +}