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,
128 LogicalResult emitOperation(
Operation &op,
bool trailingSemicolon);
144 LogicalResult emitVariableAssignment(
OpResult result);
147 LogicalResult emitVariableDeclaration(
OpResult result,
148 bool trailingSemicolon);
151 LogicalResult emitVariableDeclaration(
Location loc,
Type type,
160 LogicalResult emitAssignPrefix(
Operation &op);
163 LogicalResult emitGlobalVariable(GlobalOp op);
166 LogicalResult emitLabel(
Block &block);
170 LogicalResult emitOperandsAndAttributes(
Operation &op,
174 LogicalResult emitOperands(
Operation &op);
177 LogicalResult emitOperand(
Value value);
180 LogicalResult emitExpression(ExpressionOp expressionOp);
183 void cacheDeferredOpResult(
Value value, StringRef str);
186 StringRef getOrCreateName(
Value val);
189 std::string getSubscriptName(emitc::SubscriptOp op);
192 std::string createMemberAccess(emitc::MemberOp op);
195 std::string createMemberAccess(emitc::MemberOfPtrOp op);
198 StringRef getOrCreateName(
Block &block);
201 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
205 Scope(CppEmitter &emitter)
206 : valueMapperScope(emitter.valueMapper),
207 blockMapperScope(emitter.blockMapper), emitter(emitter) {
208 emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
209 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
212 emitter.valueInScopeCount.pop();
213 emitter.labelInScopeCount.pop();
217 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
218 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
223 bool hasValueInScope(
Value val);
226 bool hasBlockLabel(
Block &block);
233 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
236 bool shouldEmitFile(FileOp file) {
237 return !fileId.empty() && file.getId() == fileId;
241 ExpressionOp getEmittedExpression() {
return emittedExpression; }
245 bool isPartOfCurrentExpression(
Value value) {
246 if (!emittedExpression)
251 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
252 return operandExpression == emittedExpression;
256 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
257 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
265 bool declareVariablesAtTop;
271 ValueMapper valueMapper;
274 BlockMapper blockMapper;
278 std::stack<int64_t> valueInScopeCount;
279 std::stack<int64_t> labelInScopeCount;
282 ExpressionOp emittedExpression;
285 void pushExpressionPrecedence(
int precedence) {
286 emittedExpressionPrecedence.push_back(precedence);
288 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
289 static int lowestPrecedence() {
return 0; }
290 int getExpressionPrecedence() {
291 if (emittedExpressionPrecedence.empty())
292 return lowestPrecedence();
293 return emittedExpressionPrecedence.back();
300 return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
301 emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
311 if (expressionOp.getDoNotInline())
316 if (expressionOp.hasSideEffects())
320 Value result = expressionOp.getResult();
342 if (emitter.shouldDeclareVariablesAtTop()) {
344 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
345 if (oAttr.getValue().empty())
349 if (failed(emitter.emitVariableAssignment(result)))
351 return emitter.emitAttribute(operation->
getLoc(), value);
355 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
356 if (oAttr.getValue().empty())
358 return emitter.emitVariableDeclaration(result,
363 if (failed(emitter.emitAssignPrefix(*operation)))
365 return emitter.emitAttribute(operation->
getLoc(), value);
369 emitc::ConstantOp constantOp) {
370 Operation *operation = constantOp.getOperation();
377 emitc::VariableOp variableOp) {
378 Operation *operation = variableOp.getOperation();
385 emitc::GlobalOp globalOp) {
387 return emitter.emitGlobalVariable(globalOp);
391 emitc::AssignOp assignOp) {
394 if (failed(emitter.emitVariableAssignment(result)))
397 return emitter.emitOperand(assignOp.getValue());
401 if (failed(emitter.emitAssignPrefix(*loadOp)))
404 return emitter.emitOperand(loadOp.getOperand());
409 StringRef binaryOperator) {
410 raw_ostream &os = emitter.ostream();
412 if (failed(emitter.emitAssignPrefix(*operation)))
415 if (failed(emitter.emitOperand(operation->
getOperand(0))))
418 os <<
" " << binaryOperator <<
" ";
420 if (failed(emitter.emitOperand(operation->
getOperand(1))))
428 StringRef unaryOperator) {
429 raw_ostream &os = emitter.ostream();
431 if (failed(emitter.emitAssignPrefix(*operation)))
436 if (failed(emitter.emitOperand(operation->
getOperand(0))))
443 Operation *operation = addOp.getOperation();
449 Operation *operation = divOp.getOperation();
455 Operation *operation = mulOp.getOperation();
461 Operation *operation = remOp.getOperation();
467 Operation *operation = subOp.getOperation();
475 std::next(iteratorOp) != end; ++iteratorOp) {
476 if (failed(emitter.emitOperation(*iteratorOp,
true)))
484 emitc::SwitchOp switchOp) {
488 if (failed(emitter.emitOperand(switchOp.getArg())))
492 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
493 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
502 os <<
"\ndefault: {\n";
505 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
513 Operation *operation = cmpOp.getOperation();
515 StringRef binaryOperator;
517 switch (cmpOp.getPredicate()) {
518 case emitc::CmpPredicate::eq:
519 binaryOperator =
"==";
521 case emitc::CmpPredicate::ne:
522 binaryOperator =
"!=";
524 case emitc::CmpPredicate::lt:
525 binaryOperator =
"<";
527 case emitc::CmpPredicate::le:
528 binaryOperator =
"<=";
530 case emitc::CmpPredicate::gt:
531 binaryOperator =
">";
533 case emitc::CmpPredicate::ge:
534 binaryOperator =
">=";
536 case emitc::CmpPredicate::three_way:
537 binaryOperator =
"<=>";
545 emitc::ConditionalOp conditionalOp) {
546 raw_ostream &os = emitter.ostream();
548 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
551 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
556 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
561 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
568 emitc::VerbatimOp verbatimOp) {
569 raw_ostream &os = emitter.ostream();
571 FailureOr<SmallVector<ReplacementItem>> items =
572 verbatimOp.parseFormatString();
576 auto fmtArg = verbatimOp.getFmtArgs().begin();
579 if (
auto *str = std::get_if<StringRef>(&item)) {
582 if (failed(emitter.emitOperand(*fmtArg++)))
591 cf::BranchOp branchOp) {
592 raw_ostream &os = emitter.ostream();
596 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
597 Value &operand = std::get<0>(pair);
599 os << emitter.getOrCreateName(argument) <<
" = "
600 << emitter.getOrCreateName(operand) <<
";\n";
604 if (!(emitter.hasBlockLabel(successor)))
605 return branchOp.emitOpError(
"unable to find label for successor block");
606 os << emitter.getOrCreateName(successor);
611 cf::CondBranchOp condBranchOp) {
613 Block &trueSuccessor = *condBranchOp.getTrueDest();
614 Block &falseSuccessor = *condBranchOp.getFalseDest();
617 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
624 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
626 Value &operand = std::get<0>(pair);
628 os << emitter.getOrCreateName(argument) <<
" = "
629 << emitter.getOrCreateName(operand) <<
";\n";
633 if (!(emitter.hasBlockLabel(trueSuccessor))) {
634 return condBranchOp.emitOpError(
"unable to find label for successor block");
636 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
640 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
642 Value &operand = std::get<0>(pair);
644 os << emitter.getOrCreateName(argument) <<
" = "
645 << emitter.getOrCreateName(operand) <<
";\n";
649 if (!(emitter.hasBlockLabel(falseSuccessor))) {
650 return condBranchOp.emitOpError()
651 <<
"unable to find label for successor block";
653 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
660 if (failed(emitter.emitAssignPrefix(*callOp)))
663 raw_ostream &os = emitter.ostream();
665 if (failed(emitter.emitOperands(*callOp)))
672 Operation *operation = callOp.getOperation();
673 StringRef callee = callOp.getCallee();
679 Operation *operation = callOp.getOperation();
680 StringRef callee = callOp.getCallee();
686 emitc::CallOpaqueOp callOpaqueOp) {
687 raw_ostream &os = emitter.ostream();
688 Operation &op = *callOpaqueOp.getOperation();
690 if (failed(emitter.emitAssignPrefix(op)))
692 os << callOpaqueOp.getCallee();
694 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
695 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
697 if (t.getType().isIndex()) {
698 int64_t idx = t.getInt();
700 if (!emitter.hasValueInScope(operand))
702 << idx <<
"'s value not defined in scope";
703 os << emitter.getOrCreateName(operand);
707 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
713 if (callOpaqueOp.getTemplateArgs()) {
723 LogicalResult emittedArgs =
724 callOpaqueOp.getArgs()
726 : emitter.emitOperands(op);
727 if (failed(emittedArgs))
734 emitc::ApplyOp applyOp) {
735 raw_ostream &os = emitter.ostream();
738 if (failed(emitter.emitAssignPrefix(op)))
740 os << applyOp.getApplicableOperator();
741 os << emitter.getOrCreateName(applyOp.getOperand());
747 emitc::BitwiseAndOp bitwiseAndOp) {
748 Operation *operation = bitwiseAndOp.getOperation();
754 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
755 Operation *operation = bitwiseLeftShiftOp.getOperation();
760 emitc::BitwiseNotOp bitwiseNotOp) {
761 Operation *operation = bitwiseNotOp.getOperation();
766 emitc::BitwiseOrOp bitwiseOrOp) {
767 Operation *operation = bitwiseOrOp.getOperation();
773 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
774 Operation *operation = bitwiseRightShiftOp.getOperation();
779 emitc::BitwiseXorOp bitwiseXorOp) {
780 Operation *operation = bitwiseXorOp.getOperation();
785 emitc::UnaryPlusOp unaryPlusOp) {
786 Operation *operation = unaryPlusOp.getOperation();
791 emitc::UnaryMinusOp unaryMinusOp) {
792 Operation *operation = unaryMinusOp.getOperation();
797 raw_ostream &os = emitter.ostream();
800 if (failed(emitter.emitAssignPrefix(op)))
806 return emitter.emitOperand(castOp.getOperand());
810 emitc::ExpressionOp expressionOp) {
814 Operation &op = *expressionOp.getOperation();
816 if (failed(emitter.emitAssignPrefix(op)))
819 return emitter.emitExpression(expressionOp);
823 emitc::IncludeOp includeOp) {
824 raw_ostream &os = emitter.ostream();
827 if (includeOp.getIsStandardInclude())
828 os <<
"<" << includeOp.getInclude() <<
">";
830 os <<
"\"" << includeOp.getInclude() <<
"\"";
836 emitc::LogicalAndOp logicalAndOp) {
837 Operation *operation = logicalAndOp.getOperation();
842 emitc::LogicalNotOp logicalNotOp) {
843 Operation *operation = logicalNotOp.getOperation();
848 emitc::LogicalOrOp logicalOrOp) {
849 Operation *operation = logicalOrOp.getOperation();
860 auto requiresParentheses = [&](
Value value) {
870 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
873 os << emitter.getOrCreateName(forOp.getInductionVar());
875 if (failed(emitter.emitOperand(forOp.getLowerBound())))
878 os << emitter.getOrCreateName(forOp.getInductionVar());
880 Value upperBound = forOp.getUpperBound();
881 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
882 if (upperBoundRequiresParentheses)
884 if (failed(emitter.emitOperand(upperBound)))
886 if (upperBoundRequiresParentheses)
889 os << emitter.getOrCreateName(forOp.getInductionVar());
891 if (failed(emitter.emitOperand(forOp.getStep())))
896 Region &forRegion = forOp.getRegion();
897 auto regionOps = forRegion.
getOps();
900 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
901 if (failed(emitter.emitOperation(*it,
true)))
915 auto emitAllExceptLast = [&emitter](
Region ®ion) {
917 for (; std::next(it) != end; ++it) {
918 if (failed(emitter.emitOperation(*it,
true)))
921 assert(isa<emitc::YieldOp>(*it) &&
922 "Expected last operation in the region to be emitc::yield");
927 if (failed(emitter.emitOperand(ifOp.getCondition())))
931 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
935 Region &elseRegion = ifOp.getElseRegion();
936 if (!elseRegion.
empty()) {
939 if (failed(emitAllExceptLast(elseRegion)))
948 func::ReturnOp returnOp) {
949 raw_ostream &os = emitter.ostream();
951 switch (returnOp.getNumOperands()) {
956 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
960 os <<
" std::make_tuple(";
961 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
969 emitc::ReturnOp returnOp) {
970 raw_ostream &os = emitter.ostream();
972 if (returnOp.getNumOperands() == 0)
976 if (failed(emitter.emitOperand(returnOp.getOperand())))
982 CppEmitter::Scope scope(emitter);
985 if (failed(emitter.emitOperation(op,
false)))
992 if (!emitter.shouldEmitFile(file))
995 CppEmitter::Scope scope(emitter);
998 if (failed(emitter.emitOperation(op,
false)))
1011 return emitter.emitType(functionOp->
getLoc(), arg);
1022 return emitter.emitVariableDeclaration(
1023 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1033 if (emitter.shouldDeclareVariablesAtTop()) {
1038 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1039 (isa<emitc::ExpressionOp>(op) &&
1043 if (failed(emitter.emitVariableDeclaration(
1046 op->
emitError(
"unable to declare result variable for op"));
1056 for (
Block &block : blocks) {
1057 emitter.getOrCreateName(block);
1061 for (
Block &block : llvm::drop_begin(blocks)) {
1063 if (emitter.hasValueInScope(arg))
1064 return functionOp->
emitOpError(
" block argument #")
1065 << arg.getArgNumber() <<
" is out of scope";
1066 if (isa<ArrayType, LValueType>(arg.getType()))
1067 return functionOp->
emitOpError(
"cannot emit block argument #")
1068 << arg.getArgNumber() <<
" with type " << arg.getType();
1070 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1073 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1077 for (
Block &block : blocks) {
1079 if (!block.hasNoPredecessors()) {
1080 if (failed(emitter.emitLabel(block)))
1083 for (
Operation &op : block.getOperations()) {
1084 if (failed(emitter.emitOperation(op,
true)))
1095 func::FuncOp functionOp) {
1097 if (!emitter.shouldDeclareVariablesAtTop() &&
1098 functionOp.getBlocks().size() > 1) {
1099 return functionOp.emitOpError(
1100 "with multiple blocks needs variables declared at top");
1103 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1104 return functionOp.emitOpError()
1105 <<
"cannot emit lvalue type as argument type";
1108 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1109 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1112 CppEmitter::Scope scope(emitter);
1114 if (failed(emitter.emitTypes(functionOp.getLoc(),
1115 functionOp.getFunctionType().getResults())))
1117 os <<
" " << functionOp.getName();
1120 Operation *operation = functionOp.getOperation();
1132 emitc::FuncOp functionOp) {
1134 if (!emitter.shouldDeclareVariablesAtTop() &&
1135 functionOp.getBlocks().size() > 1) {
1136 return functionOp.emitOpError(
1137 "with multiple blocks needs variables declared at top");
1140 CppEmitter::Scope scope(emitter);
1142 if (functionOp.getSpecifiers()) {
1143 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1144 os << cast<StringAttr>(specifier).str() <<
" ";
1148 if (failed(emitter.emitTypes(functionOp.getLoc(),
1149 functionOp.getFunctionType().getResults())))
1151 os <<
" " << functionOp.getName();
1154 Operation *operation = functionOp.getOperation();
1155 if (functionOp.isExternal()) {
1157 functionOp.getArgumentTypes())))
1173 DeclareFuncOp declareFuncOp) {
1174 CppEmitter::Scope scope(emitter);
1177 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1178 declareFuncOp, declareFuncOp.getSymNameAttr());
1183 if (functionOp.getSpecifiers()) {
1184 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1185 os << cast<StringAttr>(specifier).str() <<
" ";
1189 if (failed(emitter.emitTypes(functionOp.getLoc(),
1190 functionOp.getFunctionType().getResults())))
1192 os <<
" " << functionOp.getName();
1195 Operation *operation = functionOp.getOperation();
1203 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
1205 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1206 fileId(fileId.str()) {
1207 valueInScopeCount.push(0);
1208 labelInScopeCount.push(0);
1211 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1213 llvm::raw_string_ostream ss(out);
1214 ss << getOrCreateName(op.getValue());
1215 for (
auto index : op.getIndices()) {
1216 ss <<
"[" << getOrCreateName(index) <<
"]";
1221 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1223 llvm::raw_string_ostream ss(out);
1224 ss << getOrCreateName(op.getOperand());
1225 ss <<
"." << op.getMember();
1229 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1231 llvm::raw_string_ostream ss(out);
1232 ss << getOrCreateName(op.getOperand());
1233 ss <<
"->" << op.getMember();
1237 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1238 if (!valueMapper.count(value))
1239 valueMapper.insert(value, str.str());
1243 StringRef CppEmitter::getOrCreateName(
Value val) {
1244 if (!valueMapper.count(val)) {
1246 "cacheDeferredOpResult should have been called on this value, "
1247 "update the emitOperation function.");
1248 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1250 return *valueMapper.begin(val);
1254 StringRef CppEmitter::getOrCreateName(
Block &block) {
1255 if (!blockMapper.count(&block))
1256 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1257 return *blockMapper.begin(&block);
1260 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1262 case IntegerType::Signless:
1266 case IntegerType::Unsigned:
1269 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1272 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1274 bool CppEmitter::hasBlockLabel(
Block &block) {
1275 return blockMapper.count(&block);
1279 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1280 if (val.getBitWidth() == 1) {
1281 if (val.getBoolValue())
1287 val.toString(strValue, 10, !isUnsigned,
false);
1292 auto printFloat = [&](
const APFloat &val) {
1293 if (val.isFinite()) {
1296 val.toString(strValue, 0, 0,
false);
1298 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1299 case llvm::APFloatBase::S_IEEEhalf:
1302 case llvm::APFloatBase::S_BFloat:
1305 case llvm::APFloatBase::S_IEEEsingle:
1308 case llvm::APFloatBase::S_IEEEdouble:
1311 llvm_unreachable(
"unsupported floating point type");
1313 }
else if (val.isNaN()) {
1315 }
else if (val.isInfinity()) {
1316 if (val.isNegative())
1323 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1324 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1327 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1329 printFloat(fAttr.getValue());
1332 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1333 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1334 dense.getElementType())) {
1336 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1339 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1345 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1346 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1347 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1350 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1351 printInt(iAttr.getValue(),
false);
1355 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1356 if (
auto iType = dyn_cast<IntegerType>(
1357 cast<TensorType>(dense.getType()).getElementType())) {
1359 interleaveComma(dense, os, [&](
const APInt &val) {
1360 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1365 if (
auto iType = dyn_cast<IndexType>(
1366 cast<TensorType>(dense.getType()).getElementType())) {
1368 interleaveComma(dense, os,
1369 [&](
const APInt &val) { printInt(val,
false); });
1376 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1377 os << oAttr.getValue();
1382 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1383 if (sAttr.getNestedReferences().size() > 1)
1384 return emitError(loc,
"attribute has more than 1 nested reference");
1385 os << sAttr.getRootReference().getValue();
1390 if (
auto type = dyn_cast<TypeAttr>(attr))
1391 return emitType(loc, type.getValue());
1393 return emitError(loc,
"cannot emit attribute: ") << attr;
1396 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1397 assert(emittedExpressionPrecedence.empty() &&
1398 "Expected precedence stack to be empty");
1399 Operation *rootOp = expressionOp.getRootOp();
1401 emittedExpression = expressionOp;
1403 if (failed(precedence))
1405 pushExpressionPrecedence(precedence.value());
1407 if (failed(emitOperation(*rootOp,
false)))
1410 popExpressionPrecedence();
1411 assert(emittedExpressionPrecedence.empty() &&
1412 "Expected precedence stack to be empty");
1413 emittedExpression =
nullptr;
1418 LogicalResult CppEmitter::emitOperand(
Value value) {
1419 if (isPartOfCurrentExpression(value)) {
1421 assert(def &&
"Expected operand to be defined by an operation");
1423 if (failed(precedence))
1429 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1430 if (encloseInParenthesis)
1432 pushExpressionPrecedence(precedence.value());
1434 if (failed(emitOperation(*def,
false)))
1437 if (encloseInParenthesis)
1440 popExpressionPrecedence();
1444 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1446 return emitExpression(expressionOp);
1448 os << getOrCreateName(value);
1452 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1456 if (getEmittedExpression())
1457 pushExpressionPrecedence(lowestPrecedence());
1458 if (failed(emitOperand(operand)))
1460 if (getEmittedExpression())
1461 popExpressionPrecedence();
1467 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1469 if (failed(emitOperands(op)))
1474 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1481 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1482 if (llvm::is_contained(exclude, attr.getName().strref()))
1484 os <<
"/* " << attr.getName().getValue() <<
" */";
1485 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1492 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1493 if (!hasValueInScope(result)) {
1495 "result variable for the operation has not been declared");
1497 os << getOrCreateName(result) <<
" = ";
1501 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1502 bool trailingSemicolon) {
1505 if (hasValueInScope(result)) {
1507 "result variable for the operation already declared");
1511 getOrCreateName(result))))
1513 if (trailingSemicolon)
1518 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1519 if (op.getExternSpecifier())
1521 else if (op.getStaticSpecifier())
1523 if (op.getConstSpecifier())
1526 if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1527 op.getSymName()))) {
1531 std::optional<Attribute> initialValue = op.getInitialValue();
1534 if (failed(emitAttribute(op->getLoc(), *initialValue)))
1542 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1544 if (getEmittedExpression())
1552 if (shouldDeclareVariablesAtTop()) {
1553 if (failed(emitVariableAssignment(result)))
1556 if (failed(emitVariableDeclaration(result,
false)))
1563 if (!shouldDeclareVariablesAtTop()) {
1565 if (failed(emitVariableDeclaration(result,
true)))
1571 [&](
Value result) { os << getOrCreateName(result); });
1577 LogicalResult CppEmitter::emitLabel(
Block &block) {
1578 if (!hasBlockLabel(block))
1582 os.getOStream() << getOrCreateName(block) <<
":\n";
1586 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1587 LogicalResult status =
1590 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1592 .Case<cf::BranchOp, cf::CondBranchOp>(
1595 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1596 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1597 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1598 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1599 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1600 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1601 emitc::DivOp, emitc::ExpressionOp, emitc::FileOp, emitc::ForOp,
1602 emitc::FuncOp, emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp,
1603 emitc::LoadOp, emitc::LogicalAndOp, emitc::LogicalNotOp,
1604 emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp,
1605 emitc::SubOp, emitc::SwitchOp, emitc::UnaryMinusOp,
1606 emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>(
1610 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1612 .Case<emitc::GetGlobalOp>([&](
auto op) {
1616 .Case<emitc::LiteralOp>([&](
auto op) {
1617 cacheDeferredOpResult(op.
getResult(), op.getValue());
1620 .Case<emitc::MemberOp>([&](
auto op) {
1621 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1624 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1625 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1628 .Case<emitc::SubscriptOp>([&](
auto op) {
1629 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1633 return op.
emitOpError(
"unable to find printer for op");
1642 if (getEmittedExpression() ||
1643 (isa<emitc::ExpressionOp>(op) &&
1649 trailingSemicolon &=
1650 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
1651 emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(
1654 os << (trailingSemicolon ?
";\n" :
"\n");
1659 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1661 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1662 if (failed(emitType(loc, arrType.getElementType())))
1665 for (
auto dim : arrType.getShape()) {
1666 os <<
"[" << dim <<
"]";
1670 if (failed(emitType(loc, type)))
1676 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1677 if (
auto iType = dyn_cast<IntegerType>(type)) {
1678 switch (iType.getWidth()) {
1680 return (os <<
"bool"), success();
1685 if (shouldMapToUnsigned(iType.getSignedness()))
1686 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1688 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1690 return emitError(loc,
"cannot emit integer type ") << type;
1693 if (
auto fType = dyn_cast<FloatType>(type)) {
1694 switch (fType.getWidth()) {
1696 if (llvm::isa<Float16Type>(type))
1697 return (os <<
"_Float16"), success();
1698 else if (llvm::isa<BFloat16Type>(type))
1699 return (os <<
"__bf16"), success();
1701 return emitError(loc,
"cannot emit float type ") << type;
1704 return (os <<
"float"), success();
1706 return (os <<
"double"), success();
1708 return emitError(loc,
"cannot emit float type ") << type;
1711 if (
auto iType = dyn_cast<IndexType>(type))
1712 return (os <<
"size_t"), success();
1713 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1714 return (os <<
"size_t"), success();
1715 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1716 return (os <<
"ssize_t"), success();
1717 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1718 return (os <<
"ptrdiff_t"), success();
1719 if (
auto tType = dyn_cast<TensorType>(type)) {
1720 if (!tType.hasRank())
1721 return emitError(loc,
"cannot emit unranked tensor type");
1722 if (!tType.hasStaticShape())
1723 return emitError(loc,
"cannot emit tensor type with non static shape");
1725 if (isa<ArrayType>(tType.getElementType()))
1726 return emitError(loc,
"cannot emit tensor of array type ") << type;
1727 if (failed(emitType(loc, tType.getElementType())))
1729 auto shape = tType.getShape();
1730 for (
auto dimSize : shape) {
1737 if (
auto tType = dyn_cast<TupleType>(type))
1738 return emitTupleType(loc, tType.getTypes());
1739 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1740 os << oType.getValue();
1743 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1744 if (failed(emitType(loc, aType.getElementType())))
1746 for (
auto dim : aType.getShape())
1747 os <<
"[" << dim <<
"]";
1750 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1751 return emitType(loc, lType.getValueType());
1752 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1753 if (isa<ArrayType>(pType.getPointee()))
1754 return emitError(loc,
"cannot emit pointer to array type ") << type;
1755 if (failed(emitType(loc, pType.getPointee())))
1760 return emitError(loc,
"cannot emit type ") << type;
1764 switch (types.size()) {
1769 return emitType(loc, types.front());
1771 return emitTupleType(loc, types);
1776 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1777 return emitError(loc,
"cannot emit tuple of array type");
1779 os <<
"std::tuple<";
1781 types, os, [&](
Type type) {
return emitType(loc, type); })))
1788 bool declareVariablesAtTop,
1790 CppEmitter emitter(os, declareVariablesAtTop, fileId);
1791 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.
MutableArrayRef< BlockArgument > BlockArgListType
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, StringRef fileId={})
Translates the given operation to C++ code.
std::variant< StringRef, Placeholder > ReplacementItem
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.