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; })
86 .Case<emitc::CmpOp>([&](
auto op) -> FailureOr<int> {
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);
123 LogicalResult emitOperation(
Operation &op,
bool trailingSemicolon);
139 LogicalResult emitVariableAssignment(
OpResult result);
142 LogicalResult emitVariableDeclaration(
OpResult result,
143 bool trailingSemicolon);
146 LogicalResult emitVariableDeclaration(
Location loc,
Type type,
155 LogicalResult emitAssignPrefix(
Operation &op);
158 LogicalResult emitGlobalVariable(GlobalOp op);
161 LogicalResult emitLabel(
Block &block);
165 LogicalResult emitOperandsAndAttributes(
Operation &op,
169 LogicalResult emitOperands(
Operation &op);
172 LogicalResult emitOperand(
Value value);
175 LogicalResult emitExpression(ExpressionOp expressionOp);
178 void cacheDeferredOpResult(
Value value, StringRef str);
181 StringRef getOrCreateName(
Value val);
184 std::string getSubscriptName(emitc::SubscriptOp op);
187 std::string createMemberAccess(emitc::MemberOp op);
190 std::string createMemberAccess(emitc::MemberOfPtrOp op);
193 StringRef getOrCreateName(
Block &block);
196 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
200 Scope(CppEmitter &emitter)
201 : valueMapperScope(emitter.valueMapper),
202 blockMapperScope(emitter.blockMapper), emitter(emitter) {
203 emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
204 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
207 emitter.valueInScopeCount.pop();
208 emitter.labelInScopeCount.pop();
212 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
213 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
218 bool hasValueInScope(
Value val);
221 bool hasBlockLabel(
Block &block);
228 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
231 ExpressionOp getEmittedExpression() {
return emittedExpression; }
235 bool isPartOfCurrentExpression(
Value value) {
236 if (!emittedExpression)
241 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
242 return operandExpression == emittedExpression;
246 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
247 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
255 bool declareVariablesAtTop;
258 ValueMapper valueMapper;
261 BlockMapper blockMapper;
265 std::stack<int64_t> valueInScopeCount;
266 std::stack<int64_t> labelInScopeCount;
269 ExpressionOp emittedExpression;
272 void pushExpressionPrecedence(
int precedence) {
273 emittedExpressionPrecedence.push_back(precedence);
275 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
276 static int lowestPrecedence() {
return 0; }
277 int getExpressionPrecedence() {
278 if (emittedExpressionPrecedence.empty())
279 return lowestPrecedence();
280 return emittedExpressionPrecedence.back();
287 return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
288 emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
298 if (expressionOp.getDoNotInline())
303 if (expressionOp.hasSideEffects())
307 Value result = expressionOp.getResult();
329 if (emitter.shouldDeclareVariablesAtTop()) {
331 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
332 if (oAttr.getValue().empty())
336 if (failed(emitter.emitVariableAssignment(result)))
338 return emitter.emitAttribute(operation->
getLoc(), value);
342 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
343 if (oAttr.getValue().empty())
345 return emitter.emitVariableDeclaration(result,
350 if (failed(emitter.emitAssignPrefix(*operation)))
352 return emitter.emitAttribute(operation->
getLoc(), value);
356 emitc::ConstantOp constantOp) {
357 Operation *operation = constantOp.getOperation();
364 emitc::VariableOp variableOp) {
365 Operation *operation = variableOp.getOperation();
372 emitc::GlobalOp globalOp) {
374 return emitter.emitGlobalVariable(globalOp);
378 emitc::AssignOp assignOp) {
381 if (failed(emitter.emitVariableAssignment(result)))
384 return emitter.emitOperand(assignOp.getValue());
389 StringRef binaryOperator) {
390 raw_ostream &os = emitter.ostream();
392 if (failed(emitter.emitAssignPrefix(*operation)))
395 if (failed(emitter.emitOperand(operation->
getOperand(0))))
398 os <<
" " << binaryOperator <<
" ";
400 if (failed(emitter.emitOperand(operation->
getOperand(1))))
408 StringRef unaryOperator) {
409 raw_ostream &os = emitter.ostream();
411 if (failed(emitter.emitAssignPrefix(*operation)))
416 if (failed(emitter.emitOperand(operation->
getOperand(0))))
423 Operation *operation = addOp.getOperation();
429 Operation *operation = divOp.getOperation();
435 Operation *operation = mulOp.getOperation();
441 Operation *operation = remOp.getOperation();
447 Operation *operation = subOp.getOperation();
453 Operation *operation = cmpOp.getOperation();
455 StringRef binaryOperator;
457 switch (cmpOp.getPredicate()) {
458 case emitc::CmpPredicate::eq:
459 binaryOperator =
"==";
461 case emitc::CmpPredicate::ne:
462 binaryOperator =
"!=";
464 case emitc::CmpPredicate::lt:
465 binaryOperator =
"<";
467 case emitc::CmpPredicate::le:
468 binaryOperator =
"<=";
470 case emitc::CmpPredicate::gt:
471 binaryOperator =
">";
473 case emitc::CmpPredicate::ge:
474 binaryOperator =
">=";
476 case emitc::CmpPredicate::three_way:
477 binaryOperator =
"<=>";
485 emitc::ConditionalOp conditionalOp) {
486 raw_ostream &os = emitter.ostream();
488 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
491 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
496 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
501 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
508 emitc::VerbatimOp verbatimOp) {
509 raw_ostream &os = emitter.ostream();
511 os << verbatimOp.getValue();
517 cf::BranchOp branchOp) {
518 raw_ostream &os = emitter.ostream();
522 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
523 Value &operand = std::get<0>(pair);
525 os << emitter.getOrCreateName(argument) <<
" = "
526 << emitter.getOrCreateName(operand) <<
";\n";
530 if (!(emitter.hasBlockLabel(successor)))
531 return branchOp.emitOpError(
"unable to find label for successor block");
532 os << emitter.getOrCreateName(successor);
537 cf::CondBranchOp condBranchOp) {
539 Block &trueSuccessor = *condBranchOp.getTrueDest();
540 Block &falseSuccessor = *condBranchOp.getFalseDest();
542 os <<
"if (" << emitter.getOrCreateName(condBranchOp.getCondition())
548 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
550 Value &operand = std::get<0>(pair);
552 os << emitter.getOrCreateName(argument) <<
" = "
553 << emitter.getOrCreateName(operand) <<
";\n";
557 if (!(emitter.hasBlockLabel(trueSuccessor))) {
558 return condBranchOp.emitOpError(
"unable to find label for successor block");
560 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
564 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
566 Value &operand = std::get<0>(pair);
568 os << emitter.getOrCreateName(argument) <<
" = "
569 << emitter.getOrCreateName(operand) <<
";\n";
573 if (!(emitter.hasBlockLabel(falseSuccessor))) {
574 return condBranchOp.emitOpError()
575 <<
"unable to find label for successor block";
577 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
584 if (failed(emitter.emitAssignPrefix(*callOp)))
587 raw_ostream &os = emitter.ostream();
589 if (failed(emitter.emitOperands(*callOp)))
596 Operation *operation = callOp.getOperation();
597 StringRef callee = callOp.getCallee();
603 Operation *operation = callOp.getOperation();
604 StringRef callee = callOp.getCallee();
610 emitc::CallOpaqueOp callOpaqueOp) {
611 raw_ostream &os = emitter.ostream();
612 Operation &op = *callOpaqueOp.getOperation();
614 if (failed(emitter.emitAssignPrefix(op)))
616 os << callOpaqueOp.getCallee();
618 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
619 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
621 if (t.getType().isIndex()) {
622 int64_t idx = t.getInt();
624 if (!emitter.hasValueInScope(operand))
626 << idx <<
"'s value not defined in scope";
627 os << emitter.getOrCreateName(operand);
631 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
637 if (callOpaqueOp.getTemplateArgs()) {
647 LogicalResult emittedArgs =
648 callOpaqueOp.getArgs()
650 : emitter.emitOperands(op);
651 if (failed(emittedArgs))
658 emitc::ApplyOp applyOp) {
659 raw_ostream &os = emitter.ostream();
662 if (failed(emitter.emitAssignPrefix(op)))
664 os << applyOp.getApplicableOperator();
665 os << emitter.getOrCreateName(applyOp.getOperand());
671 emitc::BitwiseAndOp bitwiseAndOp) {
672 Operation *operation = bitwiseAndOp.getOperation();
678 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
679 Operation *operation = bitwiseLeftShiftOp.getOperation();
684 emitc::BitwiseNotOp bitwiseNotOp) {
685 Operation *operation = bitwiseNotOp.getOperation();
690 emitc::BitwiseOrOp bitwiseOrOp) {
691 Operation *operation = bitwiseOrOp.getOperation();
697 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
698 Operation *operation = bitwiseRightShiftOp.getOperation();
703 emitc::BitwiseXorOp bitwiseXorOp) {
704 Operation *operation = bitwiseXorOp.getOperation();
709 emitc::UnaryPlusOp unaryPlusOp) {
710 Operation *operation = unaryPlusOp.getOperation();
715 emitc::UnaryMinusOp unaryMinusOp) {
716 Operation *operation = unaryMinusOp.getOperation();
721 raw_ostream &os = emitter.ostream();
724 if (failed(emitter.emitAssignPrefix(op)))
730 return emitter.emitOperand(castOp.getOperand());
734 emitc::ExpressionOp expressionOp) {
738 Operation &op = *expressionOp.getOperation();
740 if (failed(emitter.emitAssignPrefix(op)))
743 return emitter.emitExpression(expressionOp);
747 emitc::IncludeOp includeOp) {
748 raw_ostream &os = emitter.ostream();
751 if (includeOp.getIsStandardInclude())
752 os <<
"<" << includeOp.getInclude() <<
">";
754 os <<
"\"" << includeOp.getInclude() <<
"\"";
760 emitc::LogicalAndOp logicalAndOp) {
761 Operation *operation = logicalAndOp.getOperation();
766 emitc::LogicalNotOp logicalNotOp) {
767 Operation *operation = logicalNotOp.getOperation();
772 emitc::LogicalOrOp logicalOrOp) {
773 Operation *operation = logicalOrOp.getOperation();
784 auto requiresParentheses = [&](
Value value) {
794 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
797 os << emitter.getOrCreateName(forOp.getInductionVar());
799 if (failed(emitter.emitOperand(forOp.getLowerBound())))
802 os << emitter.getOrCreateName(forOp.getInductionVar());
804 Value upperBound = forOp.getUpperBound();
805 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
806 if (upperBoundRequiresParentheses)
808 if (failed(emitter.emitOperand(upperBound)))
810 if (upperBoundRequiresParentheses)
813 os << emitter.getOrCreateName(forOp.getInductionVar());
815 if (failed(emitter.emitOperand(forOp.getStep())))
820 Region &forRegion = forOp.getRegion();
821 auto regionOps = forRegion.
getOps();
824 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
825 if (failed(emitter.emitOperation(*it,
true)))
839 auto emitAllExceptLast = [&emitter](
Region ®ion) {
841 for (; std::next(it) != end; ++it) {
842 if (failed(emitter.emitOperation(*it,
true)))
845 assert(isa<emitc::YieldOp>(*it) &&
846 "Expected last operation in the region to be emitc::yield");
851 if (failed(emitter.emitOperand(ifOp.getCondition())))
855 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
859 Region &elseRegion = ifOp.getElseRegion();
860 if (!elseRegion.
empty()) {
863 if (failed(emitAllExceptLast(elseRegion)))
872 func::ReturnOp returnOp) {
873 raw_ostream &os = emitter.ostream();
875 switch (returnOp.getNumOperands()) {
880 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
884 os <<
" std::make_tuple(";
885 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
893 emitc::ReturnOp returnOp) {
894 raw_ostream &os = emitter.ostream();
896 if (returnOp.getNumOperands() == 0)
900 if (failed(emitter.emitOperand(returnOp.getOperand())))
906 CppEmitter::Scope scope(emitter);
909 if (failed(emitter.emitOperation(op,
false)))
922 return emitter.emitType(functionOp->
getLoc(), arg);
933 return emitter.emitVariableDeclaration(
934 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
944 if (emitter.shouldDeclareVariablesAtTop()) {
950 (isa<emitc::ExpressionOp>(op) &&
954 if (failed(emitter.emitVariableDeclaration(
957 op->
emitError(
"unable to declare result variable for op"));
967 for (
Block &block : blocks) {
968 emitter.getOrCreateName(block);
972 for (
Block &block : llvm::drop_begin(blocks)) {
974 if (emitter.hasValueInScope(arg))
975 return functionOp->
emitOpError(
" block argument #")
976 << arg.getArgNumber() <<
" is out of scope";
977 if (isa<ArrayType>(arg.getType()))
978 return functionOp->
emitOpError(
"cannot emit block argument #")
979 << arg.getArgNumber() <<
" with array type";
981 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
984 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
988 for (
Block &block : blocks) {
990 if (!block.hasNoPredecessors()) {
991 if (failed(emitter.emitLabel(block)))
994 for (
Operation &op : block.getOperations()) {
999 bool trailingSemicolon =
1000 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::ForOp,
1001 emitc::IfOp, emitc::VerbatimOp>(op);
1003 if (failed(emitter.emitOperation(
1004 op, trailingSemicolon)))
1015 func::FuncOp functionOp) {
1017 if (!emitter.shouldDeclareVariablesAtTop() &&
1018 functionOp.getBlocks().size() > 1) {
1019 return functionOp.emitOpError(
1020 "with multiple blocks needs variables declared at top");
1023 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1024 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1027 CppEmitter::Scope scope(emitter);
1029 if (failed(emitter.emitTypes(functionOp.getLoc(),
1030 functionOp.getFunctionType().getResults())))
1032 os <<
" " << functionOp.getName();
1035 Operation *operation = functionOp.getOperation();
1047 emitc::FuncOp functionOp) {
1049 if (!emitter.shouldDeclareVariablesAtTop() &&
1050 functionOp.getBlocks().size() > 1) {
1051 return functionOp.emitOpError(
1052 "with multiple blocks needs variables declared at top");
1055 CppEmitter::Scope scope(emitter);
1057 if (functionOp.getSpecifiers()) {
1058 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1059 os << cast<StringAttr>(specifier).str() <<
" ";
1063 if (failed(emitter.emitTypes(functionOp.getLoc(),
1064 functionOp.getFunctionType().getResults())))
1066 os <<
" " << functionOp.getName();
1069 Operation *operation = functionOp.getOperation();
1070 if (functionOp.isExternal()) {
1072 functionOp.getArgumentTypes())))
1088 DeclareFuncOp declareFuncOp) {
1089 CppEmitter::Scope scope(emitter);
1092 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1093 declareFuncOp, declareFuncOp.getSymNameAttr());
1098 if (functionOp.getSpecifiers()) {
1099 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1100 os << cast<StringAttr>(specifier).str() <<
" ";
1104 if (failed(emitter.emitTypes(functionOp.getLoc(),
1105 functionOp.getFunctionType().getResults())))
1107 os <<
" " << functionOp.getName();
1110 Operation *operation = functionOp.getOperation();
1118 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop)
1119 : os(os), declareVariablesAtTop(declareVariablesAtTop) {
1120 valueInScopeCount.push(0);
1121 labelInScopeCount.push(0);
1124 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1126 llvm::raw_string_ostream ss(out);
1127 ss << getOrCreateName(op.getValue());
1128 for (
auto index : op.getIndices()) {
1129 ss <<
"[" << getOrCreateName(index) <<
"]";
1134 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1136 llvm::raw_string_ostream ss(out);
1138 ss <<
"." << op.getMember();
1142 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1144 llvm::raw_string_ostream ss(out);
1146 ss <<
"->" << op.getMember();
1150 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1151 if (!valueMapper.count(value))
1152 valueMapper.insert(value, str.str());
1156 StringRef CppEmitter::getOrCreateName(
Value val) {
1157 if (!valueMapper.count(val)) {
1159 "cacheDeferredOpResult should have been called on this value, "
1160 "update the emitOperation function.");
1161 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1163 return *valueMapper.begin(val);
1167 StringRef CppEmitter::getOrCreateName(
Block &block) {
1168 if (!blockMapper.count(&block))
1169 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1170 return *blockMapper.begin(&block);
1173 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1175 case IntegerType::Signless:
1179 case IntegerType::Unsigned:
1182 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1185 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1187 bool CppEmitter::hasBlockLabel(
Block &block) {
1188 return blockMapper.count(&block);
1192 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1193 if (val.getBitWidth() == 1) {
1194 if (val.getBoolValue())
1200 val.toString(strValue, 10, !isUnsigned,
false);
1205 auto printFloat = [&](
const APFloat &val) {
1206 if (val.isFinite()) {
1209 val.toString(strValue, 0, 0,
false);
1211 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1212 case llvm::APFloatBase::S_IEEEsingle:
1215 case llvm::APFloatBase::S_IEEEdouble:
1218 llvm_unreachable(
"unsupported floating point type");
1220 }
else if (val.isNaN()) {
1222 }
else if (val.isInfinity()) {
1223 if (val.isNegative())
1230 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1231 if (!isa<Float32Type, Float64Type>(fAttr.getType())) {
1233 "expected floating point attribute to be f32 or f64");
1235 printFloat(fAttr.getValue());
1238 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1239 if (!isa<Float32Type, Float64Type>(dense.getElementType())) {
1241 "expected floating point attribute to be f32 or f64");
1244 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1250 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1251 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1252 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1255 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1256 printInt(iAttr.getValue(),
false);
1260 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1261 if (
auto iType = dyn_cast<IntegerType>(
1262 cast<TensorType>(dense.getType()).getElementType())) {
1264 interleaveComma(dense, os, [&](
const APInt &val) {
1265 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1270 if (
auto iType = dyn_cast<IndexType>(
1271 cast<TensorType>(dense.getType()).getElementType())) {
1273 interleaveComma(dense, os,
1274 [&](
const APInt &val) { printInt(val,
false); });
1281 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1282 os << oAttr.getValue();
1287 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1288 if (sAttr.getNestedReferences().size() > 1)
1289 return emitError(loc,
"attribute has more than 1 nested reference");
1290 os << sAttr.getRootReference().getValue();
1295 if (
auto type = dyn_cast<TypeAttr>(attr))
1296 return emitType(loc, type.getValue());
1298 return emitError(loc,
"cannot emit attribute: ") << attr;
1301 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1302 assert(emittedExpressionPrecedence.empty() &&
1303 "Expected precedence stack to be empty");
1304 Operation *rootOp = expressionOp.getRootOp();
1306 emittedExpression = expressionOp;
1308 if (failed(precedence))
1310 pushExpressionPrecedence(precedence.value());
1312 if (failed(emitOperation(*rootOp,
false)))
1315 popExpressionPrecedence();
1316 assert(emittedExpressionPrecedence.empty() &&
1317 "Expected precedence stack to be empty");
1318 emittedExpression =
nullptr;
1323 LogicalResult CppEmitter::emitOperand(
Value value) {
1324 if (isPartOfCurrentExpression(value)) {
1326 assert(def &&
"Expected operand to be defined by an operation");
1328 if (failed(precedence))
1334 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1335 if (encloseInParenthesis) {
1337 pushExpressionPrecedence(lowestPrecedence());
1339 pushExpressionPrecedence(precedence.value());
1341 if (failed(emitOperation(*def,
false)))
1344 if (encloseInParenthesis)
1347 popExpressionPrecedence();
1351 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1353 return emitExpression(expressionOp);
1355 os << getOrCreateName(value);
1359 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1363 if (getEmittedExpression())
1364 pushExpressionPrecedence(lowestPrecedence());
1365 if (failed(emitOperand(operand)))
1367 if (getEmittedExpression())
1368 popExpressionPrecedence();
1374 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1376 if (failed(emitOperands(op)))
1381 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1388 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1389 if (llvm::is_contained(exclude, attr.getName().strref()))
1391 os <<
"/* " << attr.getName().getValue() <<
" */";
1392 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1399 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1400 if (!hasValueInScope(result)) {
1402 "result variable for the operation has not been declared");
1404 os << getOrCreateName(result) <<
" = ";
1408 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1409 bool trailingSemicolon) {
1412 if (hasValueInScope(result)) {
1414 "result variable for the operation already declared");
1418 getOrCreateName(result))))
1420 if (trailingSemicolon)
1425 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1426 if (op.getExternSpecifier())
1428 else if (op.getStaticSpecifier())
1430 if (op.getConstSpecifier())
1433 if (failed(emitVariableDeclaration(op->
getLoc(), op.getType(),
1434 op.getSymName()))) {
1438 std::optional<Attribute> initialValue = op.getInitialValue();
1441 if (failed(emitAttribute(op->
getLoc(), *initialValue)))
1449 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1451 if (getEmittedExpression())
1459 if (shouldDeclareVariablesAtTop()) {
1460 if (failed(emitVariableAssignment(result)))
1463 if (failed(emitVariableDeclaration(result,
false)))
1470 if (!shouldDeclareVariablesAtTop()) {
1472 if (failed(emitVariableDeclaration(result,
true)))
1478 [&](
Value result) { os << getOrCreateName(result); });
1484 LogicalResult CppEmitter::emitLabel(
Block &block) {
1485 if (!hasBlockLabel(block))
1489 os.getOStream() << getOrCreateName(block) <<
":\n";
1493 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1494 LogicalResult status =
1497 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1499 .Case<cf::BranchOp, cf::CondBranchOp>(
1502 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1503 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1504 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1505 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1506 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1507 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1508 emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp,
1509 emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp,
1510 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1511 emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
1512 emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
1516 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1518 .Case<emitc::GetGlobalOp>([&](
auto op) {
1522 .Case<emitc::LiteralOp>([&](
auto op) {
1523 cacheDeferredOpResult(op.
getResult(), op.getValue());
1526 .Case<emitc::MemberOp>([&](
auto op) {
1527 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1530 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1531 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1534 .Case<emitc::SubscriptOp>([&](
auto op) {
1535 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1539 return op.
emitOpError(
"unable to find printer for op");
1548 if (getEmittedExpression() ||
1549 (isa<emitc::ExpressionOp>(op) &&
1553 os << (trailingSemicolon ?
";\n" :
"\n");
1558 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1560 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1561 if (failed(emitType(loc, arrType.getElementType())))
1564 for (
auto dim : arrType.getShape()) {
1565 os <<
"[" << dim <<
"]";
1569 if (failed(emitType(loc, type)))
1575 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1576 if (
auto iType = dyn_cast<IntegerType>(type)) {
1577 switch (iType.getWidth()) {
1579 return (os <<
"bool"), success();
1584 if (shouldMapToUnsigned(iType.getSignedness()))
1585 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1587 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1589 return emitError(loc,
"cannot emit integer type ") << type;
1592 if (
auto fType = dyn_cast<FloatType>(type)) {
1593 switch (fType.getWidth()) {
1595 return (os <<
"float"), success();
1597 return (os <<
"double"), success();
1599 return emitError(loc,
"cannot emit float type ") << type;
1602 if (
auto iType = dyn_cast<IndexType>(type))
1603 return (os <<
"size_t"), success();
1604 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1605 return (os <<
"size_t"), success();
1606 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1607 return (os <<
"ssize_t"), success();
1608 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1609 return (os <<
"ptrdiff_t"), success();
1610 if (
auto tType = dyn_cast<TensorType>(type)) {
1611 if (!tType.hasRank())
1612 return emitError(loc,
"cannot emit unranked tensor type");
1613 if (!tType.hasStaticShape())
1614 return emitError(loc,
"cannot emit tensor type with non static shape");
1616 if (isa<ArrayType>(tType.getElementType()))
1617 return emitError(loc,
"cannot emit tensor of array type ") << type;
1618 if (failed(emitType(loc, tType.getElementType())))
1620 auto shape = tType.getShape();
1621 for (
auto dimSize : shape) {
1628 if (
auto tType = dyn_cast<TupleType>(type))
1629 return emitTupleType(loc, tType.getTypes());
1630 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1631 os << oType.getValue();
1634 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1635 if (failed(emitType(loc, aType.getElementType())))
1637 for (
auto dim : aType.getShape())
1638 os <<
"[" << dim <<
"]";
1641 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1642 if (isa<ArrayType>(pType.getPointee()))
1643 return emitError(loc,
"cannot emit pointer to array type ") << type;
1644 if (failed(emitType(loc, pType.getPointee())))
1649 return emitError(loc,
"cannot emit type ") << type;
1653 switch (types.size()) {
1658 return emitType(loc, types.front());
1660 return emitTupleType(loc, types);
1665 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1666 return emitError(loc,
"cannot emit tuple of array type");
1668 os <<
"std::tuple<";
1670 types, os, [&](
Type type) {
return emitType(loc, type); })))
1677 bool declareVariablesAtTop) {
1678 CppEmitter emitter(os, declareVariablesAtTop);
1679 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)
static bool hasDeferredEmission(Operation *op)
Determine whether expression op should be emitted in a deferred way.
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 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)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
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...
OperationName getName()
The name of an operation is the key identifier for it.
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.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This iterator enumerates the elements in "forward" order.