20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/ScopedHashTable.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/FormatVariadic.h"
30 #define DEBUG_TYPE "translate-to-cpp"
40 typename NullaryFunctor>
43 UnaryFunctor eachFn, NullaryFunctor betweenFn) {
46 if (
failed(eachFn(*begin)))
49 for (; begin != end; ++begin) {
51 if (
failed(eachFn(*begin)))
57 template <
typename Container,
typename UnaryFunctor,
typename NullaryFunctor>
60 NullaryFunctor betweenFn) {
64 template <
typename Container,
typename UnaryFunctor>
67 UnaryFunctor eachFn) {
75 .Case<emitc::AddOp>([&](
auto op) {
return 12; })
76 .Case<emitc::ApplyOp>([&](
auto op) {
return 15; })
77 .Case<emitc::BitwiseAndOp>([&](
auto op) {
return 7; })
78 .Case<emitc::BitwiseLeftShiftOp>([&](
auto op) {
return 11; })
79 .Case<emitc::BitwiseNotOp>([&](
auto op) {
return 15; })
80 .Case<emitc::BitwiseOrOp>([&](
auto op) {
return 5; })
81 .Case<emitc::BitwiseRightShiftOp>([&](
auto op) {
return 11; })
82 .Case<emitc::BitwiseXorOp>([&](
auto op) {
return 6; })
83 .Case<emitc::CallOp>([&](
auto op) {
return 16; })
84 .Case<emitc::CallOpaqueOp>([&](
auto op) {
return 16; })
85 .Case<emitc::CastOp>([&](
auto op) {
return 15; })
87 switch (op.getPredicate()) {
88 case emitc::CmpPredicate::eq:
89 case emitc::CmpPredicate::ne:
91 case emitc::CmpPredicate::lt:
92 case emitc::CmpPredicate::le:
93 case emitc::CmpPredicate::gt:
94 case emitc::CmpPredicate::ge:
96 case emitc::CmpPredicate::three_way:
99 return op->
emitError(
"unsupported cmp predicate");
101 .Case<emitc::ConditionalOp>([&](
auto op) {
return 2; })
102 .Case<emitc::DivOp>([&](
auto op) {
return 13; })
103 .Case<emitc::LogicalAndOp>([&](
auto op) {
return 4; })
104 .Case<emitc::LogicalNotOp>([&](
auto op) {
return 15; })
105 .Case<emitc::LogicalOrOp>([&](
auto op) {
return 3; })
106 .Case<emitc::MulOp>([&](
auto op) {
return 13; })
107 .Case<emitc::RemOp>([&](
auto op) {
return 13; })
108 .Case<emitc::SubOp>([&](
auto op) {
return 12; })
109 .Case<emitc::UnaryMinusOp>([&](
auto op) {
return 15; })
110 .Case<emitc::UnaryPlusOp>([&](
auto op) {
return 15; })
111 .Default([](
auto op) {
return op->
emitError(
"unsupported operation"); });
117 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop);
143 bool trailingSemicolon);
175 StringRef getOrCreateName(
Value val);
178 std::string getSubscriptName(emitc::SubscriptOp op);
181 StringRef getOrCreateName(
Block &block);
184 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
188 Scope(CppEmitter &emitter)
189 : valueMapperScope(emitter.valueMapper),
190 blockMapperScope(emitter.blockMapper), emitter(emitter) {
191 emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
192 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
195 emitter.valueInScopeCount.pop();
196 emitter.labelInScopeCount.pop();
200 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
201 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
206 bool hasValueInScope(
Value val);
209 bool hasBlockLabel(
Block &block);
216 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
219 ExpressionOp getEmittedExpression() {
return emittedExpression; }
223 bool isPartOfCurrentExpression(
Value value) {
224 if (!emittedExpression)
229 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
230 return operandExpression == emittedExpression;
234 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
235 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
243 bool declareVariablesAtTop;
246 ValueMapper valueMapper;
249 BlockMapper blockMapper;
253 std::stack<int64_t> valueInScopeCount;
254 std::stack<int64_t> labelInScopeCount;
257 ExpressionOp emittedExpression;
260 void pushExpressionPrecedence(
int precedence) {
261 emittedExpressionPrecedence.push_back(precedence);
263 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
264 static int lowestPrecedence() {
return 0; }
265 int getExpressionPrecedence() {
266 if (emittedExpressionPrecedence.empty())
267 return lowestPrecedence();
268 return emittedExpressionPrecedence.back();
280 if (expressionOp.getDoNotInline())
285 if (expressionOp.hasSideEffects())
289 Value result = expressionOp.getResult();
305 if (emitter.shouldDeclareVariablesAtTop()) {
307 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
308 if (oAttr.getValue().empty())
312 if (
failed(emitter.emitVariableAssignment(result)))
314 return emitter.emitAttribute(operation->
getLoc(), value);
318 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
319 if (oAttr.getValue().empty())
321 return emitter.emitVariableDeclaration(result,
326 if (
failed(emitter.emitAssignPrefix(*operation)))
328 return emitter.emitAttribute(operation->
getLoc(), value);
332 emitc::ConstantOp constantOp) {
333 Operation *operation = constantOp.getOperation();
340 emitc::VariableOp variableOp) {
341 Operation *operation = variableOp.getOperation();
348 emitc::AssignOp assignOp) {
351 if (
failed(emitter.emitVariableAssignment(result)))
354 return emitter.emitOperand(assignOp.getValue());
358 emitc::SubscriptOp subscriptOp) {
360 emitter.getOrCreateName(subscriptOp.getResult());
366 StringRef binaryOperator) {
367 raw_ostream &os = emitter.ostream();
369 if (
failed(emitter.emitAssignPrefix(*operation)))
375 os <<
" " << binaryOperator <<
" ";
385 StringRef unaryOperator) {
386 raw_ostream &os = emitter.ostream();
388 if (
failed(emitter.emitAssignPrefix(*operation)))
400 Operation *operation = addOp.getOperation();
406 Operation *operation = divOp.getOperation();
412 Operation *operation = mulOp.getOperation();
418 Operation *operation = remOp.getOperation();
424 Operation *operation = subOp.getOperation();
430 Operation *operation = cmpOp.getOperation();
432 StringRef binaryOperator;
434 switch (cmpOp.getPredicate()) {
435 case emitc::CmpPredicate::eq:
436 binaryOperator =
"==";
438 case emitc::CmpPredicate::ne:
439 binaryOperator =
"!=";
441 case emitc::CmpPredicate::lt:
442 binaryOperator =
"<";
444 case emitc::CmpPredicate::le:
445 binaryOperator =
"<=";
447 case emitc::CmpPredicate::gt:
448 binaryOperator =
">";
450 case emitc::CmpPredicate::ge:
451 binaryOperator =
">=";
453 case emitc::CmpPredicate::three_way:
454 binaryOperator =
"<=>";
462 emitc::ConditionalOp conditionalOp) {
463 raw_ostream &os = emitter.ostream();
465 if (
failed(emitter.emitAssignPrefix(*conditionalOp)))
468 if (
failed(emitter.emitOperand(conditionalOp.getCondition())))
473 if (
failed(emitter.emitOperand(conditionalOp.getTrueValue())))
478 if (
failed(emitter.emitOperand(conditionalOp.getFalseValue())))
485 emitc::VerbatimOp verbatimOp) {
486 raw_ostream &os = emitter.ostream();
488 os << verbatimOp.getValue();
494 cf::BranchOp branchOp) {
495 raw_ostream &os = emitter.ostream();
499 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
500 Value &operand = std::get<0>(pair);
502 os << emitter.getOrCreateName(argument) <<
" = "
503 << emitter.getOrCreateName(operand) <<
";\n";
507 if (!(emitter.hasBlockLabel(successor)))
508 return branchOp.emitOpError(
"unable to find label for successor block");
509 os << emitter.getOrCreateName(successor);
514 cf::CondBranchOp condBranchOp) {
516 Block &trueSuccessor = *condBranchOp.getTrueDest();
517 Block &falseSuccessor = *condBranchOp.getFalseDest();
519 os <<
"if (" << emitter.getOrCreateName(condBranchOp.getCondition())
525 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
527 Value &operand = std::get<0>(pair);
529 os << emitter.getOrCreateName(argument) <<
" = "
530 << emitter.getOrCreateName(operand) <<
";\n";
534 if (!(emitter.hasBlockLabel(trueSuccessor))) {
535 return condBranchOp.emitOpError(
"unable to find label for successor block");
537 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
541 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
543 Value &operand = std::get<0>(pair);
545 os << emitter.getOrCreateName(argument) <<
" = "
546 << emitter.getOrCreateName(operand) <<
";\n";
550 if (!(emitter.hasBlockLabel(falseSuccessor))) {
551 return condBranchOp.emitOpError()
552 <<
"unable to find label for successor block";
554 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
561 if (
failed(emitter.emitAssignPrefix(*callOp)))
564 raw_ostream &os = emitter.ostream();
566 if (
failed(emitter.emitOperands(*callOp)))
573 Operation *operation = callOp.getOperation();
574 StringRef callee = callOp.getCallee();
580 Operation *operation = callOp.getOperation();
581 StringRef callee = callOp.getCallee();
587 emitc::CallOpaqueOp callOpaqueOp) {
588 raw_ostream &os = emitter.ostream();
589 Operation &op = *callOpaqueOp.getOperation();
591 if (
failed(emitter.emitAssignPrefix(op)))
593 os << callOpaqueOp.getCallee();
596 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
598 if (t.getType().isIndex()) {
599 int64_t idx = t.getInt();
603 if (!literalDef && !emitter.hasValueInScope(operand))
605 << idx <<
"'s value not defined in scope";
606 os << emitter.getOrCreateName(operand);
616 if (callOpaqueOp.getTemplateArgs()) {
627 callOpaqueOp.getArgs()
629 : emitter.emitOperands(op);
637 emitc::ApplyOp applyOp) {
638 raw_ostream &os = emitter.ostream();
641 if (
failed(emitter.emitAssignPrefix(op)))
643 os << applyOp.getApplicableOperator();
644 os << emitter.getOrCreateName(applyOp.getOperand());
650 emitc::BitwiseAndOp bitwiseAndOp) {
651 Operation *operation = bitwiseAndOp.getOperation();
657 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
658 Operation *operation = bitwiseLeftShiftOp.getOperation();
663 emitc::BitwiseNotOp bitwiseNotOp) {
664 Operation *operation = bitwiseNotOp.getOperation();
669 emitc::BitwiseOrOp bitwiseOrOp) {
670 Operation *operation = bitwiseOrOp.getOperation();
676 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
677 Operation *operation = bitwiseRightShiftOp.getOperation();
682 emitc::BitwiseXorOp bitwiseXorOp) {
683 Operation *operation = bitwiseXorOp.getOperation();
688 emitc::UnaryPlusOp unaryPlusOp) {
689 Operation *operation = unaryPlusOp.getOperation();
694 emitc::UnaryMinusOp unaryMinusOp) {
695 Operation *operation = unaryMinusOp.getOperation();
700 raw_ostream &os = emitter.ostream();
703 if (
failed(emitter.emitAssignPrefix(op)))
709 return emitter.emitOperand(castOp.getOperand());
713 emitc::ExpressionOp expressionOp) {
717 Operation &op = *expressionOp.getOperation();
719 if (
failed(emitter.emitAssignPrefix(op)))
722 return emitter.emitExpression(expressionOp);
726 emitc::IncludeOp includeOp) {
727 raw_ostream &os = emitter.ostream();
730 if (includeOp.getIsStandardInclude())
731 os <<
"<" << includeOp.getInclude() <<
">";
733 os <<
"\"" << includeOp.getInclude() <<
"\"";
739 emitc::LogicalAndOp logicalAndOp) {
740 Operation *operation = logicalAndOp.getOperation();
745 emitc::LogicalNotOp logicalNotOp) {
746 Operation *operation = logicalNotOp.getOperation();
751 emitc::LogicalOrOp logicalOrOp) {
752 Operation *operation = logicalOrOp.getOperation();
763 auto requiresParentheses = [&](
Value value) {
773 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
776 os << emitter.getOrCreateName(forOp.getInductionVar());
778 if (
failed(emitter.emitOperand(forOp.getLowerBound())))
781 os << emitter.getOrCreateName(forOp.getInductionVar());
783 Value upperBound = forOp.getUpperBound();
784 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
785 if (upperBoundRequiresParentheses)
787 if (
failed(emitter.emitOperand(upperBound)))
789 if (upperBoundRequiresParentheses)
792 os << emitter.getOrCreateName(forOp.getInductionVar());
794 if (
failed(emitter.emitOperand(forOp.getStep())))
799 Region &forRegion = forOp.getRegion();
800 auto regionOps = forRegion.
getOps();
803 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
804 if (
failed(emitter.emitOperation(*it,
true)))
818 auto emitAllExceptLast = [&emitter](
Region ®ion) {
820 for (; std::next(it) != end; ++it) {
821 if (
failed(emitter.emitOperation(*it,
true)))
824 assert(isa<emitc::YieldOp>(*it) &&
825 "Expected last operation in the region to be emitc::yield");
830 if (
failed(emitter.emitOperand(ifOp.getCondition())))
834 if (
failed(emitAllExceptLast(ifOp.getThenRegion())))
838 Region &elseRegion = ifOp.getElseRegion();
839 if (!elseRegion.
empty()) {
842 if (
failed(emitAllExceptLast(elseRegion)))
851 func::ReturnOp returnOp) {
852 raw_ostream &os = emitter.ostream();
854 switch (returnOp.getNumOperands()) {
859 if (
failed(emitter.emitOperand(returnOp.getOperand(0))))
863 os <<
" std::make_tuple(";
864 if (
failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
872 emitc::ReturnOp returnOp) {
873 raw_ostream &os = emitter.ostream();
875 if (returnOp.getNumOperands() == 0)
879 if (
failed(emitter.emitOperand(returnOp.getOperand())))
885 CppEmitter::Scope scope(emitter);
888 if (
failed(emitter.emitOperation(op,
false)))
901 return emitter.emitType(functionOp->
getLoc(), arg);
912 return emitter.emitVariableDeclaration(
913 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
923 if (emitter.shouldDeclareVariablesAtTop()) {
928 if (isa<emitc::LiteralOp>(op) ||
930 (isa<emitc::ExpressionOp>(op) &&
934 if (
failed(emitter.emitVariableDeclaration(
937 op->
emitError(
"unable to declare result variable for op"));
947 for (
Block &block : blocks) {
948 emitter.getOrCreateName(block);
952 for (
Block &block : llvm::drop_begin(blocks)) {
954 if (emitter.hasValueInScope(arg))
955 return functionOp->
emitOpError(
" block argument #")
956 << arg.getArgNumber() <<
" is out of scope";
957 if (isa<ArrayType>(arg.getType()))
958 return functionOp->
emitOpError(
"cannot emit block argument #")
959 << arg.getArgNumber() <<
" with array type";
961 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
964 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
968 for (
Block &block : blocks) {
970 if (!block.hasNoPredecessors()) {
971 if (
failed(emitter.emitLabel(block)))
974 for (
Operation &op : block.getOperations()) {
979 bool trailingSemicolon =
980 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::ForOp,
981 emitc::IfOp, emitc::LiteralOp, emitc::VerbatimOp>(op);
983 if (
failed(emitter.emitOperation(
984 op, trailingSemicolon)))
995 func::FuncOp functionOp) {
997 if (!emitter.shouldDeclareVariablesAtTop() &&
998 functionOp.getBlocks().size() > 1) {
999 return functionOp.emitOpError(
1000 "with multiple blocks needs variables declared at top");
1003 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1004 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1007 CppEmitter::Scope scope(emitter);
1009 if (
failed(emitter.emitTypes(functionOp.getLoc(),
1010 functionOp.getFunctionType().getResults())))
1012 os <<
" " << functionOp.getName();
1015 Operation *operation = functionOp.getOperation();
1027 emitc::FuncOp functionOp) {
1029 if (!emitter.shouldDeclareVariablesAtTop() &&
1030 functionOp.getBlocks().size() > 1) {
1031 return functionOp.emitOpError(
1032 "with multiple blocks needs variables declared at top");
1035 CppEmitter::Scope scope(emitter);
1037 if (functionOp.getSpecifiers()) {
1038 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1039 os << cast<StringAttr>(specifier).str() <<
" ";
1043 if (
failed(emitter.emitTypes(functionOp.getLoc(),
1044 functionOp.getFunctionType().getResults())))
1046 os <<
" " << functionOp.getName();
1049 Operation *operation = functionOp.getOperation();
1050 if (functionOp.isExternal()) {
1052 functionOp.getArgumentTypes())))
1068 DeclareFuncOp declareFuncOp) {
1069 CppEmitter::Scope scope(emitter);
1072 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1073 declareFuncOp, declareFuncOp.getSymNameAttr());
1078 if (functionOp.getSpecifiers()) {
1079 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1080 os << cast<StringAttr>(specifier).str() <<
" ";
1084 if (
failed(emitter.emitTypes(functionOp.getLoc(),
1085 functionOp.getFunctionType().getResults())))
1087 os <<
" " << functionOp.getName();
1090 Operation *operation = functionOp.getOperation();
1098 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop)
1099 : os(os), declareVariablesAtTop(declareVariablesAtTop) {
1100 valueInScopeCount.push(0);
1101 labelInScopeCount.push(0);
1104 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1106 llvm::raw_string_ostream ss(out);
1107 ss << getOrCreateName(op.getValue());
1108 for (
auto index : op.getIndices()) {
1109 ss <<
"[" << getOrCreateName(index) <<
"]";
1115 StringRef CppEmitter::getOrCreateName(
Value val) {
1116 if (
auto literal = dyn_cast_if_present<emitc::LiteralOp>(val.
getDefiningOp()))
1117 return literal.getValue();
1118 if (!valueMapper.count(val)) {
1119 if (
auto subscript =
1120 dyn_cast_if_present<emitc::SubscriptOp>(val.
getDefiningOp())) {
1121 valueMapper.insert(val, getSubscriptName(subscript));
1123 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1126 return *valueMapper.begin(val);
1130 StringRef CppEmitter::getOrCreateName(
Block &block) {
1131 if (!blockMapper.count(&block))
1132 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1133 return *blockMapper.begin(&block);
1136 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1138 case IntegerType::Signless:
1142 case IntegerType::Unsigned:
1145 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1148 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1150 bool CppEmitter::hasBlockLabel(
Block &block) {
1151 return blockMapper.count(&block);
1155 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1156 if (val.getBitWidth() == 1) {
1157 if (val.getBoolValue())
1163 val.toString(strValue, 10, !isUnsigned,
false);
1168 auto printFloat = [&](
const APFloat &val) {
1169 if (val.isFinite()) {
1172 val.toString(strValue, 0, 0,
false);
1174 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1175 case llvm::APFloatBase::S_IEEEsingle:
1178 case llvm::APFloatBase::S_IEEEdouble:
1181 llvm_unreachable(
"unsupported floating point type");
1183 }
else if (val.isNaN()) {
1185 }
else if (val.isInfinity()) {
1186 if (val.isNegative())
1193 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1194 if (!isa<Float32Type, Float64Type>(fAttr.getType())) {
1196 "expected floating point attribute to be f32 or f64");
1198 printFloat(fAttr.getValue());
1201 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1202 if (!isa<Float32Type, Float64Type>(dense.getElementType())) {
1204 "expected floating point attribute to be f32 or f64");
1207 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1213 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1214 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1215 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1218 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1219 printInt(iAttr.getValue(),
false);
1223 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1224 if (
auto iType = dyn_cast<IntegerType>(
1225 cast<TensorType>(dense.getType()).getElementType())) {
1227 interleaveComma(dense, os, [&](
const APInt &val) {
1228 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1233 if (
auto iType = dyn_cast<IndexType>(
1234 cast<TensorType>(dense.getType()).getElementType())) {
1236 interleaveComma(dense, os,
1237 [&](
const APInt &val) { printInt(val,
false); });
1244 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1245 os << oAttr.getValue();
1250 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1251 if (sAttr.getNestedReferences().size() > 1)
1252 return emitError(loc,
"attribute has more than 1 nested reference");
1253 os << sAttr.getRootReference().getValue();
1258 if (
auto type = dyn_cast<TypeAttr>(attr))
1259 return emitType(loc, type.getValue());
1261 return emitError(loc,
"cannot emit attribute: ") << attr;
1264 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1265 assert(emittedExpressionPrecedence.empty() &&
1266 "Expected precedence stack to be empty");
1267 Operation *rootOp = expressionOp.getRootOp();
1269 emittedExpression = expressionOp;
1273 pushExpressionPrecedence(precedence.value());
1275 if (
failed(emitOperation(*rootOp,
false)))
1278 popExpressionPrecedence();
1279 assert(emittedExpressionPrecedence.empty() &&
1280 "Expected precedence stack to be empty");
1281 emittedExpression =
nullptr;
1287 if (isPartOfCurrentExpression(value)) {
1289 assert(def &&
"Expected operand to be defined by an operation");
1293 bool encloseInParenthesis = precedence.value() < getExpressionPrecedence();
1294 if (encloseInParenthesis) {
1296 pushExpressionPrecedence(lowestPrecedence());
1298 pushExpressionPrecedence(precedence.value());
1300 if (
failed(emitOperation(*def,
false)))
1303 if (encloseInParenthesis)
1306 popExpressionPrecedence();
1310 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1312 return emitExpression(expressionOp);
1314 auto literalOp = dyn_cast_if_present<LiteralOp>(value.
getDefiningOp());
1315 if (!literalOp && !hasValueInScope(value))
1317 os << getOrCreateName(value);
1325 if (getEmittedExpression())
1326 pushExpressionPrecedence(lowestPrecedence());
1327 if (failed(emitOperand(operand)))
1329 if (getEmittedExpression())
1330 popExpressionPrecedence();
1336 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1338 if (
failed(emitOperands(op)))
1343 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1351 if (llvm::is_contained(exclude, attr.getName().strref()))
1353 os <<
"/* " << attr.getName().getValue() <<
" */";
1354 if (
failed(emitAttribute(op.
getLoc(), attr.getValue())))
1362 if (!hasValueInScope(result)) {
1364 "result variable for the operation has not been declared");
1366 os << getOrCreateName(result) <<
" = ";
1371 bool trailingSemicolon) {
1374 if (hasValueInScope(result)) {
1376 "result variable for the operation already declared");
1380 getOrCreateName(result))))
1382 if (trailingSemicolon)
1389 if (getEmittedExpression())
1397 if (shouldDeclareVariablesAtTop()) {
1398 if (
failed(emitVariableAssignment(result)))
1401 if (
failed(emitVariableDeclaration(result,
false)))
1408 if (!shouldDeclareVariablesAtTop()) {
1410 if (
failed(emitVariableDeclaration(result,
true)))
1416 [&](
Value result) { os << getOrCreateName(result); });
1423 if (!hasBlockLabel(block))
1427 os.getOStream() << getOrCreateName(block) <<
":\n";
1435 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1437 .Case<cf::BranchOp, cf::CondBranchOp>(
1440 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1441 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1442 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1443 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1444 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1445 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1446 emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp,
1447 emitc::IfOp, emitc::IncludeOp, emitc::LogicalAndOp,
1448 emitc::LogicalNotOp, emitc::LogicalOrOp, emitc::MulOp,
1449 emitc::RemOp, emitc::ReturnOp, emitc::SubOp, emitc::SubscriptOp,
1450 emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
1454 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1456 .Case<emitc::LiteralOp>([&](
auto op) {
return success(); })
1458 return op.
emitOpError(
"unable to find printer for op");
1464 if (isa<emitc::LiteralOp, emitc::SubscriptOp>(op))
1467 if (getEmittedExpression() ||
1468 (isa<emitc::ExpressionOp>(op) &&
1472 os << (trailingSemicolon ?
";\n" :
"\n");
1479 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1480 if (
failed(emitType(loc, arrType.getElementType())))
1483 for (
auto dim : arrType.getShape()) {
1484 os <<
"[" << dim <<
"]";
1488 if (
failed(emitType(loc, type)))
1495 if (
auto iType = dyn_cast<IntegerType>(type)) {
1496 switch (iType.getWidth()) {
1498 return (os <<
"bool"),
success();
1503 if (shouldMapToUnsigned(iType.getSignedness()))
1504 return (os <<
"uint" << iType.getWidth() <<
"_t"),
success();
1506 return (os <<
"int" << iType.getWidth() <<
"_t"),
success();
1508 return emitError(loc,
"cannot emit integer type ") << type;
1511 if (
auto fType = dyn_cast<FloatType>(type)) {
1512 switch (fType.getWidth()) {
1514 return (os <<
"float"),
success();
1516 return (os <<
"double"),
success();
1518 return emitError(loc,
"cannot emit float type ") << type;
1521 if (
auto iType = dyn_cast<IndexType>(type))
1522 return (os <<
"size_t"),
success();
1523 if (
auto tType = dyn_cast<TensorType>(type)) {
1524 if (!tType.hasRank())
1525 return emitError(loc,
"cannot emit unranked tensor type");
1526 if (!tType.hasStaticShape())
1527 return emitError(loc,
"cannot emit tensor type with non static shape");
1529 if (isa<ArrayType>(tType.getElementType()))
1530 return emitError(loc,
"cannot emit tensor of array type ") << type;
1531 if (
failed(emitType(loc, tType.getElementType())))
1533 auto shape = tType.getShape();
1534 for (
auto dimSize : shape) {
1541 if (
auto tType = dyn_cast<TupleType>(type))
1542 return emitTupleType(loc, tType.getTypes());
1543 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1544 os << oType.getValue();
1547 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1548 if (
failed(emitType(loc, aType.getElementType())))
1550 for (
auto dim : aType.getShape())
1551 os <<
"[" << dim <<
"]";
1554 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1555 if (isa<ArrayType>(pType.getPointee()))
1556 return emitError(loc,
"cannot emit pointer to array type ") << type;
1557 if (
failed(emitType(loc, pType.getPointee())))
1562 return emitError(loc,
"cannot emit type ") << type;
1566 switch (types.size()) {
1571 return emitType(loc, types.front());
1573 return emitTupleType(loc, types);
1578 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1579 return emitError(loc,
"cannot emit tuple of array type");
1581 os <<
"std::tuple<";
1583 types, os, [&](
Type type) {
return emitType(loc, type); })))
1590 bool declareVariablesAtTop) {
1591 CppEmitter emitter(os, declareVariablesAtTop);
1592 return emitter.emitOperation(*op,
false);
static LogicalResult printCallOperation(CppEmitter &emitter, Operation *callOp, StringRef callee)
static bool shouldBeInlined(ExpressionOp expressionOp)
Determine whether expression expressionOp should be emitted inline, i.e.
LogicalResult interleaveCommaWithError(const Container &c, raw_ostream &os, UnaryFunctor eachFn)
static FailureOr< int > getOperatorPrecedence(Operation *operation)
Return the precedence of a operator as an integer, higher values imply higher precedence.
static LogicalResult printFunctionArgs(CppEmitter &emitter, Operation *functionOp, ArrayRef< Type > arguments)
static LogicalResult printFunctionBody(CppEmitter &emitter, Operation *functionOp, Region::BlockListType &blocks)
static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation, Attribute value)
LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator)
static LogicalResult printOperation(CppEmitter &emitter, emitc::ConstantOp constantOp)
static LogicalResult printUnaryOperation(CppEmitter &emitter, Operation *operation, StringRef unaryOperator)
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgListType getArguments()
Block * getSuccessor(unsigned i)
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This class provides support for representing a failure result, or a valid value of type T.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
NamedAttribute represents a combination of a name and an Attribute value.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
This class provides iteration over the held operations of blocks directly within a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
llvm::iplist< Block > BlockListType
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
user_range getUsers() const
bool hasOneUse() const
Returns true if this value has exactly one use.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
bool wasInterrupted() const
Returns true if the walk was interrupted.
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & unindent()
Decreases the indent and returning this raw_indented_ostream.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
LogicalResult translateToCpp(Operation *op, raw_ostream &os, bool declareVariablesAtTop=false)
Translates the given operation to C++ code.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This iterator enumerates the elements in "forward" order.
This class represents an efficient way to signal success or failure.