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::LoadOp>([&](
auto op) {
return 16; })
104 .Case<emitc::LogicalAndOp>([&](
auto op) {
return 4; })
105 .Case<emitc::LogicalNotOp>([&](
auto op) {
return 15; })
106 .Case<emitc::LogicalOrOp>([&](
auto op) {
return 3; })
107 .Case<emitc::MulOp>([&](
auto op) {
return 13; })
108 .Case<emitc::RemOp>([&](
auto op) {
return 13; })
109 .Case<emitc::SubOp>([&](
auto op) {
return 12; })
110 .Case<emitc::UnaryMinusOp>([&](
auto op) {
return 15; })
111 .Case<emitc::UnaryPlusOp>([&](
auto op) {
return 15; })
112 .Default([](
auto op) {
return op->emitError(
"unsupported operation"); });
118 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
129 LogicalResult emitOperation(
Operation &op,
bool trailingSemicolon);
145 LogicalResult emitVariableAssignment(
OpResult result);
148 LogicalResult emitVariableDeclaration(
OpResult result,
149 bool trailingSemicolon);
152 LogicalResult emitVariableDeclaration(
Location loc,
Type type,
161 LogicalResult emitAssignPrefix(
Operation &op);
164 LogicalResult emitGlobalVariable(GlobalOp op);
167 LogicalResult emitLabel(
Block &block);
171 LogicalResult emitOperandsAndAttributes(
Operation &op,
175 LogicalResult emitOperands(
Operation &op);
178 LogicalResult emitOperand(
Value value);
181 LogicalResult emitExpression(ExpressionOp expressionOp);
184 void cacheDeferredOpResult(
Value value, StringRef str);
187 StringRef getOrCreateName(
Value val);
190 std::string getSubscriptName(emitc::SubscriptOp op);
193 std::string createMemberAccess(emitc::MemberOp op);
196 std::string createMemberAccess(emitc::MemberOfPtrOp op);
199 StringRef getOrCreateName(
Block &block);
202 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
206 Scope(CppEmitter &emitter)
207 : valueMapperScope(emitter.valueMapper),
208 blockMapperScope(emitter.blockMapper), emitter(emitter) {
209 emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
210 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
213 emitter.valueInScopeCount.pop();
214 emitter.labelInScopeCount.pop();
218 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
219 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
224 bool hasValueInScope(
Value val);
227 bool hasBlockLabel(
Block &block);
234 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
237 bool shouldEmitFile(FileOp file) {
238 return !fileId.empty() && file.getId() == fileId;
242 ExpressionOp getEmittedExpression() {
return emittedExpression; }
246 bool isPartOfCurrentExpression(
Value value) {
247 if (!emittedExpression)
252 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
253 return operandExpression == emittedExpression;
257 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
258 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
266 bool declareVariablesAtTop;
272 ValueMapper valueMapper;
275 BlockMapper blockMapper;
279 std::stack<int64_t> valueInScopeCount;
280 std::stack<int64_t> labelInScopeCount;
283 ExpressionOp emittedExpression;
286 void pushExpressionPrecedence(
int precedence) {
287 emittedExpressionPrecedence.push_back(precedence);
289 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
290 static int lowestPrecedence() {
return 0; }
291 int getExpressionPrecedence() {
292 if (emittedExpressionPrecedence.empty())
293 return lowestPrecedence();
294 return emittedExpressionPrecedence.back();
301 return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
302 emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
312 if (expressionOp.getDoNotInline())
317 if (expressionOp.hasSideEffects())
321 Value result = expressionOp.getResult();
343 if (emitter.shouldDeclareVariablesAtTop()) {
345 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
346 if (oAttr.getValue().empty())
350 if (failed(emitter.emitVariableAssignment(result)))
352 return emitter.emitAttribute(operation->
getLoc(), value);
356 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
357 if (oAttr.getValue().empty())
359 return emitter.emitVariableDeclaration(result,
364 if (failed(emitter.emitAssignPrefix(*operation)))
366 return emitter.emitAttribute(operation->
getLoc(), value);
370 emitc::ConstantOp constantOp) {
371 Operation *operation = constantOp.getOperation();
378 emitc::VariableOp variableOp) {
379 Operation *operation = variableOp.getOperation();
386 emitc::GlobalOp globalOp) {
388 return emitter.emitGlobalVariable(globalOp);
392 emitc::AssignOp assignOp) {
395 if (failed(emitter.emitVariableAssignment(result)))
398 return emitter.emitOperand(assignOp.getValue());
402 if (failed(emitter.emitAssignPrefix(*loadOp)))
405 return emitter.emitOperand(loadOp.getOperand());
410 StringRef binaryOperator) {
411 raw_ostream &os = emitter.ostream();
413 if (failed(emitter.emitAssignPrefix(*operation)))
416 if (failed(emitter.emitOperand(operation->
getOperand(0))))
419 os <<
" " << binaryOperator <<
" ";
421 if (failed(emitter.emitOperand(operation->
getOperand(1))))
429 StringRef unaryOperator) {
430 raw_ostream &os = emitter.ostream();
432 if (failed(emitter.emitAssignPrefix(*operation)))
437 if (failed(emitter.emitOperand(operation->
getOperand(0))))
444 Operation *operation = addOp.getOperation();
450 Operation *operation = divOp.getOperation();
456 Operation *operation = mulOp.getOperation();
462 Operation *operation = remOp.getOperation();
468 Operation *operation = subOp.getOperation();
476 std::next(iteratorOp) != end; ++iteratorOp) {
477 if (failed(emitter.emitOperation(*iteratorOp,
true)))
485 emitc::SwitchOp switchOp) {
489 if (failed(emitter.emitOperand(switchOp.getArg())))
493 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
494 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
503 os <<
"\ndefault: {\n";
506 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
514 Operation *operation = cmpOp.getOperation();
516 StringRef binaryOperator;
518 switch (cmpOp.getPredicate()) {
519 case emitc::CmpPredicate::eq:
520 binaryOperator =
"==";
522 case emitc::CmpPredicate::ne:
523 binaryOperator =
"!=";
525 case emitc::CmpPredicate::lt:
526 binaryOperator =
"<";
528 case emitc::CmpPredicate::le:
529 binaryOperator =
"<=";
531 case emitc::CmpPredicate::gt:
532 binaryOperator =
">";
534 case emitc::CmpPredicate::ge:
535 binaryOperator =
">=";
537 case emitc::CmpPredicate::three_way:
538 binaryOperator =
"<=>";
546 emitc::ConditionalOp conditionalOp) {
547 raw_ostream &os = emitter.ostream();
549 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
552 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
557 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
562 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
569 emitc::VerbatimOp verbatimOp) {
570 raw_ostream &os = emitter.ostream();
572 FailureOr<SmallVector<ReplacementItem>> items =
573 verbatimOp.parseFormatString();
577 auto fmtArg = verbatimOp.getFmtArgs().begin();
580 if (
auto *str = std::get_if<StringRef>(&item)) {
583 if (failed(emitter.emitOperand(*fmtArg++)))
592 cf::BranchOp branchOp) {
593 raw_ostream &os = emitter.ostream();
597 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
598 Value &operand = std::get<0>(pair);
600 os << emitter.getOrCreateName(argument) <<
" = "
601 << emitter.getOrCreateName(operand) <<
";\n";
605 if (!(emitter.hasBlockLabel(successor)))
606 return branchOp.emitOpError(
"unable to find label for successor block");
607 os << emitter.getOrCreateName(successor);
612 cf::CondBranchOp condBranchOp) {
614 Block &trueSuccessor = *condBranchOp.getTrueDest();
615 Block &falseSuccessor = *condBranchOp.getFalseDest();
618 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
625 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
627 Value &operand = std::get<0>(pair);
629 os << emitter.getOrCreateName(argument) <<
" = "
630 << emitter.getOrCreateName(operand) <<
";\n";
634 if (!(emitter.hasBlockLabel(trueSuccessor))) {
635 return condBranchOp.emitOpError(
"unable to find label for successor block");
637 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
641 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
643 Value &operand = std::get<0>(pair);
645 os << emitter.getOrCreateName(argument) <<
" = "
646 << emitter.getOrCreateName(operand) <<
";\n";
650 if (!(emitter.hasBlockLabel(falseSuccessor))) {
651 return condBranchOp.emitOpError()
652 <<
"unable to find label for successor block";
654 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
661 if (failed(emitter.emitAssignPrefix(*callOp)))
664 raw_ostream &os = emitter.ostream();
666 if (failed(emitter.emitOperands(*callOp)))
673 Operation *operation = callOp.getOperation();
674 StringRef callee = callOp.getCallee();
680 Operation *operation = callOp.getOperation();
681 StringRef callee = callOp.getCallee();
687 emitc::CallOpaqueOp callOpaqueOp) {
688 raw_ostream &os = emitter.ostream();
689 Operation &op = *callOpaqueOp.getOperation();
691 if (failed(emitter.emitAssignPrefix(op)))
693 os << callOpaqueOp.getCallee();
695 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
696 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
698 if (t.getType().isIndex()) {
699 int64_t idx = t.getInt();
701 if (!emitter.hasValueInScope(operand))
703 << idx <<
"'s value not defined in scope";
704 os << emitter.getOrCreateName(operand);
708 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
714 if (callOpaqueOp.getTemplateArgs()) {
724 LogicalResult emittedArgs =
725 callOpaqueOp.getArgs()
727 : emitter.emitOperands(op);
728 if (failed(emittedArgs))
735 emitc::ApplyOp applyOp) {
736 raw_ostream &os = emitter.ostream();
739 if (failed(emitter.emitAssignPrefix(op)))
741 os << applyOp.getApplicableOperator();
742 os << emitter.getOrCreateName(applyOp.getOperand());
748 emitc::BitwiseAndOp bitwiseAndOp) {
749 Operation *operation = bitwiseAndOp.getOperation();
755 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
756 Operation *operation = bitwiseLeftShiftOp.getOperation();
761 emitc::BitwiseNotOp bitwiseNotOp) {
762 Operation *operation = bitwiseNotOp.getOperation();
767 emitc::BitwiseOrOp bitwiseOrOp) {
768 Operation *operation = bitwiseOrOp.getOperation();
774 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
775 Operation *operation = bitwiseRightShiftOp.getOperation();
780 emitc::BitwiseXorOp bitwiseXorOp) {
781 Operation *operation = bitwiseXorOp.getOperation();
786 emitc::UnaryPlusOp unaryPlusOp) {
787 Operation *operation = unaryPlusOp.getOperation();
792 emitc::UnaryMinusOp unaryMinusOp) {
793 Operation *operation = unaryMinusOp.getOperation();
798 raw_ostream &os = emitter.ostream();
801 if (failed(emitter.emitAssignPrefix(op)))
807 return emitter.emitOperand(castOp.getOperand());
811 emitc::ExpressionOp expressionOp) {
815 Operation &op = *expressionOp.getOperation();
817 if (failed(emitter.emitAssignPrefix(op)))
820 return emitter.emitExpression(expressionOp);
824 emitc::IncludeOp includeOp) {
825 raw_ostream &os = emitter.ostream();
828 if (includeOp.getIsStandardInclude())
829 os <<
"<" << includeOp.getInclude() <<
">";
831 os <<
"\"" << includeOp.getInclude() <<
"\"";
837 emitc::LogicalAndOp logicalAndOp) {
838 Operation *operation = logicalAndOp.getOperation();
843 emitc::LogicalNotOp logicalNotOp) {
844 Operation *operation = logicalNotOp.getOperation();
849 emitc::LogicalOrOp logicalOrOp) {
850 Operation *operation = logicalOrOp.getOperation();
861 auto requiresParentheses = [&](
Value value) {
871 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
874 os << emitter.getOrCreateName(forOp.getInductionVar());
876 if (failed(emitter.emitOperand(forOp.getLowerBound())))
879 os << emitter.getOrCreateName(forOp.getInductionVar());
881 Value upperBound = forOp.getUpperBound();
882 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
883 if (upperBoundRequiresParentheses)
885 if (failed(emitter.emitOperand(upperBound)))
887 if (upperBoundRequiresParentheses)
890 os << emitter.getOrCreateName(forOp.getInductionVar());
892 if (failed(emitter.emitOperand(forOp.getStep())))
897 Region &forRegion = forOp.getRegion();
898 auto regionOps = forRegion.
getOps();
901 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
902 if (failed(emitter.emitOperation(*it,
true)))
916 auto emitAllExceptLast = [&emitter](
Region ®ion) {
918 for (; std::next(it) != end; ++it) {
919 if (failed(emitter.emitOperation(*it,
true)))
922 assert(isa<emitc::YieldOp>(*it) &&
923 "Expected last operation in the region to be emitc::yield");
928 if (failed(emitter.emitOperand(ifOp.getCondition())))
932 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
936 Region &elseRegion = ifOp.getElseRegion();
937 if (!elseRegion.
empty()) {
940 if (failed(emitAllExceptLast(elseRegion)))
949 func::ReturnOp returnOp) {
950 raw_ostream &os = emitter.ostream();
952 switch (returnOp.getNumOperands()) {
957 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
961 os <<
" std::make_tuple(";
962 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
970 emitc::ReturnOp returnOp) {
971 raw_ostream &os = emitter.ostream();
973 if (returnOp.getNumOperands() == 0)
977 if (failed(emitter.emitOperand(returnOp.getOperand())))
983 CppEmitter::Scope scope(emitter);
986 if (failed(emitter.emitOperation(op,
false)))
993 if (!emitter.shouldEmitFile(file))
996 CppEmitter::Scope scope(emitter);
999 if (failed(emitter.emitOperation(op,
false)))
1012 return emitter.emitType(functionOp->
getLoc(), arg);
1023 return emitter.emitVariableDeclaration(
1024 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1034 if (emitter.shouldDeclareVariablesAtTop()) {
1039 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1040 (isa<emitc::ExpressionOp>(op) &&
1044 if (failed(emitter.emitVariableDeclaration(
1047 op->
emitError(
"unable to declare result variable for op"));
1057 for (
Block &block : blocks) {
1058 emitter.getOrCreateName(block);
1062 for (
Block &block : llvm::drop_begin(blocks)) {
1064 if (emitter.hasValueInScope(arg))
1065 return functionOp->
emitOpError(
" block argument #")
1066 << arg.getArgNumber() <<
" is out of scope";
1067 if (isa<ArrayType, LValueType>(arg.getType()))
1068 return functionOp->
emitOpError(
"cannot emit block argument #")
1069 << arg.getArgNumber() <<
" with type " << arg.getType();
1071 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1074 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1078 for (
Block &block : blocks) {
1080 if (!block.hasNoPredecessors()) {
1081 if (failed(emitter.emitLabel(block)))
1084 for (
Operation &op : block.getOperations()) {
1085 if (failed(emitter.emitOperation(op,
true)))
1096 func::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 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1105 return functionOp.emitOpError()
1106 <<
"cannot emit lvalue type as argument type";
1109 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1110 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1113 CppEmitter::Scope scope(emitter);
1115 if (failed(emitter.emitTypes(functionOp.getLoc(),
1116 functionOp.getFunctionType().getResults())))
1118 os <<
" " << functionOp.getName();
1121 Operation *operation = functionOp.getOperation();
1133 emitc::FuncOp functionOp) {
1135 if (!emitter.shouldDeclareVariablesAtTop() &&
1136 functionOp.getBlocks().size() > 1) {
1137 return functionOp.emitOpError(
1138 "with multiple blocks needs variables declared at top");
1141 CppEmitter::Scope scope(emitter);
1143 if (functionOp.getSpecifiers()) {
1144 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1145 os << cast<StringAttr>(specifier).str() <<
" ";
1149 if (failed(emitter.emitTypes(functionOp.getLoc(),
1150 functionOp.getFunctionType().getResults())))
1152 os <<
" " << functionOp.getName();
1155 Operation *operation = functionOp.getOperation();
1156 if (functionOp.isExternal()) {
1158 functionOp.getArgumentTypes())))
1174 DeclareFuncOp declareFuncOp) {
1175 CppEmitter::Scope scope(emitter);
1178 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1179 declareFuncOp, declareFuncOp.getSymNameAttr());
1184 if (functionOp.getSpecifiers()) {
1185 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1186 os << cast<StringAttr>(specifier).str() <<
" ";
1190 if (failed(emitter.emitTypes(functionOp.getLoc(),
1191 functionOp.getFunctionType().getResults())))
1193 os <<
" " << functionOp.getName();
1196 Operation *operation = functionOp.getOperation();
1204 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
1206 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1207 fileId(fileId.str()) {
1208 valueInScopeCount.push(0);
1209 labelInScopeCount.push(0);
1212 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1214 llvm::raw_string_ostream ss(out);
1215 ss << getOrCreateName(op.getValue());
1216 for (
auto index : op.getIndices()) {
1217 ss <<
"[" << getOrCreateName(index) <<
"]";
1222 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1224 llvm::raw_string_ostream ss(out);
1225 ss << getOrCreateName(op.getOperand());
1226 ss <<
"." << op.getMember();
1230 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1232 llvm::raw_string_ostream ss(out);
1233 ss << getOrCreateName(op.getOperand());
1234 ss <<
"->" << op.getMember();
1238 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1239 if (!valueMapper.count(value))
1240 valueMapper.insert(value, str.str());
1244 StringRef CppEmitter::getOrCreateName(
Value val) {
1245 if (!valueMapper.count(val)) {
1247 "cacheDeferredOpResult should have been called on this value, "
1248 "update the emitOperation function.");
1249 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1251 return *valueMapper.begin(val);
1255 StringRef CppEmitter::getOrCreateName(
Block &block) {
1256 if (!blockMapper.count(&block))
1257 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1258 return *blockMapper.begin(&block);
1261 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1263 case IntegerType::Signless:
1267 case IntegerType::Unsigned:
1270 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1273 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1275 bool CppEmitter::hasBlockLabel(
Block &block) {
1276 return blockMapper.count(&block);
1280 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1281 if (val.getBitWidth() == 1) {
1282 if (val.getBoolValue())
1288 val.toString(strValue, 10, !isUnsigned,
false);
1293 auto printFloat = [&](
const APFloat &val) {
1294 if (val.isFinite()) {
1297 val.toString(strValue, 0, 0,
false);
1299 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1300 case llvm::APFloatBase::S_IEEEhalf:
1303 case llvm::APFloatBase::S_BFloat:
1306 case llvm::APFloatBase::S_IEEEsingle:
1309 case llvm::APFloatBase::S_IEEEdouble:
1312 llvm_unreachable(
"unsupported floating point type");
1314 }
else if (val.isNaN()) {
1316 }
else if (val.isInfinity()) {
1317 if (val.isNegative())
1324 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1325 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1328 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1330 printFloat(fAttr.getValue());
1333 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1334 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1335 dense.getElementType())) {
1337 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1340 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1346 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1347 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1348 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1351 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1352 printInt(iAttr.getValue(),
false);
1356 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1357 if (
auto iType = dyn_cast<IntegerType>(
1358 cast<TensorType>(dense.getType()).getElementType())) {
1360 interleaveComma(dense, os, [&](
const APInt &val) {
1361 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1366 if (
auto iType = dyn_cast<IndexType>(
1367 cast<TensorType>(dense.getType()).getElementType())) {
1369 interleaveComma(dense, os,
1370 [&](
const APInt &val) { printInt(val,
false); });
1377 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1378 os << oAttr.getValue();
1383 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1384 if (sAttr.getNestedReferences().size() > 1)
1385 return emitError(loc,
"attribute has more than 1 nested reference");
1386 os << sAttr.getRootReference().getValue();
1391 if (
auto type = dyn_cast<TypeAttr>(attr))
1392 return emitType(loc, type.getValue());
1394 return emitError(loc,
"cannot emit attribute: ") << attr;
1397 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1398 assert(emittedExpressionPrecedence.empty() &&
1399 "Expected precedence stack to be empty");
1400 Operation *rootOp = expressionOp.getRootOp();
1402 emittedExpression = expressionOp;
1404 if (failed(precedence))
1406 pushExpressionPrecedence(precedence.value());
1408 if (failed(emitOperation(*rootOp,
false)))
1411 popExpressionPrecedence();
1412 assert(emittedExpressionPrecedence.empty() &&
1413 "Expected precedence stack to be empty");
1414 emittedExpression =
nullptr;
1419 LogicalResult CppEmitter::emitOperand(
Value value) {
1420 if (isPartOfCurrentExpression(value)) {
1422 assert(def &&
"Expected operand to be defined by an operation");
1424 if (failed(precedence))
1430 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1431 if (encloseInParenthesis)
1433 pushExpressionPrecedence(precedence.value());
1435 if (failed(emitOperation(*def,
false)))
1438 if (encloseInParenthesis)
1441 popExpressionPrecedence();
1445 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1447 return emitExpression(expressionOp);
1449 os << getOrCreateName(value);
1453 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1457 if (getEmittedExpression())
1458 pushExpressionPrecedence(lowestPrecedence());
1459 if (failed(emitOperand(operand)))
1461 if (getEmittedExpression())
1462 popExpressionPrecedence();
1468 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1470 if (failed(emitOperands(op)))
1475 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1482 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1483 if (llvm::is_contained(exclude, attr.getName().strref()))
1485 os <<
"/* " << attr.getName().getValue() <<
" */";
1486 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1493 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1494 if (!hasValueInScope(result)) {
1496 "result variable for the operation has not been declared");
1498 os << getOrCreateName(result) <<
" = ";
1502 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1503 bool trailingSemicolon) {
1506 if (hasValueInScope(result)) {
1508 "result variable for the operation already declared");
1512 getOrCreateName(result))))
1514 if (trailingSemicolon)
1519 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1520 if (op.getExternSpecifier())
1522 else if (op.getStaticSpecifier())
1524 if (op.getConstSpecifier())
1527 if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1528 op.getSymName()))) {
1532 std::optional<Attribute> initialValue = op.getInitialValue();
1535 if (failed(emitAttribute(op->getLoc(), *initialValue)))
1543 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1545 if (getEmittedExpression())
1553 if (shouldDeclareVariablesAtTop()) {
1554 if (failed(emitVariableAssignment(result)))
1557 if (failed(emitVariableDeclaration(result,
false)))
1564 if (!shouldDeclareVariablesAtTop()) {
1566 if (failed(emitVariableDeclaration(result,
true)))
1572 [&](
Value result) { os << getOrCreateName(result); });
1578 LogicalResult CppEmitter::emitLabel(
Block &block) {
1579 if (!hasBlockLabel(block))
1583 os.getOStream() << getOrCreateName(block) <<
":\n";
1587 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1588 LogicalResult status =
1591 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1593 .Case<cf::BranchOp, cf::CondBranchOp>(
1596 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1597 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1598 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1599 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1600 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1601 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1602 emitc::DivOp, emitc::ExpressionOp, emitc::FileOp, emitc::ForOp,
1603 emitc::FuncOp, emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp,
1604 emitc::LoadOp, emitc::LogicalAndOp, emitc::LogicalNotOp,
1605 emitc::LogicalOrOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp,
1606 emitc::SubOp, emitc::SwitchOp, emitc::UnaryMinusOp,
1607 emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp>(
1611 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1613 .Case<emitc::GetGlobalOp>([&](
auto op) {
1617 .Case<emitc::LiteralOp>([&](
auto op) {
1618 cacheDeferredOpResult(op.
getResult(), op.getValue());
1621 .Case<emitc::MemberOp>([&](
auto op) {
1622 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1625 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1626 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1629 .Case<emitc::SubscriptOp>([&](
auto op) {
1630 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1634 return op.
emitOpError(
"unable to find printer for op");
1643 if (getEmittedExpression() ||
1644 (isa<emitc::ExpressionOp>(op) &&
1650 trailingSemicolon &=
1651 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
1652 emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(
1655 os << (trailingSemicolon ?
";\n" :
"\n");
1660 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1662 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1663 if (failed(emitType(loc, arrType.getElementType())))
1666 for (
auto dim : arrType.getShape()) {
1667 os <<
"[" << dim <<
"]";
1671 if (failed(emitType(loc, type)))
1677 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1678 if (
auto iType = dyn_cast<IntegerType>(type)) {
1679 switch (iType.getWidth()) {
1681 return (os <<
"bool"), success();
1686 if (shouldMapToUnsigned(iType.getSignedness()))
1687 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1689 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1691 return emitError(loc,
"cannot emit integer type ") << type;
1694 if (
auto fType = dyn_cast<FloatType>(type)) {
1695 switch (fType.getWidth()) {
1697 if (llvm::isa<Float16Type>(type))
1698 return (os <<
"_Float16"), success();
1699 else if (llvm::isa<BFloat16Type>(type))
1700 return (os <<
"__bf16"), success();
1702 return emitError(loc,
"cannot emit float type ") << type;
1705 return (os <<
"float"), success();
1707 return (os <<
"double"), success();
1709 return emitError(loc,
"cannot emit float type ") << type;
1712 if (
auto iType = dyn_cast<IndexType>(type))
1713 return (os <<
"size_t"), success();
1714 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1715 return (os <<
"size_t"), success();
1716 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1717 return (os <<
"ssize_t"), success();
1718 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1719 return (os <<
"ptrdiff_t"), success();
1720 if (
auto tType = dyn_cast<TensorType>(type)) {
1721 if (!tType.hasRank())
1722 return emitError(loc,
"cannot emit unranked tensor type");
1723 if (!tType.hasStaticShape())
1724 return emitError(loc,
"cannot emit tensor type with non static shape");
1726 if (isa<ArrayType>(tType.getElementType()))
1727 return emitError(loc,
"cannot emit tensor of array type ") << type;
1728 if (failed(emitType(loc, tType.getElementType())))
1730 auto shape = tType.getShape();
1731 for (
auto dimSize : shape) {
1738 if (
auto tType = dyn_cast<TupleType>(type))
1739 return emitTupleType(loc, tType.getTypes());
1740 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1741 os << oType.getValue();
1744 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1745 if (failed(emitType(loc, aType.getElementType())))
1747 for (
auto dim : aType.getShape())
1748 os <<
"[" << dim <<
"]";
1751 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1752 return emitType(loc, lType.getValueType());
1753 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1754 if (isa<ArrayType>(pType.getPointee()))
1755 return emitError(loc,
"cannot emit pointer to array type ") << type;
1756 if (failed(emitType(loc, pType.getPointee())))
1761 return emitError(loc,
"cannot emit type ") << type;
1765 switch (types.size()) {
1770 return emitType(loc, types.front());
1772 return emitTupleType(loc, types);
1777 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1778 return emitError(loc,
"cannot emit tuple of array type");
1780 os <<
"std::tuple<";
1782 types, os, [&](
Type type) {
return emitType(loc, type); })))
1789 bool declareVariablesAtTop,
1791 CppEmitter emitter(os, declareVariablesAtTop, fileId);
1792 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.