21#include "llvm/ADT/ScopedHashTable.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/FormatVariadic.h"
28#define DEBUG_TYPE "translate-to-cpp"
38 typename NullaryFunctor>
39static inline LogicalResult
41 UnaryFunctor eachFn, NullaryFunctor betweenFn) {
44 if (failed(eachFn(*begin)))
47 for (; begin != end; ++begin) {
49 if (failed(eachFn(*begin)))
55template <
typename Container,
typename UnaryFunctor,
typename NullaryFunctor>
58 NullaryFunctor betweenFn) {
62template <
typename Container,
typename UnaryFunctor>
65 UnaryFunctor eachFn) {
73 .Case<emitc::AddressOfOp>([&](
auto op) {
return 15; })
74 .Case<emitc::AddOp>([&](
auto op) {
return 12; })
75 .Case<emitc::ApplyOp>([&](
auto op) {
return 15; })
76 .Case<emitc::BitwiseAndOp>([&](
auto op) {
return 7; })
77 .Case<emitc::BitwiseLeftShiftOp>([&](
auto op) {
return 11; })
78 .Case<emitc::BitwiseNotOp>([&](
auto op) {
return 15; })
79 .Case<emitc::BitwiseOrOp>([&](
auto op) {
return 5; })
80 .Case<emitc::BitwiseRightShiftOp>([&](
auto op) {
return 11; })
81 .Case<emitc::BitwiseXorOp>([&](
auto op) {
return 6; })
82 .Case<emitc::CallOp>([&](
auto op) {
return 16; })
83 .Case<emitc::CallOpaqueOp>([&](
auto op) {
return 16; })
84 .Case<emitc::CastOp>([&](
auto op) {
return 15; })
85 .Case<emitc::CmpOp>([&](
auto op) -> FailureOr<int> {
86 switch (op.getPredicate()) {
87 case emitc::CmpPredicate::eq:
88 case emitc::CmpPredicate::ne:
90 case emitc::CmpPredicate::lt:
91 case emitc::CmpPredicate::le:
92 case emitc::CmpPredicate::gt:
93 case emitc::CmpPredicate::ge:
95 case emitc::CmpPredicate::three_way:
98 return op->emitError(
"unsupported cmp predicate");
100 .Case<emitc::ConditionalOp>([&](
auto op) {
return 2; })
101 .Case<emitc::ConstantOp>([&](
auto op) {
return 17; })
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"); });
120 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
124 LogicalResult emitAttribute(Location loc, Attribute attr);
131 LogicalResult emitOperation(Operation &op,
bool trailingSemicolon);
134 LogicalResult emitType(Location loc, Type type);
140 LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
144 LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
147 LogicalResult emitVariableAssignment(OpResult
result);
150 LogicalResult emitVariableDeclaration(OpResult
result,
151 bool trailingSemicolon);
154 LogicalResult emitVariableDeclaration(Location loc, Type type,
163 LogicalResult emitAssignPrefix(Operation &op);
166 LogicalResult emitGlobalVariable(GlobalOp op);
169 LogicalResult emitLabel(
Block &block);
173 LogicalResult emitOperandsAndAttributes(Operation &op,
174 ArrayRef<StringRef> exclude = {});
177 LogicalResult emitOperands(Operation &op);
183 LogicalResult emitOperand(Value value,
bool isInBrackets =
false);
186 LogicalResult emitExpression(ExpressionOp expressionOp);
189 void cacheDeferredOpResult(Value value, StringRef str);
192 StringRef getOrCreateName(Value val);
196 StringRef getOrCreateInductionVarName(Value val);
199 StringRef getOrCreateName(
Block &block);
201 LogicalResult emitInlinedExpression(Value value);
204 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
208 ~Scope() { emitter.labelInScopeCount.pop(); }
211 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
212 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
215 Scope(CppEmitter &emitter)
216 : valueMapperScope(emitter.valueMapper),
217 blockMapperScope(emitter.blockMapper), emitter(emitter) {
218 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
225 struct FunctionScope : Scope {
226 FunctionScope(CppEmitter &emitter) : Scope(emitter) {
228 emitter.resetValueCounter();
234 struct LoopScope : Scope {
235 LoopScope(CppEmitter &emitter) : Scope(emitter) {
236 emitter.increaseLoopNestingLevel();
238 ~LoopScope() { emitter.decreaseLoopNestingLevel(); }
242 bool hasValueInScope(Value val);
245 bool hasBlockLabel(
Block &block);
248 raw_indented_ostream &ostream() {
return os; };
252 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
255 bool shouldEmitFile(FileOp file) {
256 return !fileId.empty() && file.getId() == fileId;
260 bool isEmittingExpression() {
return !emittedExpressionPrecedence.empty(); }
264 bool isPartOfCurrentExpression(Value value) {
266 return def ? isPartOfCurrentExpression(def) :
false;
271 bool isPartOfCurrentExpression(Operation *def) {
276 void resetValueCounter();
279 void increaseLoopNestingLevel();
282 void decreaseLoopNestingLevel();
285 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
286 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
289 raw_indented_ostream os;
294 bool declareVariablesAtTop;
300 ValueMapper valueMapper;
303 BlockMapper blockMapper;
306 llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
307 llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
309 std::stack<int64_t> labelInScopeCount;
313 uint64_t loopNestingLevel{0};
316 unsigned int valueCount{0};
319 SmallVector<int> emittedExpressionPrecedence;
321 void pushExpressionPrecedence(
int precedence) {
322 emittedExpressionPrecedence.push_back(precedence);
324 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
325 static int lowestPrecedence() {
return 0; }
326 int getExpressionPrecedence() {
327 if (emittedExpressionPrecedence.empty())
328 return lowestPrecedence();
329 return emittedExpressionPrecedence.back();
336 return isa_and_nonnull<emitc::DereferenceOp, emitc::GetGlobalOp,
337 emitc::LiteralOp, emitc::MemberOp,
338 emitc::MemberOfPtrOp, emitc::SubscriptOp,
339 emitc::GetFieldOp>(op);
350 if (isa<CExpressionInterface>(op))
354 ExpressionOp expressionOp = dyn_cast<ExpressionOp>(op);
359 if (expressionOp.getDoNotInline())
377 if (isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user))
381 if (!expressionOp.hasSideEffects())
392 if (isa<emitc::IfOp, emitc::SwitchOp, emitc::ReturnOp>(user))
397 if (
auto assignOp = dyn_cast<emitc::AssignOp>(user)) {
399 if (expressionOp.getResult() == assignOp.getValue() &&
400 isa_and_present<VariableOp>(assignOp.getVar().getDefiningOp()))
408 emitc::DereferenceOp dereferenceOp) {
410 llvm::raw_string_ostream ss(out);
411 ss <<
"*" << emitter.getOrCreateName(dereferenceOp.getPointer());
412 emitter.cacheDeferredOpResult(dereferenceOp.getResult(), out);
417 emitc::GetFieldOp getFieldOp) {
418 emitter.cacheDeferredOpResult(getFieldOp.getResult(),
419 getFieldOp.getFieldName());
424 emitc::GetGlobalOp getGlobalOp) {
425 emitter.cacheDeferredOpResult(getGlobalOp.getResult(), getGlobalOp.getName());
430 emitc::LiteralOp literalOp) {
431 emitter.cacheDeferredOpResult(literalOp.getResult(), literalOp.getValue());
436 emitc::MemberOp memberOp) {
438 llvm::raw_string_ostream ss(out);
439 ss << emitter.getOrCreateName(memberOp.getOperand());
440 ss <<
"." << memberOp.getMember();
441 emitter.cacheDeferredOpResult(memberOp.getResult(), out);
446 emitc::MemberOfPtrOp memberOfPtrOp) {
448 llvm::raw_string_ostream ss(out);
449 ss << emitter.getOrCreateName(memberOfPtrOp.getOperand());
450 ss <<
"->" << memberOfPtrOp.getMember();
451 emitter.cacheDeferredOpResult(memberOfPtrOp.getResult(), out);
456 emitc::SubscriptOp subscriptOp) {
458 llvm::raw_string_ostream ss(out);
459 ss << emitter.getOrCreateName(subscriptOp.getValue());
460 for (
auto index : subscriptOp.getIndices()) {
461 ss <<
"[" << emitter.getOrCreateName(
index) <<
"]";
463 emitter.cacheDeferredOpResult(subscriptOp.getResult(), out);
473 if (emitter.shouldDeclareVariablesAtTop()) {
475 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
476 if (oAttr.getValue().empty())
480 if (failed(emitter.emitVariableAssignment(
result)))
482 return emitter.emitAttribute(operation->
getLoc(), value);
486 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
487 if (oAttr.getValue().empty())
489 return emitter.emitVariableDeclaration(
result,
494 if (failed(emitter.emitAssignPrefix(*operation)))
496 return emitter.emitAttribute(operation->
getLoc(), value);
500 emitc::AddressOfOp addressOfOp) {
502 Operation &op = *addressOfOp.getOperation();
504 if (failed(emitter.emitAssignPrefix(op)))
507 return emitter.emitOperand(addressOfOp.getReference());
511 emitc::ConstantOp constantOp) {
512 Operation *operation = constantOp.getOperation();
515 if (emitter.isPartOfCurrentExpression(operation))
516 return emitter.emitAttribute(operation->
getLoc(), value);
522 emitc::VariableOp variableOp) {
523 Operation *operation = variableOp.getOperation();
530 emitc::GlobalOp globalOp) {
532 return emitter.emitGlobalVariable(globalOp);
536 emitc::AssignOp assignOp) {
537 OpResult result = assignOp.getVar().getDefiningOp()->getResult(0);
539 if (failed(emitter.emitVariableAssignment(
result)))
542 return emitter.emitOperand(assignOp.getValue());
546 if (failed(emitter.emitAssignPrefix(*loadOp)))
549 return emitter.emitOperand(loadOp.getOperand());
554 StringRef binaryOperator) {
557 if (failed(emitter.emitAssignPrefix(*operation)))
560 if (failed(emitter.emitOperand(operation->
getOperand(0))))
563 os <<
" " << binaryOperator <<
" ";
565 if (failed(emitter.emitOperand(operation->
getOperand(1))))
573 StringRef unaryOperator) {
576 if (failed(emitter.emitAssignPrefix(*operation)))
581 if (failed(emitter.emitOperand(operation->
getOperand(0))))
588 Operation *operation = addOp.getOperation();
594 Operation *operation = divOp.getOperation();
600 Operation *operation = mulOp.getOperation();
606 Operation *operation = remOp.getOperation();
612 Operation *operation = subOp.getOperation();
620 std::next(iteratorOp) != end; ++iteratorOp) {
621 if (failed(emitter.emitOperation(*iteratorOp,
true)))
629 emitc::SwitchOp switchOp) {
633 if (failed(emitter.emitOperand(switchOp.getArg())))
637 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
638 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
647 os <<
"\ndefault: {\n";
650 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
663 Block &bodyBlock = doOp.getBodyRegion().
front();
665 if (failed(emitter.emitOperation(op,
true)))
671 Block &condBlock = doOp.getConditionRegion().
front();
672 auto condYield = cast<emitc::YieldOp>(condBlock.
back());
673 if (failed(emitter.emitExpression(
674 cast<emitc::ExpressionOp>(condYield.getOperand(0).getDefiningOp()))))
682 Operation *operation = cmpOp.getOperation();
684 StringRef binaryOperator;
686 switch (cmpOp.getPredicate()) {
687 case emitc::CmpPredicate::eq:
688 binaryOperator =
"==";
690 case emitc::CmpPredicate::ne:
691 binaryOperator =
"!=";
693 case emitc::CmpPredicate::lt:
694 binaryOperator =
"<";
696 case emitc::CmpPredicate::le:
697 binaryOperator =
"<=";
699 case emitc::CmpPredicate::gt:
700 binaryOperator =
">";
702 case emitc::CmpPredicate::ge:
703 binaryOperator =
">=";
705 case emitc::CmpPredicate::three_way:
706 binaryOperator =
"<=>";
714 emitc::ConditionalOp conditionalOp) {
717 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
720 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
725 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
730 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
737 emitc::VerbatimOp verbatimOp) {
740 FailureOr<SmallVector<ReplacementItem>> items =
741 verbatimOp.parseFormatString();
745 auto fmtArg = verbatimOp.getFmtArgs().begin();
748 if (
auto *str = std::get_if<StringRef>(&item)) {
751 if (failed(emitter.emitOperand(*fmtArg++)))
760 cf::BranchOp branchOp) {
765 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
766 Value &operand = std::get<0>(pair);
768 os << emitter.getOrCreateName(argument) <<
" = "
769 << emitter.getOrCreateName(operand) <<
";\n";
773 if (!(emitter.hasBlockLabel(successor)))
774 return branchOp.emitOpError(
"unable to find label for successor block");
775 os << emitter.getOrCreateName(successor);
780 cf::CondBranchOp condBranchOp) {
782 Block &trueSuccessor = *condBranchOp.getTrueDest();
783 Block &falseSuccessor = *condBranchOp.getFalseDest();
786 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
793 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
795 Value &operand = std::get<0>(pair);
797 os << emitter.getOrCreateName(argument) <<
" = "
798 << emitter.getOrCreateName(operand) <<
";\n";
802 if (!(emitter.hasBlockLabel(trueSuccessor))) {
803 return condBranchOp.emitOpError(
"unable to find label for successor block");
805 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
809 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
811 Value &operand = std::get<0>(pair);
813 os << emitter.getOrCreateName(argument) <<
" = "
814 << emitter.getOrCreateName(operand) <<
";\n";
818 if (!(emitter.hasBlockLabel(falseSuccessor))) {
819 return condBranchOp.emitOpError()
820 <<
"unable to find label for successor block";
822 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
829 if (failed(emitter.emitAssignPrefix(*callOp)))
834 if (failed(emitter.emitOperands(*callOp)))
841 Operation *operation = callOp.getOperation();
842 StringRef callee = callOp.getCallee();
848 Operation *operation = callOp.getOperation();
849 StringRef callee = callOp.getCallee();
855 emitc::CallOpaqueOp callOpaqueOp) {
857 Operation &op = *callOpaqueOp.getOperation();
859 if (failed(emitter.emitAssignPrefix(op)))
861 os << callOpaqueOp.getCallee();
867 auto emitTemplateArgs = [&](
Attribute attr) -> LogicalResult {
868 return emitter.emitAttribute(op.
getLoc(), attr);
871 if (callOpaqueOp.getTemplateArgs()) {
879 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
880 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
882 if (t.getType().isIndex()) {
885 return emitter.emitOperand(operand);
888 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
896 LogicalResult emittedArgs =
897 callOpaqueOp.getArgs()
899 : emitter.emitOperands(op);
900 if (failed(emittedArgs))
907 emitc::ApplyOp applyOp) {
911 if (failed(emitter.emitAssignPrefix(op)))
913 os << applyOp.getApplicableOperator();
914 return emitter.emitOperand(applyOp.getOperand());
918 emitc::BitwiseAndOp bitwiseAndOp) {
919 Operation *operation = bitwiseAndOp.getOperation();
925 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
926 Operation *operation = bitwiseLeftShiftOp.getOperation();
931 emitc::BitwiseNotOp bitwiseNotOp) {
932 Operation *operation = bitwiseNotOp.getOperation();
937 emitc::BitwiseOrOp bitwiseOrOp) {
938 Operation *operation = bitwiseOrOp.getOperation();
944 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
945 Operation *operation = bitwiseRightShiftOp.getOperation();
950 emitc::BitwiseXorOp bitwiseXorOp) {
951 Operation *operation = bitwiseXorOp.getOperation();
956 emitc::UnaryPlusOp unaryPlusOp) {
957 Operation *operation = unaryPlusOp.getOperation();
962 emitc::UnaryMinusOp unaryMinusOp) {
963 Operation *operation = unaryMinusOp.getOperation();
971 if (failed(emitter.emitAssignPrefix(op)))
977 return emitter.emitOperand(castOp.getOperand());
981 emitc::ExpressionOp expressionOp) {
985 Operation &op = *expressionOp.getOperation();
987 if (failed(emitter.emitAssignPrefix(op)))
990 return emitter.emitExpression(expressionOp);
994 emitc::IncludeOp includeOp) {
998 if (includeOp.getIsStandardInclude())
999 os <<
"<" << includeOp.getInclude() <<
">";
1001 os <<
"\"" << includeOp.getInclude() <<
"\"";
1007 emitc::LogicalAndOp logicalAndOp) {
1008 Operation *operation = logicalAndOp.getOperation();
1013 emitc::LogicalNotOp logicalNotOp) {
1014 Operation *operation = logicalNotOp.getOperation();
1019 emitc::LogicalOrOp logicalOrOp) {
1020 Operation *operation = logicalOrOp.getOperation();
1030 auto requiresParentheses = [&](
Value value) {
1039 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
1042 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1044 if (failed(emitter.emitOperand(forOp.getLowerBound())))
1047 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1049 Value upperBound = forOp.getUpperBound();
1050 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
1051 if (upperBoundRequiresParentheses)
1053 if (failed(emitter.emitOperand(upperBound)))
1055 if (upperBoundRequiresParentheses)
1058 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1060 if (failed(emitter.emitOperand(forOp.getStep())))
1065 CppEmitter::LoopScope lScope(emitter);
1067 Region &forRegion = forOp.getRegion();
1068 auto regionOps = forRegion.
getOps();
1071 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
1072 if (failed(emitter.emitOperation(*it,
true)))
1086 auto emitAllExceptLast = [&emitter](
Region ®ion) {
1088 for (; std::next(it) != end; ++it) {
1089 if (failed(emitter.emitOperation(*it,
true)))
1092 assert(isa<emitc::YieldOp>(*it) &&
1093 "Expected last operation in the region to be emitc::yield");
1098 if (failed(emitter.emitOperand(ifOp.getCondition())))
1102 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
1106 Region &elseRegion = ifOp.getElseRegion();
1107 if (!elseRegion.
empty()) {
1110 if (failed(emitAllExceptLast(elseRegion)))
1119 func::ReturnOp returnOp) {
1122 switch (returnOp.getNumOperands()) {
1127 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
1131 os <<
" std::make_tuple(";
1132 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
1140 emitc::ReturnOp returnOp) {
1143 if (returnOp.getNumOperands() == 0)
1147 if (failed(emitter.emitOperand(returnOp.getOperand())))
1154 if (failed(emitter.emitOperation(op,
false)))
1162 os <<
"class " << classOp.getSymName();
1163 if (classOp.getFinalSpecifier())
1165 os <<
" {\n public:\n";
1169 if (failed(emitter.emitOperation(op,
false)))
1180 if (failed(emitter.emitVariableDeclaration(
1181 fieldOp->getLoc(), fieldOp.getType(), fieldOp.getSymName())))
1183 std::optional<Attribute> initialValue = fieldOp.getInitialValue();
1186 if (failed(emitter.emitAttribute(fieldOp->getLoc(), *initialValue)))
1195 if (!emitter.shouldEmitFile(file))
1199 if (failed(emitter.emitOperation(op,
false)))
1212 return emitter.emitType(functionOp->
getLoc(), arg);
1223 return emitter.emitVariableDeclaration(
1224 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1234 if (emitter.shouldDeclareVariablesAtTop()) {
1239 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1240 (isa<emitc::ExpressionOp>(op) &&
1244 if (failed(emitter.emitVariableDeclaration(
1247 op->
emitError(
"unable to declare result variable for op"));
1252 if (
result.wasInterrupted())
1257 for (
Block &block : blocks) {
1258 emitter.getOrCreateName(block);
1262 for (
Block &block : llvm::drop_begin(blocks)) {
1264 if (emitter.hasValueInScope(arg))
1265 return functionOp->
emitOpError(
" block argument #")
1266 << arg.getArgNumber() <<
" is out of scope";
1267 if (isa<ArrayType, LValueType>(arg.getType()))
1268 return functionOp->
emitOpError(
"cannot emit block argument #")
1269 << arg.getArgNumber() <<
" with type " << arg.getType();
1271 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1274 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1278 for (
Block &block : blocks) {
1280 if (!block.hasNoPredecessors()) {
1281 if (failed(emitter.emitLabel(block)))
1284 for (
Operation &op : block.getOperations()) {
1285 if (failed(emitter.emitOperation(op,
true)))
1296 func::FuncOp functionOp) {
1298 if (!emitter.shouldDeclareVariablesAtTop() &&
1299 functionOp.getBlocks().size() > 1) {
1300 return functionOp.emitOpError(
1301 "with multiple blocks needs variables declared at top");
1304 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1305 return functionOp.emitOpError()
1306 <<
"cannot emit lvalue type as argument type";
1309 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1310 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1313 CppEmitter::FunctionScope scope(emitter);
1315 if (failed(emitter.emitTypes(functionOp.getLoc(),
1316 functionOp.getFunctionType().getResults())))
1318 os <<
" " << functionOp.getName();
1321 Operation *operation = functionOp.getOperation();
1333 emitc::FuncOp functionOp) {
1335 if (!emitter.shouldDeclareVariablesAtTop() &&
1336 functionOp.getBlocks().size() > 1) {
1337 return functionOp.emitOpError(
1338 "with multiple blocks needs variables declared at top");
1341 CppEmitter::FunctionScope scope(emitter);
1343 if (functionOp.getSpecifiers()) {
1344 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1345 os << cast<StringAttr>(specifier).str() <<
" ";
1349 if (failed(emitter.emitTypes(functionOp.getLoc(),
1350 functionOp.getFunctionType().getResults())))
1352 os <<
" " << functionOp.getName();
1355 Operation *operation = functionOp.getOperation();
1356 if (functionOp.isExternal()) {
1358 functionOp.getArgumentTypes())))
1374 DeclareFuncOp declareFuncOp) {
1377 CppEmitter::FunctionScope scope(emitter);
1379 declareFuncOp, declareFuncOp.getSymNameAttr());
1384 if (functionOp.getSpecifiers()) {
1385 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1386 os << cast<StringAttr>(specifier).str() <<
" ";
1390 if (failed(emitter.emitTypes(functionOp.getLoc(),
1391 functionOp.getFunctionType().getResults())))
1393 os <<
" " << functionOp.getName();
1396 Operation *operation = functionOp.getOperation();
1404CppEmitter::CppEmitter(
raw_ostream &os,
bool declareVariablesAtTop,
1406 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1407 fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1408 defaultBlockMapperScope(blockMapper) {
1409 labelInScopeCount.push(0);
1412void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1413 if (!valueMapper.count(value))
1414 valueMapper.insert(value, str.str());
1418StringRef CppEmitter::getOrCreateName(Value val) {
1419 if (!valueMapper.count(val)) {
1421 "cacheDeferredOpResult should have been called on this value, "
1422 "update the emitOperation function.");
1424 valueMapper.insert(val, formatv(
"v{0}", ++valueCount));
1426 return *valueMapper.begin(val);
1431StringRef CppEmitter::getOrCreateInductionVarName(Value val) {
1432 if (!valueMapper.count(val)) {
1434 int64_t identifier =
'i' + loopNestingLevel;
1436 if (identifier >=
'i' && identifier <=
't') {
1437 valueMapper.insert(val,
1438 formatv(
"{0}{1}", (
char)identifier, ++valueCount));
1441 valueMapper.insert(val, formatv(
"u{0}", ++valueCount));
1444 return *valueMapper.begin(val);
1448StringRef CppEmitter::getOrCreateName(
Block &block) {
1449 if (!blockMapper.count(&block))
1450 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1451 return *blockMapper.begin(&block);
1454bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1456 case IntegerType::Signless:
1458 case IntegerType::Signed:
1460 case IntegerType::Unsigned:
1463 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1466bool CppEmitter::hasValueInScope(Value val) {
return valueMapper.count(val); }
1468bool CppEmitter::hasBlockLabel(
Block &block) {
1469 return blockMapper.count(&block);
1472LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) {
1473 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1474 if (val.getBitWidth() == 1) {
1475 if (val.getBoolValue())
1480 SmallString<128> strValue;
1481 val.toString(strValue, 10, !isUnsigned,
false);
1486 auto printFloat = [&](
const APFloat &val) {
1487 if (val.isFinite()) {
1488 SmallString<128> strValue;
1490 val.toString(strValue, 0, 0,
false);
1492 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1493 case llvm::APFloatBase::S_IEEEhalf:
1496 case llvm::APFloatBase::S_BFloat:
1499 case llvm::APFloatBase::S_IEEEsingle:
1502 case llvm::APFloatBase::S_IEEEdouble:
1505 llvm_unreachable(
"unsupported floating point type");
1507 }
else if (val.isNaN()) {
1509 }
else if (val.isInfinity()) {
1510 if (val.isNegative())
1517 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1518 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1521 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1523 printFloat(fAttr.getValue());
1526 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1527 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1528 dense.getElementType())) {
1530 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1533 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1539 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1540 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1541 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1544 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1545 printInt(iAttr.getValue(),
false);
1549 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1550 if (
auto iType = dyn_cast<IntegerType>(
1551 cast<ShapedType>(dense.getType()).getElementType())) {
1553 interleaveComma(dense, os, [&](
const APInt &val) {
1554 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1559 if (
auto iType = dyn_cast<IndexType>(
1560 cast<ShapedType>(dense.getType()).getElementType())) {
1562 interleaveComma(dense, os,
1563 [&](
const APInt &val) { printInt(val,
false); });
1570 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1571 os << oAttr.getValue();
1576 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1577 if (sAttr.getNestedReferences().size() > 1)
1578 return emitError(loc,
"attribute has more than 1 nested reference");
1579 os << sAttr.getRootReference().getValue();
1584 if (
auto type = dyn_cast<TypeAttr>(attr))
1585 return emitType(loc, type.getValue());
1587 return emitError(loc,
"cannot emit attribute: ") << attr;
1590LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1591 assert(emittedExpressionPrecedence.empty() &&
1592 "Expected precedence stack to be empty");
1593 Operation *rootOp = expressionOp.getRootOp();
1598 pushExpressionPrecedence(precedence.value());
1600 if (
failed(emitOperation(*rootOp,
false)))
1603 popExpressionPrecedence();
1604 assert(emittedExpressionPrecedence.empty() &&
1605 "Expected precedence stack to be empty");
1610LogicalResult CppEmitter::emitOperand(Value value,
bool isInBrackets) {
1611 if (isPartOfCurrentExpression(value)) {
1613 assert(def &&
"Expected operand to be defined by an operation");
1621 bool encloseInParenthesis =
1622 !isInBrackets && precedence.value() <= getExpressionPrecedence();
1624 if (encloseInParenthesis)
1626 pushExpressionPrecedence(precedence.value());
1628 if (
failed(emitOperation(*def,
false)))
1631 if (encloseInParenthesis)
1634 popExpressionPrecedence();
1640 return emitExpression(expressionOp);
1642 if (BlockArgument arg = dyn_cast<BlockArgument>(value)) {
1645 Operation *argOp = arg.getParentBlock()->getParentOp();
1646 if (
auto expressionOp = dyn_cast<ExpressionOp>(argOp))
1647 return emitOperand(expressionOp->getOperand(arg.getArgNumber()));
1650 os << getOrCreateName(value);
1654LogicalResult CppEmitter::emitOperands(Operation &op) {
1658 return emitOperand(operand, true);
1663CppEmitter::emitOperandsAndAttributes(Operation &op,
1664 ArrayRef<StringRef> exclude) {
1665 if (
failed(emitOperands(op)))
1669 for (NamedAttribute attr : op.
getAttrs()) {
1670 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1677 auto emitNamedAttribute = [&](NamedAttribute attr) -> LogicalResult {
1678 if (llvm::is_contained(exclude, attr.getName().strref()))
1680 os <<
"/* " << attr.getName().getValue() <<
" */";
1681 if (
failed(emitAttribute(op.
getLoc(), attr.getValue())))
1688LogicalResult CppEmitter::emitVariableAssignment(OpResult
result) {
1689 if (!hasValueInScope(
result)) {
1690 return result.getDefiningOp()->emitOpError(
1691 "result variable for the operation has not been declared");
1693 os << getOrCreateName(
result) <<
" = ";
1697LogicalResult CppEmitter::emitVariableDeclaration(OpResult
result,
1698 bool trailingSemicolon) {
1701 if (hasValueInScope(
result)) {
1702 return result.getDefiningOp()->emitError(
1703 "result variable for the operation already declared");
1705 if (
failed(emitVariableDeclaration(
result.getOwner()->getLoc(),
1707 getOrCreateName(
result))))
1709 if (trailingSemicolon)
1714LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1715 if (op.getExternSpecifier())
1717 else if (op.getStaticSpecifier())
1719 if (op.getConstSpecifier())
1722 if (
failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1723 op.getSymName()))) {
1727 std::optional<Attribute> initialValue = op.getInitialValue();
1730 if (
failed(emitAttribute(op->getLoc(), *initialValue)))
1738LogicalResult CppEmitter::emitAssignPrefix(Operation &op) {
1740 if (isEmittingExpression())
1748 if (shouldDeclareVariablesAtTop()) {
1759 if (!shouldDeclareVariablesAtTop()) {
1767 [&](Value
result) { os << getOrCreateName(result); });
1773LogicalResult CppEmitter::emitLabel(
Block &block) {
1774 if (!hasBlockLabel(block))
1778 os.getOStream() << getOrCreateName(block) <<
":\n";
1782LogicalResult CppEmitter::emitOperation(Operation &op,
bool trailingSemicolon) {
1783 LogicalResult status =
1784 llvm::TypeSwitch<Operation *, LogicalResult>(&op)
1786 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1788 .Case<cf::BranchOp, cf::CondBranchOp>(
1791 .Case<emitc::AddressOfOp, emitc::AddOp, emitc::ApplyOp,
1792 emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1793 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1794 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1795 emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
1796 emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1797 emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivOp,
1798 emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
1799 emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
1800 emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
1801 emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
1802 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1803 emitc::MemberOfPtrOp, emitc::MemberOp, emitc::MulOp,
1804 emitc::RemOp, emitc::ReturnOp, emitc::SubscriptOp, emitc::SubOp,
1805 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1806 emitc::VariableOp, emitc::VerbatimOp>(
1810 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1812 .Default([&](Operation *) {
1813 return op.
emitOpError(
"unable to find printer for op");
1822 if (isEmittingExpression() ||
1823 (isa<emitc::ExpressionOp>(op) &&
1829 trailingSemicolon &=
1830 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::DoOp, emitc::FileOp,
1831 emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp,
1832 emitc::VerbatimOp>(op);
1834 os << (trailingSemicolon ?
";\n" :
"\n");
1839LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
1841 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1842 if (
failed(emitType(loc, arrType.getElementType())))
1845 for (
auto dim : arrType.getShape()) {
1846 os <<
"[" << dim <<
"]";
1850 if (
failed(emitType(loc, type)))
1856LogicalResult CppEmitter::emitType(Location loc, Type type) {
1857 if (
auto iType = dyn_cast<IntegerType>(type)) {
1858 switch (iType.getWidth()) {
1860 return (os <<
"bool"),
success();
1865 if (shouldMapToUnsigned(iType.getSignedness()))
1866 return (os <<
"uint" << iType.getWidth() <<
"_t"),
success();
1868 return (os <<
"int" << iType.getWidth() <<
"_t"),
success();
1870 return emitError(loc,
"cannot emit integer type ") << type;
1873 if (
auto fType = dyn_cast<FloatType>(type)) {
1874 switch (fType.getWidth()) {
1876 if (llvm::isa<Float16Type>(type))
1877 return (os <<
"_Float16"),
success();
1878 if (llvm::isa<BFloat16Type>(type))
1879 return (os <<
"__bf16"),
success();
1881 return emitError(loc,
"cannot emit float type ") << type;
1884 return (os <<
"float"),
success();
1886 return (os <<
"double"),
success();
1888 return emitError(loc,
"cannot emit float type ") << type;
1891 if (
auto iType = dyn_cast<IndexType>(type))
1892 return (os <<
"size_t"),
success();
1893 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1894 return (os <<
"size_t"),
success();
1895 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1896 return (os <<
"ssize_t"),
success();
1897 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1898 return (os <<
"ptrdiff_t"),
success();
1899 if (
auto tType = dyn_cast<TensorType>(type)) {
1900 if (!tType.hasRank())
1901 return emitError(loc,
"cannot emit unranked tensor type");
1902 if (!tType.hasStaticShape())
1903 return emitError(loc,
"cannot emit tensor type with non static shape");
1905 if (isa<ArrayType>(tType.getElementType()))
1906 return emitError(loc,
"cannot emit tensor of array type ") << type;
1907 if (
failed(emitType(loc, tType.getElementType())))
1909 auto shape = tType.getShape();
1910 for (
auto dimSize : shape) {
1917 if (
auto tType = dyn_cast<TupleType>(type))
1918 return emitTupleType(loc, tType.getTypes());
1919 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1920 os << oType.getValue();
1923 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1924 if (
failed(emitType(loc, aType.getElementType())))
1926 for (
auto dim : aType.getShape())
1927 os <<
"[" << dim <<
"]";
1930 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1931 return emitType(loc, lType.getValueType());
1932 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1933 if (isa<ArrayType>(pType.getPointee()))
1934 return emitError(loc,
"cannot emit pointer to array type ") << type;
1935 if (
failed(emitType(loc, pType.getPointee())))
1940 return emitError(loc,
"cannot emit type ") << type;
1943LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
1944 switch (types.size()) {
1949 return emitType(loc, types.front());
1951 return emitTupleType(loc, types);
1955LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
1956 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1957 return emitError(loc,
"cannot emit tuple of array type");
1959 os <<
"std::tuple<";
1961 types, os, [&](Type type) {
return emitType(loc, type); })))
1967void CppEmitter::resetValueCounter() { valueCount = 0; }
1969void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
1971void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
1974 bool declareVariablesAtTop,
1976 CppEmitter emitter(os, declareVariablesAtTop, fileId);
1977 return emitter.emitOperation(*op,
false);
false
Parses a map_entries map type from a string format back into its numeric value.
static LogicalResult printCallOperation(CppEmitter &emitter, Operation *callOp, StringRef callee)
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)
static LogicalResult interleaveCommaWithError(const Container &c, raw_ostream &os, UnaryFunctor eachFn)
static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator)
static bool shouldBeInlined(Operation *op)
Determine whether operation op should be emitted inline, i.e.
static LogicalResult printOperation(CppEmitter &emitter, emitc::DereferenceOp dereferenceOp)
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.
static LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
OpListType::iterator iterator
BlockArgListType getArguments()
Block * getSuccessor(unsigned i)
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
unsigned getNumOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
operand_range getOperands()
Returns an iterator on the underlying Value's.
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),...
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.
llvm::iplist< Block > BlockListType
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
iterator_range< OpIterator > getOps()
MutableArrayRef< BlockArgument > BlockArgListType
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
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.
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()
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
raw_indented_ostream & unindent()
Decreases 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.