diff --git a/CMakeLists.txt b/CMakeLists.txt index 0da07396..bd4c8d82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) else () set(LLVM_SOURCE_DIR ${LLVM_MAIN_SRC_DIR}) set(MLIR_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../mlir) - set(MLIR_INCLUDE_DIRS ${MLIR_MAIN_SRC_DIR}/include) + set(MLIR_INCLUDE_DIR ${MLIR_MAIN_SRC_DIR}/include) set(MLIR_CMAKE_DIR ${MLIR_MAIN_SRC_DIR}/cmake/modules) set(MLIR_TABLEGEN_EXE $) set(MLIR_TABLEGEN_OUTPUT_DIR ${LLVM_BINARY_DIR}/tools/mlir/include) diff --git a/include/scalehls/Utils/Utils.h b/include/scalehls/Utils/Utils.h index f840e387..586d81cc 100644 --- a/include/scalehls/Utils/Utils.h +++ b/include/scalehls/Utils/Utils.h @@ -55,6 +55,11 @@ getEvenlyDistributedFactors(unsigned maxFactor, FactorList &factors, const SmallVectorImpl &constrFactors, bool powerOf2Constr = false); +/// Compose any affine.apply ops feeding into `operands` of the integer set +/// `set` by composing the maps of such affine.apply ops with the integer +/// set constraints. +void composeSetAndOperands(IntegerSet &set, SmallVectorImpl &operands); + /// Return a pair which indicates whether the if statement is always true or /// false, respectively. The returned result is one-hot. std::pair ifAlwaysTrueOrFalse(affine::AffineIfOp ifOp); diff --git a/include/scalehls/Utils/Visitor.h b/include/scalehls/Utils/Visitor.h index a2d3a305..5b210244 100644 --- a/include/scalehls/Utils/Visitor.h +++ b/include/scalehls/Utils/Visitor.h @@ -58,7 +58,7 @@ class HLSVisitorBase { // Float binary expressions. arith::CmpFOp, arith::AddFOp, arith::SubFOp, arith::MulFOp, - arith::DivFOp, arith::RemFOp, arith::MaxFOp, arith::MinFOp, + arith::DivFOp, arith::RemFOp, arith::MaximumFOp, arith::MinimumFOp, math::PowFOp, // Integer binary expressions. @@ -171,8 +171,8 @@ class HLSVisitorBase { HANDLE(arith::MulFOp); HANDLE(arith::DivFOp); HANDLE(arith::RemFOp); - HANDLE(arith::MaxFOp); - HANDLE(arith::MinFOp); + HANDLE(arith::MaximumFOp); + HANDLE(arith::MinimumFOp); HANDLE(math::PowFOp); // Integer binary expressions. diff --git a/lib/Dialect/HLS/IR/HLS.cpp b/lib/Dialect/HLS/IR/HLS.cpp index 90178ceb..d23c93a8 100644 --- a/lib/Dialect/HLS/IR/HLS.cpp +++ b/lib/Dialect/HLS/IR/HLS.cpp @@ -8,6 +8,7 @@ #include "mlir/IR/DialectImplementation.h" #include "mlir/IR/IntegerSet.h" #include "scalehls/Dialect/HLS/Utils/Utils.h" +#include "scalehls/Utils/Utils.h" #include "llvm/ADT/TypeSwitch.h" using namespace mlir; @@ -145,7 +146,7 @@ struct AlwaysTrueOrFalseSelect : public OpRewritePattern { else if (set.getNumInputs() == 0) { SmallVector flagList; for (auto expr : llvm::enumerate(set.getConstraints())) { - auto constValue = expr.value().cast().getValue(); + auto constValue = cast(expr.value()).getValue(); flagList.push_back(set.isEq(expr.index()) ? constValue == 0 : constValue >= 0); } @@ -262,6 +263,16 @@ ParseResult AffineSelectOp::parse(OpAsmParser &parser, OperationState &result) { return success(); } +/// Prints dimension and symbol list. +static void printDimAndSymbolList(Operation::operand_iterator begin, + Operation::operand_iterator end, + unsigned numDims, OpAsmPrinter &printer) { + OperandRange operands(begin, end); + printer << '(' << operands.take_front(numDims) << ')'; + if (operands.size() > numDims) + printer << '[' << operands.drop_front(numDims) << ']'; +} + void AffineSelectOp::print(OpAsmPrinter &p) { auto conditionAttr = (*this)->getAttrOfType(getConditionAttrStrName()); diff --git a/lib/Dialect/HLS/Transforms/BufferizableOpInterfaceImpl.cpp b/lib/Dialect/HLS/Transforms/BufferizableOpInterfaceImpl.cpp index c2615a3f..bc7d1412 100644 --- a/lib/Dialect/HLS/Transforms/BufferizableOpInterfaceImpl.cpp +++ b/lib/Dialect/HLS/Transforms/BufferizableOpInterfaceImpl.cpp @@ -20,13 +20,13 @@ struct DispatchOrTaskOpInterface : public BufferizableOpInterface::ExternalModel< DispatchOrTaskOpInterface, OpType> { AliasingOpOperandList - getAliasingOpOperands(Operation *op, OpResult opResult, + getAliasingOpOperands(Operation *op, Value value, const AnalysisState &state) const { // Dispatch/task do not have tensor OpOperands. The yielded value can be any // SSA value that is in scope. To allow for use-def chain traversal in the // analysis, the yielded value is aliasing with the result. size_t resultNum = std::distance(op->getOpResults().begin(), - llvm::find(op->getOpResults(), opResult)); + llvm::find(op->getOpResults(), value)); OpOperand *operand = &cast(op).getYieldOp()->getOpOperand(resultNum); return {{operand, BufferRelation::Equivalent}}; @@ -63,7 +63,7 @@ struct DispatchOrTaskOpInterface FailureOr getBufferType(Operation *op, Value value, const BufferizationOptions &options, - const DenseMap &fixedTypes) const { + SmallVector &invocationStack) const { assert(value.getDefiningOp() == op && "invalid value"); auto yieldedValue = cast(op).getYieldOp().getOperand( value.cast().getResultNumber()); @@ -73,7 +73,7 @@ struct DispatchOrTaskOpInterface return bufferType; auto maybeBufferType = - bufferization::getBufferType(yieldedValue, options, fixedTypes); + bufferization::getBufferType(yieldedValue, options, invocationStack); if (failed(maybeBufferType)) return failure(); return *maybeBufferType; @@ -94,8 +94,8 @@ struct YieldOpInterface return false; } - AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand, - const AnalysisState &state) const { + AliasingValueList getAliasingOpResults(Operation *op, OpOperand &opOperand, + const AnalysisState &state) const { if (isa(op->getParentOp())) return {{op->getParentOp()->getResult(opOperand.getOperandNumber()), BufferRelation::Equivalent}}; @@ -172,19 +172,17 @@ struct AllocTensorOpInterface return false; } - bool bufferizesToAllocation(Operation *op, OpResult opResult) const { - return true; - } + bool bufferizesToAllocation(Operation *op, Value value) const { return true; } - AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand, - const AnalysisState &state) const { + AliasingValueList getAliasingOpResults(Operation *op, OpOperand &opOperand, + const AnalysisState &state) const { // This is a new allocation. It does not alias with any other buffer. return {}; } FailureOr getBufferType(Operation *op, Value value, const BufferizationOptions &options, - const DenseMap &fixedTypes) const { + SmallVector &invocationStack) const { auto allocTensor = cast(op); assert(value == allocTensor.getResult() && "invalid value"); @@ -256,8 +254,8 @@ struct InstanceOpInterface return success(); } - AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand, - const AnalysisState &state) const { + AliasingValueList getAliasingOpResults(Operation *op, OpOperand &opOperand, + const AnalysisState &state) const { // Output operands alias with their respective tied OpResults. auto instance = cast(op); if (instance.getPortKind(opOperand) == PortKind::OUTPUT) diff --git a/lib/Dialect/HLS/Transforms/SimplifyDesignSpace.cpp b/lib/Dialect/HLS/Transforms/SimplifyDesignSpace.cpp index a2682850..42b59c16 100644 --- a/lib/Dialect/HLS/Transforms/SimplifyDesignSpace.cpp +++ b/lib/Dialect/HLS/Transforms/SimplifyDesignSpace.cpp @@ -24,10 +24,10 @@ struct ConstantizeParamOpPattern : public OpRewritePattern { constValue = op.getCandidates().value()[0]; } else if (op.isRangeConstrained()) - if (auto constLb = op.getLowerBound().dyn_cast()) { + if (auto constLb = dyn_cast(op.getLowerBound())) { auto ub = op.getUpperBound(); auto diff = simplifyAffineExpr(ub - constLb, 0, op.getNumOperands()); - if (auto constDiff = diff.dyn_cast()) + if (auto constDiff = dyn_cast(diff)) if (constDiff.getValue() <= op.getStepAttr().getInt()) constValue = Builder(op.getContext()).getIndexAttr(constLb.getValue()); diff --git a/lib/Dialect/HLS/Utils/Matchers.cpp b/lib/Dialect/HLS/Utils/Matchers.cpp index 4dcb5cc3..7d7cba70 100644 --- a/lib/Dialect/HLS/Utils/Matchers.cpp +++ b/lib/Dialect/HLS/Utils/Matchers.cpp @@ -370,14 +370,14 @@ FailureOr IPMatcher::match() { // to generate corresponding buffer-level hls.instance. // Value matchedPort; - if (auto ipInputIndex = getIndex(ipLinalgOp.getDpsInputOperands())) { + if (auto ipInputIndex = getIndex(ipLinalgOp.getDpsInputs())) { // When the argument is "input" port, the "mapLhsArgIndexToRhs" is used // for the step 3) mapping. auto payloadInputIndex = linalgMatchingResult->mapLhsArgIndexToRhs(ipInputIndex.value()); matchedPort = payload.getDpsInputOperand(payloadInputIndex)->get(); - } else if (auto ipInitIndex = getIndex(ipLinalgOp.getDpsInitOperands())) { + } else if (auto ipInitIndex = getIndex(ipLinalgOp.getDpsInits())) { // When the argument is "initiation" port, the "mapLhsResIndexToRhs" is // used for the step 3) mapping. auto payloadInitIndex = diff --git a/lib/Transforms/ComprehensiveBufferize.cpp b/lib/Transforms/ComprehensiveBufferize.cpp index 364cdf4a..a33912c7 100644 --- a/lib/Transforms/ComprehensiveBufferize.cpp +++ b/lib/Transforms/ComprehensiveBufferize.cpp @@ -114,7 +114,7 @@ struct ComprehensiveBufferize OneShotBufferizationOptions options = getBufferizationOptions(); options.allocationFn = allocationFn; options.memCpyFn = memCpyFn; - options.allowReturnAllocs = true; + options.allowReturnAllocsFromLoops = true; options.bufferizeFunctionBoundaries = true; if (failed(runScaleHLSOneShotBufferize(moduleOp, options))) diff --git a/lib/Translation/EmitHLSCpp.cpp b/lib/Translation/EmitHLSCpp.cpp index 8d2ab94f..3c3f3af4 100644 --- a/lib/Translation/EmitHLSCpp.cpp +++ b/lib/Translation/EmitHLSCpp.cpp @@ -413,7 +413,7 @@ class AffineExprEmitter : public ScaleHLSEmitterBase, /// Affine expression emitters. void emitAffineBinary(AffineBinaryOpExpr expr, const char *syntax) { os << "("; - if (auto constRHS = expr.getRHS().dyn_cast()) { + if (auto constRHS = dyn_cast(expr.getRHS())) { if ((unsigned)*syntax == (unsigned)*"*" && constRHS.getValue() == -1) { os << "-"; visit(expr.getLHS()); @@ -428,8 +428,8 @@ class AffineExprEmitter : public ScaleHLSEmitterBase, return; } } - if (auto binaryRHS = expr.getRHS().dyn_cast()) { - if (auto constRHS = binaryRHS.getRHS().dyn_cast()) { + if (auto binaryRHS = dyn_cast(expr.getRHS())) { + if (auto constRHS = dyn_cast(binaryRHS.getRHS())) { if ((unsigned)*syntax == (unsigned)*"+" && constRHS.getValue() == -1 && binaryRHS.getKind() == AffineExprKind::Mul) { visit(expr.getLHS()); @@ -593,8 +593,12 @@ class ExprVisitor : public HLSVisitorBase { bool visitOp(arith::MulFOp op) { return emitter.emitBinary(op, "*"), true; } bool visitOp(arith::DivFOp op) { return emitter.emitBinary(op, "/"), true; } bool visitOp(arith::RemFOp op) { return emitter.emitBinary(op, "%"), true; } - bool visitOp(arith::MaxFOp op) { return emitter.emitMaxMin(op, "max"), true; } - bool visitOp(arith::MinFOp op) { return emitter.emitMaxMin(op, "min"), true; } + bool visitOp(arith::MaximumFOp op) { + return emitter.emitMaxMin(op, "max"), true; + } + bool visitOp(arith::MinimumFOp op) { + return emitter.emitMaxMin(op, "min"), true; + } bool visitOp(math::PowFOp op) { return emitter.emitMaxMin(op, "pow"), true; } /// Integer binary expressions. @@ -1228,7 +1232,8 @@ void ModuleEmitter::emitAffineYield(affine::AffineYieldOp op) { os << " = "; emitValue(op.getOperand(resultIdx++), rank); break; - case (arith::AtomicRMWKind::maxf): + case (arith::AtomicRMWKind::maximumf): + case (arith::AtomicRMWKind::maxnumf): case (arith::AtomicRMWKind::maxs): case (arith::AtomicRMWKind::maxu): os << " = max("; @@ -1237,7 +1242,8 @@ void ModuleEmitter::emitAffineYield(affine::AffineYieldOp op) { emitValue(op.getOperand(resultIdx++), rank); os << ")"; break; - case (arith::AtomicRMWKind::minf): + case (arith::AtomicRMWKind::minimumf): + case (arith::AtomicRMWKind::minnumf): case (arith::AtomicRMWKind::mins): case (arith::AtomicRMWKind::minu): os << " = min("; @@ -1283,7 +1289,7 @@ ModuleEmitter::getTransferIndices(TransferOpType op) { // Construct the physical indices. for (unsigned i = 0, e = op.getPermutationMap().getNumResults(); i < e; ++i) { auto expr = op.getPermutationMap().getResult(i); - if (auto dimExpr = expr.template dyn_cast()) + if (auto dimExpr = dyn_cast(expr)) indices[dimExpr.getPosition()] += " + iv" + std::to_string(i); } return indices; @@ -1304,7 +1310,7 @@ getTransferCondition(TransferOpType op, SmallString<16> condition; for (auto i : outOfBoundDims) { auto expr = op.getPermutationMap().getResult(i); - if (auto dimExpr = expr.template dyn_cast()) { + if (auto dimExpr = dyn_cast(expr)) { auto pos = dimExpr.getPosition(); condition += indices[pos]; condition += " < " + std::to_string(op.getShapedType().getDimSize(pos)); @@ -1320,7 +1326,7 @@ void ModuleEmitter::emitInsert(vector::InsertOp op) { addAlias(op.getDest(), op.getResult()); indent(); emitValue(op.getDest()); - os << "[" << op.getPosition()[0].cast().getInt() << "] = "; + os << "[" << op.getStaticPosition()[0] << "] = "; emitValue(op.getSource()); os << ";"; emitInfoAndNewLine(op); @@ -1331,7 +1337,7 @@ void ModuleEmitter::emitExtract(vector::ExtractOp op) { emitValue(op.getResult()); os << " = "; emitValue(op.getVector()); - os << "[" << op.getPosition()[0].cast().getInt() << "];"; + os << "[" << op.getStaticPosition()[0] << "];"; emitInfoAndNewLine(op); } diff --git a/lib/Utils/Utils.cpp b/lib/Utils/Utils.cpp index 1e64f9ba..269db5e7 100644 --- a/lib/Utils/Utils.cpp +++ b/lib/Utils/Utils.cpp @@ -265,6 +265,146 @@ LogicalResult scalehls::getEvenlyDistributedFactors( return success(); } +/// Replace all occurrences of AffineExpr at position `pos` in `map` by the +/// defining AffineApplyOp expression and operands. +/// When `dimOrSymbolPosition < dims.size()`, AffineDimExpr@[pos] is replaced. +/// When `dimOrSymbolPosition >= dims.size()`, +/// AffineSymbolExpr@[pos - dims.size()] is replaced. +/// Mutate `map`,`dims` and `syms` in place as follows: +/// 1. `dims` and `syms` are only appended to. +/// 2. `map` dim and symbols are gradually shifted to higher positions. +/// 3. Old `dim` and `sym` entries are replaced by nullptr +/// This avoids the need for any bookkeeping. +static LogicalResult replaceDimOrSym(AffineMap *map, + unsigned dimOrSymbolPosition, + SmallVectorImpl &dims, + SmallVectorImpl &syms) { + MLIRContext *ctx = map->getContext(); + bool isDimReplacement = (dimOrSymbolPosition < dims.size()); + unsigned pos = isDimReplacement ? dimOrSymbolPosition + : dimOrSymbolPosition - dims.size(); + Value &v = isDimReplacement ? dims[pos] : syms[pos]; + if (!v) + return failure(); + + auto affineApply = v.getDefiningOp(); + if (!affineApply) + return failure(); + + // At this point we will perform a replacement of `v`, set the entry in `dim` + // or `sym` to nullptr immediately. + v = nullptr; + + // Compute the map, dims and symbols coming from the AffineApplyOp. + AffineMap composeMap = affineApply.getAffineMap(); + assert(composeMap.getNumResults() == 1 && "affine.apply with >1 results"); + SmallVector composeOperands(affineApply.getMapOperands().begin(), + affineApply.getMapOperands().end()); + // Canonicalize the map to promote dims to symbols when possible. This is to + // avoid generating invalid maps. + canonicalizeMapAndOperands(&composeMap, &composeOperands); + AffineExpr replacementExpr = + composeMap.shiftDims(dims.size()).shiftSymbols(syms.size()).getResult(0); + ValueRange composeDims = + ArrayRef(composeOperands).take_front(composeMap.getNumDims()); + ValueRange composeSyms = + ArrayRef(composeOperands).take_back(composeMap.getNumSymbols()); + AffineExpr toReplace = isDimReplacement ? getAffineDimExpr(pos, ctx) + : getAffineSymbolExpr(pos, ctx); + + // Append the dims and symbols where relevant and perform the replacement. + dims.append(composeDims.begin(), composeDims.end()); + syms.append(composeSyms.begin(), composeSyms.end()); + *map = map->replace(toReplace, replacementExpr, dims.size(), syms.size()); + + return success(); +} + +/// Iterate over `operands` and fold away all those produced by an AffineApplyOp +/// iteratively. Perform canonicalization of map and operands as well as +/// AffineMap simplification. `map` and `operands` are mutated in place. +static void composeAffineMapAndOperands(AffineMap *map, + SmallVectorImpl *operands) { + if (map->getNumResults() == 0) { + canonicalizeMapAndOperands(map, operands); + *map = simplifyAffineMap(*map); + return; + } + + MLIRContext *ctx = map->getContext(); + SmallVector dims(operands->begin(), + operands->begin() + map->getNumDims()); + SmallVector syms(operands->begin() + map->getNumDims(), + operands->end()); + + // Iterate over dims and symbols coming from AffineApplyOp and replace until + // exhaustion. This iteratively mutates `map`, `dims` and `syms`. Both `dims` + // and `syms` can only increase by construction. + // The implementation uses a `while` loop to support the case of symbols + // that may be constructed from dims ;this may be overkill. + while (true) { + bool changed = false; + for (unsigned pos = 0; pos != dims.size() + syms.size(); ++pos) + if ((changed |= succeeded(replaceDimOrSym(map, pos, dims, syms)))) + break; + if (!changed) + break; + } + + // Clear operands so we can fill them anew. + operands->clear(); + + // At this point we may have introduced null operands, prune them out before + // canonicalizing map and operands. + unsigned nDims = 0, nSyms = 0; + SmallVector dimReplacements, symReplacements; + dimReplacements.reserve(dims.size()); + symReplacements.reserve(syms.size()); + for (auto *container : {&dims, &syms}) { + bool isDim = (container == &dims); + auto &repls = isDim ? dimReplacements : symReplacements; + for (const auto &en : llvm::enumerate(*container)) { + Value v = en.value(); + if (!v) { + assert(isDim ? !map->isFunctionOfDim(en.index()) + : !map->isFunctionOfSymbol(en.index()) && + "map is function of unexpected expr@pos"); + repls.push_back(getAffineConstantExpr(0, ctx)); + continue; + } + repls.push_back(isDim ? getAffineDimExpr(nDims++, ctx) + : getAffineSymbolExpr(nSyms++, ctx)); + operands->push_back(v); + } + } + *map = map->replaceDimsAndSymbols(dimReplacements, symReplacements, nDims, + nSyms); + + // Canonicalize and simplify before returning. + canonicalizeMapAndOperands(map, operands); + *map = simplifyAffineMap(*map); +} + +/// Compose any affine.apply ops feeding into `operands` of the integer set +/// `set` by composing the maps of such affine.apply ops with the integer +/// set constraints. +void scalehls::composeSetAndOperands(IntegerSet &set, + SmallVectorImpl &operands) { + // We will simply reuse the API of the map composition by viewing the LHSs of + // the equalities and inequalities of `set` as the affine exprs of an affine + // map. Convert to equivalent map, compose, and convert back to set. + auto map = AffineMap::get(set.getNumDims(), set.getNumSymbols(), + set.getConstraints(), set.getContext()); + // Check if any composition is possible. + if (llvm::none_of(operands, + [](Value v) { return v.getDefiningOp(); })) + return; + + composeAffineMapAndOperands(&map, &operands); + set = IntegerSet::get(map.getNumDims(), map.getNumSymbols(), map.getResults(), + set.getEqFlags()); +} + /// Return a pair which indicates whether the if statement is always true or /// false, respectively. The returned result is one-hot. std::pair scalehls::ifAlwaysTrueOrFalse(AffineIfOp ifOp) { @@ -305,7 +445,7 @@ std::pair scalehls::ifAlwaysTrueOrFalse(AffineIfOp ifOp) { unsigned idx = 0; for (auto expr : set.getConstraints()) { bool eqFlag = set.isEq(idx++); - auto constValue = expr.cast().getValue(); + auto constValue = cast(expr).getValue(); if (eqFlag) flagList.push_back(constValue == 0); @@ -490,7 +630,7 @@ scalehls::getBoundOfAffineMap(AffineMap map, ValueRange operands) { auto lb = forOp.getConstantLowerBound(); auto ub = forOp.getConstantUpperBound(); - auto step = forOp.getStep(); + auto step = forOp.getStep().getSExtValue(); lbs.push_back(lb); ubs.push_back(ub - 1 - (ub - 1 - lb) % step); @@ -509,7 +649,7 @@ scalehls::getBoundOfAffineMap(AffineMap map, ValueRange operands) { } auto newExpr = map.getResult(0).replaceDimsAndSymbols(replacements, {}); - if (auto constExpr = newExpr.dyn_cast()) + if (auto constExpr = dyn_cast(newExpr)) results.push_back(constExpr.getValue()); else return std::optional>(); diff --git a/llvm-project b/llvm-project index 7e125f83..23b82c98 160000 --- a/llvm-project +++ b/llvm-project @@ -1 +1 @@ -Subproject commit 7e125f8382c0124f4375a3a94b08d7eb78ea0ff2 +Subproject commit 23b82c987d690939f3e7b1431d6004f409c10425 diff --git a/test/EmitHLSCpp/test-affine-loop.mlir b/test/EmitHLSCpp/test-affine-loop.mlir index 3661f053..0a165bdf 100644 --- a/test/EmitHLSCpp/test-affine-loop.mlir +++ b/test/EmitHLSCpp/test-affine-loop.mlir @@ -32,37 +32,3 @@ func.func @test_affine_for(%arg0: memref<16xindex>, %arg1: index) { } return } - -func.func @test_affine_parallel(%arg0: memref<16xindex>) { - - // CHECK: int v8; - // CHECK: int v9; - // CHECK: for (int v10 = 0; v10 < 2; v10 += 1) { - // CHECK: for (int v11 = 0; v11 < 4; v11 += 2) { - // CHECK: for (int v12 = 0; v12 < 8; v12 += 3) { - %0:2 = affine.parallel (%x, %y, %z) = (0, 0, 0) to (2, 4, 8) step (1, 2, 3) reduce ("maxs", "addi") -> (index, index){ - - // CHECK: int v13 = v7[v10]; - %1 = memref.load %arg0[%x] : memref<16xindex> - - // CHECK: int v14 = v13 + v11; - %2 = arith.addi %1, %y : index - - // CHECK: int v15 = v14 - v12; - %3 = arith.subi %2, %z : index - - // CHECK: if (v10 == 0 && v11 == 0 && v12 == 0) { - // CHECK: v8 = v14; - // CHECK: v9 = v15; - // CHECK: } else { - // CHECK: v8 = max(v8, v14); - // CHECK: v9 += v15; - // CHECK: } - affine.yield %2, %3 : index, index - - // CHECK: } - // CHECK: } - // CHECK: } - } - return -} diff --git a/test/EmitHLSCpp/test-expression.mlir b/test/EmitHLSCpp/test-expression.mlir index a3a12181..04b24cca 100644 --- a/test/EmitHLSCpp/test-expression.mlir +++ b/test/EmitHLSCpp/test-expression.mlir @@ -78,10 +78,10 @@ func.func @test_float_binary_unary(%arg0: f32, %arg1: f32) -> f32 { %17 = math.log10 %16 : f32 // CHECK: float [[VAL_4:.*]] = max([[ARG_0:.*]], [[VAL_3:.*]]); - %18 = arith.maxf %arg0, %17 : f32 + %18 = arith.maximumf %arg0, %17 : f32 // CHECK: *[[VAL_5:.*]] = min([[ARG_0:.*]], [[VAL_4]]); - %19 = arith.minf %arg0, %18 : f32 + %19 = arith.minimumf %arg0, %18 : f32 return %19 : f32 }