22#include "llvm/ADT/ScopedHashTable.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/TypeSwitch.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/FormatVariadic.h"
30#define DEBUG_TYPE "translate-to-cpp"
40 typename NullaryFunctor>
41static inline LogicalResult
43 UnaryFunctor eachFn, NullaryFunctor betweenFn) {
46 if (failed(eachFn(*begin)))
49 for (; begin != end; ++begin) {
51 if (failed(eachFn(*begin)))
57template <
typename Container,
typename UnaryFunctor,
typename NullaryFunctor>
60 NullaryFunctor betweenFn) {
64template <
typename Container,
typename UnaryFunctor>
67 UnaryFunctor eachFn) {
75 .Case([&](emitc::AddressOfOp op) {
return 15; })
76 .Case([&](emitc::AddOp op) {
return 12; })
77 .Case([&](emitc::ApplyOp op) {
return 15; })
78 .Case([&](emitc::BitwiseAndOp op) {
return 7; })
79 .Case([&](emitc::BitwiseLeftShiftOp op) {
return 11; })
80 .Case([&](emitc::BitwiseNotOp op) {
return 15; })
81 .Case([&](emitc::BitwiseOrOp op) {
return 5; })
82 .Case([&](emitc::BitwiseRightShiftOp op) {
return 11; })
83 .Case([&](emitc::BitwiseXorOp op) {
return 6; })
84 .Case([&](emitc::CallOp op) {
return 16; })
85 .Case([&](emitc::CallOpaqueOp op) {
return 16; })
86 .Case([&](emitc::CastOp op) {
return 15; })
87 .Case([&](emitc::CmpOp op) -> FailureOr<int> {
88 switch (op.getPredicate()) {
89 case emitc::CmpPredicate::eq:
90 case emitc::CmpPredicate::ne:
92 case emitc::CmpPredicate::lt:
93 case emitc::CmpPredicate::le:
94 case emitc::CmpPredicate::gt:
95 case emitc::CmpPredicate::ge:
97 case emitc::CmpPredicate::three_way:
100 return op->emitError(
"unsupported cmp predicate");
102 .Case([&](emitc::ConditionalOp op) {
return 2; })
103 .Case([&](emitc::ConstantOp op) {
return 17; })
104 .Case([&](emitc::DereferenceOp op) {
return 15; })
105 .Case([&](emitc::DivOp op) {
return 13; })
106 .Case([&](emitc::GetGlobalOp op) {
return 18; })
107 .Case([&](emitc::LiteralOp op) {
return 18; })
108 .Case([&](emitc::LoadOp op) {
return 16; })
109 .Case([&](emitc::LogicalAndOp op) {
return 4; })
110 .Case([&](emitc::LogicalNotOp op) {
return 15; })
111 .Case([&](emitc::LogicalOrOp op) {
return 3; })
112 .Case([&](emitc::MemberOfPtrOp op) {
return 17; })
113 .Case([&](emitc::MemberOp op) {
return 17; })
114 .Case([&](emitc::MulOp op) {
return 13; })
115 .Case([&](emitc::RemOp op) {
return 13; })
116 .Case([&](emitc::SubOp op) {
return 12; })
117 .Case([&](emitc::SubscriptOp op) {
return 17; })
118 .Case([&](emitc::UnaryMinusOp op) {
return 15; })
119 .Case([&](emitc::UnaryPlusOp op) {
return 15; })
120 .Default([](
auto op) {
return op->emitError(
"unsupported operation"); });
128 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
132 LogicalResult emitAttribute(Location loc, Attribute attr);
139 LogicalResult emitOperation(Operation &op,
bool trailingSemicolon);
142 LogicalResult emitType(Location loc, Type type);
148 LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
152 LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
155 LogicalResult emitVariableAssignment(OpResult
result);
158 LogicalResult emitVariableDeclaration(OpResult
result,
159 bool trailingSemicolon);
162 LogicalResult emitVariableDeclaration(Location loc, Type type,
171 LogicalResult emitAssignPrefix(Operation &op);
174 LogicalResult emitGlobalVariable(GlobalOp op);
177 LogicalResult emitLabel(
Block &block);
181 LogicalResult emitOperandsAndAttributes(Operation &op,
182 ArrayRef<StringRef> exclude = {});
185 LogicalResult emitOperands(Operation &op);
191 LogicalResult emitOperand(Value value,
bool isInBrackets =
false);
194 LogicalResult emitExpression(Operation *op);
197 StringRef getOrCreateName(Value val);
201 StringRef getOrCreateInductionVarName(Value val);
204 StringRef getOrCreateName(
Block &block);
206 LogicalResult emitInlinedExpression(Value value);
209 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
213 ~Scope() { emitter.labelInScopeCount.pop(); }
216 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
217 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
220 Scope(CppEmitter &emitter)
221 : valueMapperScope(emitter.valueMapper),
222 blockMapperScope(emitter.blockMapper), emitter(emitter) {
223 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
230 struct FunctionScope : Scope {
231 FunctionScope(CppEmitter &emitter) : Scope(emitter) {
233 emitter.resetValueCounter();
239 struct LoopScope : Scope {
240 LoopScope(CppEmitter &emitter) : Scope(emitter) {
241 emitter.increaseLoopNestingLevel();
243 ~LoopScope() { emitter.decreaseLoopNestingLevel(); }
247 bool hasValueInScope(Value val);
250 bool hasBlockLabel(
Block &block);
253 raw_indented_ostream &ostream() {
return os; };
257 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
260 bool shouldEmitFile(FileOp file) {
261 return !fileId.empty() && file.getId() == fileId;
265 bool isEmittingExpression() {
return !emittedExpressionPrecedence.empty(); }
269 bool isPartOfCurrentExpression(Value value) {
271 return def ? isPartOfCurrentExpression(def) :
false;
276 bool isPartOfCurrentExpression(Operation *def) {
281 void resetValueCounter();
284 void increaseLoopNestingLevel();
287 void decreaseLoopNestingLevel();
290 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
291 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
294 raw_indented_ostream os;
299 bool declareVariablesAtTop;
305 ValueMapper valueMapper;
308 BlockMapper blockMapper;
311 llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
312 llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
314 std::stack<int64_t> labelInScopeCount;
318 uint64_t loopNestingLevel{0};
321 unsigned int valueCount{0};
324 SmallVector<int> emittedExpressionPrecedence;
326 void pushExpressionPrecedence(
int precedence) {
327 emittedExpressionPrecedence.push_back(precedence);
329 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
330 static int lowestPrecedence() {
return 0; }
331 int getExpressionPrecedence() {
332 if (emittedExpressionPrecedence.empty())
333 return lowestPrecedence();
334 return emittedExpressionPrecedence.back();
347 if (
auto cExpression = dyn_cast<CExpressionInterface>(op))
348 return cExpression.alwaysInline() || isa<ExpressionOp>(op->
getParentOp());
351 ExpressionOp expressionOp = dyn_cast<ExpressionOp>(op);
356 if (cast<CExpressionInterface>(expressionOp.getRootOp()).alwaysInline())
360 if (expressionOp.getDoNotInline())
373 if (isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user))
377 if (!expressionOp.hasSideEffects())
388 if (isa<emitc::IfOp, emitc::SwitchOp, emitc::ReturnOp>(user))
393 if (
auto assignOp = dyn_cast<emitc::AssignOp>(user)) {
395 if (expressionOp.getResult() == assignOp.getValue() &&
396 isa_and_present<VariableOp>(assignOp.getVar().getDefiningOp()))
407 while (
auto subscriptOp = value.
getDefiningOp<emitc::SubscriptOp>()) {
408 value = subscriptOp.getValue();
411 auto getGlobalOp = value.
getDefiningOp<emitc::GetGlobalOp>();
417 fromOp, getGlobalOp.getNameAttr());
419 if (globalOp && globalOp.getConstSpecifier())
434 if (failed(emitter.emitOperand(operand)))
441 emitc::DereferenceOp dereferenceOp) {
443 Operation &op = *dereferenceOp.getOperation();
445 if (failed(emitter.emitAssignPrefix(op)))
448 return emitter.emitOperand(dereferenceOp.getPointer());
452 emitc::GetFieldOp getFieldOp) {
453 if (!emitter.isPartOfCurrentExpression(getFieldOp.getOperation()))
456 emitter.ostream() << getFieldOp.getFieldName();
461 emitc::GetGlobalOp getGlobalOp) {
462 if (!emitter.isPartOfCurrentExpression(getGlobalOp.getOperation()))
465 emitter.ostream() << getGlobalOp.getName();
470 emitc::LiteralOp literalOp) {
471 if (!emitter.isPartOfCurrentExpression(literalOp.getOperation()))
474 emitter.ostream() << literalOp.getValue();
479 emitc::MemberOp memberOp) {
480 if (!emitter.isPartOfCurrentExpression(memberOp.getOperation()))
483 if (failed(emitter.emitOperand(memberOp.getOperand())))
485 emitter.ostream() <<
"." << memberOp.getMember();
490 emitc::MemberOfPtrOp memberOfPtrOp) {
491 if (!emitter.isPartOfCurrentExpression(memberOfPtrOp.getOperation()))
494 if (failed(emitter.emitOperand(memberOfPtrOp.getOperand())))
496 emitter.ostream() <<
"->" << memberOfPtrOp.getMember();
501 emitc::SubscriptOp subscriptOp) {
502 if (!emitter.isPartOfCurrentExpression(subscriptOp.getOperation())) {
507 if (failed(emitter.emitOperand(subscriptOp.getValue())))
509 for (
auto index : subscriptOp.getIndices()) {
511 if (failed(emitter.emitOperand(
index,
true)))
524 if (emitter.shouldDeclareVariablesAtTop()) {
526 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
527 if (oAttr.getValue().empty())
531 if (failed(emitter.emitVariableAssignment(
result)))
533 return emitter.emitAttribute(operation->
getLoc(), value);
537 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
538 if (oAttr.getValue().empty())
540 return emitter.emitVariableDeclaration(
result,
545 if (failed(emitter.emitAssignPrefix(*operation)))
547 return emitter.emitAttribute(operation->
getLoc(), value);
551 emitc::AddressOfOp addressOfOp) {
553 Operation &op = *addressOfOp.getOperation();
555 if (failed(emitter.emitAssignPrefix(op)))
558 Value operand = addressOfOp.getReference();
565 return emitter.emitOperand(operand);
569 emitc::ConstantOp constantOp) {
570 Operation *operation = constantOp.getOperation();
573 if (emitter.isPartOfCurrentExpression(operation))
574 return emitter.emitAttribute(operation->
getLoc(), value);
580 emitc::VariableOp variableOp) {
581 Operation *operation = variableOp.getOperation();
588 emitc::GlobalOp globalOp) {
590 return emitter.emitGlobalVariable(globalOp);
594 emitc::AssignOp assignOp) {
595 if (failed(emitter.emitOperand(assignOp.getVar())))
598 emitter.ostream() <<
" = ";
600 return emitter.emitOperand(assignOp.getValue());
604 if (failed(emitter.emitAssignPrefix(*loadOp)))
607 return emitter.emitOperand(loadOp.getOperand());
612 StringRef binaryOperator) {
615 if (failed(emitter.emitAssignPrefix(*operation)))
618 if (failed(emitter.emitOperand(operation->
getOperand(0))))
621 os <<
" " << binaryOperator <<
" ";
623 if (failed(emitter.emitOperand(operation->
getOperand(1))))
631 StringRef unaryOperator) {
634 if (failed(emitter.emitAssignPrefix(*operation)))
639 if (failed(emitter.emitOperand(operation->
getOperand(0))))
646 Operation *operation = addOp.getOperation();
652 Operation *operation = divOp.getOperation();
658 Operation *operation = mulOp.getOperation();
664 Operation *operation = remOp.getOperation();
670 Operation *operation = subOp.getOperation();
678 std::next(iteratorOp) != end; ++iteratorOp) {
679 if (failed(emitter.emitOperation(*iteratorOp,
true)))
687 emitc::SwitchOp switchOp) {
691 if (failed(emitter.emitOperand(switchOp.getArg())))
695 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
696 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
705 os <<
"\ndefault: {\n";
708 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
721 Block &bodyBlock = doOp.getBodyRegion().
front();
723 if (failed(emitter.emitOperation(op,
true)))
729 Block &condBlock = doOp.getConditionRegion().
front();
730 auto condYield = cast<emitc::YieldOp>(condBlock.
back());
731 if (failed(emitter.emitExpression(
732 cast<emitc::ExpressionOp>(condYield.getOperand(0).getDefiningOp()))))
740 Operation *operation = cmpOp.getOperation();
742 StringRef binaryOperator;
744 switch (cmpOp.getPredicate()) {
745 case emitc::CmpPredicate::eq:
746 binaryOperator =
"==";
748 case emitc::CmpPredicate::ne:
749 binaryOperator =
"!=";
751 case emitc::CmpPredicate::lt:
752 binaryOperator =
"<";
754 case emitc::CmpPredicate::le:
755 binaryOperator =
"<=";
757 case emitc::CmpPredicate::gt:
758 binaryOperator =
">";
760 case emitc::CmpPredicate::ge:
761 binaryOperator =
">=";
763 case emitc::CmpPredicate::three_way:
764 binaryOperator =
"<=>";
772 emitc::ConditionalOp conditionalOp) {
775 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
778 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
783 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
788 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
795 emitc::VerbatimOp verbatimOp) {
798 FailureOr<SmallVector<ReplacementItem>> items =
799 verbatimOp.parseFormatString();
803 auto fmtArg = verbatimOp.getFmtArgs().begin();
806 if (
auto *str = std::get_if<StringRef>(&item)) {
809 if (failed(emitter.emitOperand(*fmtArg++)))
818 cf::BranchOp branchOp) {
823 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
824 Value &operand = std::get<0>(pair);
826 os << emitter.getOrCreateName(argument) <<
" = "
827 << emitter.getOrCreateName(operand) <<
";\n";
831 if (!(emitter.hasBlockLabel(successor)))
832 return branchOp.emitOpError(
"unable to find label for successor block");
833 os << emitter.getOrCreateName(successor);
838 cf::CondBranchOp condBranchOp) {
840 Block &trueSuccessor = *condBranchOp.getTrueDest();
841 Block &falseSuccessor = *condBranchOp.getFalseDest();
844 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
851 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
853 Value &operand = std::get<0>(pair);
855 os << emitter.getOrCreateName(argument) <<
" = "
856 << emitter.getOrCreateName(operand) <<
";\n";
860 if (!(emitter.hasBlockLabel(trueSuccessor))) {
861 return condBranchOp.emitOpError(
"unable to find label for successor block");
863 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
867 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
869 Value &operand = std::get<0>(pair);
871 os << emitter.getOrCreateName(argument) <<
" = "
872 << emitter.getOrCreateName(operand) <<
";\n";
876 if (!(emitter.hasBlockLabel(falseSuccessor))) {
877 return condBranchOp.emitOpError()
878 <<
"unable to find label for successor block";
880 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
887 if (failed(emitter.emitAssignPrefix(*callOp)))
892 if (failed(emitter.emitOperands(*callOp)))
899 Operation *operation = callOp.getOperation();
900 StringRef callee = callOp.getCallee();
906 Operation *operation = callOp.getOperation();
907 StringRef callee = callOp.getCallee();
913 emitc::CallOpaqueOp callOpaqueOp) {
915 Operation &op = *callOpaqueOp.getOperation();
917 if (failed(emitter.emitAssignPrefix(op)))
919 os << callOpaqueOp.getCallee();
925 auto emitTemplateArgs = [&](
Attribute attr) -> LogicalResult {
926 return emitter.emitAttribute(op.
getLoc(), attr);
929 if (callOpaqueOp.getTemplateArgs()) {
937 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
938 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
940 if (t.getType().isIndex()) {
943 return emitter.emitOperand(operand);
946 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
954 LogicalResult emittedArgs =
955 callOpaqueOp.getArgs()
957 : emitter.emitOperands(op);
958 if (failed(emittedArgs))
965 emitc::ApplyOp applyOp) {
969 if (failed(emitter.emitAssignPrefix(op)))
972 StringRef applicableOperator = applyOp.getApplicableOperator();
973 Value operand = applyOp.getOperand();
979 os << applicableOperator;
980 return emitter.emitOperand(operand);
984 emitc::BitwiseAndOp bitwiseAndOp) {
985 Operation *operation = bitwiseAndOp.getOperation();
991 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
992 Operation *operation = bitwiseLeftShiftOp.getOperation();
997 emitc::BitwiseNotOp bitwiseNotOp) {
998 Operation *operation = bitwiseNotOp.getOperation();
1003 emitc::BitwiseOrOp bitwiseOrOp) {
1004 Operation *operation = bitwiseOrOp.getOperation();
1010 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
1011 Operation *operation = bitwiseRightShiftOp.getOperation();
1016 emitc::BitwiseXorOp bitwiseXorOp) {
1017 Operation *operation = bitwiseXorOp.getOperation();
1022 emitc::UnaryPlusOp unaryPlusOp) {
1023 Operation *operation = unaryPlusOp.getOperation();
1028 emitc::UnaryMinusOp unaryMinusOp) {
1029 Operation *operation = unaryMinusOp.getOperation();
1037 if (failed(emitter.emitAssignPrefix(op)))
1043 return emitter.emitOperand(castOp.getOperand());
1047 emitc::ExpressionOp expressionOp) {
1051 Operation &op = *expressionOp.getOperation();
1053 if (failed(emitter.emitAssignPrefix(op)))
1056 return emitter.emitExpression(expressionOp);
1060 emitc::IncludeOp includeOp) {
1064 if (includeOp.getIsStandardInclude())
1065 os <<
"<" << includeOp.getInclude() <<
">";
1067 os <<
"\"" << includeOp.getInclude() <<
"\"";
1073 emitc::LogicalAndOp logicalAndOp) {
1074 Operation *operation = logicalAndOp.getOperation();
1079 emitc::LogicalNotOp logicalNotOp) {
1080 Operation *operation = logicalNotOp.getOperation();
1085 emitc::LogicalOrOp logicalOrOp) {
1086 Operation *operation = logicalOrOp.getOperation();
1096 auto requiresParentheses = [&](
Value value) {
1105 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
1108 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1110 if (failed(emitter.emitOperand(forOp.getLowerBound())))
1113 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1115 Value upperBound = forOp.getUpperBound();
1116 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
1117 if (upperBoundRequiresParentheses)
1119 if (failed(emitter.emitOperand(upperBound)))
1121 if (upperBoundRequiresParentheses)
1124 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1126 if (failed(emitter.emitOperand(forOp.getStep())))
1131 CppEmitter::LoopScope lScope(emitter);
1133 Region &forRegion = forOp.getRegion();
1134 auto regionOps = forRegion.
getOps();
1137 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
1138 if (failed(emitter.emitOperation(*it,
true)))
1152 auto emitAllExceptLast = [&emitter](
Region ®ion) {
1154 for (; std::next(it) != end; ++it) {
1155 if (failed(emitter.emitOperation(*it,
true)))
1158 assert(isa<emitc::YieldOp>(*it) &&
1159 "Expected last operation in the region to be emitc::yield");
1164 if (failed(emitter.emitOperand(ifOp.getCondition())))
1168 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
1172 Region &elseRegion = ifOp.getElseRegion();
1173 if (!elseRegion.
empty()) {
1176 if (failed(emitAllExceptLast(elseRegion)))
1185 func::ReturnOp returnOp) {
1188 switch (returnOp.getNumOperands()) {
1193 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
1197 os <<
" std::make_tuple(";
1198 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
1206 emitc::ReturnOp returnOp) {
1209 if (returnOp.getNumOperands() == 0)
1213 if (failed(emitter.emitOperand(returnOp.getOperand())))
1220 if (failed(emitter.emitOperation(op,
false)))
1228 os <<
"class " << classOp.getSymName();
1229 if (classOp.getFinalSpecifier())
1231 os <<
" {\n public:\n";
1235 if (failed(emitter.emitOperation(op,
false)))
1246 if (failed(emitter.emitVariableDeclaration(
1247 fieldOp->getLoc(), fieldOp.getType(), fieldOp.getSymName())))
1249 std::optional<Attribute> initialValue = fieldOp.getInitialValue();
1252 if (failed(emitter.emitAttribute(fieldOp->getLoc(), *initialValue)))
1261 if (!emitter.shouldEmitFile(file))
1265 if (failed(emitter.emitOperation(op,
false)))
1278 return emitter.emitType(functionOp->
getLoc(), arg);
1289 return emitter.emitVariableDeclaration(
1290 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1300 if (emitter.shouldDeclareVariablesAtTop()) {
1305 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1306 (isa<emitc::ExpressionOp>(op) &&
1310 if (failed(emitter.emitVariableDeclaration(
1313 op->
emitError(
"unable to declare result variable for op"));
1318 if (
result.wasInterrupted())
1323 for (
Block &block : blocks) {
1324 emitter.getOrCreateName(block);
1328 for (
Block &block : llvm::drop_begin(blocks)) {
1330 if (emitter.hasValueInScope(arg))
1331 return functionOp->
emitOpError(
" block argument #")
1332 << arg.getArgNumber() <<
" is out of scope";
1333 if (isa<ArrayType, LValueType>(arg.getType()))
1334 return functionOp->
emitOpError(
"cannot emit block argument #")
1335 << arg.getArgNumber() <<
" with type " << arg.getType();
1337 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1340 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1344 for (
Block &block : blocks) {
1346 if (!block.hasNoPredecessors()) {
1347 if (failed(emitter.emitLabel(block)))
1350 for (
Operation &op : block.getOperations()) {
1351 if (failed(emitter.emitOperation(op,
true)))
1362 func::FuncOp functionOp) {
1364 if (!emitter.shouldDeclareVariablesAtTop() &&
1365 functionOp.getBlocks().size() > 1) {
1366 return functionOp.emitOpError(
1367 "with multiple blocks needs variables declared at top");
1370 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1371 return functionOp.emitOpError()
1372 <<
"cannot emit lvalue type as argument type";
1375 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1376 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1379 CppEmitter::FunctionScope scope(emitter);
1381 if (failed(emitter.emitTypes(functionOp.getLoc(),
1382 functionOp.getFunctionType().getResults())))
1384 os <<
" " << functionOp.getName();
1387 Operation *operation = functionOp.getOperation();
1399 emitc::FuncOp functionOp) {
1401 if (!emitter.shouldDeclareVariablesAtTop() &&
1402 functionOp.getBlocks().size() > 1) {
1403 return functionOp.emitOpError(
1404 "with multiple blocks needs variables declared at top");
1407 CppEmitter::FunctionScope scope(emitter);
1409 if (functionOp.getSpecifiers()) {
1410 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1411 os << cast<StringAttr>(specifier).str() <<
" ";
1415 if (failed(emitter.emitTypes(functionOp.getLoc(),
1416 functionOp.getFunctionType().getResults())))
1418 os <<
" " << functionOp.getName();
1421 Operation *operation = functionOp.getOperation();
1422 if (functionOp.isExternal()) {
1424 functionOp.getArgumentTypes())))
1440 DeclareFuncOp declareFuncOp) {
1443 CppEmitter::FunctionScope scope(emitter);
1445 declareFuncOp, declareFuncOp.getSymNameAttr());
1450 if (functionOp.getSpecifiers()) {
1451 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1452 os << cast<StringAttr>(specifier).str() <<
" ";
1456 if (failed(emitter.emitTypes(functionOp.getLoc(),
1457 functionOp.getFunctionType().getResults())))
1459 os <<
" " << functionOp.getName();
1462 Operation *operation = functionOp.getOperation();
1470CppEmitter::CppEmitter(
raw_ostream &os,
bool declareVariablesAtTop,
1472 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1473 fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1474 defaultBlockMapperScope(blockMapper) {
1475 labelInScopeCount.push(0);
1479StringRef CppEmitter::getOrCreateName(
Value val) {
1480 if (!valueMapper.count(val)) {
1481 valueMapper.insert(val, formatv(
"v{0}", ++valueCount));
1483 return *valueMapper.begin(val);
1488StringRef CppEmitter::getOrCreateInductionVarName(Value val) {
1489 if (!valueMapper.count(val)) {
1491 int64_t identifier =
'i' + loopNestingLevel;
1493 if (identifier >=
'i' && identifier <=
't') {
1494 valueMapper.insert(val,
1495 formatv(
"{0}{1}", (
char)identifier, ++valueCount));
1498 valueMapper.insert(val, formatv(
"u{0}", ++valueCount));
1501 return *valueMapper.begin(val);
1505StringRef CppEmitter::getOrCreateName(
Block &block) {
1506 if (!blockMapper.count(&block))
1507 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1508 return *blockMapper.begin(&block);
1511bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1513 case IntegerType::Signless:
1515 case IntegerType::Signed:
1517 case IntegerType::Unsigned:
1520 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1523bool CppEmitter::hasValueInScope(Value val) {
return valueMapper.count(val); }
1525bool CppEmitter::hasBlockLabel(
Block &block) {
1526 return blockMapper.count(&block);
1529LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) {
1530 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1531 if (val.getBitWidth() == 1) {
1532 if (val.getBoolValue())
1537 SmallString<128> strValue;
1538 val.toString(strValue, 10, !isUnsigned,
false);
1543 auto printFloat = [&](
const APFloat &val) {
1544 if (val.isFinite()) {
1545 SmallString<128> strValue;
1547 val.toString(strValue, 0, 0,
false);
1549 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1550 case llvm::APFloatBase::S_IEEEhalf:
1553 case llvm::APFloatBase::S_BFloat:
1556 case llvm::APFloatBase::S_IEEEsingle:
1559 case llvm::APFloatBase::S_IEEEdouble:
1562 llvm_unreachable(
"unsupported floating point type");
1564 }
else if (val.isNaN()) {
1566 }
else if (val.isInfinity()) {
1567 if (val.isNegative())
1574 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1575 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1578 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1580 printFloat(fAttr.getValue());
1583 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1584 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1585 dense.getElementType())) {
1587 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1590 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1596 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1597 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1598 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1601 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1602 printInt(iAttr.getValue(),
false);
1606 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1607 if (
auto iType = dyn_cast<IntegerType>(
1608 cast<ShapedType>(dense.getType()).getElementType())) {
1610 interleaveComma(dense, os, [&](
const APInt &val) {
1611 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1616 if (
auto iType = dyn_cast<IndexType>(
1617 cast<ShapedType>(dense.getType()).getElementType())) {
1619 interleaveComma(dense, os,
1620 [&](
const APInt &val) { printInt(val,
false); });
1627 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1628 os << oAttr.getValue();
1633 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1634 if (sAttr.getNestedReferences().size() > 1)
1635 return emitError(loc,
"attribute has more than 1 nested reference");
1636 os << sAttr.getRootReference().getValue();
1641 if (
auto type = dyn_cast<TypeAttr>(attr))
1642 return emitType(loc, type.getValue());
1644 return emitError(loc,
"cannot emit attribute: ") << attr;
1647LogicalResult CppEmitter::emitExpression(Operation *op) {
1648 assert(emittedExpressionPrecedence.empty() &&
1649 "Expected precedence stack to be empty");
1650 Operation *rootOp =
nullptr;
1652 if (
auto expressionOp = dyn_cast<ExpressionOp>(op)) {
1653 rootOp = expressionOp.getRootOp();
1655 assert(cast<CExpressionInterface>(op).alwaysInline() &&
1656 "Expected an always-inline operation");
1658 "Expected operation to have no containing expression");
1664 pushExpressionPrecedence(precedence.value());
1666 if (
failed(emitOperation(*rootOp,
false)))
1669 popExpressionPrecedence();
1670 assert(emittedExpressionPrecedence.empty() &&
1671 "Expected precedence stack to be empty");
1676LogicalResult CppEmitter::emitOperand(Value value,
bool isInBrackets) {
1677 if (isPartOfCurrentExpression(value)) {
1679 assert(def &&
"Expected operand to be defined by an operation");
1680 if (
auto expressionOp = dyn_cast<ExpressionOp>(def))
1681 def = expressionOp.getRootOp();
1689 bool encloseInParenthesis =
1690 !isInBrackets && precedence.value() <= getExpressionPrecedence();
1692 if (encloseInParenthesis)
1694 pushExpressionPrecedence(precedence.value());
1696 if (
failed(emitOperation(*def,
false)))
1699 if (encloseInParenthesis)
1702 popExpressionPrecedence();
1707 return emitExpression(def);
1709 if (BlockArgument arg = dyn_cast<BlockArgument>(value)) {
1712 Operation *argOp = arg.getParentBlock()->getParentOp();
1713 if (
auto expressionOp = dyn_cast<ExpressionOp>(argOp))
1714 return emitOperand(expressionOp->getOperand(arg.getArgNumber()));
1717 os << getOrCreateName(value);
1721LogicalResult CppEmitter::emitOperands(Operation &op) {
1725 return emitOperand(operand, true);
1730CppEmitter::emitOperandsAndAttributes(Operation &op,
1731 ArrayRef<StringRef> exclude) {
1732 if (
failed(emitOperands(op)))
1736 for (NamedAttribute attr : op.
getAttrs()) {
1737 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1744 auto emitNamedAttribute = [&](NamedAttribute attr) -> LogicalResult {
1745 if (llvm::is_contained(exclude, attr.getName().strref()))
1747 os <<
"/* " << attr.getName().getValue() <<
" */";
1748 if (
failed(emitAttribute(op.
getLoc(), attr.getValue())))
1755LogicalResult CppEmitter::emitVariableAssignment(OpResult
result) {
1756 if (!hasValueInScope(
result)) {
1757 return result.getDefiningOp()->emitOpError(
1758 "result variable for the operation has not been declared");
1760 os << getOrCreateName(
result) <<
" = ";
1764LogicalResult CppEmitter::emitVariableDeclaration(OpResult
result,
1765 bool trailingSemicolon) {
1766 if (
auto cExpression =
1767 dyn_cast<CExpressionInterface>(
result.getDefiningOp())) {
1768 if (cExpression.alwaysInline())
1771 if (hasValueInScope(
result)) {
1772 return result.getDefiningOp()->emitError(
1773 "result variable for the operation already declared");
1775 if (
failed(emitVariableDeclaration(
result.getOwner()->getLoc(),
1777 getOrCreateName(
result))))
1779 if (trailingSemicolon)
1784LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1785 if (op.getExternSpecifier())
1787 else if (op.getStaticSpecifier())
1789 if (op.getConstSpecifier())
1792 if (
failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1793 op.getSymName()))) {
1797 std::optional<Attribute> initialValue = op.getInitialValue();
1800 if (
failed(emitAttribute(op->getLoc(), *initialValue)))
1808LogicalResult CppEmitter::emitAssignPrefix(Operation &op) {
1810 if (isEmittingExpression())
1818 if (shouldDeclareVariablesAtTop()) {
1829 if (!shouldDeclareVariablesAtTop()) {
1837 [&](Value
result) { os << getOrCreateName(result); });
1843LogicalResult CppEmitter::emitLabel(
Block &block) {
1844 if (!hasBlockLabel(block))
1848 os.getOStream() << getOrCreateName(block) <<
":\n";
1852LogicalResult CppEmitter::emitOperation(Operation &op,
bool trailingSemicolon) {
1853 LogicalResult status =
1854 llvm::TypeSwitch<Operation *, LogicalResult>(&op)
1858 .Case<cf::BranchOp, cf::CondBranchOp>(
1861 .Case<emitc::AddressOfOp, emitc::AddOp, emitc::ApplyOp,
1862 emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1863 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1864 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1865 emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
1866 emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1867 emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivOp,
1868 emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
1869 emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
1870 emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
1871 emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
1872 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1873 emitc::MemberOfPtrOp, emitc::MemberOp, emitc::MulOp,
1874 emitc::RemOp, emitc::ReturnOp, emitc::SubscriptOp, emitc::SubOp,
1875 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1876 emitc::VariableOp, emitc::VerbatimOp>(
1880 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1882 .Default([&](Operation *) {
1883 return op.emitOpError(
"unable to find printer for op");
1889 if (
auto cExpression = dyn_cast<CExpressionInterface>(op)) {
1890 if (cExpression.alwaysInline())
1894 if (isEmittingExpression() ||
1895 (isa<emitc::ExpressionOp>(op) &&
1901 trailingSemicolon &=
1902 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::DoOp, emitc::FileOp,
1903 emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp,
1904 emitc::VerbatimOp>(op);
1906 os << (trailingSemicolon ?
";\n" :
"\n");
1911LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
1913 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1914 if (
failed(emitType(loc, arrType.getElementType())))
1917 for (
auto dim : arrType.getShape()) {
1918 os <<
"[" << dim <<
"]";
1922 if (
failed(emitType(loc, type)))
1928LogicalResult CppEmitter::emitType(Location loc, Type type) {
1929 if (
auto iType = dyn_cast<IntegerType>(type)) {
1930 switch (iType.getWidth()) {
1932 return (os <<
"bool"),
success();
1937 if (shouldMapToUnsigned(iType.getSignedness()))
1938 return (os <<
"uint" << iType.getWidth() <<
"_t"),
success();
1940 return (os <<
"int" << iType.getWidth() <<
"_t"),
success();
1942 return emitError(loc,
"cannot emit integer type ") << type;
1945 if (
auto fType = dyn_cast<FloatType>(type)) {
1946 switch (fType.getWidth()) {
1948 if (llvm::isa<Float16Type>(type))
1949 return (os <<
"_Float16"),
success();
1950 if (llvm::isa<BFloat16Type>(type))
1951 return (os <<
"__bf16"),
success();
1953 return emitError(loc,
"cannot emit float type ") << type;
1956 return (os <<
"float"),
success();
1958 return (os <<
"double"),
success();
1960 return emitError(loc,
"cannot emit float type ") << type;
1963 if (
auto iType = dyn_cast<IndexType>(type))
1964 return (os <<
"size_t"),
success();
1965 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1966 return (os <<
"size_t"),
success();
1967 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1968 return (os <<
"ssize_t"),
success();
1969 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1970 return (os <<
"ptrdiff_t"),
success();
1971 if (
auto tType = dyn_cast<TensorType>(type)) {
1972 if (!tType.hasRank())
1973 return emitError(loc,
"cannot emit unranked tensor type");
1974 if (!tType.hasStaticShape())
1975 return emitError(loc,
"cannot emit tensor type with non static shape");
1977 if (isa<ArrayType>(tType.getElementType()))
1978 return emitError(loc,
"cannot emit tensor of array type ") << type;
1979 if (
failed(emitType(loc, tType.getElementType())))
1981 auto shape = tType.getShape();
1982 for (
auto dimSize : shape) {
1989 if (
auto tType = dyn_cast<TupleType>(type))
1990 return emitTupleType(loc, tType.getTypes());
1991 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1992 os << oType.getValue();
1995 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1996 if (
failed(emitType(loc, aType.getElementType())))
1998 for (
auto dim : aType.getShape())
1999 os <<
"[" << dim <<
"]";
2002 if (
auto lType = dyn_cast<emitc::LValueType>(type))
2003 return emitType(loc, lType.getValueType());
2004 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
2005 if (isa<ArrayType>(pType.getPointee()))
2006 return emitError(loc,
"cannot emit pointer to array type ") << type;
2007 if (
failed(emitType(loc, pType.getPointee())))
2012 return emitError(loc,
"cannot emit type ") << type;
2015LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
2016 switch (types.size()) {
2021 return emitType(loc, types.front());
2023 return emitTupleType(loc, types);
2027LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
2028 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
2029 return emitError(loc,
"cannot emit tuple of array type");
2031 os <<
"std::tuple<";
2033 types, os, [&](Type type) {
return emitType(loc, type); })))
2039void CppEmitter::resetValueCounter() { valueCount = 0; }
2041void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
2043void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
2046 bool declareVariablesAtTop,
2048 CppEmitter emitter(os, declareVariablesAtTop, fileId);
2049 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 LogicalResult emitAddressOfWithConstCast(CppEmitter &emitter, Operation &op, Value operand)
Emit address-of with a cast to strip const qualification.
static LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
static emitc::GlobalOp getConstGlobal(Value value, Operation *fromOp)
Helper function to check if a value traces back to a const global.
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.