20 #include "llvm/ADT/DenseMap.h"
21 #include "llvm/ADT/ScopedHashTable.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/FormatVariadic.h"
30 #define DEBUG_TYPE "translate-to-cpp"
40 typename NullaryFunctor>
43 UnaryFunctor eachFn, NullaryFunctor betweenFn) {
46 if (failed(eachFn(*begin)))
49 for (; begin != end; ++begin) {
51 if (failed(eachFn(*begin)))
57 template <
typename Container,
typename UnaryFunctor,
typename NullaryFunctor>
60 NullaryFunctor betweenFn) {
64 template <
typename Container,
typename UnaryFunctor>
67 UnaryFunctor eachFn) {
75 .Case<emitc::AddOp>([&](
auto op) {
return 12; })
76 .Case<emitc::ApplyOp>([&](
auto op) {
return 15; })
77 .Case<emitc::BitwiseAndOp>([&](
auto op) {
return 7; })
78 .Case<emitc::BitwiseLeftShiftOp>([&](
auto op) {
return 11; })
79 .Case<emitc::BitwiseNotOp>([&](
auto op) {
return 15; })
80 .Case<emitc::BitwiseOrOp>([&](
auto op) {
return 5; })
81 .Case<emitc::BitwiseRightShiftOp>([&](
auto op) {
return 11; })
82 .Case<emitc::BitwiseXorOp>([&](
auto op) {
return 6; })
83 .Case<emitc::CallOp>([&](
auto op) {
return 16; })
84 .Case<emitc::CallOpaqueOp>([&](
auto op) {
return 16; })
85 .Case<emitc::CastOp>([&](
auto op) {
return 15; })
86 .Case<emitc::CmpOp>([&](
auto op) -> FailureOr<int> {
87 switch (op.getPredicate()) {
88 case emitc::CmpPredicate::eq:
89 case emitc::CmpPredicate::ne:
91 case emitc::CmpPredicate::lt:
92 case emitc::CmpPredicate::le:
93 case emitc::CmpPredicate::gt:
94 case emitc::CmpPredicate::ge:
96 case emitc::CmpPredicate::three_way:
99 return op->emitError(
"unsupported cmp predicate");
101 .Case<emitc::ConditionalOp>([&](
auto op) {
return 2; })
102 .Case<emitc::DivOp>([&](
auto op) {
return 13; })
103 .Case<emitc::LogicalAndOp>([&](
auto op) {
return 4; })
104 .Case<emitc::LogicalNotOp>([&](
auto op) {
return 15; })
105 .Case<emitc::LogicalOrOp>([&](
auto op) {
return 3; })
106 .Case<emitc::MulOp>([&](
auto op) {
return 13; })
107 .Case<emitc::RemOp>([&](
auto op) {
return 13; })
108 .Case<emitc::SubOp>([&](
auto op) {
return 12; })
109 .Case<emitc::UnaryMinusOp>([&](
auto op) {
return 15; })
110 .Case<emitc::UnaryPlusOp>([&](
auto op) {
return 15; })
111 .Default([](
auto op) {
return op->emitError(
"unsupported operation"); });
117 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop);
127 LogicalResult emitOperation(
Operation &op,
bool trailingSemicolon);
143 LogicalResult emitVariableAssignment(
OpResult result);
146 LogicalResult emitVariableDeclaration(
OpResult result,
147 bool trailingSemicolon);
150 LogicalResult emitVariableDeclaration(
Location loc,
Type type,
159 LogicalResult emitAssignPrefix(
Operation &op);
162 LogicalResult emitGlobalVariable(GlobalOp op);
165 LogicalResult emitLabel(
Block &block);
169 LogicalResult emitOperandsAndAttributes(
Operation &op,
173 LogicalResult emitOperands(
Operation &op);
176 LogicalResult emitOperand(
Value value);
179 LogicalResult emitExpression(ExpressionOp expressionOp);
182 void cacheDeferredOpResult(
Value value, StringRef str);
185 StringRef getOrCreateName(
Value val);
188 std::string getSubscriptName(emitc::SubscriptOp op);
191 std::string createMemberAccess(emitc::MemberOp op);
194 std::string createMemberAccess(emitc::MemberOfPtrOp op);
197 StringRef getOrCreateName(
Block &block);
200 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
204 Scope(CppEmitter &emitter)
205 : valueMapperScope(emitter.valueMapper),
206 blockMapperScope(emitter.blockMapper), emitter(emitter) {
207 emitter.valueInScopeCount.push(emitter.valueInScopeCount.top());
208 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
211 emitter.valueInScopeCount.pop();
212 emitter.labelInScopeCount.pop();
216 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
217 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
222 bool hasValueInScope(
Value val);
225 bool hasBlockLabel(
Block &block);
232 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
235 ExpressionOp getEmittedExpression() {
return emittedExpression; }
239 bool isPartOfCurrentExpression(
Value value) {
240 if (!emittedExpression)
245 auto operandExpression = dyn_cast<ExpressionOp>(def->
getParentOp());
246 return operandExpression == emittedExpression;
250 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
251 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
259 bool declareVariablesAtTop;
262 ValueMapper valueMapper;
265 BlockMapper blockMapper;
269 std::stack<int64_t> valueInScopeCount;
270 std::stack<int64_t> labelInScopeCount;
273 ExpressionOp emittedExpression;
276 void pushExpressionPrecedence(
int precedence) {
277 emittedExpressionPrecedence.push_back(precedence);
279 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
280 static int lowestPrecedence() {
return 0; }
281 int getExpressionPrecedence() {
282 if (emittedExpressionPrecedence.empty())
283 return lowestPrecedence();
284 return emittedExpressionPrecedence.back();
291 return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
292 emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
302 if (expressionOp.getDoNotInline())
307 if (expressionOp.hasSideEffects())
311 Value result = expressionOp.getResult();
333 if (emitter.shouldDeclareVariablesAtTop()) {
335 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
336 if (oAttr.getValue().empty())
340 if (failed(emitter.emitVariableAssignment(result)))
342 return emitter.emitAttribute(operation->
getLoc(), value);
346 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
347 if (oAttr.getValue().empty())
349 return emitter.emitVariableDeclaration(result,
354 if (failed(emitter.emitAssignPrefix(*operation)))
356 return emitter.emitAttribute(operation->
getLoc(), value);
360 emitc::ConstantOp constantOp) {
361 Operation *operation = constantOp.getOperation();
368 emitc::VariableOp variableOp) {
369 Operation *operation = variableOp.getOperation();
376 emitc::GlobalOp globalOp) {
378 return emitter.emitGlobalVariable(globalOp);
382 emitc::AssignOp assignOp) {
385 if (failed(emitter.emitVariableAssignment(result)))
388 return emitter.emitOperand(assignOp.getValue());
392 if (failed(emitter.emitAssignPrefix(*loadOp)))
395 return emitter.emitOperand(loadOp.getOperand());
400 StringRef binaryOperator) {
401 raw_ostream &os = emitter.ostream();
403 if (failed(emitter.emitAssignPrefix(*operation)))
406 if (failed(emitter.emitOperand(operation->
getOperand(0))))
409 os <<
" " << binaryOperator <<
" ";
411 if (failed(emitter.emitOperand(operation->
getOperand(1))))
419 StringRef unaryOperator) {
420 raw_ostream &os = emitter.ostream();
422 if (failed(emitter.emitAssignPrefix(*operation)))
427 if (failed(emitter.emitOperand(operation->
getOperand(0))))
434 Operation *operation = addOp.getOperation();
440 Operation *operation = divOp.getOperation();
446 Operation *operation = mulOp.getOperation();
452 Operation *operation = remOp.getOperation();
458 Operation *operation = subOp.getOperation();
466 std::next(iteratorOp) != end; ++iteratorOp) {
467 if (failed(emitter.emitOperation(*iteratorOp,
true)))
475 emitc::SwitchOp switchOp) {
479 if (failed(emitter.emitOperand(switchOp.getArg())))
483 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
484 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
493 os <<
"\ndefault: {\n";
496 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
504 Operation *operation = cmpOp.getOperation();
506 StringRef binaryOperator;
508 switch (cmpOp.getPredicate()) {
509 case emitc::CmpPredicate::eq:
510 binaryOperator =
"==";
512 case emitc::CmpPredicate::ne:
513 binaryOperator =
"!=";
515 case emitc::CmpPredicate::lt:
516 binaryOperator =
"<";
518 case emitc::CmpPredicate::le:
519 binaryOperator =
"<=";
521 case emitc::CmpPredicate::gt:
522 binaryOperator =
">";
524 case emitc::CmpPredicate::ge:
525 binaryOperator =
">=";
527 case emitc::CmpPredicate::three_way:
528 binaryOperator =
"<=>";
536 emitc::ConditionalOp conditionalOp) {
537 raw_ostream &os = emitter.ostream();
539 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
542 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
547 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
552 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
559 emitc::VerbatimOp verbatimOp) {
560 raw_ostream &os = emitter.ostream();
562 os << verbatimOp.getValue();
568 cf::BranchOp branchOp) {
569 raw_ostream &os = emitter.ostream();
573 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
574 Value &operand = std::get<0>(pair);
576 os << emitter.getOrCreateName(argument) <<
" = "
577 << emitter.getOrCreateName(operand) <<
";\n";
581 if (!(emitter.hasBlockLabel(successor)))
582 return branchOp.emitOpError(
"unable to find label for successor block");
583 os << emitter.getOrCreateName(successor);
588 cf::CondBranchOp condBranchOp) {
590 Block &trueSuccessor = *condBranchOp.getTrueDest();
591 Block &falseSuccessor = *condBranchOp.getFalseDest();
593 os <<
"if (" << emitter.getOrCreateName(condBranchOp.getCondition())
599 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
601 Value &operand = std::get<0>(pair);
603 os << emitter.getOrCreateName(argument) <<
" = "
604 << emitter.getOrCreateName(operand) <<
";\n";
608 if (!(emitter.hasBlockLabel(trueSuccessor))) {
609 return condBranchOp.emitOpError(
"unable to find label for successor block");
611 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
615 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
617 Value &operand = std::get<0>(pair);
619 os << emitter.getOrCreateName(argument) <<
" = "
620 << emitter.getOrCreateName(operand) <<
";\n";
624 if (!(emitter.hasBlockLabel(falseSuccessor))) {
625 return condBranchOp.emitOpError()
626 <<
"unable to find label for successor block";
628 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
635 if (failed(emitter.emitAssignPrefix(*callOp)))
638 raw_ostream &os = emitter.ostream();
640 if (failed(emitter.emitOperands(*callOp)))
647 Operation *operation = callOp.getOperation();
648 StringRef callee = callOp.getCallee();
654 Operation *operation = callOp.getOperation();
655 StringRef callee = callOp.getCallee();
661 emitc::CallOpaqueOp callOpaqueOp) {
662 raw_ostream &os = emitter.ostream();
663 Operation &op = *callOpaqueOp.getOperation();
665 if (failed(emitter.emitAssignPrefix(op)))
667 os << callOpaqueOp.getCallee();
669 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
670 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
672 if (t.getType().isIndex()) {
673 int64_t idx = t.getInt();
675 if (!emitter.hasValueInScope(operand))
677 << idx <<
"'s value not defined in scope";
678 os << emitter.getOrCreateName(operand);
682 if (failed(emitter.emitAttribute(op.
getLoc(), attr)))
688 if (callOpaqueOp.getTemplateArgs()) {
698 LogicalResult emittedArgs =
699 callOpaqueOp.getArgs()
701 : emitter.emitOperands(op);
702 if (failed(emittedArgs))
709 emitc::ApplyOp applyOp) {
710 raw_ostream &os = emitter.ostream();
713 if (failed(emitter.emitAssignPrefix(op)))
715 os << applyOp.getApplicableOperator();
716 os << emitter.getOrCreateName(applyOp.getOperand());
722 emitc::BitwiseAndOp bitwiseAndOp) {
723 Operation *operation = bitwiseAndOp.getOperation();
729 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
730 Operation *operation = bitwiseLeftShiftOp.getOperation();
735 emitc::BitwiseNotOp bitwiseNotOp) {
736 Operation *operation = bitwiseNotOp.getOperation();
741 emitc::BitwiseOrOp bitwiseOrOp) {
742 Operation *operation = bitwiseOrOp.getOperation();
748 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
749 Operation *operation = bitwiseRightShiftOp.getOperation();
754 emitc::BitwiseXorOp bitwiseXorOp) {
755 Operation *operation = bitwiseXorOp.getOperation();
760 emitc::UnaryPlusOp unaryPlusOp) {
761 Operation *operation = unaryPlusOp.getOperation();
766 emitc::UnaryMinusOp unaryMinusOp) {
767 Operation *operation = unaryMinusOp.getOperation();
772 raw_ostream &os = emitter.ostream();
775 if (failed(emitter.emitAssignPrefix(op)))
781 return emitter.emitOperand(castOp.getOperand());
785 emitc::ExpressionOp expressionOp) {
789 Operation &op = *expressionOp.getOperation();
791 if (failed(emitter.emitAssignPrefix(op)))
794 return emitter.emitExpression(expressionOp);
798 emitc::IncludeOp includeOp) {
799 raw_ostream &os = emitter.ostream();
802 if (includeOp.getIsStandardInclude())
803 os <<
"<" << includeOp.getInclude() <<
">";
805 os <<
"\"" << includeOp.getInclude() <<
"\"";
811 emitc::LogicalAndOp logicalAndOp) {
812 Operation *operation = logicalAndOp.getOperation();
817 emitc::LogicalNotOp logicalNotOp) {
818 Operation *operation = logicalNotOp.getOperation();
823 emitc::LogicalOrOp logicalOrOp) {
824 Operation *operation = logicalOrOp.getOperation();
835 auto requiresParentheses = [&](
Value value) {
845 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
848 os << emitter.getOrCreateName(forOp.getInductionVar());
850 if (failed(emitter.emitOperand(forOp.getLowerBound())))
853 os << emitter.getOrCreateName(forOp.getInductionVar());
855 Value upperBound = forOp.getUpperBound();
856 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
857 if (upperBoundRequiresParentheses)
859 if (failed(emitter.emitOperand(upperBound)))
861 if (upperBoundRequiresParentheses)
864 os << emitter.getOrCreateName(forOp.getInductionVar());
866 if (failed(emitter.emitOperand(forOp.getStep())))
871 Region &forRegion = forOp.getRegion();
872 auto regionOps = forRegion.
getOps();
875 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
876 if (failed(emitter.emitOperation(*it,
true)))
890 auto emitAllExceptLast = [&emitter](
Region ®ion) {
892 for (; std::next(it) != end; ++it) {
893 if (failed(emitter.emitOperation(*it,
true)))
896 assert(isa<emitc::YieldOp>(*it) &&
897 "Expected last operation in the region to be emitc::yield");
902 if (failed(emitter.emitOperand(ifOp.getCondition())))
906 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
910 Region &elseRegion = ifOp.getElseRegion();
911 if (!elseRegion.
empty()) {
914 if (failed(emitAllExceptLast(elseRegion)))
923 func::ReturnOp returnOp) {
924 raw_ostream &os = emitter.ostream();
926 switch (returnOp.getNumOperands()) {
931 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
935 os <<
" std::make_tuple(";
936 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
944 emitc::ReturnOp returnOp) {
945 raw_ostream &os = emitter.ostream();
947 if (returnOp.getNumOperands() == 0)
951 if (failed(emitter.emitOperand(returnOp.getOperand())))
957 CppEmitter::Scope scope(emitter);
960 if (failed(emitter.emitOperation(op,
false)))
973 return emitter.emitType(functionOp->
getLoc(), arg);
984 return emitter.emitVariableDeclaration(
985 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
995 if (emitter.shouldDeclareVariablesAtTop()) {
1000 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1001 (isa<emitc::ExpressionOp>(op) &&
1005 if (failed(emitter.emitVariableDeclaration(
1008 op->
emitError(
"unable to declare result variable for op"));
1018 for (
Block &block : blocks) {
1019 emitter.getOrCreateName(block);
1023 for (
Block &block : llvm::drop_begin(blocks)) {
1025 if (emitter.hasValueInScope(arg))
1026 return functionOp->
emitOpError(
" block argument #")
1027 << arg.getArgNumber() <<
" is out of scope";
1028 if (isa<ArrayType, LValueType>(arg.getType()))
1029 return functionOp->
emitOpError(
"cannot emit block argument #")
1030 << arg.getArgNumber() <<
" with type " << arg.getType();
1032 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1035 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1039 for (
Block &block : blocks) {
1041 if (!block.hasNoPredecessors()) {
1042 if (failed(emitter.emitLabel(block)))
1045 for (
Operation &op : block.getOperations()) {
1046 if (failed(emitter.emitOperation(op,
true)))
1057 func::FuncOp functionOp) {
1059 if (!emitter.shouldDeclareVariablesAtTop() &&
1060 functionOp.getBlocks().size() > 1) {
1061 return functionOp.emitOpError(
1062 "with multiple blocks needs variables declared at top");
1065 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1066 return functionOp.emitOpError()
1067 <<
"cannot emit lvalue type as argument type";
1070 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1071 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1074 CppEmitter::Scope scope(emitter);
1076 if (failed(emitter.emitTypes(functionOp.getLoc(),
1077 functionOp.getFunctionType().getResults())))
1079 os <<
" " << functionOp.getName();
1082 Operation *operation = functionOp.getOperation();
1094 emitc::FuncOp functionOp) {
1096 if (!emitter.shouldDeclareVariablesAtTop() &&
1097 functionOp.getBlocks().size() > 1) {
1098 return functionOp.emitOpError(
1099 "with multiple blocks needs variables declared at top");
1102 CppEmitter::Scope scope(emitter);
1104 if (functionOp.getSpecifiers()) {
1105 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1106 os << cast<StringAttr>(specifier).str() <<
" ";
1110 if (failed(emitter.emitTypes(functionOp.getLoc(),
1111 functionOp.getFunctionType().getResults())))
1113 os <<
" " << functionOp.getName();
1116 Operation *operation = functionOp.getOperation();
1117 if (functionOp.isExternal()) {
1119 functionOp.getArgumentTypes())))
1135 DeclareFuncOp declareFuncOp) {
1136 CppEmitter::Scope scope(emitter);
1139 auto functionOp = SymbolTable::lookupNearestSymbolFrom<emitc::FuncOp>(
1140 declareFuncOp, declareFuncOp.getSymNameAttr());
1145 if (functionOp.getSpecifiers()) {
1146 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1147 os << cast<StringAttr>(specifier).str() <<
" ";
1151 if (failed(emitter.emitTypes(functionOp.getLoc(),
1152 functionOp.getFunctionType().getResults())))
1154 os <<
" " << functionOp.getName();
1157 Operation *operation = functionOp.getOperation();
1165 CppEmitter::CppEmitter(raw_ostream &os,
bool declareVariablesAtTop)
1166 : os(os), declareVariablesAtTop(declareVariablesAtTop) {
1167 valueInScopeCount.push(0);
1168 labelInScopeCount.push(0);
1171 std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
1173 llvm::raw_string_ostream ss(out);
1174 ss << getOrCreateName(op.getValue());
1175 for (
auto index : op.getIndices()) {
1176 ss <<
"[" << getOrCreateName(index) <<
"]";
1181 std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1183 llvm::raw_string_ostream ss(out);
1184 ss << getOrCreateName(op.getOperand());
1185 ss <<
"." << op.getMember();
1189 std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1191 llvm::raw_string_ostream ss(out);
1192 ss << getOrCreateName(op.getOperand());
1193 ss <<
"->" << op.getMember();
1197 void CppEmitter::cacheDeferredOpResult(
Value value, StringRef str) {
1198 if (!valueMapper.count(value))
1199 valueMapper.insert(value, str.str());
1203 StringRef CppEmitter::getOrCreateName(
Value val) {
1204 if (!valueMapper.count(val)) {
1206 "cacheDeferredOpResult should have been called on this value, "
1207 "update the emitOperation function.");
1208 valueMapper.insert(val, formatv(
"v{0}", ++valueInScopeCount.top()));
1210 return *valueMapper.begin(val);
1214 StringRef CppEmitter::getOrCreateName(
Block &block) {
1215 if (!blockMapper.count(&block))
1216 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1217 return *blockMapper.begin(&block);
1220 bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1222 case IntegerType::Signless:
1226 case IntegerType::Unsigned:
1229 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1232 bool CppEmitter::hasValueInScope(
Value val) {
return valueMapper.count(val); }
1234 bool CppEmitter::hasBlockLabel(
Block &block) {
1235 return blockMapper.count(&block);
1239 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1240 if (val.getBitWidth() == 1) {
1241 if (val.getBoolValue())
1247 val.toString(strValue, 10, !isUnsigned,
false);
1252 auto printFloat = [&](
const APFloat &val) {
1253 if (val.isFinite()) {
1256 val.toString(strValue, 0, 0,
false);
1258 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1259 case llvm::APFloatBase::S_IEEEhalf:
1262 case llvm::APFloatBase::S_BFloat:
1265 case llvm::APFloatBase::S_IEEEsingle:
1268 case llvm::APFloatBase::S_IEEEdouble:
1271 llvm_unreachable(
"unsupported floating point type");
1273 }
else if (val.isNaN()) {
1275 }
else if (val.isInfinity()) {
1276 if (val.isNegative())
1283 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1284 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1287 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1289 printFloat(fAttr.getValue());
1292 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1293 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1294 dense.getElementType())) {
1296 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1299 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1305 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1306 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1307 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1310 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1311 printInt(iAttr.getValue(),
false);
1315 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1316 if (
auto iType = dyn_cast<IntegerType>(
1317 cast<TensorType>(dense.getType()).getElementType())) {
1319 interleaveComma(dense, os, [&](
const APInt &val) {
1320 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1325 if (
auto iType = dyn_cast<IndexType>(
1326 cast<TensorType>(dense.getType()).getElementType())) {
1328 interleaveComma(dense, os,
1329 [&](
const APInt &val) { printInt(val,
false); });
1336 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1337 os << oAttr.getValue();
1342 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1343 if (sAttr.getNestedReferences().size() > 1)
1344 return emitError(loc,
"attribute has more than 1 nested reference");
1345 os << sAttr.getRootReference().getValue();
1350 if (
auto type = dyn_cast<TypeAttr>(attr))
1351 return emitType(loc, type.getValue());
1353 return emitError(loc,
"cannot emit attribute: ") << attr;
1356 LogicalResult CppEmitter::emitExpression(ExpressionOp expressionOp) {
1357 assert(emittedExpressionPrecedence.empty() &&
1358 "Expected precedence stack to be empty");
1359 Operation *rootOp = expressionOp.getRootOp();
1361 emittedExpression = expressionOp;
1363 if (failed(precedence))
1365 pushExpressionPrecedence(precedence.value());
1367 if (failed(emitOperation(*rootOp,
false)))
1370 popExpressionPrecedence();
1371 assert(emittedExpressionPrecedence.empty() &&
1372 "Expected precedence stack to be empty");
1373 emittedExpression =
nullptr;
1378 LogicalResult CppEmitter::emitOperand(
Value value) {
1379 if (isPartOfCurrentExpression(value)) {
1381 assert(def &&
"Expected operand to be defined by an operation");
1383 if (failed(precedence))
1389 bool encloseInParenthesis = precedence.value() <= getExpressionPrecedence();
1390 if (encloseInParenthesis)
1392 pushExpressionPrecedence(precedence.value());
1394 if (failed(emitOperation(*def,
false)))
1397 if (encloseInParenthesis)
1400 popExpressionPrecedence();
1404 auto expressionOp = dyn_cast_if_present<ExpressionOp>(value.
getDefiningOp());
1406 return emitExpression(expressionOp);
1408 os << getOrCreateName(value);
1412 LogicalResult CppEmitter::emitOperands(
Operation &op) {
1416 if (getEmittedExpression())
1417 pushExpressionPrecedence(lowestPrecedence());
1418 if (failed(emitOperand(operand)))
1420 if (getEmittedExpression())
1421 popExpressionPrecedence();
1427 CppEmitter::emitOperandsAndAttributes(
Operation &op,
1429 if (failed(emitOperands(op)))
1434 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1441 auto emitNamedAttribute = [&](
NamedAttribute attr) -> LogicalResult {
1442 if (llvm::is_contained(exclude, attr.getName().strref()))
1444 os <<
"/* " << attr.getName().getValue() <<
" */";
1445 if (failed(emitAttribute(op.
getLoc(), attr.getValue())))
1452 LogicalResult CppEmitter::emitVariableAssignment(
OpResult result) {
1453 if (!hasValueInScope(result)) {
1455 "result variable for the operation has not been declared");
1457 os << getOrCreateName(result) <<
" = ";
1461 LogicalResult CppEmitter::emitVariableDeclaration(
OpResult result,
1462 bool trailingSemicolon) {
1465 if (hasValueInScope(result)) {
1467 "result variable for the operation already declared");
1471 getOrCreateName(result))))
1473 if (trailingSemicolon)
1478 LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1479 if (op.getExternSpecifier())
1481 else if (op.getStaticSpecifier())
1483 if (op.getConstSpecifier())
1486 if (failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1487 op.getSymName()))) {
1491 std::optional<Attribute> initialValue = op.getInitialValue();
1494 if (failed(emitAttribute(op->getLoc(), *initialValue)))
1502 LogicalResult CppEmitter::emitAssignPrefix(
Operation &op) {
1504 if (getEmittedExpression())
1512 if (shouldDeclareVariablesAtTop()) {
1513 if (failed(emitVariableAssignment(result)))
1516 if (failed(emitVariableDeclaration(result,
false)))
1523 if (!shouldDeclareVariablesAtTop()) {
1525 if (failed(emitVariableDeclaration(result,
true)))
1531 [&](
Value result) { os << getOrCreateName(result); });
1537 LogicalResult CppEmitter::emitLabel(
Block &block) {
1538 if (!hasBlockLabel(block))
1542 os.getOStream() << getOrCreateName(block) <<
":\n";
1546 LogicalResult CppEmitter::emitOperation(
Operation &op,
bool trailingSemicolon) {
1547 LogicalResult status =
1550 .Case<ModuleOp>([&](
auto op) {
return printOperation(*
this, op); })
1552 .Case<cf::BranchOp, cf::CondBranchOp>(
1555 .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1556 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1557 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1558 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1559 emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
1560 emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
1561 emitc::DivOp, emitc::ExpressionOp, emitc::ForOp, emitc::FuncOp,
1562 emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp, emitc::LoadOp,
1563 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1564 emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
1565 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1566 emitc::VariableOp, emitc::VerbatimOp>(
1569 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1571 .Case<emitc::GetGlobalOp>([&](
auto op) {
1575 .Case<emitc::LiteralOp>([&](
auto op) {
1576 cacheDeferredOpResult(op.
getResult(), op.getValue());
1579 .Case<emitc::MemberOp>([&](
auto op) {
1580 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1583 .Case<emitc::MemberOfPtrOp>([&](
auto op) {
1584 cacheDeferredOpResult(op.
getResult(), createMemberAccess(op));
1587 .Case<emitc::SubscriptOp>([&](
auto op) {
1588 cacheDeferredOpResult(op.
getResult(), getSubscriptName(op));
1592 return op.
emitOpError(
"unable to find printer for op");
1601 if (getEmittedExpression() ||
1602 (isa<emitc::ExpressionOp>(op) &&
1608 trailingSemicolon &=
1609 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::ForOp, emitc::IfOp,
1610 emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(op);
1612 os << (trailingSemicolon ?
";\n" :
"\n");
1617 LogicalResult CppEmitter::emitVariableDeclaration(
Location loc,
Type type,
1619 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
1620 if (failed(emitType(loc, arrType.getElementType())))
1623 for (
auto dim : arrType.getShape()) {
1624 os <<
"[" << dim <<
"]";
1628 if (failed(emitType(loc, type)))
1634 LogicalResult CppEmitter::emitType(
Location loc,
Type type) {
1635 if (
auto iType = dyn_cast<IntegerType>(type)) {
1636 switch (iType.getWidth()) {
1638 return (os <<
"bool"), success();
1643 if (shouldMapToUnsigned(iType.getSignedness()))
1644 return (os <<
"uint" << iType.getWidth() <<
"_t"), success();
1646 return (os <<
"int" << iType.getWidth() <<
"_t"), success();
1648 return emitError(loc,
"cannot emit integer type ") << type;
1651 if (
auto fType = dyn_cast<FloatType>(type)) {
1652 switch (fType.getWidth()) {
1654 if (llvm::isa<Float16Type>(type))
1655 return (os <<
"_Float16"), success();
1656 else if (llvm::isa<BFloat16Type>(type))
1657 return (os <<
"__bf16"), success();
1659 return emitError(loc,
"cannot emit float type ") << type;
1662 return (os <<
"float"), success();
1664 return (os <<
"double"), success();
1666 return emitError(loc,
"cannot emit float type ") << type;
1669 if (
auto iType = dyn_cast<IndexType>(type))
1670 return (os <<
"size_t"), success();
1671 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
1672 return (os <<
"size_t"), success();
1673 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
1674 return (os <<
"ssize_t"), success();
1675 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
1676 return (os <<
"ptrdiff_t"), success();
1677 if (
auto tType = dyn_cast<TensorType>(type)) {
1678 if (!tType.hasRank())
1679 return emitError(loc,
"cannot emit unranked tensor type");
1680 if (!tType.hasStaticShape())
1681 return emitError(loc,
"cannot emit tensor type with non static shape");
1683 if (isa<ArrayType>(tType.getElementType()))
1684 return emitError(loc,
"cannot emit tensor of array type ") << type;
1685 if (failed(emitType(loc, tType.getElementType())))
1687 auto shape = tType.getShape();
1688 for (
auto dimSize : shape) {
1695 if (
auto tType = dyn_cast<TupleType>(type))
1696 return emitTupleType(loc, tType.getTypes());
1697 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
1698 os << oType.getValue();
1701 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
1702 if (failed(emitType(loc, aType.getElementType())))
1704 for (
auto dim : aType.getShape())
1705 os <<
"[" << dim <<
"]";
1708 if (
auto lType = dyn_cast<emitc::LValueType>(type))
1709 return emitType(loc, lType.getValueType());
1710 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
1711 if (isa<ArrayType>(pType.getPointee()))
1712 return emitError(loc,
"cannot emit pointer to array type ") << type;
1713 if (failed(emitType(loc, pType.getPointee())))
1718 return emitError(loc,
"cannot emit type ") << type;
1722 switch (types.size()) {
1727 return emitType(loc, types.front());
1729 return emitTupleType(loc, types);
1734 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
1735 return emitError(loc,
"cannot emit tuple of array type");
1737 os <<
"std::tuple<";
1739 types, os, [&](
Type type) {
return emitType(loc, type); })))
1746 bool declareVariablesAtTop) {
1747 CppEmitter emitter(os, declareVariablesAtTop);
1748 return emitter.emitOperation(*op,
false);
static LogicalResult printCallOperation(CppEmitter &emitter, Operation *callOp, StringRef callee)
static bool shouldBeInlined(ExpressionOp expressionOp)
Determine whether expression expressionOp should be emitted inline, i.e.
LogicalResult interleaveCommaWithError(const Container &c, raw_ostream &os, UnaryFunctor eachFn)
static FailureOr< int > getOperatorPrecedence(Operation *operation)
Return the precedence of a operator as an integer, higher values imply higher precedence.
static LogicalResult printFunctionArgs(CppEmitter &emitter, Operation *functionOp, ArrayRef< Type > arguments)
static LogicalResult printFunctionBody(CppEmitter &emitter, Operation *functionOp, Region::BlockListType &blocks)
static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation, Attribute value)
static LogicalResult emitSwitchCase(CppEmitter &emitter, raw_indented_ostream &os, Region ®ion)
LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
static LogicalResult printBinaryOperation(CppEmitter &emitter, Operation *operation, StringRef binaryOperator)
static LogicalResult printOperation(CppEmitter &emitter, emitc::ConstantOp constantOp)
static LogicalResult printUnaryOperation(CppEmitter &emitter, Operation *operation, StringRef unaryOperator)
static bool hasDeferredEmission(Operation *op)
Determine whether expression op should be emitted in a deferred way.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgListType getArguments()
Block * getSuccessor(unsigned i)
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
NamedAttribute represents a combination of a name and an Attribute value.
This is a value defined by a result of an operation.
Operation * getOwner() const
Returns the operation that owns this result.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OperationName getName()
The name of an operation is the key identifier for it.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
This class provides iteration over the held operations of blocks directly within a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
llvm::iplist< Block > BlockListType
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
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)
Translates the given operation to C++ code.
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.