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>
60 UnaryFunctor eachFn) {
68 .Case([&](emitc::AddressOfOp op) {
return 15; })
69 .Case([&](emitc::AddOp op) {
return 12; })
70 .Case([&](emitc::BitwiseAndOp op) {
return 7; })
71 .Case([&](emitc::BitwiseLeftShiftOp op) {
return 11; })
72 .Case([&](emitc::BitwiseNotOp op) {
return 15; })
73 .Case([&](emitc::BitwiseOrOp op) {
return 5; })
74 .Case([&](emitc::BitwiseRightShiftOp op) {
return 11; })
75 .Case([&](emitc::BitwiseXorOp op) {
return 6; })
76 .Case([&](emitc::CallOp op) {
return 16; })
77 .Case([&](emitc::CallOpaqueOp op) {
return 16; })
78 .Case([&](emitc::CastOp op) {
return 15; })
79 .Case([&](emitc::CmpOp op) -> FailureOr<int> {
80 switch (op.getPredicate()) {
81 case emitc::CmpPredicate::eq:
82 case emitc::CmpPredicate::ne:
84 case emitc::CmpPredicate::lt:
85 case emitc::CmpPredicate::le:
86 case emitc::CmpPredicate::gt:
87 case emitc::CmpPredicate::ge:
89 case emitc::CmpPredicate::three_way:
92 return op->emitError(
"unsupported cmp predicate");
94 .Case([&](emitc::ConditionalOp op) {
return 2; })
95 .Case([&](emitc::ConstantOp op) {
return 17; })
96 .Case([&](emitc::DereferenceOp op) {
return 15; })
97 .Case([&](emitc::DivOp op) {
return 13; })
98 .Case([&](emitc::GetGlobalOp op) {
return 18; })
99 .Case([&](emitc::GetFieldOp op) {
return 18; })
100 .Case([&](emitc::LiteralOp op) {
return 18; })
101 .Case([&](emitc::LoadOp op) {
return 16; })
102 .Case([&](emitc::LogicalAndOp op) {
return 4; })
103 .Case([&](emitc::LogicalNotOp op) {
return 15; })
104 .Case([&](emitc::LogicalOrOp op) {
return 3; })
105 .Case([&](emitc::MemberCallOpaqueOp op) {
return 16; })
106 .Case([&](emitc::MemberOfPtrOp op) {
return 17; })
107 .Case([&](emitc::MemberOp op) {
return 17; })
108 .Case([&](emitc::MulOp op) {
return 13; })
109 .Case([&](emitc::PostDecrementOp op) {
return 16; })
110 .Case([&](emitc::PostIncrementOp op) {
return 16; })
111 .Case([&](emitc::PreDecrementOp op) {
return 15; })
112 .Case([&](emitc::PreIncrementOp op) {
return 15; })
113 .Case([&](emitc::RemOp op) {
return 13; })
114 .Case([&](emitc::SubOp op) {
return 12; })
115 .Case([&](emitc::SubscriptOp op) {
return 17; })
116 .Case([&](emitc::UnaryMinusOp op) {
return 15; })
117 .Case([&](emitc::UnaryPlusOp op) {
return 15; })
118 .Default([](
auto op) {
return op->emitError(
"unsupported operation"); });
126 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
130 LogicalResult emitAttribute(Location loc, Attribute attr);
137 LogicalResult emitOperation(Operation &op,
bool trailingSemicolon);
140 LogicalResult emitType(Location loc, Type type);
146 LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
150 LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
153 LogicalResult emitVariableAssignment(OpResult
result);
156 LogicalResult emitVariableDeclaration(OpResult
result,
157 bool trailingSemicolon);
160 LogicalResult emitVariableDeclaration(Location loc, Type type,
169 LogicalResult emitAssignPrefix(Operation &op);
172 LogicalResult emitGlobalVariable(GlobalOp op);
175 LogicalResult emitLabel(
Block &block);
179 LogicalResult emitOperandsAndAttributes(Operation &op,
180 ArrayRef<StringRef> exclude = {});
183 LogicalResult emitOperands(Operation &op);
189 LogicalResult emitOperand(Value value,
bool isInBrackets =
false);
192 LogicalResult emitExpression(Operation *op);
195 StringRef getOrCreateName(Value val);
199 StringRef getOrCreateInductionVarName(Value val);
202 StringRef getOrCreateName(
Block &block);
204 LogicalResult emitInlinedExpression(Value value);
207 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
211 ~Scope() { emitter.labelInScopeCount.pop(); }
214 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
215 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
218 Scope(CppEmitter &emitter)
219 : valueMapperScope(emitter.valueMapper),
220 blockMapperScope(emitter.blockMapper), emitter(emitter) {
221 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
228 struct FunctionScope : Scope {
229 FunctionScope(CppEmitter &emitter) : Scope(emitter) {
231 emitter.resetValueCounter();
237 struct LoopScope : Scope {
238 LoopScope(CppEmitter &emitter) : Scope(emitter) {
239 emitter.increaseLoopNestingLevel();
241 ~LoopScope() { emitter.decreaseLoopNestingLevel(); }
245 bool hasValueInScope(Value val);
248 bool hasBlockLabel(
Block &block);
251 raw_indented_ostream &ostream() {
return os; };
255 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
258 bool shouldEmitFile(FileOp file) {
259 return !fileId.empty() && file.getId() == fileId;
263 bool isEmittingExpression() {
return !emittedExpressionPrecedence.empty(); }
267 bool isPartOfCurrentExpression(Value value) {
269 return def ? isPartOfCurrentExpression(def) :
false;
274 bool isPartOfCurrentExpression(Operation *def) {
279 void resetValueCounter();
282 void increaseLoopNestingLevel();
285 void decreaseLoopNestingLevel();
288 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
289 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
292 raw_indented_ostream os;
297 bool declareVariablesAtTop;
303 ValueMapper valueMapper;
306 BlockMapper blockMapper;
309 llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
310 llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
312 std::stack<int64_t> labelInScopeCount;
316 uint64_t loopNestingLevel{0};
319 unsigned int valueCount{0};
322 SmallVector<int> emittedExpressionPrecedence;
324 void pushExpressionPrecedence(
int precedence) {
325 emittedExpressionPrecedence.push_back(precedence);
327 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
328 static int lowestPrecedence() {
return 0; }
329 int getExpressionPrecedence() {
330 if (emittedExpressionPrecedence.empty())
331 return lowestPrecedence();
332 return emittedExpressionPrecedence.back();
345 if (
auto cExpression = dyn_cast<CExpressionInterface>(op))
346 return cExpression.alwaysInline() || isa<ExpressionOp>(op->
getParentOp());
349 ExpressionOp expressionOp = dyn_cast<ExpressionOp>(op);
354 if (cast<CExpressionInterface>(expressionOp.getRootOp()).alwaysInline())
358 if (expressionOp.getDoNotInline())
371 if (isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user))
375 if (!expressionOp.hasSideEffects())
386 if (isa<emitc::IfOp, emitc::SwitchOp, emitc::ReturnOp>(user))
391 if (
auto assignOp = dyn_cast<emitc::AssignOp>(user)) {
393 if (expressionOp.getResult() == assignOp.getValue() &&
394 isa_and_present<VariableOp>(assignOp.getVar().getDefiningOp()))
405 while (
auto subscriptOp = value.
getDefiningOp<emitc::SubscriptOp>()) {
406 value = subscriptOp.getValue();
409 auto getGlobalOp = value.
getDefiningOp<emitc::GetGlobalOp>();
415 fromOp, getGlobalOp.getNameAttr());
417 if (globalOp && globalOp.getConstSpecifier())
432 if (failed(emitter.emitOperand(operand)))
439 emitc::DereferenceOp dereferenceOp) {
441 Operation &op = *dereferenceOp.getOperation();
443 if (failed(emitter.emitAssignPrefix(op)))
446 return emitter.emitOperand(dereferenceOp.getPointer());
450 emitc::GetFieldOp getFieldOp) {
451 if (!emitter.isPartOfCurrentExpression(getFieldOp.getOperation()))
454 emitter.ostream() << getFieldOp.getFieldName();
459 emitc::GetGlobalOp getGlobalOp) {
460 if (!emitter.isPartOfCurrentExpression(getGlobalOp.getOperation()))
463 emitter.ostream() << getGlobalOp.getName();
468 emitc::LiteralOp literalOp) {
469 if (!emitter.isPartOfCurrentExpression(literalOp.getOperation()))
472 emitter.ostream() << literalOp.getValue();
477 emitc::MemberOp memberOp) {
478 if (memberOp.alwaysInline()) {
479 if (!emitter.isPartOfCurrentExpression(memberOp.getOperation()))
482 if (failed(emitter.emitAssignPrefix(*memberOp.getOperation())))
485 if (failed(emitter.emitOperand(memberOp.getOperand())))
487 emitter.ostream() <<
"." << memberOp.getMember();
492 emitc::MemberOfPtrOp memberOfPtrOp) {
493 if (!emitter.isPartOfCurrentExpression(memberOfPtrOp.getOperation()))
496 if (failed(emitter.emitOperand(memberOfPtrOp.getOperand())))
498 emitter.ostream() <<
"->" << memberOfPtrOp.getMember();
503 emitc::SubscriptOp subscriptOp) {
504 if (!emitter.isPartOfCurrentExpression(subscriptOp.getOperation())) {
509 if (failed(emitter.emitOperand(subscriptOp.getValue())))
511 for (
auto index : subscriptOp.getIndices()) {
513 if (failed(emitter.emitOperand(
index,
true)))
526 if (emitter.shouldDeclareVariablesAtTop()) {
528 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
529 if (oAttr.getValue().empty())
533 if (failed(emitter.emitVariableAssignment(
result)))
535 return emitter.emitAttribute(operation->
getLoc(), value);
539 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
540 if (oAttr.getValue().empty())
542 return emitter.emitVariableDeclaration(
result,
547 if (failed(emitter.emitAssignPrefix(*operation)))
549 return emitter.emitAttribute(operation->
getLoc(), value);
553 emitc::AddressOfOp addressOfOp) {
555 Operation &op = *addressOfOp.getOperation();
557 if (failed(emitter.emitAssignPrefix(op)))
560 Value operand = addressOfOp.getReference();
567 return emitter.emitOperand(operand);
571 emitc::ConstantOp constantOp) {
572 Operation *operation = constantOp.getOperation();
575 if (emitter.isPartOfCurrentExpression(operation))
576 return emitter.emitAttribute(operation->
getLoc(), value);
582 emitc::VariableOp variableOp) {
583 Operation *operation = variableOp.getOperation();
590 emitc::GlobalOp globalOp) {
592 return emitter.emitGlobalVariable(globalOp);
596 emitc::AssignOp assignOp) {
597 if (failed(emitter.emitOperand(assignOp.getVar())))
600 emitter.ostream() <<
" = ";
602 return emitter.emitOperand(assignOp.getValue());
607 StringRef compoundAssignmentOperator) {
608 if (failed(emitter.emitOperand(operation->
getOperand(0))))
611 emitter.ostream() <<
" " << compoundAssignmentOperator <<
" ";
613 return emitter.emitOperand(operation->
getOperand(1));
617 emitc::AddAssignOp addAssignOp) {
622 emitc::SubAssignOp subAssignOp) {
627 emitc::MulAssignOp mulAssignOp) {
632 emitc::DivAssignOp divAssignOp) {
637 emitc::RemAssignOp remAssignOp) {
642 if (failed(emitter.emitAssignPrefix(*loadOp)))
645 return emitter.emitOperand(loadOp.getOperand());
650 StringRef binaryOperator) {
653 if (failed(emitter.emitAssignPrefix(*operation)))
656 if (failed(emitter.emitOperand(operation->
getOperand(0))))
659 os <<
" " << binaryOperator <<
" ";
661 if (failed(emitter.emitOperand(operation->
getOperand(1))))
669 StringRef unaryOperator) {
672 if (failed(emitter.emitAssignPrefix(*operation)))
677 if (failed(emitter.emitOperand(operation->
getOperand(0))))
685 StringRef unaryOperator) {
688 if (failed(emitter.emitAssignPrefix(*operation)))
691 if (failed(emitter.emitOperand(operation->
getOperand(0))))
700 Operation *operation = addOp.getOperation();
706 Operation *operation = divOp.getOperation();
712 Operation *operation = mulOp.getOperation();
718 Operation *operation = remOp.getOperation();
724 Operation *operation = subOp.getOperation();
732 std::next(iteratorOp) != end; ++iteratorOp) {
733 if (failed(emitter.emitOperation(*iteratorOp,
true)))
741 emitc::SwitchOp switchOp) {
745 if (failed(emitter.emitOperand(switchOp.getArg())))
749 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
750 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
759 os <<
"\ndefault: {\n";
762 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
775 Block &bodyBlock = doOp.getBodyRegion().
front();
777 if (failed(emitter.emitOperation(op,
true)))
783 Block &condBlock = doOp.getConditionRegion().
front();
784 auto condYield = cast<emitc::YieldOp>(condBlock.
back());
785 if (failed(emitter.emitExpression(
786 cast<emitc::ExpressionOp>(condYield.getOperand(0).getDefiningOp()))))
794 Operation *operation = cmpOp.getOperation();
796 StringRef binaryOperator;
798 switch (cmpOp.getPredicate()) {
799 case emitc::CmpPredicate::eq:
800 binaryOperator =
"==";
802 case emitc::CmpPredicate::ne:
803 binaryOperator =
"!=";
805 case emitc::CmpPredicate::lt:
806 binaryOperator =
"<";
808 case emitc::CmpPredicate::le:
809 binaryOperator =
"<=";
811 case emitc::CmpPredicate::gt:
812 binaryOperator =
">";
814 case emitc::CmpPredicate::ge:
815 binaryOperator =
">=";
817 case emitc::CmpPredicate::three_way:
818 binaryOperator =
"<=>";
826 emitc::ConditionalOp conditionalOp) {
829 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
832 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
837 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
842 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
849 emitc::VerbatimOp verbatimOp) {
852 FailureOr<SmallVector<ReplacementItem>> items =
853 verbatimOp.parseFormatString();
857 auto fmtArg = verbatimOp.getFmtArgs().begin();
860 if (
auto *str = std::get_if<StringRef>(&item)) {
863 if (failed(emitter.emitOperand(*fmtArg++)))
872 cf::BranchOp branchOp) {
877 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
878 Value &operand = std::get<0>(pair);
880 os << emitter.getOrCreateName(argument) <<
" = "
881 << emitter.getOrCreateName(operand) <<
";\n";
885 if (!(emitter.hasBlockLabel(successor)))
886 return branchOp.emitOpError(
"unable to find label for successor block");
887 os << emitter.getOrCreateName(successor);
892 cf::CondBranchOp condBranchOp) {
894 Block &trueSuccessor = *condBranchOp.getTrueDest();
895 Block &falseSuccessor = *condBranchOp.getFalseDest();
898 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
905 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
907 Value &operand = std::get<0>(pair);
909 os << emitter.getOrCreateName(argument) <<
" = "
910 << emitter.getOrCreateName(operand) <<
";\n";
914 if (!(emitter.hasBlockLabel(trueSuccessor))) {
915 return condBranchOp.emitOpError(
"unable to find label for successor block");
917 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
921 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
923 Value &operand = std::get<0>(pair);
925 os << emitter.getOrCreateName(argument) <<
" = "
926 << emitter.getOrCreateName(operand) <<
";\n";
930 if (!(emitter.hasBlockLabel(falseSuccessor))) {
931 return condBranchOp.emitOpError()
932 <<
"unable to find label for successor block";
934 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
941 if (failed(emitter.emitAssignPrefix(*callOp)))
946 if (failed(emitter.emitOperands(*callOp)))
953 Operation *operation = callOp.getOperation();
954 StringRef callee = callOp.getCallee();
960 Operation *operation = callOp.getOperation();
961 StringRef callee = callOp.getCallee();
966template <
typename OpTy>
969 std::optional<ArrayAttr> templateArgs,
970 std::optional<ArrayAttr> args,
bool isMemberCall,
971 Value receiver =
nullptr) {
974 if (failed(emitter.emitAssignPrefix(*op.getOperation())))
978 assert(receiver &&
"Expected receiver for member call");
979 if (failed(emitter.emitOperand(receiver)))
982 if (llvm::isa<emitc::PointerType>(receiver.getType()))
994 auto emitTemplateArgs = [&](
Attribute attr) -> LogicalResult {
995 return emitter.emitAttribute(op.getLoc(), attr);
1005 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
1006 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
1007 if (t.getType().isIndex()) {
1009 Value operand = op.getArgOperands()[idx];
1010 return emitter.emitOperand(operand,
false);
1013 if (failed(emitter.emitAttribute(op.getLoc(), attr)))
1021 LogicalResult emittedArgs =
success();
1027 return emitter.emitOperand(operand, true);
1030 if (failed(emittedArgs))
1037 emitc::CallOpaqueOp callOpaqueOp) {
1039 callOpaqueOp.getTemplateArgs(),
1040 callOpaqueOp.getArgs(),
1046 emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
1048 emitter, memberCallOpaqueOp, memberCallOpaqueOp.getCallee(),
1049 memberCallOpaqueOp.getTemplateArgs(), memberCallOpaqueOp.getArgs(),
1050 true, memberCallOpaqueOp.getReceiver());
1054 emitc::BitwiseAndOp bitwiseAndOp) {
1055 Operation *operation = bitwiseAndOp.getOperation();
1061 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
1062 Operation *operation = bitwiseLeftShiftOp.getOperation();
1067 emitc::BitwiseNotOp bitwiseNotOp) {
1068 Operation *operation = bitwiseNotOp.getOperation();
1073 emitc::BitwiseOrOp bitwiseOrOp) {
1074 Operation *operation = bitwiseOrOp.getOperation();
1080 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
1081 Operation *operation = bitwiseRightShiftOp.getOperation();
1086 emitc::BitwiseXorOp bitwiseXorOp) {
1087 Operation *operation = bitwiseXorOp.getOperation();
1092 emitc::PreIncrementOp preIncrementOp) {
1093 Operation *operation = preIncrementOp.getOperation();
1098 emitc::PostIncrementOp postIncrementOp) {
1099 Operation *operation = postIncrementOp.getOperation();
1104 emitc::PreDecrementOp preDecrementOp) {
1105 Operation *operation = preDecrementOp.getOperation();
1110 emitc::PostDecrementOp postDecrementOp) {
1111 Operation *operation = postDecrementOp.getOperation();
1116 emitc::UnaryPlusOp unaryPlusOp) {
1117 Operation *operation = unaryPlusOp.getOperation();
1122 emitc::UnaryMinusOp unaryMinusOp) {
1123 Operation *operation = unaryMinusOp.getOperation();
1131 if (failed(emitter.emitAssignPrefix(op)))
1137 return emitter.emitOperand(castOp.getOperand());
1141 emitc::ExpressionOp expressionOp) {
1145 Operation &op = *expressionOp.getOperation();
1147 if (failed(emitter.emitAssignPrefix(op)))
1150 return emitter.emitExpression(expressionOp);
1154 emitc::IncludeOp includeOp) {
1158 if (includeOp.getIsStandardInclude())
1159 os <<
"<" << includeOp.getInclude() <<
">";
1161 os <<
"\"" << includeOp.getInclude() <<
"\"";
1167 emitc::LogicalAndOp logicalAndOp) {
1168 Operation *operation = logicalAndOp.getOperation();
1173 emitc::LogicalNotOp logicalNotOp) {
1174 Operation *operation = logicalNotOp.getOperation();
1179 emitc::LogicalOrOp logicalOrOp) {
1180 Operation *operation = logicalOrOp.getOperation();
1190 auto requiresParentheses = [&](
Value value) {
1199 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
1202 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1204 if (failed(emitter.emitOperand(forOp.getLowerBound())))
1207 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1209 Value upperBound = forOp.getUpperBound();
1210 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
1211 if (upperBoundRequiresParentheses)
1213 if (failed(emitter.emitOperand(upperBound)))
1215 if (upperBoundRequiresParentheses)
1218 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1220 if (failed(emitter.emitOperand(forOp.getStep())))
1225 CppEmitter::LoopScope lScope(emitter);
1227 Region &forRegion = forOp.getRegion();
1228 auto regionOps = forRegion.
getOps();
1231 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
1232 if (failed(emitter.emitOperation(*it,
true)))
1246 auto emitAllExceptLast = [&emitter](
Region ®ion) {
1248 for (; std::next(it) != end; ++it) {
1249 if (failed(emitter.emitOperation(*it,
true)))
1252 assert(isa<emitc::YieldOp>(*it) &&
1253 "Expected last operation in the region to be emitc::yield");
1258 if (failed(emitter.emitOperand(ifOp.getCondition())))
1262 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
1266 Region &elseRegion = ifOp.getElseRegion();
1267 if (!elseRegion.
empty()) {
1270 if (failed(emitAllExceptLast(elseRegion)))
1279 func::ReturnOp returnOp) {
1282 switch (returnOp.getNumOperands()) {
1287 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
1291 os <<
" std::make_tuple(";
1292 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
1300 emitc::ReturnOp returnOp) {
1303 if (returnOp.getNumOperands() == 0)
1307 if (failed(emitter.emitOperand(returnOp.getOperand())))
1314 if (failed(emitter.emitOperation(op,
false)))
1322 ClassType classType = classOp.getClassType();
1323 os << stringifyClassType(classType) <<
" " << classOp.getSymName();
1324 if (classOp.getFinalSpecifier())
1328 if (classType == ClassType::class_)
1334 if (failed(emitter.emitOperation(op,
false)))
1345 if (failed(emitter.emitVariableDeclaration(
1346 fieldOp->getLoc(), fieldOp.getType(), fieldOp.getSymName())))
1348 std::optional<Attribute> initialValue = fieldOp.getInitialValue();
1351 if (failed(emitter.emitAttribute(fieldOp->getLoc(), *initialValue)))
1360 if (!emitter.shouldEmitFile(file))
1364 if (failed(emitter.emitOperation(op,
false)))
1377 return emitter.emitType(functionOp->
getLoc(), arg);
1388 return emitter.emitVariableDeclaration(
1389 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1399 if (emitter.shouldDeclareVariablesAtTop()) {
1404 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1405 (isa<emitc::ExpressionOp>(op) &&
1409 if (failed(emitter.emitVariableDeclaration(
1412 op->
emitError(
"unable to declare result variable for op"));
1417 if (
result.wasInterrupted())
1422 for (
Block &block : blocks) {
1423 emitter.getOrCreateName(block);
1427 for (
Block &block : llvm::drop_begin(blocks)) {
1429 if (emitter.hasValueInScope(arg))
1430 return functionOp->
emitOpError(
" block argument #")
1431 << arg.getArgNumber() <<
" is out of scope";
1432 if (isa<ArrayType, LValueType>(arg.getType()))
1433 return functionOp->
emitOpError(
"cannot emit block argument #")
1434 << arg.getArgNumber() <<
" with type " << arg.getType();
1436 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1439 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1443 for (
Block &block : blocks) {
1445 if (!block.hasNoPredecessors()) {
1446 if (failed(emitter.emitLabel(block)))
1449 for (
Operation &op : block.getOperations()) {
1450 if (failed(emitter.emitOperation(op,
true)))
1461 func::FuncOp functionOp) {
1463 if (!emitter.shouldDeclareVariablesAtTop() &&
1464 functionOp.getBlocks().size() > 1) {
1465 return functionOp.emitOpError(
1466 "with multiple blocks needs variables declared at top");
1469 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1470 return functionOp.emitOpError()
1471 <<
"cannot emit lvalue type as argument type";
1474 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1475 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1478 CppEmitter::FunctionScope scope(emitter);
1480 if (failed(emitter.emitTypes(functionOp.getLoc(),
1481 functionOp.getFunctionType().getResults())))
1483 os <<
" " << functionOp.getName();
1486 Operation *operation = functionOp.getOperation();
1498 emitc::FuncOp functionOp) {
1500 if (!emitter.shouldDeclareVariablesAtTop() &&
1501 functionOp.getBlocks().size() > 1) {
1502 return functionOp.emitOpError(
1503 "with multiple blocks needs variables declared at top");
1506 CppEmitter::FunctionScope scope(emitter);
1508 if (functionOp.getSpecifiers()) {
1509 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1510 os << cast<StringAttr>(specifier).str() <<
" ";
1514 if (failed(emitter.emitTypes(functionOp.getLoc(),
1515 functionOp.getFunctionType().getResults())))
1517 os <<
" " << functionOp.getName();
1520 Operation *operation = functionOp.getOperation();
1521 if (functionOp.isExternal()) {
1523 functionOp.getArgumentTypes())))
1539 DeclareFuncOp declareFuncOp) {
1542 CppEmitter::FunctionScope scope(emitter);
1544 declareFuncOp, declareFuncOp.getSymNameAttr());
1549 if (functionOp.getSpecifiers()) {
1550 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1551 os << cast<StringAttr>(specifier).str() <<
" ";
1555 if (failed(emitter.emitTypes(functionOp.getLoc(),
1556 functionOp.getFunctionType().getResults())))
1558 os <<
" " << functionOp.getName();
1561 Operation *operation = functionOp.getOperation();
1569CppEmitter::CppEmitter(
raw_ostream &os,
bool declareVariablesAtTop,
1571 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1572 fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1573 defaultBlockMapperScope(blockMapper) {
1574 labelInScopeCount.push(0);
1578StringRef CppEmitter::getOrCreateName(
Value val) {
1579 if (!valueMapper.count(val)) {
1580 valueMapper.insert(val, formatv(
"v{0}", ++valueCount));
1582 return *valueMapper.begin(val);
1587StringRef CppEmitter::getOrCreateInductionVarName(Value val) {
1588 if (!valueMapper.count(val)) {
1590 int64_t identifier =
'i' + loopNestingLevel;
1592 if (identifier >=
'i' && identifier <=
't') {
1593 valueMapper.insert(val,
1594 formatv(
"{0}{1}", (
char)identifier, ++valueCount));
1597 valueMapper.insert(val, formatv(
"u{0}", ++valueCount));
1600 return *valueMapper.begin(val);
1604StringRef CppEmitter::getOrCreateName(
Block &block) {
1605 if (!blockMapper.count(&block))
1606 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1607 return *blockMapper.begin(&block);
1610bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1612 case IntegerType::Signless:
1614 case IntegerType::Signed:
1616 case IntegerType::Unsigned:
1619 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1622bool CppEmitter::hasValueInScope(Value val) {
return valueMapper.count(val); }
1624bool CppEmitter::hasBlockLabel(
Block &block) {
1625 return blockMapper.count(&block);
1628LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) {
1629 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1630 if (val.getBitWidth() == 1) {
1631 if (val.getBoolValue())
1636 SmallString<128> strValue;
1637 val.toString(strValue, 10, !isUnsigned,
false);
1642 auto printFloat = [&](
const APFloat &val) {
1643 if (val.isFinite()) {
1644 SmallString<128> strValue;
1646 val.toString(strValue, 0, 0,
false);
1648 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1649 case llvm::APFloatBase::S_IEEEhalf:
1652 case llvm::APFloatBase::S_BFloat:
1655 case llvm::APFloatBase::S_IEEEsingle:
1658 case llvm::APFloatBase::S_IEEEdouble:
1661 llvm_unreachable(
"unsupported floating point type");
1663 }
else if (val.isNaN()) {
1665 }
else if (val.isInfinity()) {
1666 if (val.isNegative())
1673 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1674 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1677 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1679 printFloat(fAttr.getValue());
1682 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1683 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1684 dense.getElementType())) {
1686 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1689 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1695 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1696 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1697 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1700 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1701 printInt(iAttr.getValue(),
false);
1705 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1706 if (
auto iType = dyn_cast<IntegerType>(
1707 cast<ShapedType>(dense.getType()).getElementType())) {
1709 interleaveComma(dense, os, [&](
const APInt &val) {
1710 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1715 if (
auto iType = dyn_cast<IndexType>(
1716 cast<ShapedType>(dense.getType()).getElementType())) {
1718 interleaveComma(dense, os,
1719 [&](
const APInt &val) { printInt(val,
false); });
1726 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1727 os << oAttr.getValue();
1732 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1733 if (sAttr.getNestedReferences().size() > 1)
1734 return emitError(loc,
"attribute has more than 1 nested reference");
1735 os << sAttr.getRootReference().getValue();
1740 if (
auto type = dyn_cast<TypeAttr>(attr))
1741 return emitType(loc, type.getValue());
1743 return emitError(loc,
"cannot emit attribute: ") << attr;
1746LogicalResult CppEmitter::emitExpression(Operation *op) {
1747 assert(emittedExpressionPrecedence.empty() &&
1748 "Expected precedence stack to be empty");
1749 Operation *rootOp =
nullptr;
1751 if (
auto expressionOp = dyn_cast<ExpressionOp>(op)) {
1752 rootOp = expressionOp.getRootOp();
1754 assert(cast<CExpressionInterface>(op).alwaysInline() &&
1755 "Expected an always-inline operation");
1757 "Expected operation to have no containing expression");
1763 pushExpressionPrecedence(precedence.value());
1765 if (
failed(emitOperation(*rootOp,
false)))
1768 popExpressionPrecedence();
1769 assert(emittedExpressionPrecedence.empty() &&
1770 "Expected precedence stack to be empty");
1775LogicalResult CppEmitter::emitOperand(Value value,
bool isInBrackets) {
1776 if (isPartOfCurrentExpression(value)) {
1778 assert(def &&
"Expected operand to be defined by an operation");
1779 if (
auto expressionOp = dyn_cast<ExpressionOp>(def))
1780 def = expressionOp.getRootOp();
1783 if (
auto loadOp = dyn_cast<emitc::LoadOp>(def))
1784 return emitOperand(loadOp.getOperand(), isInBrackets);
1792 bool encloseInParenthesis =
1793 !isInBrackets && precedence.value() <= getExpressionPrecedence();
1795 if (encloseInParenthesis)
1797 pushExpressionPrecedence(precedence.value());
1799 if (
failed(emitOperation(*def,
false)))
1802 if (encloseInParenthesis)
1805 popExpressionPrecedence();
1810 return emitExpression(def);
1812 if (BlockArgument arg = dyn_cast<BlockArgument>(value)) {
1815 Operation *argOp = arg.getParentBlock()->getParentOp();
1816 if (
auto expressionOp = dyn_cast<ExpressionOp>(argOp))
1817 return emitOperand(expressionOp->getOperand(arg.getArgNumber()));
1820 os << getOrCreateName(value);
1824LogicalResult CppEmitter::emitOperands(Operation &op) {
1828 return emitOperand(operand, true);
1833CppEmitter::emitOperandsAndAttributes(Operation &op,
1834 ArrayRef<StringRef> exclude) {
1835 if (
failed(emitOperands(op)))
1840 for (NamedAttribute attr : attrs) {
1841 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1848 auto emitNamedAttribute = [&](NamedAttribute attr) -> LogicalResult {
1849 if (llvm::is_contained(exclude, attr.getName().strref()))
1851 os <<
"/* " << attr.getName().getValue() <<
" */";
1852 if (
failed(emitAttribute(op.
getLoc(), attr.getValue())))
1859LogicalResult CppEmitter::emitVariableAssignment(OpResult
result) {
1860 if (!hasValueInScope(
result)) {
1861 return result.getDefiningOp()->emitOpError(
1862 "result variable for the operation has not been declared");
1864 os << getOrCreateName(
result) <<
" = ";
1868LogicalResult CppEmitter::emitVariableDeclaration(OpResult
result,
1869 bool trailingSemicolon) {
1870 if (
auto cExpression =
1871 dyn_cast<CExpressionInterface>(
result.getDefiningOp())) {
1872 if (cExpression.alwaysInline())
1875 if (hasValueInScope(
result)) {
1876 return result.getDefiningOp()->emitError(
1877 "result variable for the operation already declared");
1879 if (
failed(emitVariableDeclaration(
result.getOwner()->getLoc(),
1881 getOrCreateName(
result))))
1883 if (trailingSemicolon)
1888LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1889 if (op.getExternSpecifier())
1891 else if (op.getStaticSpecifier())
1893 if (op.getConstSpecifier())
1896 if (
failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1897 op.getSymName()))) {
1901 std::optional<Attribute> initialValue = op.getInitialValue();
1904 if (
failed(emitAttribute(op->getLoc(), *initialValue)))
1912LogicalResult CppEmitter::emitAssignPrefix(Operation &op) {
1914 if (isEmittingExpression())
1922 if (shouldDeclareVariablesAtTop()) {
1933 if (!shouldDeclareVariablesAtTop()) {
1941 [&](Value
result) { os << getOrCreateName(result); });
1947LogicalResult CppEmitter::emitLabel(
Block &block) {
1948 if (!hasBlockLabel(block))
1952 os.getOStream() << getOrCreateName(block) <<
":\n";
1956LogicalResult CppEmitter::emitOperation(Operation &op,
bool trailingSemicolon) {
1957 LogicalResult status =
1958 llvm::TypeSwitch<Operation *, LogicalResult>(&op)
1962 .Case<cf::BranchOp, cf::CondBranchOp>(
1965 .Case<emitc::AddAssignOp, emitc::AddressOfOp, emitc::AddOp,
1966 emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1967 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1968 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1969 emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
1970 emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1971 emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivAssignOp,
1972 emitc::DivOp, emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp,
1973 emitc::FileOp, emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
1974 emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
1975 emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
1976 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1977 emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
1978 emitc::MemberOp, emitc::MulAssignOp, emitc::MulOp,
1979 emitc::PostDecrementOp, emitc::PostIncrementOp,
1980 emitc::PreDecrementOp, emitc::PreIncrementOp,
1981 emitc::RemAssignOp, emitc::RemOp, emitc::ReturnOp,
1982 emitc::SubAssignOp, emitc::SubscriptOp, emitc::SubOp,
1983 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1984 emitc::VariableOp, emitc::VerbatimOp>(
1988 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1990 .Default([&](Operation *) {
1991 return op.emitOpError(
"unable to find printer for op");
1997 if (
auto cExpression = dyn_cast<CExpressionInterface>(op)) {
1998 if (cExpression.alwaysInline())
2002 if (isEmittingExpression() ||
2003 (isa<emitc::ExpressionOp>(op) &&
2009 trailingSemicolon &=
2010 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::DoOp, emitc::FileOp,
2011 emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp,
2012 emitc::VerbatimOp>(op);
2014 os << (trailingSemicolon ?
";\n" :
"\n");
2019LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
2021 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
2022 if (
failed(emitType(loc, arrType.getElementType())))
2025 for (
auto dim : arrType.getShape()) {
2026 os <<
"[" << dim <<
"]";
2030 if (
failed(emitType(loc, type)))
2036LogicalResult CppEmitter::emitType(Location loc, Type type) {
2037 if (
auto iType = dyn_cast<IntegerType>(type)) {
2038 switch (iType.getWidth()) {
2040 return (os <<
"bool"),
success();
2045 if (shouldMapToUnsigned(iType.getSignedness()))
2046 return (os <<
"uint" << iType.getWidth() <<
"_t"),
success();
2048 return (os <<
"int" << iType.getWidth() <<
"_t"),
success();
2050 return emitError(loc,
"cannot emit integer type ") << type;
2053 if (
auto fType = dyn_cast<FloatType>(type)) {
2054 switch (fType.getWidth()) {
2056 if (llvm::isa<Float16Type>(type))
2057 return (os <<
"_Float16"),
success();
2058 if (llvm::isa<BFloat16Type>(type))
2059 return (os <<
"__bf16"),
success();
2061 return emitError(loc,
"cannot emit float type ") << type;
2064 return (os <<
"float"),
success();
2066 return (os <<
"double"),
success();
2068 return emitError(loc,
"cannot emit float type ") << type;
2071 if (
auto iType = dyn_cast<IndexType>(type))
2072 return (os <<
"size_t"),
success();
2073 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
2074 return (os <<
"size_t"),
success();
2075 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
2076 return (os <<
"ssize_t"),
success();
2077 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
2078 return (os <<
"ptrdiff_t"),
success();
2079 if (
auto tType = dyn_cast<TensorType>(type)) {
2080 if (!tType.hasRank())
2081 return emitError(loc,
"cannot emit unranked tensor type");
2082 if (!tType.hasStaticShape())
2083 return emitError(loc,
"cannot emit tensor type with non static shape");
2085 if (isa<ArrayType>(tType.getElementType()))
2086 return emitError(loc,
"cannot emit tensor of array type ") << type;
2087 if (
failed(emitType(loc, tType.getElementType())))
2089 auto shape = tType.getShape();
2090 for (
auto dimSize : shape) {
2097 if (
auto tType = dyn_cast<TupleType>(type))
2098 return emitTupleType(loc, tType.getTypes());
2099 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
2100 os << oType.getValue();
2103 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
2104 if (
failed(emitType(loc, aType.getElementType())))
2106 for (
auto dim : aType.getShape())
2107 os <<
"[" << dim <<
"]";
2110 if (
auto lType = dyn_cast<emitc::LValueType>(type))
2111 return emitType(loc, lType.getValueType());
2112 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
2113 if (isa<ArrayType>(pType.getPointee()))
2114 return emitError(loc,
"cannot emit pointer to array type ") << type;
2115 if (
failed(emitType(loc, pType.getPointee())))
2120 return emitError(loc,
"cannot emit type ") << type;
2123LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
2124 switch (types.size()) {
2129 return emitType(loc, types.front());
2131 return emitTupleType(loc, types);
2135LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
2136 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
2137 return emitError(loc,
"cannot emit tuple of array type");
2139 os <<
"std::tuple<";
2141 types, os, [&](Type type) {
return emitType(loc, type); })))
2147void CppEmitter::resetValueCounter() { valueCount = 0; }
2149void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
2151void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
2154 bool declareVariablesAtTop,
2156 CppEmitter emitter(os, declareVariablesAtTop, fileId);
2157 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 printCompoundAssignmentOperation(CppEmitter &emitter, Operation *operation, StringRef compoundAssignmentOperator)
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 printPostfixUnaryOperation(CppEmitter &emitter, Operation *operation, StringRef unaryOperator)
static LogicalResult interleaveWithError(ForwardIterator begin, ForwardIterator end, UnaryFunctor eachFn, NullaryFunctor betweenFn)
Convenience functions to produce interleaved output with functions returning a LogicalResult.
static LogicalResult printOpaqueCallCommon(CppEmitter &emitter, OpTy op, StringRef callee, std::optional< ArrayAttr > templateArgs, std::optional< ArrayAttr > args, bool isMemberCall, Value receiver=nullptr)
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)
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...
auto getDiscardableAttrs()
Return a range of all of discardable attributes on this operation.
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.