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());
388 if (failed(emitter.emitAssignPrefix(*loadOp)))
391 return emitter.emitOperand(loadOp.getOperand());
396 StringRef binaryOperator) {
397 raw_ostream &os = emitter.ostream();
399 if (failed(emitter.emitAssignPrefix(*operation)))
402 if (failed(emitter.emitOperand(operation->
getOperand(0))))
405 os <<
" " << binaryOperator <<
" ";
407 if (failed(emitter.emitOperand(operation->
getOperand(1))))
415 StringRef unaryOperator) {
416 raw_ostream &os = emitter.ostream();
418 if (failed(emitter.emitAssignPrefix(*operation)))
423 if (failed(emitter.emitOperand(operation->
getOperand(0))))
430 Operation *operation = addOp.getOperation();
436 Operation *operation = divOp.getOperation();
442 Operation *operation = mulOp.getOperation();
448 Operation *operation = remOp.getOperation();
454 Operation *operation = subOp.getOperation();
462 std::next(iteratorOp) != end; ++iteratorOp) {
463 if (failed(emitter.emitOperation(*iteratorOp,
true)))
471 emitc::SwitchOp switchOp) {
474 os <<
"\nswitch (" << emitter.getOrCreateName(switchOp.getArg()) <<
") {";
476 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
477 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
486 os <<
"\ndefault: {\n";
489 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
497 Operation *operation = cmpOp.getOperation();
499 StringRef binaryOperator;
501 switch (cmpOp.getPredicate()) {
502 case emitc::CmpPredicate::eq:
503 binaryOperator =
"==";
505 case emitc::CmpPredicate::ne:
506 binaryOperator =
"!=";
508 case emitc::CmpPredicate::lt:
509 binaryOperator =
"<";
511 case emitc::CmpPredicate::le:
512 binaryOperator =
"<=";
514 case emitc::CmpPredicate::gt:
515 binaryOperator =
">";
517 case emitc::CmpPredicate::ge:
518 binaryOperator =
">=";
520 case emitc::CmpPredicate::three_way:
521 binaryOperator =
"<=>";
529 emitc::ConditionalOp conditionalOp) {
530 raw_ostream &os = emitter.ostream();
532 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
535 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
540 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
545 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
552 emitc::VerbatimOp verbatimOp) {
553 raw_ostream &os = emitter.ostream();
555 os << verbatimOp.getValue();
561 cf::BranchOp branchOp) {
562 raw_ostream &os = emitter.ostream();
566 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
567 Value &operand = std::get<0>(pair);
569 os << emitter.getOrCreateName(argument) <<
" = "
570 << emitter.getOrCreateName(operand) <<
";\n";
574 if (!(emitter.hasBlockLabel(successor)))
575 return branchOp.emitOpError(
"unable to find label for successor block");
576 os << emitter.getOrCreateName(successor);
581 cf::CondBranchOp condBranchOp) {
583 Block &trueSuccessor = *condBranchOp.getTrueDest();
584 Block &falseSuccessor = *condBranchOp.getFalseDest();
586 os <<
"if (" << emitter.getOrCreateName(condBranchOp.getCondition())
592 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
594 Value &operand = std::get<0>(pair);
596 os << emitter.getOrCreateName(argument) <<
" = "
597 << emitter.getOrCreateName(operand) <<
";\n";
601 if (!(emitter.hasBlockLabel(trueSuccessor))) {
602 return condBranchOp.emitOpError(
"unable to find label for successor block");
604 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
608 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
610 Value &operand = std::get<0>(pair);
612 os << emitter.getOrCreateName(argument) <<
" = "
613 << emitter.getOrCreateName(operand) <<
";\n";
617 if (!(emitter.hasBlockLabel(falseSuccessor))) {
618 return condBranchOp.emitOpError()
619 <<
"unable to find label for successor block";
621 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
628 if (failed(emitter.emitAssignPrefix(*callOp)))
631 raw_ostream &os = emitter.ostream();
633 if (failed(emitter.emitOperands(*callOp)))
640 Operation *operation = callOp.getOperation();
641 StringRef callee = callOp.getCallee();
647 Operation *operation = callOp.getOperation();
648 StringRef callee = callOp.getCallee();
654 emitc::CallOpaqueOp callOpaqueOp) {
655 raw_ostream &os = emitter.ostream();
656 Operation &op = *callOpaqueOp.getOperation();
658 if (failed(emitter.emitAssignPrefix(op)))
660 os << callOpaqueOp.getCallee();
662 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
663 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
665 if (t.getType().isIndex()) {
666 int64_t idx = t.getInt();
668 if (!emitter.hasValueInScope(operand))
670 << idx <<
"'s value not defined in scope";
671 os << emitter.getOrCreateName(operand);
675 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
681 if (callOpaqueOp.getTemplateArgs()) {
691 LogicalResult emittedArgs =
692 callOpaqueOp.getArgs()
694 : emitter.emitOperands(op);
695 if (failed(emittedArgs))
702 emitc::ApplyOp applyOp) {
703 raw_ostream &os = emitter.ostream();
706 if (failed(emitter.emitAssignPrefix(op)))
708 os << applyOp.getApplicableOperator();
709 os << emitter.getOrCreateName(applyOp.getOperand());
715 emitc::BitwiseAndOp bitwiseAndOp) {
716 Operation *operation = bitwiseAndOp.getOperation();
722 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
723 Operation *operation = bitwiseLeftShiftOp.getOperation();
728 emitc::BitwiseNotOp bitwiseNotOp) {
729 Operation *operation = bitwiseNotOp.getOperation();
734 emitc::BitwiseOrOp bitwiseOrOp) {
735 Operation *operation = bitwiseOrOp.getOperation();
741 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
742 Operation *operation = bitwiseRightShiftOp.getOperation();
747 emitc::BitwiseXorOp bitwiseXorOp) {
748 Operation *operation = bitwiseXorOp.getOperation();
753 emitc::UnaryPlusOp unaryPlusOp) {
754 Operation *operation = unaryPlusOp.getOperation();
759 emitc::UnaryMinusOp unaryMinusOp) {
760 Operation *operation = unaryMinusOp.getOperation();
765 raw_ostream &os = emitter.ostream();
768 if (failed(emitter.emitAssignPrefix(op)))
774 return emitter.emitOperand(castOp.getOperand());
778 emitc::ExpressionOp expressionOp) {
782 Operation &op = *expressionOp.getOperation();
784 if (failed(emitter.emitAssignPrefix(op)))
787 return emitter.emitExpression(expressionOp);
791 emitc::IncludeOp includeOp) {
792 raw_ostream &os = emitter.ostream();
795 if (includeOp.getIsStandardInclude())
796 os <<
"<" << includeOp.getInclude() <<
">";
798 os <<
"\"" << includeOp.getInclude() <<
"\"";
804 emitc::LogicalAndOp logicalAndOp) {
805 Operation *operation = logicalAndOp.getOperation();
810 emitc::LogicalNotOp logicalNotOp) {
811 Operation *operation = logicalNotOp.getOperation();
816 emitc::LogicalOrOp logicalOrOp) {
817 Operation *operation = logicalOrOp.getOperation();
828 auto requiresParentheses = [&](
Value value) {
838 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
841 os << emitter.getOrCreateName(forOp.getInductionVar());
843 if (failed(emitter.emitOperand(forOp.getLowerBound())))
846 os << emitter.getOrCreateName(forOp.getInductionVar());
848 Value upperBound = forOp.getUpperBound();
849 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
850 if (upperBoundRequiresParentheses)
852 if (failed(emitter.emitOperand(upperBound)))
854 if (upperBoundRequiresParentheses)
857 os << emitter.getOrCreateName(forOp.getInductionVar());
859 if (failed(emitter.emitOperand(forOp.getStep())))
864 Region &forRegion = forOp.getRegion();
865 auto regionOps = forRegion.
getOps();
868 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
869 if (failed(emitter.emitOperation(*it,
true)))
883 auto emitAllExceptLast = [&emitter](
Region ®ion) {
885 for (; std::next(it) != end; ++it) {
886 if (failed(emitter.emitOperation(*it,
true)))
889 assert(isa<emitc::YieldOp>(*it) &&
890 "Expected last operation in the region to be emitc::yield");
895 if (failed(emitter.emitOperand(ifOp.getCondition())))
899 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
903 Region &elseRegion = ifOp.getElseRegion();
904 if (!elseRegion.
empty()) {
907 if (failed(emitAllExceptLast(elseRegion)))
916 func::ReturnOp returnOp) {
917 raw_ostream &os = emitter.ostream();
919 switch (returnOp.getNumOperands()) {
924 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
928 os <<
" std::make_tuple(";
929 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
937 emitc::ReturnOp returnOp) {
938 raw_ostream &os = emitter.ostream();
940 if (returnOp.getNumOperands() == 0)
944 if (failed(emitter.emitOperand(returnOp.getOperand())))
950 CppEmitter::Scope scope(emitter);
953 if (failed(emitter.emitOperation(op,
false)))
966 return emitter.emitType(functionOp->
getLoc(), arg);
977 return emitter.emitVariableDeclaration(
978 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
988 if (emitter.shouldDeclareVariablesAtTop()) {
994 (isa<emitc::ExpressionOp>(op) &&
998 if (failed(emitter.emitVariableDeclaration(
1001 op->
emitError(
"unable to declare result variable for op"));
1011 for (
Block &block : blocks) {
1012 emitter.getOrCreateName(block);
1016 for (
Block &block : llvm::drop_begin(blocks)) {
1018 if (emitter.hasValueInScope(arg))
1019 return functionOp->
emitOpError(
" block argument #")
1020 << arg.getArgNumber() <<
" is out of scope";
1021 if (isa<ArrayType, LValueType>(arg.getType()))
1022 return functionOp->
emitOpError(
"cannot emit block argument #")
1023 << arg.getArgNumber() <<
" with type " << arg.getType();
1025 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1028 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1032 for (
Block &block : blocks) {
1034 if (!block.hasNoPredecessors()) {
1035 if (failed(emitter.emitLabel(block)))
1038 for (
Operation &op : block.getOperations()) {
1043 bool trailingSemicolon =
1044 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::ForOp,
1045 emitc::IfOp, emitc::SwitchOp, emitc::VerbatimOp>(op);
1047 if (failed(emitter.emitOperation(
1048 op, trailingSemicolon)))
1059 func::FuncOp functionOp) {
1061 if (!emitter.shouldDeclareVariablesAtTop() &&
1062 functionOp.getBlocks().size() > 1) {
1063 return functionOp.emitOpError(
1064 "with multiple blocks needs variables declared at top");
1067 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1068 return functionOp.emitOpError()
1069 <<
"cannot emit lvalue type as argument type";
1072 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1073 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1076 CppEmitter::Scope scope(emitter);
1078 if (failed(emitter.emitTypes(functionOp.getLoc(),
1079 functionOp.getFunctionType().getResults())))
1081 os <<
" " << functionOp.getName();
1084 Operation *operation = functionOp.getOperation();
1096 emitc::FuncOp functionOp) {
1098 if (!emitter.shouldDeclareVariablesAtTop() &&
1099 functionOp.getBlocks().size() > 1) {
1100 return functionOp.emitOpError(
1101 "with multiple blocks needs variables declared at top");
1104 CppEmitter::Scope scope(emitter);
1106 if (functionOp.getSpecifiers()) {
1107 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1108 os << cast<StringAttr>(specifier).str() <<
" ";
1112 if (failed(emitter.emitTypes(functionOp.getLoc(),
1113 functionOp.getFunctionType().getResults())))
1115 os <<
" " << functionOp.getName();
1118 Operation *operation = functionOp.getOperation();
1119 if (functionOp.isExternal()) {
1121 functionOp.getArgumentTypes())))
1137 DeclareFuncOp declareFuncOp) {
1138 CppEmitter::Scope scope(emitter);
1141 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1142 declareFuncOp, declareFuncOp.getSymNameAttr());
1147 if (functionOp.getSpecifiers()) {
1148 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1149 os << cast<StringAttr>(specifier).str() <<
" ";
1153 if (failed(emitter.emitTypes(functionOp.getLoc(),
1154 functionOp.getFunctionType().getResults())))
1156 os <<
" " << functionOp.getName();
1159 Operation *operation = functionOp.getOperation();
1167 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop)
1168 : os(os), declareVariablesAtTop(declareVariablesAtTop) {
1169 valueInScopeCount.push(0);
1170 labelInScopeCount.push(0);
1173 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1175 llvm::raw_string_ostream ss(out);
1176 ss << getOrCreateName(op.getValue());
1177 for (
auto index : op.getIndices()) {
1178 ss <<
"[" << getOrCreateName(index) <<
"]";
1183 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1185 llvm::raw_string_ostream ss(out);
1186 ss << getOrCreateName(op.getOperand());
1187 ss <<
"." << op.getMember();
1191 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1193 llvm::raw_string_ostream ss(out);
1194 ss << getOrCreateName(op.getOperand());
1195 ss <<
"->" << op.getMember();
1199 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1200 if (!valueMapper.count(value))
1201 valueMapper.insert(value, str.str());
1205 StringRef CppEmitter::getOrCreateName(
Value val) {
1206 if (!valueMapper.count(val)) {
1208 "cacheDeferredOpResult should have been called on this value, "
1209 "update the emitOperation function.");
1210 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1212 return *valueMapper.begin(val);
1216 StringRef CppEmitter::getOrCreateName(
Block &block) {
1217 if (!blockMapper.count(&block))
1218 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1219 return *blockMapper.begin(&block);
1222 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1224 case IntegerType::Signless:
1228 case IntegerType::Unsigned:
1231 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1234 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1236 bool CppEmitter::hasBlockLabel(
Block &block) {
1237 return blockMapper.count(&block);
1241 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1242 if (val.getBitWidth() == 1) {
1243 if (val.getBoolValue())
1249 val.toString(strValue, 10, !isUnsigned,
false);
1254 auto printFloat = [&](
const APFloat &val) {
1255 if (val.isFinite()) {
1258 val.toString(strValue, 0, 0,
false);
1260 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1261 case llvm::APFloatBase::S_IEEEhalf:
1264 case llvm::APFloatBase::S_BFloat:
1267 case llvm::APFloatBase::S_IEEEsingle:
1270 case llvm::APFloatBase::S_IEEEdouble:
1273 llvm_unreachable(
"unsupported floating point type");
1275 }
else if (val.isNaN()) {
1277 }
else if (val.isInfinity()) {
1278 if (val.isNegative())
1285 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1286 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1289 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1291 printFloat(fAttr.getValue());
1294 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1295 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1296 dense.getElementType())) {
1298 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1301 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1307 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1308 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1309 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1312 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1313 printInt(iAttr.getValue(),
false);
1317 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1318 if (
auto iType = dyn_cast<IntegerType>(
1319 cast<TensorType>(dense.getType()).getElementType())) {
1321 interleaveComma(dense, os, [&](
const APInt &val) {
1322 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1327 if (
auto iType = dyn_cast<IndexType>(
1328 cast<TensorType>(dense.getType()).getElementType())) {
1330 interleaveComma(dense, os,
1331 [&](
const APInt &val) { printInt(val,
false); });
1338 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1339 os << oAttr.getValue();
1344 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1345 if (sAttr.getNestedReferences().size() > 1)
1346 return emitError(loc,
"attribute has more than 1 nested reference");
1347 os << sAttr.getRootReference().getValue();
1352 if (
auto type = dyn_cast<TypeAttr>(attr))
1353 return emitType(loc, type.getValue());
1355 return emitError(loc,
"cannot emit attribute: ") << attr;
1358 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1359 assert(emittedExpressionPrecedence.empty() &&
1360 "Expected precedence stack to be empty");
1361 Operation *rootOp = expressionOp.getRootOp();
1363 emittedExpression = expressionOp;
1365 if (failed(precedence))
1367 pushExpressionPrecedence(precedence.value());
1369 if (failed(emitOperation(*rootOp,
false)))
1372 popExpressionPrecedence();
1373 assert(emittedExpressionPrecedence.empty() &&
1374 "Expected precedence stack to be empty");
1375 emittedExpression =
nullptr;
1380 LogicalResult CppEmitter::emitOperand(
Value value) {
1381 if (isPartOfCurrentExpression(value)) {
1383 assert(def &&
"Expected operand to be defined by an operation");
1385 if (failed(precedence))
1391 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1392 if (encloseInParenthesis) {
1394 pushExpressionPrecedence(lowestPrecedence());
1396 pushExpressionPrecedence(precedence.value());
1398 if (failed(emitOperation(*def,
false)))
1401 if (encloseInParenthesis)
1404 popExpressionPrecedence();
1408 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1410 return emitExpression(expressionOp);
1412 os << getOrCreateName(value);
1416 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1420 if (getEmittedExpression())
1421 pushExpressionPrecedence(lowestPrecedence());
1422 if (failed(emitOperand(operand)))
1424 if (getEmittedExpression())
1425 popExpressionPrecedence();
1431 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1433 if (failed(emitOperands(op)))
1438 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1445 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1446 if (llvm::is_contained(exclude, attr.getName().strref()))
1448 os <<
"/* " << attr.getName().getValue() <<
" */";
1449 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1456 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1457 if (!hasValueInScope(result)) {
1459 "result variable for the operation has not been declared");
1461 os << getOrCreateName(result) <<
" = ";
1465 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1466 bool trailingSemicolon) {
1469 if (hasValueInScope(result)) {
1471 "result variable for the operation already declared");
1475 getOrCreateName(result))))
1477 if (trailingSemicolon)
1482 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1483 if (op.getExternSpecifier())
1485 else if (op.getStaticSpecifier())
1487 if (op.getConstSpecifier())
1490 if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1491 op.getSymName()))) {
1495 std::optional<Attribute> initialValue = op.getInitialValue();
1498 if (failed(emitAttribute(op->getLoc(), *initialValue)))
1506 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1508 if (getEmittedExpression())
1516 if (shouldDeclareVariablesAtTop()) {
1517 if (failed(emitVariableAssignment(result)))
1520 if (failed(emitVariableDeclaration(result,
false)))
1527 if (!shouldDeclareVariablesAtTop()) {
1529 if (failed(emitVariableDeclaration(result,
true)))
1535 [&](
Value result) { os << getOrCreateName(result); });
1541 LogicalResult CppEmitter::emitLabel(
Block &block) {
1542 if (!hasBlockLabel(block))
1546 os.getOStream() << getOrCreateName(block) <<
":\n";
1550 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1551 LogicalResult status =
1554 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1556 .Case<cf::BranchOp, cf::CondBranchOp>(
1559 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1560 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1561 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1562 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1563 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1564 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1565 emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp,
1566 emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, emitc::LoadOp,
1567 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1568 emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
1569 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1570 emitc::VariableOp, emitc::VerbatimOp>(
1573 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1575 .Case<emitc::GetGlobalOp>([&](
auto op) {
1579 .Case<emitc::LiteralOp>([&](
auto op) {
1580 cacheDeferredOpResult(op.
getResult(), op.getValue());
1583 .Case<emitc::MemberOp>([&](
auto op) {
1584 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1587 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1588 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1591 .Case<emitc::SubscriptOp>([&](
auto op) {
1592 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1596 return op.
emitOpError(
"unable to find printer for op");
1605 if (getEmittedExpression() ||
1606 (isa<emitc::ExpressionOp>(op) &&
1610 os << (trailingSemicolon ?
";\n" :
"\n");
1615 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1617 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1618 if (failed(emitType(loc, arrType.getElementType())))
1621 for (
auto dim : arrType.getShape()) {
1622 os <<
"[" << dim <<
"]";
1626 if (failed(emitType(loc, type)))
1632 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1633 if (
auto iType = dyn_cast<IntegerType>(type)) {
1634 switch (iType.getWidth()) {
1636 return (os <<
"bool"), success();
1641 if (shouldMapToUnsigned(iType.getSignedness()))
1642 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1644 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1646 return emitError(loc,
"cannot emit integer type ") << type;
1649 if (
auto fType = dyn_cast<FloatType>(type)) {
1650 switch (fType.getWidth()) {
1652 if (llvm::isa<Float16Type>(type))
1653 return (os <<
"_Float16"), success();
1654 else if (llvm::isa<BFloat16Type>(type))
1655 return (os <<
"__bf16"), success();
1657 return emitError(loc,
"cannot emit float type ") << type;
1660 return (os <<
"float"), success();
1662 return (os <<
"double"), success();
1664 return emitError(loc,
"cannot emit float type ") << type;
1667 if (
auto iType = dyn_cast<IndexType>(type))
1668 return (os <<
"size_t"), success();
1669 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1670 return (os <<
"size_t"), success();
1671 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1672 return (os <<
"ssize_t"), success();
1673 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1674 return (os <<
"ptrdiff_t"), success();
1675 if (
auto tType = dyn_cast<TensorType>(type)) {
1676 if (!tType.hasRank())
1677 return emitError(loc,
"cannot emit unranked tensor type");
1678 if (!tType.hasStaticShape())
1679 return emitError(loc,
"cannot emit tensor type with non static shape");
1681 if (isa<ArrayType>(tType.getElementType()))
1682 return emitError(loc,
"cannot emit tensor of array type ") << type;
1683 if (failed(emitType(loc, tType.getElementType())))
1685 auto shape = tType.getShape();
1686 for (
auto dimSize : shape) {
1693 if (
auto tType = dyn_cast<TupleType>(type))
1694 return emitTupleType(loc, tType.getTypes());
1695 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1696 os << oType.getValue();
1699 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1700 if (failed(emitType(loc, aType.getElementType())))
1702 for (
auto dim : aType.getShape())
1703 os <<
"[" << dim <<
"]";
1706 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1707 return emitType(loc, lType.getValueType());
1708 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1709 if (isa<ArrayType>(pType.getPointee()))
1710 return emitError(loc,
"cannot emit pointer to array type ") << type;
1711 if (failed(emitType(loc, pType.getPointee())))
1716 return emitError(loc,
"cannot emit type ") << type;
1720 switch (types.size()) {
1725 return emitType(loc, types.front());
1727 return emitTupleType(loc, types);
1732 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1733 return emitError(loc,
"cannot emit tuple of array type");
1735 os <<
"std::tuple<";
1737 types, os, [&](
Type type) {
return emitType(loc, type); })))
1744 bool declareVariablesAtTop) {
1745 CppEmitter emitter(os, declareVariablesAtTop);
1746 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)
static LogicalResult emitSwitchCase(CppEmitter &emitter, raw_indented_ostream &os, Region ®ion)
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
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
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.