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);
191 StringRef getOrCreateInductionVarName(
Value val);
194 std::string getSubscriptName(emitc::SubscriptOp op);
197 std::string createMemberAccess(emitc::MemberOp op);
200 std::string createMemberAccess(emitc::MemberOfPtrOp op);
203 StringRef getOrCreateName(
Block &block);
206 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
210 ~Scope() { emitter.labelInScopeCount.pop(); }
213 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
214 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
217 Scope(CppEmitter &emitter)
218 : valueMapperScope(emitter.valueMapper),
219 blockMapperScope(emitter.blockMapper), emitter(emitter) {
220 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
227 struct FunctionScope : Scope {
228 FunctionScope(CppEmitter &emitter) : Scope(emitter) {
230 emitter.resetValueCounter();
236 struct LoopScope : Scope {
237 LoopScope(CppEmitter &emitter) : Scope(emitter) {
238 emitter.increaseLoopNestingLevel();
240 ~LoopScope() { emitter.decreaseLoopNestingLevel(); }
244 bool hasValueInScope(
Value val);
247 bool hasBlockLabel(
Block &block);
254 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
257 bool shouldEmitFile(FileOp file) {
258 return !fileId.empty() && file.getId() == fileId;
262 ExpressionOp getEmittedExpression() {
return emittedExpression; }
266 bool isPartOfCurrentExpression(
Value value) {
267 if (!emittedExpression)
272 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
273 return operandExpression == emittedExpression;
277 void resetValueCounter();
280 void increaseLoopNestingLevel();
283 void decreaseLoopNestingLevel();
286 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
287 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
295 bool declareVariablesAtTop;
301 ValueMapper valueMapper;
304 BlockMapper blockMapper;
307 llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
308 llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
310 std::stack<int64_t> labelInScopeCount;
314 uint64_t loopNestingLevel{0};
317 unsigned int valueCount{0};
320 ExpressionOp emittedExpression;
323 void pushExpressionPrecedence(
int precedence) {
324 emittedExpressionPrecedence.push_back(precedence);
326 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
327 static int lowestPrecedence() {
return 0; }
328 int getExpressionPrecedence() {
329 if (emittedExpressionPrecedence.empty())
330 return lowestPrecedence();
331 return emittedExpressionPrecedence.back();
338 return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
339 emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
349 if (expressionOp.getDoNotInline())
354 if (expressionOp.hasSideEffects())
358 Value result = expressionOp.getResult();
371 return !isa<emitc::CExpressionInterface>(*user);
380 if (emitter.shouldDeclareVariablesAtTop()) {
382 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
383 if (oAttr.getValue().empty())
387 if (failed(emitter.emitVariableAssignment(result)))
389 return emitter.emitAttribute(operation->
getLoc(), value);
393 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
394 if (oAttr.getValue().empty())
396 return emitter.emitVariableDeclaration(result,
401 if (failed(emitter.emitAssignPrefix(*operation)))
403 return emitter.emitAttribute(operation->
getLoc(), value);
407 emitc::ConstantOp constantOp) {
408 Operation *operation = constantOp.getOperation();
415 emitc::VariableOp variableOp) {
416 Operation *operation = variableOp.getOperation();
423 emitc::GlobalOp globalOp) {
425 return emitter.emitGlobalVariable(globalOp);
429 emitc::AssignOp assignOp) {
432 if (failed(emitter.emitVariableAssignment(result)))
435 return emitter.emitOperand(assignOp.getValue());
439 if (failed(emitter.emitAssignPrefix(*loadOp)))
442 return emitter.emitOperand(loadOp.getOperand());
447 StringRef binaryOperator) {
448 raw_ostream &os = emitter.ostream();
450 if (failed(emitter.emitAssignPrefix(*operation)))
453 if (failed(emitter.emitOperand(operation->
getOperand(0))))
456 os <<
" " << binaryOperator <<
" ";
458 if (failed(emitter.emitOperand(operation->
getOperand(1))))
466 StringRef unaryOperator) {
467 raw_ostream &os = emitter.ostream();
469 if (failed(emitter.emitAssignPrefix(*operation)))
474 if (failed(emitter.emitOperand(operation->
getOperand(0))))
481 Operation *operation = addOp.getOperation();
487 Operation *operation = divOp.getOperation();
493 Operation *operation = mulOp.getOperation();
499 Operation *operation = remOp.getOperation();
505 Operation *operation = subOp.getOperation();
513 std::next(iteratorOp) != end; ++iteratorOp) {
514 if (failed(emitter.emitOperation(*iteratorOp,
true)))
522 emitc::SwitchOp switchOp) {
526 if (failed(emitter.emitOperand(switchOp.getArg())))
530 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
531 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
540 os <<
"\ndefault: {\n";
543 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
551 Operation *operation = cmpOp.getOperation();
553 StringRef binaryOperator;
555 switch (cmpOp.getPredicate()) {
556 case emitc::CmpPredicate::eq:
557 binaryOperator =
"==";
559 case emitc::CmpPredicate::ne:
560 binaryOperator =
"!=";
562 case emitc::CmpPredicate::lt:
563 binaryOperator =
"<";
565 case emitc::CmpPredicate::le:
566 binaryOperator =
"<=";
568 case emitc::CmpPredicate::gt:
569 binaryOperator =
">";
571 case emitc::CmpPredicate::ge:
572 binaryOperator =
">=";
574 case emitc::CmpPredicate::three_way:
575 binaryOperator =
"<=>";
583 emitc::ConditionalOp conditionalOp) {
584 raw_ostream &os = emitter.ostream();
586 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
589 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
594 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
599 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
606 emitc::VerbatimOp verbatimOp) {
607 raw_ostream &os = emitter.ostream();
609 FailureOr<SmallVector<ReplacementItem>> items =
610 verbatimOp.parseFormatString();
614 auto fmtArg = verbatimOp.getFmtArgs().begin();
617 if (
auto *str = std::get_if<StringRef>(&item)) {
620 if (failed(emitter.emitOperand(*fmtArg++)))
629 cf::BranchOp branchOp) {
630 raw_ostream &os = emitter.ostream();
634 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
635 Value &operand = std::get<0>(pair);
637 os << emitter.getOrCreateName(argument) <<
" = "
638 << emitter.getOrCreateName(operand) <<
";\n";
642 if (!(emitter.hasBlockLabel(successor)))
643 return branchOp.emitOpError(
"unable to find label for successor block");
644 os << emitter.getOrCreateName(successor);
649 cf::CondBranchOp condBranchOp) {
651 Block &trueSuccessor = *condBranchOp.getTrueDest();
652 Block &falseSuccessor = *condBranchOp.getFalseDest();
655 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
662 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
664 Value &operand = std::get<0>(pair);
666 os << emitter.getOrCreateName(argument) <<
" = "
667 << emitter.getOrCreateName(operand) <<
";\n";
671 if (!(emitter.hasBlockLabel(trueSuccessor))) {
672 return condBranchOp.emitOpError(
"unable to find label for successor block");
674 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
678 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
680 Value &operand = std::get<0>(pair);
682 os << emitter.getOrCreateName(argument) <<
" = "
683 << emitter.getOrCreateName(operand) <<
";\n";
687 if (!(emitter.hasBlockLabel(falseSuccessor))) {
688 return condBranchOp.emitOpError()
689 <<
"unable to find label for successor block";
691 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
698 if (failed(emitter.emitAssignPrefix(*callOp)))
701 raw_ostream &os = emitter.ostream();
703 if (failed(emitter.emitOperands(*callOp)))
710 Operation *operation = callOp.getOperation();
711 StringRef callee = callOp.getCallee();
717 Operation *operation = callOp.getOperation();
718 StringRef callee = callOp.getCallee();
724 emitc::CallOpaqueOp callOpaqueOp) {
725 raw_ostream &os = emitter.ostream();
726 Operation &op = *callOpaqueOp.getOperation();
728 if (failed(emitter.emitAssignPrefix(op)))
730 os << callOpaqueOp.getCallee();
736 auto emitTemplateArgs = [&](
Attribute attr) -> LogicalResult {
737 return emitter.emitAttribute(op.
getLoc(), attr);
740 if (callOpaqueOp.getTemplateArgs()) {
748 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
749 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
751 if (t.getType().isIndex()) {
752 int64_t idx = t.getInt();
754 if (!emitter.hasValueInScope(operand))
756 << idx <<
"'s value not defined in scope";
757 os << emitter.getOrCreateName(operand);
761 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
769 LogicalResult emittedArgs =
770 callOpaqueOp.getArgs()
772 : emitter.emitOperands(op);
773 if (failed(emittedArgs))
780 emitc::ApplyOp applyOp) {
781 raw_ostream &os = emitter.ostream();
784 if (failed(emitter.emitAssignPrefix(op)))
786 os << applyOp.getApplicableOperator();
787 os << emitter.getOrCreateName(applyOp.getOperand());
793 emitc::BitwiseAndOp bitwiseAndOp) {
794 Operation *operation = bitwiseAndOp.getOperation();
800 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
801 Operation *operation = bitwiseLeftShiftOp.getOperation();
806 emitc::BitwiseNotOp bitwiseNotOp) {
807 Operation *operation = bitwiseNotOp.getOperation();
812 emitc::BitwiseOrOp bitwiseOrOp) {
813 Operation *operation = bitwiseOrOp.getOperation();
819 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
820 Operation *operation = bitwiseRightShiftOp.getOperation();
825 emitc::BitwiseXorOp bitwiseXorOp) {
826 Operation *operation = bitwiseXorOp.getOperation();
831 emitc::UnaryPlusOp unaryPlusOp) {
832 Operation *operation = unaryPlusOp.getOperation();
837 emitc::UnaryMinusOp unaryMinusOp) {
838 Operation *operation = unaryMinusOp.getOperation();
843 raw_ostream &os = emitter.ostream();
846 if (failed(emitter.emitAssignPrefix(op)))
852 return emitter.emitOperand(castOp.getOperand());
856 emitc::ExpressionOp expressionOp) {
860 Operation &op = *expressionOp.getOperation();
862 if (failed(emitter.emitAssignPrefix(op)))
865 return emitter.emitExpression(expressionOp);
869 emitc::IncludeOp includeOp) {
870 raw_ostream &os = emitter.ostream();
873 if (includeOp.getIsStandardInclude())
874 os <<
"<" << includeOp.getInclude() <<
">";
876 os <<
"\"" << includeOp.getInclude() <<
"\"";
882 emitc::LogicalAndOp logicalAndOp) {
883 Operation *operation = logicalAndOp.getOperation();
888 emitc::LogicalNotOp logicalNotOp) {
889 Operation *operation = logicalNotOp.getOperation();
894 emitc::LogicalOrOp logicalOrOp) {
895 Operation *operation = logicalOrOp.getOperation();
905 auto requiresParentheses = [&](
Value value) {
915 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
918 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
920 if (failed(emitter.emitOperand(forOp.getLowerBound())))
923 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
925 Value upperBound = forOp.getUpperBound();
926 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
927 if (upperBoundRequiresParentheses)
929 if (failed(emitter.emitOperand(upperBound)))
931 if (upperBoundRequiresParentheses)
934 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
936 if (failed(emitter.emitOperand(forOp.getStep())))
941 CppEmitter::LoopScope lScope(emitter);
943 Region &forRegion = forOp.getRegion();
944 auto regionOps = forRegion.
getOps();
947 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
948 if (failed(emitter.emitOperation(*it,
true)))
962 auto emitAllExceptLast = [&emitter](
Region ®ion) {
964 for (; std::next(it) != end; ++it) {
965 if (failed(emitter.emitOperation(*it,
true)))
968 assert(isa<emitc::YieldOp>(*it) &&
969 "Expected last operation in the region to be emitc::yield");
974 if (failed(emitter.emitOperand(ifOp.getCondition())))
978 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
982 Region &elseRegion = ifOp.getElseRegion();
983 if (!elseRegion.
empty()) {
986 if (failed(emitAllExceptLast(elseRegion)))
995 func::ReturnOp returnOp) {
996 raw_ostream &os = emitter.ostream();
998 switch (returnOp.getNumOperands()) {
1003 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
1007 os <<
" std::make_tuple(";
1008 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
1016 emitc::ReturnOp returnOp) {
1017 raw_ostream &os = emitter.ostream();
1019 if (returnOp.getNumOperands() == 0)
1023 if (failed(emitter.emitOperand(returnOp.getOperand())))
1030 if (failed(emitter.emitOperation(op,
false)))
1038 os <<
"class " << classOp.getSymName();
1039 if (classOp.getFinalSpecifier())
1041 os <<
" {\n public:\n";
1045 if (failed(emitter.emitOperation(op,
false)))
1055 raw_ostream &os = emitter.ostream();
1056 if (failed(emitter.emitType(fieldOp->getLoc(), fieldOp.getType())))
1058 os <<
" " << fieldOp.getSymName() <<
";";
1063 GetFieldOp getFieldOp) {
1066 Value result = getFieldOp.getResult();
1067 if (failed(emitter.emitType(getFieldOp->getLoc(), result.
getType())))
1070 if (failed(emitter.emitOperand(result)))
1074 os << getFieldOp.getFieldName().str();
1079 if (!emitter.shouldEmitFile(file))
1083 if (failed(emitter.emitOperation(op,
false)))
1096 return emitter.emitType(functionOp->
getLoc(), arg);
1107 return emitter.emitVariableDeclaration(
1108 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1118 if (emitter.shouldDeclareVariablesAtTop()) {
1123 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1124 (isa<emitc::ExpressionOp>(op) &&
1128 if (failed(emitter.emitVariableDeclaration(
1131 op->
emitError(
"unable to declare result variable for op"));
1141 for (
Block &block : blocks) {
1142 emitter.getOrCreateName(block);
1146 for (
Block &block : llvm::drop_begin(blocks)) {
1148 if (emitter.hasValueInScope(arg))
1149 return functionOp->
emitOpError(
" block argument #")
1150 << arg.getArgNumber() <<
" is out of scope";
1151 if (isa<ArrayType, LValueType>(arg.getType()))
1152 return functionOp->
emitOpError(
"cannot emit block argument #")
1153 << arg.getArgNumber() <<
" with type " << arg.getType();
1155 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1158 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1162 for (
Block &block : blocks) {
1164 if (!block.hasNoPredecessors()) {
1165 if (failed(emitter.emitLabel(block)))
1168 for (
Operation &op : block.getOperations()) {
1169 if (failed(emitter.emitOperation(op,
true)))
1180 func::FuncOp functionOp) {
1182 if (!emitter.shouldDeclareVariablesAtTop() &&
1183 functionOp.getBlocks().size() > 1) {
1184 return functionOp.emitOpError(
1185 "with multiple blocks needs variables declared at top");
1188 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1189 return functionOp.emitOpError()
1190 <<
"cannot emit lvalue type as argument type";
1193 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1194 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1197 CppEmitter::FunctionScope scope(emitter);
1199 if (failed(emitter.emitTypes(functionOp.getLoc(),
1200 functionOp.getFunctionType().getResults())))
1202 os <<
" " << functionOp.getName();
1205 Operation *operation = functionOp.getOperation();
1217 emitc::FuncOp functionOp) {
1219 if (!emitter.shouldDeclareVariablesAtTop() &&
1220 functionOp.getBlocks().size() > 1) {
1221 return functionOp.emitOpError(
1222 "with multiple blocks needs variables declared at top");
1225 CppEmitter::FunctionScope scope(emitter);
1227 if (functionOp.getSpecifiers()) {
1228 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1229 os << cast<StringAttr>(specifier).str() <<
" ";
1233 if (failed(emitter.emitTypes(functionOp.getLoc(),
1234 functionOp.getFunctionType().getResults())))
1236 os <<
" " << functionOp.getName();
1239 Operation *operation = functionOp.getOperation();
1240 if (functionOp.isExternal()) {
1242 functionOp.getArgumentTypes())))
1258 DeclareFuncOp declareFuncOp) {
1261 CppEmitter::FunctionScope scope(emitter);
1262 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1263 declareFuncOp, declareFuncOp.getSymNameAttr());
1268 if (functionOp.getSpecifiers()) {
1269 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1270 os << cast<StringAttr>(specifier).str() <<
" ";
1274 if (failed(emitter.emitTypes(functionOp.getLoc(),
1275 functionOp.getFunctionType().getResults())))
1277 os <<
" " << functionOp.getName();
1280 Operation *operation = functionOp.getOperation();
1288 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
1290 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1291 fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1292 defaultBlockMapperScope(blockMapper) {
1293 labelInScopeCount.push(0);
1296 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1298 llvm::raw_string_ostream ss(out);
1299 ss << getOrCreateName(op.getValue());
1300 for (
auto index : op.getIndices()) {
1301 ss <<
"[" << getOrCreateName(index) <<
"]";
1306 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1308 llvm::raw_string_ostream ss(out);
1309 ss << getOrCreateName(op.getOperand());
1310 ss <<
"." << op.getMember();
1314 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1316 llvm::raw_string_ostream ss(out);
1317 ss << getOrCreateName(op.getOperand());
1318 ss <<
"->" << op.getMember();
1322 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1323 if (!valueMapper.count(value))
1324 valueMapper.insert(value, str.str());
1328 StringRef CppEmitter::getOrCreateName(
Value val) {
1329 if (!valueMapper.count(val)) {
1331 "cacheDeferredOpResult should have been called on this value, "
1332 "update the emitOperation function.");
1334 valueMapper.insert(val, formatv(
"v{0}", ++valueCount));
1336 return *valueMapper.begin(val);
1341 StringRef CppEmitter::getOrCreateInductionVarName(
Value val) {
1342 if (!valueMapper.count(val)) {
1344 int64_t identifier =
'i' + loopNestingLevel;
1346 if (identifier >=
'i' && identifier <=
't') {
1347 valueMapper.insert(val,
1348 formatv(
"{0}{1}", (
char)identifier, ++valueCount));
1351 valueMapper.insert(val, formatv(
"u{0}", ++valueCount));
1354 return *valueMapper.begin(val);
1358 StringRef CppEmitter::getOrCreateName(
Block &block) {
1359 if (!blockMapper.count(&block))
1360 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1361 return *blockMapper.begin(&block);
1364 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1366 case IntegerType::Signless:
1370 case IntegerType::Unsigned:
1373 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1376 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1378 bool CppEmitter::hasBlockLabel(
Block &block) {
1379 return blockMapper.count(&block);
1383 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1384 if (val.getBitWidth() == 1) {
1385 if (val.getBoolValue())
1391 val.toString(strValue, 10, !isUnsigned,
false);
1396 auto printFloat = [&](
const APFloat &val) {
1397 if (val.isFinite()) {
1400 val.toString(strValue, 0, 0,
false);
1402 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1403 case llvm::APFloatBase::S_IEEEhalf:
1406 case llvm::APFloatBase::S_BFloat:
1409 case llvm::APFloatBase::S_IEEEsingle:
1412 case llvm::APFloatBase::S_IEEEdouble:
1415 llvm_unreachable(
"unsupported floating point type");
1417 }
else if (val.isNaN()) {
1419 }
else if (val.isInfinity()) {
1420 if (val.isNegative())
1427 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1428 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1431 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1433 printFloat(fAttr.getValue());
1436 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1437 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1438 dense.getElementType())) {
1440 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1443 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1449 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1450 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1451 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1454 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1455 printInt(iAttr.getValue(),
false);
1459 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1460 if (
auto iType = dyn_cast<IntegerType>(
1461 cast<TensorType>(dense.getType()).getElementType())) {
1463 interleaveComma(dense, os, [&](
const APInt &val) {
1464 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1469 if (
auto iType = dyn_cast<IndexType>(
1470 cast<TensorType>(dense.getType()).getElementType())) {
1472 interleaveComma(dense, os,
1473 [&](
const APInt &val) { printInt(val,
false); });
1480 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1481 os << oAttr.getValue();
1486 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1487 if (sAttr.getNestedReferences().size() > 1)
1488 return emitError(loc,
"attribute has more than 1 nested reference");
1489 os << sAttr.getRootReference().getValue();
1494 if (
auto type = dyn_cast<TypeAttr>(attr))
1495 return emitType(loc, type.getValue());
1497 return emitError(loc,
"cannot emit attribute: ") << attr;
1500 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1501 assert(emittedExpressionPrecedence.empty() &&
1502 "Expected precedence stack to be empty");
1503 Operation *rootOp = expressionOp.getRootOp();
1505 emittedExpression = expressionOp;
1507 if (failed(precedence))
1509 pushExpressionPrecedence(precedence.value());
1511 if (failed(emitOperation(*rootOp,
false)))
1514 popExpressionPrecedence();
1515 assert(emittedExpressionPrecedence.empty() &&
1516 "Expected precedence stack to be empty");
1517 emittedExpression =
nullptr;
1522 LogicalResult CppEmitter::emitOperand(
Value value) {
1523 if (isPartOfCurrentExpression(value)) {
1525 assert(def &&
"Expected operand to be defined by an operation");
1527 if (failed(precedence))
1533 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1534 if (encloseInParenthesis)
1536 pushExpressionPrecedence(precedence.value());
1538 if (failed(emitOperation(*def,
false)))
1541 if (encloseInParenthesis)
1544 popExpressionPrecedence();
1548 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1550 return emitExpression(expressionOp);
1552 os << getOrCreateName(value);
1556 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1560 if (getEmittedExpression())
1561 pushExpressionPrecedence(lowestPrecedence());
1562 if (failed(emitOperand(operand)))
1564 if (getEmittedExpression())
1565 popExpressionPrecedence();
1571 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1573 if (failed(emitOperands(op)))
1578 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1585 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1586 if (llvm::is_contained(exclude, attr.getName().strref()))
1588 os <<
"/* " << attr.getName().getValue() <<
" */";
1589 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1596 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1597 if (!hasValueInScope(result)) {
1599 "result variable for the operation has not been declared");
1601 os << getOrCreateName(result) <<
" = ";
1605 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1606 bool trailingSemicolon) {
1609 if (hasValueInScope(result)) {
1611 "result variable for the operation already declared");
1615 getOrCreateName(result))))
1617 if (trailingSemicolon)
1622 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1623 if (op.getExternSpecifier())
1625 else if (op.getStaticSpecifier())
1627 if (op.getConstSpecifier())
1630 if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1631 op.getSymName()))) {
1635 std::optional<Attribute> initialValue = op.getInitialValue();
1638 if (failed(emitAttribute(op->getLoc(), *initialValue)))
1646 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1648 if (getEmittedExpression())
1656 if (shouldDeclareVariablesAtTop()) {
1657 if (failed(emitVariableAssignment(result)))
1660 if (failed(emitVariableDeclaration(result,
false)))
1667 if (!shouldDeclareVariablesAtTop()) {
1669 if (failed(emitVariableDeclaration(result,
true)))
1675 [&](
Value result) { os << getOrCreateName(result); });
1681 LogicalResult CppEmitter::emitLabel(
Block &block) {
1682 if (!hasBlockLabel(block))
1686 os.getOStream() << getOrCreateName(block) <<
":\n";
1690 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1691 LogicalResult status =
1694 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1696 .Case<cf::BranchOp, cf::CondBranchOp>(
1699 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1700 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1701 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1702 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1703 emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
1704 emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1705 emitc::DeclareFuncOp, emitc::DivOp, emitc::ExpressionOp,
1706 emitc::FieldOp, emitc::FileOp, emitc::ForOp, emitc::FuncOp,
1707 emitc::GetFieldOp, emitc::GlobalOp, emitc::IfOp,
1708 emitc::IncludeOp, emitc::LoadOp, emitc::LogicalAndOp,
1709 emitc::LogicalNotOp, emitc::LogicalOrOp, emitc::MulOp,
1710 emitc::RemOp, emitc::ReturnOp, emitc::SubOp, emitc::SwitchOp,
1711 emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
1716 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1718 .Case<emitc::GetGlobalOp>([&](
auto op) {
1722 .Case<emitc::LiteralOp>([&](
auto op) {
1723 cacheDeferredOpResult(op.
getResult(), op.getValue());
1726 .Case<emitc::MemberOp>([&](
auto op) {
1727 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1730 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1731 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1734 .Case<emitc::SubscriptOp>([&](
auto op) {
1735 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1739 return op.
emitOpError(
"unable to find printer for op");
1748 if (getEmittedExpression() ||
1749 (isa<emitc::ExpressionOp>(op) &&
1755 trailingSemicolon &=
1756 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
1757 emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(
1760 os << (trailingSemicolon ?
";\n" :
"\n");
1765 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1767 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1768 if (failed(emitType(loc, arrType.getElementType())))
1771 for (
auto dim : arrType.getShape()) {
1772 os <<
"[" << dim <<
"]";
1776 if (failed(emitType(loc, type)))
1782 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1783 if (
auto iType = dyn_cast<IntegerType>(type)) {
1784 switch (iType.getWidth()) {
1786 return (os <<
"bool"), success();
1791 if (shouldMapToUnsigned(iType.getSignedness()))
1792 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1794 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1796 return emitError(loc,
"cannot emit integer type ") << type;
1799 if (
auto fType = dyn_cast<FloatType>(type)) {
1800 switch (fType.getWidth()) {
1802 if (llvm::isa<Float16Type>(type))
1803 return (os <<
"_Float16"), success();
1804 else if (llvm::isa<BFloat16Type>(type))
1805 return (os <<
"__bf16"), success();
1807 return emitError(loc,
"cannot emit float type ") << type;
1810 return (os <<
"float"), success();
1812 return (os <<
"double"), success();
1814 return emitError(loc,
"cannot emit float type ") << type;
1817 if (
auto iType = dyn_cast<IndexType>(type))
1818 return (os <<
"size_t"), success();
1819 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1820 return (os <<
"size_t"), success();
1821 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1822 return (os <<
"ssize_t"), success();
1823 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1824 return (os <<
"ptrdiff_t"), success();
1825 if (
auto tType = dyn_cast<TensorType>(type)) {
1826 if (!tType.hasRank())
1827 return emitError(loc,
"cannot emit unranked tensor type");
1828 if (!tType.hasStaticShape())
1829 return emitError(loc,
"cannot emit tensor type with non static shape");
1831 if (isa<ArrayType>(tType.getElementType()))
1832 return emitError(loc,
"cannot emit tensor of array type ") << type;
1833 if (failed(emitType(loc, tType.getElementType())))
1835 auto shape = tType.getShape();
1836 for (
auto dimSize : shape) {
1843 if (
auto tType = dyn_cast<TupleType>(type))
1844 return emitTupleType(loc, tType.getTypes());
1845 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1846 os << oType.getValue();
1849 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1850 if (failed(emitType(loc, aType.getElementType())))
1852 for (
auto dim : aType.getShape())
1853 os <<
"[" << dim <<
"]";
1856 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1857 return emitType(loc, lType.getValueType());
1858 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1859 if (isa<ArrayType>(pType.getPointee()))
1860 return emitError(loc,
"cannot emit pointer to array type ") << type;
1861 if (failed(emitType(loc, pType.getPointee())))
1866 return emitError(loc,
"cannot emit type ") << type;
1870 switch (types.size()) {
1875 return emitType(loc, types.front());
1877 return emitTupleType(loc, types);
1882 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1883 return emitError(loc,
"cannot emit tuple of array type");
1885 os <<
"std::tuple<";
1887 types, os, [&](
Type type) {
return emitType(loc, type); })))
1893 void CppEmitter::resetValueCounter() { valueCount = 0; }
1895 void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
1897 void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
1900 bool declareVariablesAtTop,
1902 CppEmitter emitter(os, declareVariablesAtTop, fileId);
1903 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)
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.