From 76cebadc6d1460ad0b882b0ec58e89c24b124556 Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Tue, 10 Dec 2024 15:55:33 +0000 Subject: [PATCH 01/10] Fix bug where emitc constants wouldn't be directly emitted in subscripts. --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 85 +++++++++++-------- .../Cpp/emitc-constants-as-variables.mlir | 12 ++- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index a2e368e502737..22396e6d4f0b5 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -297,6 +297,9 @@ struct CppEmitter { return lowestPrecedence(); return emittedExpressionPrecedence.back(); } + + LogicalResult emitAttributeToArbitraryStream(Location loc, Attribute attr, + raw_ostream &ss); }; } // namespace @@ -1290,7 +1293,15 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { llvm::raw_string_ostream ss(out); ss << getOrCreateName(op.getValue()); for (auto index : op.getIndices()) { - ss << "[" << getOrCreateName(index) << "]"; + ss << "["; + if (auto constant = dyn_cast_if_present(index.getDefiningOp()); + constant && !shouldUseConstantsAsVariables()) { + assert(llvm::succeeded(emitAttributeToArbitraryStream( + op->getLoc(), constant.getValue(), ss))); + } else { + ss << getOrCreateName(index); + } + ss << "]"; } return out; } @@ -1353,16 +1364,22 @@ bool CppEmitter::hasBlockLabel(Block &block) { } LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { + return CppEmitter::emitAttributeToArbitraryStream(loc, attr, os); +} + +LogicalResult CppEmitter::emitAttributeToArbitraryStream(Location loc, + Attribute attr, + raw_ostream &ss) { auto printInt = [&](const APInt &val, bool isUnsigned) { if (val.getBitWidth() == 1) { if (val.getBoolValue()) - os << "true"; + ss << "true"; else - os << "false"; + ss << "false"; } else { SmallString<128> strValue; val.toString(strValue, 10, !isUnsigned, false); - os << strValue; + ss << strValue; } }; @@ -1371,16 +1388,16 @@ LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { SmallString<128> strValue; // Use default values of toString except don't truncate zeros. val.toString(strValue, 0, 0, false); - os << strValue; + ss << strValue; switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) { case llvm::APFloatBase::S_IEEEhalf: - os << "f16"; + ss << "f16"; break; case llvm::APFloatBase::S_BFloat: - os << "bf16"; + ss << "bf16"; break; case llvm::APFloatBase::S_IEEEsingle: - os << "f"; + ss << "f"; break; case llvm::APFloatBase::S_IEEEdouble: break; @@ -1388,11 +1405,11 @@ LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { llvm_unreachable("unsupported floating point type"); }; } else if (val.isNaN()) { - os << "NAN"; + ss << "NAN"; } else if (val.isInfinity()) { if (val.isNegative()) - os << "-"; - os << "INFINITY"; + ss << "-"; + ss << "INFINITY"; } }; @@ -1412,9 +1429,9 @@ LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { return emitError( loc, "expected floating point attribute to be f16, bf16, f32 or f64"); } - os << '{'; - interleaveComma(dense, os, [&](const APFloat &val) { printFloat(val); }); - os << '}'; + ss << '{'; + interleaveComma(dense, ss, [&](const APFloat &val) { printFloat(val); }); + ss << '}'; return success(); } @@ -1432,26 +1449,26 @@ LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { if (auto dense = dyn_cast(attr)) { if (auto iType = dyn_cast( cast(dense.getType()).getElementType())) { - os << '{'; - interleaveComma(dense, os, [&](const APInt &val) { + ss << '{'; + interleaveComma(dense, ss, [&](const APInt &val) { printInt(val, shouldMapToUnsigned(iType.getSignedness())); }); - os << '}'; + ss << '}'; return success(); } if (auto iType = dyn_cast( cast(dense.getType()).getElementType())) { - os << '{'; - interleaveComma(dense, os, + ss << '{'; + interleaveComma(dense, ss, [&](const APInt &val) { printInt(val, false); }); - os << '}'; + ss << '}'; return success(); } } // Print opaque attributes. if (auto oAttr = dyn_cast(attr)) { - os << oAttr.getValue(); + ss << oAttr.getValue(); return success(); } @@ -1459,7 +1476,7 @@ LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { if (auto sAttr = dyn_cast(attr)) { if (sAttr.getNestedReferences().size() > 1) return emitError(loc, "attribute has more than 1 nested reference"); - os << sAttr.getRootReference().getValue(); + ss << sAttr.getRootReference().getValue(); return success(); } @@ -1494,21 +1511,21 @@ LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) { LogicalResult CppEmitter::emitOperand(Value value) { Operation *def = value.getDefiningOp(); - if (!shouldUseConstantsAsVariables()) { - if (auto constant = dyn_cast_if_present(def)) { - os << "(("; - if (failed(emitType(constant.getLoc(), constant.getType()))) { - return failure(); - } - os << ") "; + if (auto constant = dyn_cast_if_present(def); + constant && !shouldUseConstantsAsVariables()) { + os << "(("; - if (failed(emitAttribute(constant.getLoc(), constant.getValue()))) { - return failure(); - } - os << ")"; - return success(); + if (failed(emitType(constant.getLoc(), constant.getType()))) { + return failure(); + } + os << ") "; + + if (failed(emitAttribute(constant.getLoc(), constant.getValue()))) { + return failure(); } + os << ")"; + return success(); } if (isPartOfCurrentExpression(value)) { diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index 5774bdc47308f..0ee4a4cbd8426 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -11,9 +11,19 @@ func.func @test() { return } - // CPP-DEFAULT: void test() { // CPP-DEFAULT-NEXT: for (size_t v1 = ((size_t) 0); v1 < ((size_t) 10); v1 += ((size_t) 1)) { // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: return; // CPP-DEFAULT-NEXT: } + +// ----- + +func.func @test_subscript(%arg0: !emitc.array<4xf32>) -> (!emitc.lvalue) { + %c0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t + %0 = emitc.subscript %arg0[%c0] : (!emitc.array<4xf32>, !emitc.size_t) -> !emitc.lvalue + return %0 : !emitc.lvalue +} +// CPP-DEFAULT: float test_subscript(float v1[4]) { +// CPP-DEFAULT-NEXT: return v1[0]; +// CPP-DEFAULT-NEXT: } \ No newline at end of file From e1f758dde45393efad0a575cd093b1719c1278f2 Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Tue, 10 Dec 2024 16:04:30 +0000 Subject: [PATCH 02/10] Forgot trailing newline --- mlir/test/Target/Cpp/emitc-constants-as-variables.mlir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index 0ee4a4cbd8426..50df9ab035630 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -26,4 +26,4 @@ func.func @test_subscript(%arg0: !emitc.array<4xf32>) -> (!emitc.lvalue) { } // CPP-DEFAULT: float test_subscript(float v1[4]) { // CPP-DEFAULT-NEXT: return v1[0]; -// CPP-DEFAULT-NEXT: } \ No newline at end of file +// CPP-DEFAULT-NEXT: } From f5bbcfe80ee21161848f725780e19cde3fd5bf44 Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Wed, 11 Dec 2024 12:49:13 +0000 Subject: [PATCH 03/10] Cover more casses of improper non-variable ConstantOp prints --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 39 +++++++++--------- .../Cpp/emitc-constants-as-variables.mlir | 41 ++++++++++++++++++- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 22396e6d4f0b5..fcc864ab33a0c 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -298,8 +298,8 @@ struct CppEmitter { return emittedExpressionPrecedence.back(); } - LogicalResult emitAttributeToArbitraryStream(Location loc, Attribute attr, - raw_ostream &ss); + LogicalResult emitAttributeToStream(Location loc, Attribute attr, + raw_ostream &ss); }; } // namespace @@ -1293,15 +1293,7 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { llvm::raw_string_ostream ss(out); ss << getOrCreateName(op.getValue()); for (auto index : op.getIndices()) { - ss << "["; - if (auto constant = dyn_cast_if_present(index.getDefiningOp()); - constant && !shouldUseConstantsAsVariables()) { - assert(llvm::succeeded(emitAttributeToArbitraryStream( - op->getLoc(), constant.getValue(), ss))); - } else { - ss << getOrCreateName(index); - } - ss << "]"; + ss << "[" << getOrCreateName(index) << "]"; } return out; } @@ -1330,10 +1322,20 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { if (!valueMapper.count(val)) { - assert(!hasDeferredEmission(val.getDefiningOp()) && - "cacheDeferredOpResult should have been called on this value, " - "update the emitOperation function."); - valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); + if (auto constant = dyn_cast_if_present(val.getDefiningOp()); + constant && !shouldUseConstantsAsVariables()) { + std::string constantValueString; + llvm::raw_string_ostream ss(constantValueString); + bool success = llvm::succeeded( + emitAttributeToStream(val.getLoc(), constant.getValue(), ss)); + assert(success); + valueMapper.insert(val, constantValueString); + } else { + assert(!hasDeferredEmission(val.getDefiningOp()) && + "cacheDeferredOpResult should have been called on this value, " + "update the emitOperation function."); + valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); + } } return *valueMapper.begin(val); } @@ -1364,12 +1366,11 @@ bool CppEmitter::hasBlockLabel(Block &block) { } LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { - return CppEmitter::emitAttributeToArbitraryStream(loc, attr, os); + return CppEmitter::emitAttributeToStream(loc, attr, os); } -LogicalResult CppEmitter::emitAttributeToArbitraryStream(Location loc, - Attribute attr, - raw_ostream &ss) { +LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, + raw_ostream &ss) { auto printInt = [&](const APInt &val, bool isUnsigned) { if (val.getBitWidth() == 1) { if (val.getBoolValue()) diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index 50df9ab035630..532688eff127b 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -11,7 +11,7 @@ func.func @test() { return } -// CPP-DEFAULT: void test() { +// CPP-DEFAULT-LABEL: void test() { // CPP-DEFAULT-NEXT: for (size_t v1 = ((size_t) 0); v1 < ((size_t) 10); v1 += ((size_t) 1)) { // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: return; @@ -24,6 +24,43 @@ func.func @test_subscript(%arg0: !emitc.array<4xf32>) -> (!emitc.lvalue) { %0 = emitc.subscript %arg0[%c0] : (!emitc.array<4xf32>, !emitc.size_t) -> !emitc.lvalue return %0 : !emitc.lvalue } -// CPP-DEFAULT: float test_subscript(float v1[4]) { +// CPP-DEFAULT-LABEL: float test_subscript(float v1[4]) { // CPP-DEFAULT-NEXT: return v1[0]; // CPP-DEFAULT-NEXT: } + +// ----- + +func.func @emitc_switch_ui64() { + %0 = "emitc.constant"(){value = 1 : ui64} : () -> ui64 + + emitc.switch %0 : ui64 + case 2 { + %1 = emitc.call_opaque "func_b" () : () -> i32 + emitc.yield + } + case 5 { + %2 = emitc.call_opaque "func_a" () : () -> i32 + emitc.yield + } + default { + emitc.call_opaque "func2" (%0) : (ui64) -> () + emitc.yield + } + return +} +// CPP-DEFAULT-LABEL: void emitc_switch_ui64() { +// CPP-DEFAULT: switch (1) { +// CPP-DEFAULT-NEXT: case 2: { +// CPP-DEFAULT-NEXT: int32_t v1 = func_b(); +// CPP-DEFAULT-NEXT: break; +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: case 5: { +// CPP-DEFAULT-NEXT: int32_t v2 = func_a(); +// CPP-DEFAULT-NEXT: break; +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: default: { +// CPP-DEFAULT-NEXT: func2(((uint64_t) 1)); +// CPP-DEFAULT-NEXT: break; +// CPP-DEFAULT-NEXT: } +// CPP-DEFAULT-NEXT: return; +// CPP-DEFAULT-NEXT: } From 570e8b80607bb552a062e65ca0b0c939dccc3204 Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Wed, 11 Dec 2024 13:40:53 +0000 Subject: [PATCH 04/10] Refactor ConstantOp printing to enable caching --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 101 ++++++++++-------- .../Cpp/emitc-constants-as-variables.mlir | 23 +++- 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index fcc864ab33a0c..5a8597ff86ebd 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -298,8 +298,17 @@ struct CppEmitter { return emittedExpressionPrecedence.back(); } + /// Emits attribute to the specified stream or returns failure. LogicalResult emitAttributeToStream(Location loc, Attribute attr, raw_ostream &ss); + + /// Emits type 'type' to the specified stream or returns failure. + LogicalResult emitTypeToStream(Location loc, Type type, raw_ostream &ss); + + /// Emits array of types as a std::tuple of the emitted types independently of + /// the array size to the specified stream. + LogicalResult emitTupleTypeToStream(Location loc, ArrayRef types, + raw_ostream &ss); }; } // namespace @@ -1326,9 +1335,17 @@ StringRef CppEmitter::getOrCreateName(Value val) { constant && !shouldUseConstantsAsVariables()) { std::string constantValueString; llvm::raw_string_ostream ss(constantValueString); - bool success = llvm::succeeded( + + ss << "("; + bool success = + succeeded(emitTypeToStream(val.getLoc(), constant.getType(), ss)); + assert(success); + ss << ") "; + + success = succeeded( emitAttributeToStream(val.getLoc(), constant.getValue(), ss)); assert(success); + valueMapper.insert(val, constantValueString); } else { assert(!hasDeferredEmission(val.getDefiningOp()) && @@ -1513,22 +1530,6 @@ LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) { LogicalResult CppEmitter::emitOperand(Value value) { Operation *def = value.getDefiningOp(); - if (auto constant = dyn_cast_if_present(def); - constant && !shouldUseConstantsAsVariables()) { - os << "(("; - - if (failed(emitType(constant.getLoc(), constant.getType()))) { - return failure(); - } - os << ") "; - - if (failed(emitAttribute(constant.getLoc(), constant.getValue()))) { - return failure(); - } - os << ")"; - return success(); - } - if (isPartOfCurrentExpression(value)) { assert(def && "Expected operand to be defined by an operation"); FailureOr precedence = getOperatorPrecedence(def); @@ -1827,18 +1828,23 @@ LogicalResult CppEmitter::emitReferenceToType(Location loc, Type type) { } LogicalResult CppEmitter::emitType(Location loc, Type type) { + return emitTypeToStream(loc, type, os); +} + +LogicalResult CppEmitter::emitTypeToStream(Location loc, Type type, + raw_ostream &ss) { if (auto iType = dyn_cast(type)) { switch (iType.getWidth()) { case 1: - return (os << "bool"), success(); + return (ss << "bool"), success(); case 8: case 16: case 32: case 64: if (shouldMapToUnsigned(iType.getSignedness())) - return (os << "uint" << iType.getWidth() << "_t"), success(); + return (ss << "uint" << iType.getWidth() << "_t"), success(); else - return (os << "int" << iType.getWidth() << "_t"), success(); + return (ss << "int" << iType.getWidth() << "_t"), success(); default: return emitError(loc, "cannot emit integer type ") << type; } @@ -1847,48 +1853,48 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { switch (fType.getWidth()) { case 16: { if (llvm::isa(type)) - return (os << "_Float16"), success(); + return (ss << "_Float16"), success(); else if (llvm::isa(type)) - return (os << "__bf16"), success(); + return (ss << "__bf16"), success(); else return emitError(loc, "cannot emit float type ") << type; } case 32: - return (os << "float"), success(); + return (ss << "float"), success(); case 64: - return (os << "double"), success(); + return (ss << "double"), success(); default: return emitError(loc, "cannot emit float type ") << type; } } if (auto iType = dyn_cast(type)) - return (os << "size_t"), success(); + return (ss << "size_t"), success(); if (auto sType = dyn_cast(type)) - return (os << "size_t"), success(); + return (ss << "size_t"), success(); if (auto sType = dyn_cast(type)) - return (os << "ssize_t"), success(); + return (ss << "ssize_t"), success(); if (auto pType = dyn_cast(type)) - return (os << "ptrdiff_t"), success(); + return (ss << "ptrdiff_t"), success(); if (auto tType = dyn_cast(type)) { if (!tType.hasRank()) return emitError(loc, "cannot emit unranked tensor type"); if (!tType.hasStaticShape()) return emitError(loc, "cannot emit tensor type with non static shape"); - os << "Tensor<"; + ss << "Tensor<"; if (isa(tType.getElementType())) return emitError(loc, "cannot emit tensor of array type ") << type; - if (failed(emitType(loc, tType.getElementType()))) + if (failed(emitTypeToStream(loc, tType.getElementType(), ss))) return failure(); auto shape = tType.getShape(); for (auto dimSize : shape) { - os << ", "; - os << dimSize; + ss << ", "; + ss << dimSize; } - os << ">"; + ss << ">"; return success(); } if (auto tType = dyn_cast(type)) - return emitTupleType(loc, tType.getTypes()); + return emitTupleTypeToStream(loc, tType.getTypes(), ss); if (auto oType = dyn_cast(type)) { FailureOr> items = oType.parseFormatString(); if (failed(items)) @@ -1897,9 +1903,9 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { auto fmtArg = oType.getFmtArgs().begin(); for (ReplacementItem &item : *items) { if (auto *str = std::get_if(&item)) { - os << *str; + ss << *str; } else { - if (failed(emitType(loc, *fmtArg++))) { + if (failed(emitTypeToStream(loc, *fmtArg++, ss))) { return failure(); } } @@ -1907,24 +1913,24 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { return success(); - os << oType.getValue(); + ss << oType.getValue(); return success(); } if (auto aType = dyn_cast(type)) { - if (failed(emitType(loc, aType.getElementType()))) + if (failed(emitTypeToStream(loc, aType.getElementType(), ss))) return failure(); for (auto dim : aType.getShape()) - os << "[" << dim << "]"; + ss << "[" << dim << "]"; return success(); } if (auto lType = dyn_cast(type)) - return emitType(loc, lType.getValueType()); + return emitTypeToStream(loc, lType.getValueType(), ss); if (auto pType = dyn_cast(type)) { if (isa(pType.getPointee())) return emitError(loc, "cannot emit pointer to array type ") << type; - if (failed(emitType(loc, pType.getPointee()))) + if (failed(emitTypeToStream(loc, pType.getPointee(), ss))) return failure(); - os << "*"; + ss << "*"; return success(); } return emitError(loc, "cannot emit type ") << type; @@ -1943,14 +1949,19 @@ LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef types) { } LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { + return emitTupleTypeToStream(loc, types, os); +} +LogicalResult CppEmitter::emitTupleTypeToStream(Location loc, + ArrayRef types, + raw_ostream &ss) { if (llvm::any_of(types, llvm::IsaPred)) { return emitError(loc, "cannot emit tuple of array type"); } - os << "std::tuple<"; + ss << "std::tuple<"; if (failed(interleaveCommaWithError( - types, os, [&](Type type) { return emitType(loc, type); }))) + types, ss, [&](Type type) { return emitType(loc, type); }))) return failure(); - os << ">"; + ss << ">"; return success(); } diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index 532688eff127b..065c1a3c65d3f 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -12,7 +12,7 @@ func.func @test() { return } // CPP-DEFAULT-LABEL: void test() { -// CPP-DEFAULT-NEXT: for (size_t v1 = ((size_t) 0); v1 < ((size_t) 10); v1 += ((size_t) 1)) { +// CPP-DEFAULT-NEXT: for (size_t v1 = (size_t) 0; v1 < (size_t) 10; v1 += (size_t) 1) { // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: return; // CPP-DEFAULT-NEXT: } @@ -25,7 +25,7 @@ func.func @test_subscript(%arg0: !emitc.array<4xf32>) -> (!emitc.lvalue) { return %0 : !emitc.lvalue } // CPP-DEFAULT-LABEL: float test_subscript(float v1[4]) { -// CPP-DEFAULT-NEXT: return v1[0]; +// CPP-DEFAULT-NEXT: return v1[(size_t) 0]; // CPP-DEFAULT-NEXT: } // ----- @@ -49,7 +49,7 @@ func.func @emitc_switch_ui64() { return } // CPP-DEFAULT-LABEL: void emitc_switch_ui64() { -// CPP-DEFAULT: switch (1) { +// CPP-DEFAULT: switch ((uint64_t) 1) { // CPP-DEFAULT-NEXT: case 2: { // CPP-DEFAULT-NEXT: int32_t v1 = func_b(); // CPP-DEFAULT-NEXT: break; @@ -59,8 +59,23 @@ func.func @emitc_switch_ui64() { // CPP-DEFAULT-NEXT: break; // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: default: { -// CPP-DEFAULT-NEXT: func2(((uint64_t) 1)); +// CPP-DEFAULT-NEXT: func2((uint64_t) 1); // CPP-DEFAULT-NEXT: break; // CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: return; // CPP-DEFAULT-NEXT: } + +// ----- + +func.func @negative_values() { + %1 = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t + %2 = "emitc.constant"() <{value = -3000000000 : index}> : () -> !emitc.size_t + + %3 = emitc.add %1, %2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + + return +} +// CPP-DEFAULT-LABEL: void negative_values() { +// CPP-DEFAULT-NEXT: size_t v1 = (size_t) 10 + (size_t) -3000000000; +// CPP-DEFAULT-NEXT: return; +// CPP-DEFAULT-NEXT: } \ No newline at end of file From 1f87ef480b475feb7c1028a0d78684d2d7e8ffe4 Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Wed, 11 Dec 2024 16:01:18 +0000 Subject: [PATCH 05/10] Use emitOperand in all relevant locations as not only variable references are emited in the cpp code. --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 72 +++++++++++++++----------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 5a8597ff86ebd..5aa76822cbcc5 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -505,7 +505,11 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::SwitchOp switchOp) { raw_indented_ostream &os = emitter.ostream(); - os << "\nswitch (" << emitter.getOrCreateName(switchOp.getArg()) << ") {"; + os << "\nswitch ("; + if (failed(emitter.emitOperand(switchOp.getArg()))) { + return failure(); + } + os << ") {"; for (auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) { os << "\ncase " << std::get<0>(pair) << ": {\n"; @@ -614,8 +618,10 @@ static LogicalResult printOperation(CppEmitter &emitter, llvm::zip(branchOp.getOperands(), successor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = " - << emitter.getOrCreateName(operand) << ";\n"; + os << emitter.getOrCreateName(argument) << " = "; + if (failed(emitter.emitOperand(operand))) + return failure(); + os << ";\n"; } os << "goto "; @@ -631,8 +637,10 @@ static LogicalResult printOperation(CppEmitter &emitter, Block &trueSuccessor = *condBranchOp.getTrueDest(); Block &falseSuccessor = *condBranchOp.getFalseDest(); - os << "if (" << emitter.getOrCreateName(condBranchOp.getCondition()) - << ") {\n"; + os << "if ("; + if (failed(emitter.emitOperand(condBranchOp.getCondition()))) + return failure(); + os << ") {\n"; os.indent(); @@ -641,8 +649,10 @@ static LogicalResult printOperation(CppEmitter &emitter, trueSuccessor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = " - << emitter.getOrCreateName(operand) << ";\n"; + os << emitter.getOrCreateName(argument) << " = "; + if (failed(emitter.emitOperand(operand))) + return failure(); + os << ";\n"; } os << "goto "; @@ -657,8 +667,10 @@ static LogicalResult printOperation(CppEmitter &emitter, falseSuccessor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = " - << emitter.getOrCreateName(operand) << ";\n"; + os << emitter.getOrCreateName(argument) << " = "; + if (failed(emitter.emitOperand(operand))) + return failure(); + os << ";\n"; } os << "goto "; @@ -716,7 +728,8 @@ static LogicalResult printOperation(CppEmitter &emitter, if (!emitter.hasValueInScope(operand)) return op.emitOpError("operand ") << idx << "'s value not defined in scope"; - os << emitter.getOrCreateName(operand); + if (failed(emitter.emitOperand(operand))) + return failure(); return success(); } } @@ -774,7 +787,8 @@ static LogicalResult printOperation(CppEmitter &emitter, if (failed(emitter.emitAssignPrefix(op))) return failure(); os << applyOp.getApplicableOperator(); - os << emitter.getOrCreateName(applyOp.getOperand()); + if (failed(emitter.emitOperand(applyOp.getOperand()))) + return failure(); return success(); } @@ -1159,7 +1173,10 @@ static LogicalResult printFunctionBody(CppEmitter &emitter, emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) { return failure(); } - os << " " << emitter.getOrCreateName(arg) << ";\n"; + os << " "; + if (failed(emitter.emitOperand(arg))) + return failure(); + os << ";\n"; } } @@ -1331,28 +1348,10 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { if (!valueMapper.count(val)) { - if (auto constant = dyn_cast_if_present(val.getDefiningOp()); - constant && !shouldUseConstantsAsVariables()) { - std::string constantValueString; - llvm::raw_string_ostream ss(constantValueString); - - ss << "("; - bool success = - succeeded(emitTypeToStream(val.getLoc(), constant.getType(), ss)); - assert(success); - ss << ") "; - - success = succeeded( - emitAttributeToStream(val.getLoc(), constant.getValue(), ss)); - assert(success); - - valueMapper.insert(val, constantValueString); - } else { assert(!hasDeferredEmission(val.getDefiningOp()) && "cacheDeferredOpResult should have been called on this value, " "update the emitOperation function."); valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); - } } return *valueMapper.begin(val); } @@ -1530,6 +1529,19 @@ LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) { LogicalResult CppEmitter::emitOperand(Value value) { Operation *def = value.getDefiningOp(); + if (auto constant = dyn_cast_if_present(def); + constant && !shouldUseConstantsAsVariables()) { + os << "("; + if (failed(emitType(value.getLoc(), constant.getType()))) + return failure(); + os << ") "; + + if (failed(emitAttribute(value.getLoc(), constant.getValue()))) + return failure(); + + return success(); + } + if (isPartOfCurrentExpression(value)) { assert(def && "Expected operand to be defined by an operation"); FailureOr precedence = getOperatorPrecedence(def); From ed4fee6e8748bfc3060872cc8b9ce88bba913abf Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Wed, 11 Dec 2024 17:28:59 +0000 Subject: [PATCH 06/10] Remove duplicate code --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 5aa76822cbcc5..32694e723f9e5 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -1348,10 +1348,10 @@ void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) { /// Return the existing or a new name for a Value. StringRef CppEmitter::getOrCreateName(Value val) { if (!valueMapper.count(val)) { - assert(!hasDeferredEmission(val.getDefiningOp()) && - "cacheDeferredOpResult should have been called on this value, " - "update the emitOperation function."); - valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); + assert(!hasDeferredEmission(val.getDefiningOp()) && + "cacheDeferredOpResult should have been called on this value, " + "update the emitOperation function."); + valueMapper.insert(val, formatv("v{0}", ++valueInScopeCount.top())); } return *valueMapper.begin(val); } @@ -1752,11 +1752,7 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) { cacheDeferredOpResult(op.getResult(), op.getValue()); return success(); }) - .Case([&](auto op) { - cacheDeferredOpResult(op.getResult(), createMemberAccess(op)); - return success(); - }) - .Case([&](auto op) { + .Case([&](auto op) { cacheDeferredOpResult(op.getResult(), createMemberAccess(op)); return success(); }) From 5981c2fba9751fbd5bd7b8f4a10e382c69c4fe9b Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Wed, 11 Dec 2024 17:32:44 +0000 Subject: [PATCH 07/10] Make defered emission ops print inline constants again --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 32694e723f9e5..49509f9fc26df 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -298,6 +298,9 @@ struct CppEmitter { return emittedExpressionPrecedence.back(); } + /// Emits value as an operands of an operation to the specified stream. + LogicalResult emitOperandToStream(Value value, raw_ostream &ss); + /// Emits attribute to the specified stream or returns failure. LogicalResult emitAttributeToStream(Location loc, Attribute attr, raw_ostream &ss); @@ -1319,7 +1322,9 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { llvm::raw_string_ostream ss(out); ss << getOrCreateName(op.getValue()); for (auto index : op.getIndices()) { - ss << "[" << getOrCreateName(index) << "]"; + ss << "["; + emitOperandToStream(index, ss); + ss << "]"; } return out; } @@ -1527,16 +1532,20 @@ LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) { } LogicalResult CppEmitter::emitOperand(Value value) { + return emitOperandToStream(value, os); +} + +LogicalResult CppEmitter::emitOperandToStream(Value value, raw_ostream &ss) { Operation *def = value.getDefiningOp(); if (auto constant = dyn_cast_if_present(def); constant && !shouldUseConstantsAsVariables()) { - os << "("; - if (failed(emitType(value.getLoc(), constant.getType()))) + ss << "("; + if (failed(emitTypeToStream(value.getLoc(), constant.getType(), ss))) return failure(); - os << ") "; + ss << ") "; - if (failed(emitAttribute(value.getLoc(), constant.getValue()))) + if (failed(emitAttributeToStream(value.getLoc(), constant.getValue(), ss))) return failure(); return success(); @@ -1572,7 +1581,7 @@ LogicalResult CppEmitter::emitOperand(Value value) { if (expressionOp && shouldBeInlined(expressionOp)) return emitExpression(expressionOp); - os << getOrCreateName(value); + ss << getOrCreateName(value); return success(); } From 84652151afb824346793c40de00a1cc70df1f46f Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Thu, 12 Dec 2024 14:28:45 +0000 Subject: [PATCH 08/10] Revert "Use emitOperand in all relevant locations as not only variable references are emited in the cpp code." This reverts commit 1f87ef480b475feb7c1028a0d78684d2d7e8ffe4. --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 41 ++++++++------------------ 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 49509f9fc26df..90a74631b6d79 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -508,11 +508,7 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::SwitchOp switchOp) { raw_indented_ostream &os = emitter.ostream(); - os << "\nswitch ("; - if (failed(emitter.emitOperand(switchOp.getArg()))) { - return failure(); - } - os << ") {"; + os << "\nswitch (" << emitter.getOrCreateName(switchOp.getArg()) << ") {"; for (auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) { os << "\ncase " << std::get<0>(pair) << ": {\n"; @@ -621,10 +617,8 @@ static LogicalResult printOperation(CppEmitter &emitter, llvm::zip(branchOp.getOperands(), successor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = "; - if (failed(emitter.emitOperand(operand))) - return failure(); - os << ";\n"; + os << emitter.getOrCreateName(argument) << " = " + << emitter.getOrCreateName(operand) << ";\n"; } os << "goto "; @@ -640,10 +634,8 @@ static LogicalResult printOperation(CppEmitter &emitter, Block &trueSuccessor = *condBranchOp.getTrueDest(); Block &falseSuccessor = *condBranchOp.getFalseDest(); - os << "if ("; - if (failed(emitter.emitOperand(condBranchOp.getCondition()))) - return failure(); - os << ") {\n"; + os << "if (" << emitter.getOrCreateName(condBranchOp.getCondition()) + << ") {\n"; os.indent(); @@ -652,10 +644,8 @@ static LogicalResult printOperation(CppEmitter &emitter, trueSuccessor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = "; - if (failed(emitter.emitOperand(operand))) - return failure(); - os << ";\n"; + os << emitter.getOrCreateName(argument) << " = " + << emitter.getOrCreateName(operand) << ";\n"; } os << "goto "; @@ -670,10 +660,8 @@ static LogicalResult printOperation(CppEmitter &emitter, falseSuccessor.getArguments())) { Value &operand = std::get<0>(pair); BlockArgument &argument = std::get<1>(pair); - os << emitter.getOrCreateName(argument) << " = "; - if (failed(emitter.emitOperand(operand))) - return failure(); - os << ";\n"; + os << emitter.getOrCreateName(argument) << " = " + << emitter.getOrCreateName(operand) << ";\n"; } os << "goto "; @@ -731,8 +719,7 @@ static LogicalResult printOperation(CppEmitter &emitter, if (!emitter.hasValueInScope(operand)) return op.emitOpError("operand ") << idx << "'s value not defined in scope"; - if (failed(emitter.emitOperand(operand))) - return failure(); + os << emitter.getOrCreateName(operand); return success(); } } @@ -790,8 +777,7 @@ static LogicalResult printOperation(CppEmitter &emitter, if (failed(emitter.emitAssignPrefix(op))) return failure(); os << applyOp.getApplicableOperator(); - if (failed(emitter.emitOperand(applyOp.getOperand()))) - return failure(); + os << emitter.getOrCreateName(applyOp.getOperand()); return success(); } @@ -1176,10 +1162,7 @@ static LogicalResult printFunctionBody(CppEmitter &emitter, emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) { return failure(); } - os << " "; - if (failed(emitter.emitOperand(arg))) - return failure(); - os << ";\n"; + os << " " << emitter.getOrCreateName(arg) << ";\n"; } } From e35eb2fa07d753a16968d02e7bb86b9bf13357aa Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Thu, 12 Dec 2024 15:36:06 +0000 Subject: [PATCH 09/10] Use ConstantOp as a deferred op when constantsAsVariables=false --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 77 ++++++++++--------- .../Cpp/emitc-constants-as-variables.mlir | 22 +----- 2 files changed, 43 insertions(+), 56 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 90a74631b6d79..5f98424ea7363 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -254,6 +254,13 @@ struct CppEmitter { return operandExpression == emittedExpression; }; + /// Determine whether expression \p expressionOp should be emitted inline, + /// i.e. as part of its user. This function recommends inlining of any + /// expressions that can be inlined unless it is used by another expression, + /// under the assumption that any expression fusion/re-materialization was + /// taken care of by transformations run by the backend. + bool shouldBeInlined(ExpressionOp expressionOp); + private: using ValueMapper = llvm::ScopedHashTable; using BlockMapper = llvm::ScopedHashTable; @@ -298,9 +305,10 @@ struct CppEmitter { return emittedExpressionPrecedence.back(); } - /// Emits value as an operands of an operation to the specified stream. - LogicalResult emitOperandToStream(Value value, raw_ostream &ss); + /// Determine whether expression \p op should be emitted in a deferred way. + bool hasDeferredEmission(Operation *op); +public: /// Emits attribute to the specified stream or returns failure. LogicalResult emitAttributeToStream(Location loc, Attribute attr, raw_ostream &ss); @@ -308,6 +316,7 @@ struct CppEmitter { /// Emits type 'type' to the specified stream or returns failure. LogicalResult emitTypeToStream(Location loc, Type type, raw_ostream &ss); +private: /// Emits array of types as a std::tuple of the emitted types independently of /// the array size to the specified stream. LogicalResult emitTupleTypeToStream(Location loc, ArrayRef types, @@ -315,18 +324,16 @@ struct CppEmitter { }; } // namespace -/// Determine whether expression \p op should be emitted in a deferred way. -static bool hasDeferredEmission(Operation *op) { +bool CppEmitter::hasDeferredEmission(Operation *op) { + if (llvm::isa_and_nonnull(op)) { + return !shouldUseConstantsAsVariables(); + } + return isa_and_nonnull(op); } -/// Determine whether expression \p expressionOp should be emitted inline, i.e. -/// as part of its user. This function recommends inlining of any expressions -/// that can be inlined unless it is used by another expression, under the -/// assumption that any expression fusion/re-materialization was taken care of -/// by transformations run by the backend. -static bool shouldBeInlined(ExpressionOp expressionOp) { +bool CppEmitter::shouldBeInlined(ExpressionOp expressionOp) { // Do not inline if expression is marked as such. if (expressionOp.getDoNotInline()) return false; @@ -388,6 +395,20 @@ static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation, static LogicalResult printOperation(CppEmitter &emitter, emitc::ConstantOp constantOp) { if (!emitter.shouldUseConstantsAsVariables()) { + std::string out; + llvm::raw_string_ostream ss(out); + + ss << "("; + if (failed(emitter.emitTypeToStream(constantOp.getLoc(), + constantOp.getType(), ss))) + return failure(); + ss << ") "; + + if (failed(emitter.emitAttributeToStream(constantOp.getLoc(), + constantOp.getValue(), ss))) + return failure(); + + emitter.cacheDeferredOpResult(constantOp.getResult(), out); return success(); } @@ -853,7 +874,7 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) { static LogicalResult printOperation(CppEmitter &emitter, emitc::ExpressionOp expressionOp) { - if (shouldBeInlined(expressionOp)) + if (emitter.shouldBeInlined(expressionOp)) return success(); Operation &op = *expressionOp.getOperation(); @@ -907,7 +928,7 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::ForOp forOp) { dyn_cast_if_present(value.getDefiningOp()); if (!expressionOp) return false; - return shouldBeInlined(expressionOp); + return emitter.shouldBeInlined(expressionOp); }; os << "for ("; @@ -1129,7 +1150,7 @@ static LogicalResult printFunctionBody(CppEmitter &emitter, functionOp->walk([&](Operation *op) -> WalkResult { if (isa(op->getParentOp()) || (isa(op) && - shouldBeInlined(cast(op)))) + emitter.shouldBeInlined(cast(op)))) return WalkResult::skip(); for (OpResult result : op->getResults()) { if (failed(emitter.emitVariableDeclaration( @@ -1305,9 +1326,7 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) { llvm::raw_string_ostream ss(out); ss << getOrCreateName(op.getValue()); for (auto index : op.getIndices()) { - ss << "["; - emitOperandToStream(index, ss); - ss << "]"; + ss << "[" << getOrCreateName(index) << "]"; } return out; } @@ -1487,7 +1506,7 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, // Print type attributes. if (auto type = dyn_cast(attr)) - return emitType(loc, type.getValue()); + return emitTypeToStream(loc, type.getValue(), ss); return emitError(loc, "cannot emit attribute: ") << attr; } @@ -1515,25 +1534,8 @@ LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) { } LogicalResult CppEmitter::emitOperand(Value value) { - return emitOperandToStream(value, os); -} - -LogicalResult CppEmitter::emitOperandToStream(Value value, raw_ostream &ss) { Operation *def = value.getDefiningOp(); - if (auto constant = dyn_cast_if_present(def); - constant && !shouldUseConstantsAsVariables()) { - ss << "("; - if (failed(emitTypeToStream(value.getLoc(), constant.getType(), ss))) - return failure(); - ss << ") "; - - if (failed(emitAttributeToStream(value.getLoc(), constant.getValue(), ss))) - return failure(); - - return success(); - } - if (isPartOfCurrentExpression(value)) { assert(def && "Expected operand to be defined by an operation"); FailureOr precedence = getOperatorPrecedence(def); @@ -1564,7 +1566,7 @@ LogicalResult CppEmitter::emitOperandToStream(Value value, raw_ostream &ss) { if (expressionOp && shouldBeInlined(expressionOp)) return emitExpression(expressionOp); - ss << getOrCreateName(value); + os << getOrCreateName(value); return success(); } @@ -1958,8 +1960,9 @@ LogicalResult CppEmitter::emitTupleTypeToStream(Location loc, return emitError(loc, "cannot emit tuple of array type"); } ss << "std::tuple<"; - if (failed(interleaveCommaWithError( - types, ss, [&](Type type) { return emitType(loc, type); }))) + if (failed(interleaveCommaWithError(types, ss, [&](Type type) { + return emitTypeToStream(loc, type, ss); + }))) return failure(); ss << ">"; return success(); diff --git a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir index 065c1a3c65d3f..c908ecc460edf 100644 --- a/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir +++ b/mlir/test/Target/Cpp/emitc-constants-as-variables.mlir @@ -34,14 +34,6 @@ func.func @emitc_switch_ui64() { %0 = "emitc.constant"(){value = 1 : ui64} : () -> ui64 emitc.switch %0 : ui64 - case 2 { - %1 = emitc.call_opaque "func_b" () : () -> i32 - emitc.yield - } - case 5 { - %2 = emitc.call_opaque "func_a" () : () -> i32 - emitc.yield - } default { emitc.call_opaque "func2" (%0) : (ui64) -> () emitc.yield @@ -50,14 +42,6 @@ func.func @emitc_switch_ui64() { } // CPP-DEFAULT-LABEL: void emitc_switch_ui64() { // CPP-DEFAULT: switch ((uint64_t) 1) { -// CPP-DEFAULT-NEXT: case 2: { -// CPP-DEFAULT-NEXT: int32_t v1 = func_b(); -// CPP-DEFAULT-NEXT: break; -// CPP-DEFAULT-NEXT: } -// CPP-DEFAULT-NEXT: case 5: { -// CPP-DEFAULT-NEXT: int32_t v2 = func_a(); -// CPP-DEFAULT-NEXT: break; -// CPP-DEFAULT-NEXT: } // CPP-DEFAULT-NEXT: default: { // CPP-DEFAULT-NEXT: func2((uint64_t) 1); // CPP-DEFAULT-NEXT: break; @@ -69,13 +53,13 @@ func.func @emitc_switch_ui64() { func.func @negative_values() { %1 = "emitc.constant"() <{value = 10 : index}> : () -> !emitc.size_t - %2 = "emitc.constant"() <{value = -3000000000 : index}> : () -> !emitc.size_t + %2 = "emitc.constant"() <{value = -3000000000 : index}> : () -> !emitc.ssize_t - %3 = emitc.add %1, %2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t + %3 = emitc.add %1, %2 : (!emitc.size_t, !emitc.ssize_t) -> !emitc.ssize_t return } // CPP-DEFAULT-LABEL: void negative_values() { -// CPP-DEFAULT-NEXT: size_t v1 = (size_t) 10 + (size_t) -3000000000; +// CPP-DEFAULT-NEXT: ssize_t v1 = (size_t) 10 + (ssize_t) -3000000000; // CPP-DEFAULT-NEXT: return; // CPP-DEFAULT-NEXT: } \ No newline at end of file From 2dd8f12a2b28d658cdfb97da6e1aabf2eb38c14b Mon Sep 17 00:00:00 2001 From: Luis Miguel Sousa Date: Thu, 12 Dec 2024 17:34:10 +0000 Subject: [PATCH 10/10] Capture output of defered ConstantOps without major modification of CppEmitter methods --- mlir/lib/Target/Cpp/TranslateToCpp.cpp | 148 +++++++++++-------------- 1 file changed, 63 insertions(+), 85 deletions(-) diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 5f98424ea7363..e09fe1d1126be 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -261,6 +261,9 @@ struct CppEmitter { /// taken care of by transformations run by the backend. bool shouldBeInlined(ExpressionOp expressionOp); + /// This emitter will only emit translation units whos id matches this value. + StringRef willOnlyEmitTu() { return onlyTu; } + private: using ValueMapper = llvm::ScopedHashTable; using BlockMapper = llvm::ScopedHashTable; @@ -307,20 +310,6 @@ struct CppEmitter { /// Determine whether expression \p op should be emitted in a deferred way. bool hasDeferredEmission(Operation *op); - -public: - /// Emits attribute to the specified stream or returns failure. - LogicalResult emitAttributeToStream(Location loc, Attribute attr, - raw_ostream &ss); - - /// Emits type 'type' to the specified stream or returns failure. - LogicalResult emitTypeToStream(Location loc, Type type, raw_ostream &ss); - -private: - /// Emits array of types as a std::tuple of the emitted types independently of - /// the array size to the specified stream. - LogicalResult emitTupleTypeToStream(Location loc, ArrayRef types, - raw_ostream &ss); }; } // namespace @@ -398,14 +387,19 @@ static LogicalResult printOperation(CppEmitter &emitter, std::string out; llvm::raw_string_ostream ss(out); + /// Temporary emitter object that writes to our stream instead of the output + /// allowing for the capture and caching of the produced string. + CppEmitter sniffer = CppEmitter(ss, emitter.shouldDeclareVariablesAtTop(), + emitter.willOnlyEmitTu(), + emitter.shouldUseConstantsAsVariables()); + ss << "("; - if (failed(emitter.emitTypeToStream(constantOp.getLoc(), - constantOp.getType(), ss))) + if (failed(sniffer.emitType(constantOp.getLoc(), constantOp.getType()))) return failure(); ss << ") "; - if (failed(emitter.emitAttributeToStream(constantOp.getLoc(), - constantOp.getValue(), ss))) + if (failed( + sniffer.emitAttribute(constantOp.getLoc(), constantOp.getValue()))) return failure(); emitter.cacheDeferredOpResult(constantOp.getResult(), out); @@ -1389,21 +1383,16 @@ bool CppEmitter::hasBlockLabel(Block &block) { } LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) { - return CppEmitter::emitAttributeToStream(loc, attr, os); -} - -LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, - raw_ostream &ss) { auto printInt = [&](const APInt &val, bool isUnsigned) { if (val.getBitWidth() == 1) { if (val.getBoolValue()) - ss << "true"; + os << "true"; else - ss << "false"; + os << "false"; } else { SmallString<128> strValue; val.toString(strValue, 10, !isUnsigned, false); - ss << strValue; + os << strValue; } }; @@ -1412,16 +1401,16 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, SmallString<128> strValue; // Use default values of toString except don't truncate zeros. val.toString(strValue, 0, 0, false); - ss << strValue; + os << strValue; switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) { case llvm::APFloatBase::S_IEEEhalf: - ss << "f16"; + os << "f16"; break; case llvm::APFloatBase::S_BFloat: - ss << "bf16"; + os << "bf16"; break; case llvm::APFloatBase::S_IEEEsingle: - ss << "f"; + os << "f"; break; case llvm::APFloatBase::S_IEEEdouble: break; @@ -1429,11 +1418,11 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, llvm_unreachable("unsupported floating point type"); }; } else if (val.isNaN()) { - ss << "NAN"; + os << "NAN"; } else if (val.isInfinity()) { if (val.isNegative()) - ss << "-"; - ss << "INFINITY"; + os << "-"; + os << "INFINITY"; } }; @@ -1453,9 +1442,9 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, return emitError( loc, "expected floating point attribute to be f16, bf16, f32 or f64"); } - ss << '{'; - interleaveComma(dense, ss, [&](const APFloat &val) { printFloat(val); }); - ss << '}'; + os << '{'; + interleaveComma(dense, os, [&](const APFloat &val) { printFloat(val); }); + os << '}'; return success(); } @@ -1473,26 +1462,26 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, if (auto dense = dyn_cast(attr)) { if (auto iType = dyn_cast( cast(dense.getType()).getElementType())) { - ss << '{'; - interleaveComma(dense, ss, [&](const APInt &val) { + os << '{'; + interleaveComma(dense, os, [&](const APInt &val) { printInt(val, shouldMapToUnsigned(iType.getSignedness())); }); - ss << '}'; + os << '}'; return success(); } if (auto iType = dyn_cast( cast(dense.getType()).getElementType())) { - ss << '{'; - interleaveComma(dense, ss, + os << '{'; + interleaveComma(dense, os, [&](const APInt &val) { printInt(val, false); }); - ss << '}'; + os << '}'; return success(); } } // Print opaque attributes. if (auto oAttr = dyn_cast(attr)) { - ss << oAttr.getValue(); + os << oAttr.getValue(); return success(); } @@ -1500,13 +1489,13 @@ LogicalResult CppEmitter::emitAttributeToStream(Location loc, Attribute attr, if (auto sAttr = dyn_cast(attr)) { if (sAttr.getNestedReferences().size() > 1) return emitError(loc, "attribute has more than 1 nested reference"); - ss << sAttr.getRootReference().getValue(); + os << sAttr.getRootReference().getValue(); return success(); } // Print type attributes. if (auto type = dyn_cast(attr)) - return emitTypeToStream(loc, type.getValue(), ss); + return emitType(loc, type.getValue()); return emitError(loc, "cannot emit attribute: ") << attr; } @@ -1830,23 +1819,18 @@ LogicalResult CppEmitter::emitReferenceToType(Location loc, Type type) { } LogicalResult CppEmitter::emitType(Location loc, Type type) { - return emitTypeToStream(loc, type, os); -} - -LogicalResult CppEmitter::emitTypeToStream(Location loc, Type type, - raw_ostream &ss) { if (auto iType = dyn_cast(type)) { switch (iType.getWidth()) { case 1: - return (ss << "bool"), success(); + return (os << "bool"), success(); case 8: case 16: case 32: case 64: if (shouldMapToUnsigned(iType.getSignedness())) - return (ss << "uint" << iType.getWidth() << "_t"), success(); + return (os << "uint" << iType.getWidth() << "_t"), success(); else - return (ss << "int" << iType.getWidth() << "_t"), success(); + return (os << "int" << iType.getWidth() << "_t"), success(); default: return emitError(loc, "cannot emit integer type ") << type; } @@ -1855,48 +1839,48 @@ LogicalResult CppEmitter::emitTypeToStream(Location loc, Type type, switch (fType.getWidth()) { case 16: { if (llvm::isa(type)) - return (ss << "_Float16"), success(); + return (os << "_Float16"), success(); else if (llvm::isa(type)) - return (ss << "__bf16"), success(); + return (os << "__bf16"), success(); else return emitError(loc, "cannot emit float type ") << type; } case 32: - return (ss << "float"), success(); + return (os << "float"), success(); case 64: - return (ss << "double"), success(); + return (os << "double"), success(); default: return emitError(loc, "cannot emit float type ") << type; } } if (auto iType = dyn_cast(type)) - return (ss << "size_t"), success(); + return (os << "size_t"), success(); if (auto sType = dyn_cast(type)) - return (ss << "size_t"), success(); + return (os << "size_t"), success(); if (auto sType = dyn_cast(type)) - return (ss << "ssize_t"), success(); + return (os << "ssize_t"), success(); if (auto pType = dyn_cast(type)) - return (ss << "ptrdiff_t"), success(); + return (os << "ptrdiff_t"), success(); if (auto tType = dyn_cast(type)) { if (!tType.hasRank()) return emitError(loc, "cannot emit unranked tensor type"); if (!tType.hasStaticShape()) return emitError(loc, "cannot emit tensor type with non static shape"); - ss << "Tensor<"; + os << "Tensor<"; if (isa(tType.getElementType())) return emitError(loc, "cannot emit tensor of array type ") << type; - if (failed(emitTypeToStream(loc, tType.getElementType(), ss))) + if (failed(emitType(loc, tType.getElementType()))) return failure(); auto shape = tType.getShape(); for (auto dimSize : shape) { - ss << ", "; - ss << dimSize; + os << ", "; + os << dimSize; } - ss << ">"; + os << ">"; return success(); } if (auto tType = dyn_cast(type)) - return emitTupleTypeToStream(loc, tType.getTypes(), ss); + return emitTupleType(loc, tType.getTypes()); if (auto oType = dyn_cast(type)) { FailureOr> items = oType.parseFormatString(); if (failed(items)) @@ -1905,9 +1889,9 @@ LogicalResult CppEmitter::emitTypeToStream(Location loc, Type type, auto fmtArg = oType.getFmtArgs().begin(); for (ReplacementItem &item : *items) { if (auto *str = std::get_if(&item)) { - ss << *str; + os << *str; } else { - if (failed(emitTypeToStream(loc, *fmtArg++, ss))) { + if (failed(emitType(loc, *fmtArg++))) { return failure(); } } @@ -1915,24 +1899,24 @@ LogicalResult CppEmitter::emitTypeToStream(Location loc, Type type, return success(); - ss << oType.getValue(); + os << oType.getValue(); return success(); } if (auto aType = dyn_cast(type)) { - if (failed(emitTypeToStream(loc, aType.getElementType(), ss))) + if (failed(emitType(loc, aType.getElementType()))) return failure(); for (auto dim : aType.getShape()) - ss << "[" << dim << "]"; + os << "[" << dim << "]"; return success(); } if (auto lType = dyn_cast(type)) - return emitTypeToStream(loc, lType.getValueType(), ss); + return emitType(loc, lType.getValueType()); if (auto pType = dyn_cast(type)) { if (isa(pType.getPointee())) return emitError(loc, "cannot emit pointer to array type ") << type; - if (failed(emitTypeToStream(loc, pType.getPointee(), ss))) + if (failed(emitType(loc, pType.getPointee()))) return failure(); - ss << "*"; + os << "*"; return success(); } return emitError(loc, "cannot emit type ") << type; @@ -1951,20 +1935,14 @@ LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef types) { } LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { - return emitTupleTypeToStream(loc, types, os); -} -LogicalResult CppEmitter::emitTupleTypeToStream(Location loc, - ArrayRef types, - raw_ostream &ss) { if (llvm::any_of(types, llvm::IsaPred)) { return emitError(loc, "cannot emit tuple of array type"); } - ss << "std::tuple<"; - if (failed(interleaveCommaWithError(types, ss, [&](Type type) { - return emitTypeToStream(loc, type, ss); - }))) + os << "std::tuple<"; + if (failed(interleaveCommaWithError( + types, os, [&](Type type) { return emitType(loc, type); }))) return failure(); - ss << ">"; + os << ">"; return success(); }