22#include "llvm/ADT/ScopedHashTable.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/TypeSwitch.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/FormatVariadic.h"
30#define DEBUG_TYPE "translate-to-cpp"
40 typename NullaryFunctor>
41static inline LogicalResult
43 UnaryFunctor eachFn, NullaryFunctor betweenFn) {
46 if (failed(eachFn(*begin)))
49 for (; begin != end; ++begin) {
51 if (failed(eachFn(*begin)))
57template <
typename Container,
typename UnaryFunctor,
typename NullaryFunctor>
60 NullaryFunctor betweenFn) {
64template <
typename Container,
typename UnaryFunctor>
67 UnaryFunctor eachFn) {
75 .Case([&](emitc::AddressOfOp op) {
return 15; })
76 .Case([&](emitc::AddOp op) {
return 12; })
77 .Case([&](emitc::BitwiseAndOp op) {
return 7; })
78 .Case([&](emitc::BitwiseLeftShiftOp op) {
return 11; })
79 .Case([&](emitc::BitwiseNotOp op) {
return 15; })
80 .Case([&](emitc::BitwiseOrOp op) {
return 5; })
81 .Case([&](emitc::BitwiseRightShiftOp op) {
return 11; })
82 .Case([&](emitc::BitwiseXorOp op) {
return 6; })
83 .Case([&](emitc::CallOp op) {
return 16; })
84 .Case([&](emitc::CallOpaqueOp op) {
return 16; })
85 .Case([&](emitc::CastOp op) {
return 15; })
86 .Case([&](emitc::CmpOp 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 op) {
return 2; })
102 .Case([&](emitc::ConstantOp op) {
return 17; })
103 .Case([&](emitc::DereferenceOp op) {
return 15; })
104 .Case([&](emitc::DivOp op) {
return 13; })
105 .Case([&](emitc::GetGlobalOp op) {
return 18; })
106 .Case([&](emitc::GetFieldOp op) {
return 18; })
107 .Case([&](emitc::LiteralOp op) {
return 18; })
108 .Case([&](emitc::LoadOp op) {
return 16; })
109 .Case([&](emitc::LogicalAndOp op) {
return 4; })
110 .Case([&](emitc::LogicalNotOp op) {
return 15; })
111 .Case([&](emitc::LogicalOrOp op) {
return 3; })
112 .Case([&](emitc::MemberOfPtrOp op) {
return 17; })
113 .Case([&](emitc::MemberOp op) {
return 17; })
114 .Case([&](emitc::MulOp op) {
return 13; })
115 .Case([&](emitc::PostDecrementOp op) {
return 16; })
116 .Case([&](emitc::PostIncrementOp op) {
return 16; })
117 .Case([&](emitc::PreDecrementOp op) {
return 15; })
118 .Case([&](emitc::PreIncrementOp op) {
return 15; })
119 .Case([&](emitc::RemOp op) {
return 13; })
120 .Case([&](emitc::SubOp op) {
return 12; })
121 .Case([&](emitc::SubscriptOp op) {
return 17; })
122 .Case([&](emitc::UnaryMinusOp op) {
return 15; })
123 .Case([&](emitc::UnaryPlusOp op) {
return 15; })
124 .Default([](
auto op) {
return op->emitError(
"unsupported operation"); });
132 explicit CppEmitter(raw_ostream &os,
bool declareVariablesAtTop,
136 LogicalResult emitAttribute(Location loc, Attribute attr);
143 LogicalResult emitOperation(Operation &op,
bool trailingSemicolon);
146 LogicalResult emitType(Location loc, Type type);
152 LogicalResult emitTypes(Location loc, ArrayRef<Type> types);
156 LogicalResult emitTupleType(Location loc, ArrayRef<Type> types);
159 LogicalResult emitVariableAssignment(OpResult
result);
162 LogicalResult emitVariableDeclaration(OpResult
result,
163 bool trailingSemicolon);
166 LogicalResult emitVariableDeclaration(Location loc, Type type,
175 LogicalResult emitAssignPrefix(Operation &op);
178 LogicalResult emitGlobalVariable(GlobalOp op);
181 LogicalResult emitLabel(
Block &block);
185 LogicalResult emitOperandsAndAttributes(Operation &op,
186 ArrayRef<StringRef> exclude = {});
189 LogicalResult emitOperands(Operation &op);
195 LogicalResult emitOperand(Value value,
bool isInBrackets =
false);
198 LogicalResult emitExpression(Operation *op);
201 StringRef getOrCreateName(Value val);
205 StringRef getOrCreateInductionVarName(Value val);
208 StringRef getOrCreateName(
Block &block);
210 LogicalResult emitInlinedExpression(Value value);
213 bool shouldMapToUnsigned(IntegerType::SignednessSemantics val);
217 ~Scope() { emitter.labelInScopeCount.pop(); }
220 llvm::ScopedHashTableScope<Value, std::string> valueMapperScope;
221 llvm::ScopedHashTableScope<Block *, std::string> blockMapperScope;
224 Scope(CppEmitter &emitter)
225 : valueMapperScope(emitter.valueMapper),
226 blockMapperScope(emitter.blockMapper), emitter(emitter) {
227 emitter.labelInScopeCount.push(emitter.labelInScopeCount.top());
234 struct FunctionScope : Scope {
235 FunctionScope(CppEmitter &emitter) : Scope(emitter) {
237 emitter.resetValueCounter();
243 struct LoopScope : Scope {
244 LoopScope(CppEmitter &emitter) : Scope(emitter) {
245 emitter.increaseLoopNestingLevel();
247 ~LoopScope() { emitter.decreaseLoopNestingLevel(); }
251 bool hasValueInScope(Value val);
254 bool hasBlockLabel(
Block &block);
257 raw_indented_ostream &ostream() {
return os; };
261 bool shouldDeclareVariablesAtTop() {
return declareVariablesAtTop; };
264 bool shouldEmitFile(FileOp file) {
265 return !fileId.empty() && file.getId() == fileId;
269 bool isEmittingExpression() {
return !emittedExpressionPrecedence.empty(); }
273 bool isPartOfCurrentExpression(Value value) {
275 return def ? isPartOfCurrentExpression(def) :
false;
280 bool isPartOfCurrentExpression(Operation *def) {
285 void resetValueCounter();
288 void increaseLoopNestingLevel();
291 void decreaseLoopNestingLevel();
294 using ValueMapper = llvm::ScopedHashTable<Value, std::string>;
295 using BlockMapper = llvm::ScopedHashTable<Block *, std::string>;
298 raw_indented_ostream os;
303 bool declareVariablesAtTop;
309 ValueMapper valueMapper;
312 BlockMapper blockMapper;
315 llvm::ScopedHashTableScope<Value, std::string> defaultValueMapperScope;
316 llvm::ScopedHashTableScope<Block *, std::string> defaultBlockMapperScope;
318 std::stack<int64_t> labelInScopeCount;
322 uint64_t loopNestingLevel{0};
325 unsigned int valueCount{0};
328 SmallVector<int> emittedExpressionPrecedence;
330 void pushExpressionPrecedence(
int precedence) {
331 emittedExpressionPrecedence.push_back(precedence);
333 void popExpressionPrecedence() { emittedExpressionPrecedence.pop_back(); }
334 static int lowestPrecedence() {
return 0; }
335 int getExpressionPrecedence() {
336 if (emittedExpressionPrecedence.empty())
337 return lowestPrecedence();
338 return emittedExpressionPrecedence.back();
351 if (
auto cExpression = dyn_cast<CExpressionInterface>(op))
352 return cExpression.alwaysInline() || isa<ExpressionOp>(op->
getParentOp());
355 ExpressionOp expressionOp = dyn_cast<ExpressionOp>(op);
360 if (cast<CExpressionInterface>(expressionOp.getRootOp()).alwaysInline())
364 if (expressionOp.getDoNotInline())
377 if (isa<emitc::ExpressionOp, emitc::CExpressionInterface>(*user))
381 if (!expressionOp.hasSideEffects())
392 if (isa<emitc::IfOp, emitc::SwitchOp, emitc::ReturnOp>(user))
397 if (
auto assignOp = dyn_cast<emitc::AssignOp>(user)) {
399 if (expressionOp.getResult() == assignOp.getValue() &&
400 isa_and_present<VariableOp>(assignOp.getVar().getDefiningOp()))
411 while (
auto subscriptOp = value.
getDefiningOp<emitc::SubscriptOp>()) {
412 value = subscriptOp.getValue();
415 auto getGlobalOp = value.
getDefiningOp<emitc::GetGlobalOp>();
421 fromOp, getGlobalOp.getNameAttr());
423 if (globalOp && globalOp.getConstSpecifier())
438 if (failed(emitter.emitOperand(operand)))
445 emitc::DereferenceOp dereferenceOp) {
447 Operation &op = *dereferenceOp.getOperation();
449 if (failed(emitter.emitAssignPrefix(op)))
452 return emitter.emitOperand(dereferenceOp.getPointer());
456 emitc::GetFieldOp getFieldOp) {
457 if (!emitter.isPartOfCurrentExpression(getFieldOp.getOperation()))
460 emitter.ostream() << getFieldOp.getFieldName();
465 emitc::GetGlobalOp getGlobalOp) {
466 if (!emitter.isPartOfCurrentExpression(getGlobalOp.getOperation()))
469 emitter.ostream() << getGlobalOp.getName();
474 emitc::LiteralOp literalOp) {
475 if (!emitter.isPartOfCurrentExpression(literalOp.getOperation()))
478 emitter.ostream() << literalOp.getValue();
483 emitc::MemberOp memberOp) {
484 if (memberOp.alwaysInline()) {
485 if (!emitter.isPartOfCurrentExpression(memberOp.getOperation()))
488 if (failed(emitter.emitAssignPrefix(*memberOp.getOperation())))
491 if (failed(emitter.emitOperand(memberOp.getOperand())))
493 emitter.ostream() <<
"." << memberOp.getMember();
498 emitc::MemberOfPtrOp memberOfPtrOp) {
499 if (!emitter.isPartOfCurrentExpression(memberOfPtrOp.getOperation()))
502 if (failed(emitter.emitOperand(memberOfPtrOp.getOperand())))
504 emitter.ostream() <<
"->" << memberOfPtrOp.getMember();
509 emitc::SubscriptOp subscriptOp) {
510 if (!emitter.isPartOfCurrentExpression(subscriptOp.getOperation())) {
515 if (failed(emitter.emitOperand(subscriptOp.getValue())))
517 for (
auto index : subscriptOp.getIndices()) {
519 if (failed(emitter.emitOperand(
index,
true)))
532 if (emitter.shouldDeclareVariablesAtTop()) {
534 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
535 if (oAttr.getValue().empty())
539 if (failed(emitter.emitVariableAssignment(
result)))
541 return emitter.emitAttribute(operation->
getLoc(), value);
545 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(value)) {
546 if (oAttr.getValue().empty())
548 return emitter.emitVariableDeclaration(
result,
553 if (failed(emitter.emitAssignPrefix(*operation)))
555 return emitter.emitAttribute(operation->
getLoc(), value);
559 emitc::AddressOfOp addressOfOp) {
561 Operation &op = *addressOfOp.getOperation();
563 if (failed(emitter.emitAssignPrefix(op)))
566 Value operand = addressOfOp.getReference();
573 return emitter.emitOperand(operand);
577 emitc::ConstantOp constantOp) {
578 Operation *operation = constantOp.getOperation();
581 if (emitter.isPartOfCurrentExpression(operation))
582 return emitter.emitAttribute(operation->
getLoc(), value);
588 emitc::VariableOp variableOp) {
589 Operation *operation = variableOp.getOperation();
596 emitc::GlobalOp globalOp) {
598 return emitter.emitGlobalVariable(globalOp);
602 emitc::AssignOp assignOp) {
603 if (failed(emitter.emitOperand(assignOp.getVar())))
606 emitter.ostream() <<
" = ";
608 return emitter.emitOperand(assignOp.getValue());
613 StringRef compoundAssignmentOperator) {
614 if (failed(emitter.emitOperand(operation->
getOperand(0))))
617 emitter.ostream() <<
" " << compoundAssignmentOperator <<
" ";
619 return emitter.emitOperand(operation->
getOperand(1));
623 emitc::AddAssignOp addAssignOp) {
628 emitc::SubAssignOp subAssignOp) {
633 emitc::MulAssignOp mulAssignOp) {
638 emitc::DivAssignOp divAssignOp) {
643 emitc::RemAssignOp remAssignOp) {
648 if (failed(emitter.emitAssignPrefix(*loadOp)))
651 return emitter.emitOperand(loadOp.getOperand());
656 StringRef binaryOperator) {
659 if (failed(emitter.emitAssignPrefix(*operation)))
662 if (failed(emitter.emitOperand(operation->
getOperand(0))))
665 os <<
" " << binaryOperator <<
" ";
667 if (failed(emitter.emitOperand(operation->
getOperand(1))))
675 StringRef unaryOperator) {
678 if (failed(emitter.emitAssignPrefix(*operation)))
683 if (failed(emitter.emitOperand(operation->
getOperand(0))))
691 StringRef unaryOperator) {
694 if (failed(emitter.emitAssignPrefix(*operation)))
697 if (failed(emitter.emitOperand(operation->
getOperand(0))))
706 Operation *operation = addOp.getOperation();
712 Operation *operation = divOp.getOperation();
718 Operation *operation = mulOp.getOperation();
724 Operation *operation = remOp.getOperation();
730 Operation *operation = subOp.getOperation();
738 std::next(iteratorOp) != end; ++iteratorOp) {
739 if (failed(emitter.emitOperation(*iteratorOp,
true)))
747 emitc::SwitchOp switchOp) {
751 if (failed(emitter.emitOperand(switchOp.getArg())))
755 for (
auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
756 os <<
"\ncase " << std::get<0>(pair) <<
": {\n";
765 os <<
"\ndefault: {\n";
768 if (failed(
emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
781 Block &bodyBlock = doOp.getBodyRegion().
front();
783 if (failed(emitter.emitOperation(op,
true)))
789 Block &condBlock = doOp.getConditionRegion().
front();
790 auto condYield = cast<emitc::YieldOp>(condBlock.
back());
791 if (failed(emitter.emitExpression(
792 cast<emitc::ExpressionOp>(condYield.getOperand(0).getDefiningOp()))))
800 Operation *operation = cmpOp.getOperation();
802 StringRef binaryOperator;
804 switch (cmpOp.getPredicate()) {
805 case emitc::CmpPredicate::eq:
806 binaryOperator =
"==";
808 case emitc::CmpPredicate::ne:
809 binaryOperator =
"!=";
811 case emitc::CmpPredicate::lt:
812 binaryOperator =
"<";
814 case emitc::CmpPredicate::le:
815 binaryOperator =
"<=";
817 case emitc::CmpPredicate::gt:
818 binaryOperator =
">";
820 case emitc::CmpPredicate::ge:
821 binaryOperator =
">=";
823 case emitc::CmpPredicate::three_way:
824 binaryOperator =
"<=>";
832 emitc::ConditionalOp conditionalOp) {
835 if (failed(emitter.emitAssignPrefix(*conditionalOp)))
838 if (failed(emitter.emitOperand(conditionalOp.getCondition())))
843 if (failed(emitter.emitOperand(conditionalOp.getTrueValue())))
848 if (failed(emitter.emitOperand(conditionalOp.getFalseValue())))
855 emitc::VerbatimOp verbatimOp) {
858 FailureOr<SmallVector<ReplacementItem>> items =
859 verbatimOp.parseFormatString();
863 auto fmtArg = verbatimOp.getFmtArgs().begin();
866 if (
auto *str = std::get_if<StringRef>(&item)) {
869 if (failed(emitter.emitOperand(*fmtArg++)))
878 cf::BranchOp branchOp) {
883 llvm::zip(branchOp.getOperands(), successor.
getArguments())) {
884 Value &operand = std::get<0>(pair);
886 os << emitter.getOrCreateName(argument) <<
" = "
887 << emitter.getOrCreateName(operand) <<
";\n";
891 if (!(emitter.hasBlockLabel(successor)))
892 return branchOp.emitOpError(
"unable to find label for successor block");
893 os << emitter.getOrCreateName(successor);
898 cf::CondBranchOp condBranchOp) {
900 Block &trueSuccessor = *condBranchOp.getTrueDest();
901 Block &falseSuccessor = *condBranchOp.getFalseDest();
904 if (failed(emitter.emitOperand(condBranchOp.getCondition())))
911 for (
auto pair : llvm::zip(condBranchOp.getTrueOperands(),
913 Value &operand = std::get<0>(pair);
915 os << emitter.getOrCreateName(argument) <<
" = "
916 << emitter.getOrCreateName(operand) <<
";\n";
920 if (!(emitter.hasBlockLabel(trueSuccessor))) {
921 return condBranchOp.emitOpError(
"unable to find label for successor block");
923 os << emitter.getOrCreateName(trueSuccessor) <<
";\n";
927 for (
auto pair : llvm::zip(condBranchOp.getFalseOperands(),
929 Value &operand = std::get<0>(pair);
931 os << emitter.getOrCreateName(argument) <<
" = "
932 << emitter.getOrCreateName(operand) <<
";\n";
936 if (!(emitter.hasBlockLabel(falseSuccessor))) {
937 return condBranchOp.emitOpError()
938 <<
"unable to find label for successor block";
940 os << emitter.getOrCreateName(falseSuccessor) <<
";\n";
947 if (failed(emitter.emitAssignPrefix(*callOp)))
952 if (failed(emitter.emitOperands(*callOp)))
959 Operation *operation = callOp.getOperation();
960 StringRef callee = callOp.getCallee();
966 Operation *operation = callOp.getOperation();
967 StringRef callee = callOp.getCallee();
972template <
typename OpTy>
975 std::optional<ArrayAttr> templateArgs,
976 std::optional<ArrayAttr> args,
bool isMemberCall,
977 Value receiver =
nullptr) {
980 if (failed(emitter.emitAssignPrefix(*op.getOperation())))
984 assert(receiver &&
"Expected receiver for member call");
985 if (failed(emitter.emitOperand(receiver)))
988 if (llvm::isa<emitc::PointerType>(receiver.getType()))
1000 auto emitTemplateArgs = [&](
Attribute attr) -> LogicalResult {
1001 return emitter.emitAttribute(op.getLoc(), attr);
1011 auto emitArgs = [&](
Attribute attr) -> LogicalResult {
1012 if (
auto t = dyn_cast<IntegerAttr>(attr)) {
1013 if (t.getType().isIndex()) {
1015 Value operand = op.getArgOperands()[idx];
1016 return emitter.emitOperand(operand,
false);
1019 if (failed(emitter.emitAttribute(op.getLoc(), attr)))
1027 LogicalResult emittedArgs =
success();
1033 return emitter.emitOperand(operand, true);
1036 if (failed(emittedArgs))
1043 emitc::CallOpaqueOp callOpaqueOp) {
1045 callOpaqueOp.getTemplateArgs(),
1046 callOpaqueOp.getArgs(),
1052 emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
1054 emitter, memberCallOpaqueOp, memberCallOpaqueOp.getCallee(),
1055 memberCallOpaqueOp.getTemplateArgs(), memberCallOpaqueOp.getArgs(),
1056 true, memberCallOpaqueOp.getReceiver());
1060 emitc::BitwiseAndOp bitwiseAndOp) {
1061 Operation *operation = bitwiseAndOp.getOperation();
1067 emitc::BitwiseLeftShiftOp bitwiseLeftShiftOp) {
1068 Operation *operation = bitwiseLeftShiftOp.getOperation();
1073 emitc::BitwiseNotOp bitwiseNotOp) {
1074 Operation *operation = bitwiseNotOp.getOperation();
1079 emitc::BitwiseOrOp bitwiseOrOp) {
1080 Operation *operation = bitwiseOrOp.getOperation();
1086 emitc::BitwiseRightShiftOp bitwiseRightShiftOp) {
1087 Operation *operation = bitwiseRightShiftOp.getOperation();
1092 emitc::BitwiseXorOp bitwiseXorOp) {
1093 Operation *operation = bitwiseXorOp.getOperation();
1098 emitc::PreIncrementOp preIncrementOp) {
1099 Operation *operation = preIncrementOp.getOperation();
1104 emitc::PostIncrementOp postIncrementOp) {
1105 Operation *operation = postIncrementOp.getOperation();
1110 emitc::PreDecrementOp preDecrementOp) {
1111 Operation *operation = preDecrementOp.getOperation();
1116 emitc::PostDecrementOp postDecrementOp) {
1117 Operation *operation = postDecrementOp.getOperation();
1122 emitc::UnaryPlusOp unaryPlusOp) {
1123 Operation *operation = unaryPlusOp.getOperation();
1128 emitc::UnaryMinusOp unaryMinusOp) {
1129 Operation *operation = unaryMinusOp.getOperation();
1137 if (failed(emitter.emitAssignPrefix(op)))
1143 return emitter.emitOperand(castOp.getOperand());
1147 emitc::ExpressionOp expressionOp) {
1151 Operation &op = *expressionOp.getOperation();
1153 if (failed(emitter.emitAssignPrefix(op)))
1156 return emitter.emitExpression(expressionOp);
1160 emitc::IncludeOp includeOp) {
1164 if (includeOp.getIsStandardInclude())
1165 os <<
"<" << includeOp.getInclude() <<
">";
1167 os <<
"\"" << includeOp.getInclude() <<
"\"";
1173 emitc::LogicalAndOp logicalAndOp) {
1174 Operation *operation = logicalAndOp.getOperation();
1179 emitc::LogicalNotOp logicalNotOp) {
1180 Operation *operation = logicalNotOp.getOperation();
1185 emitc::LogicalOrOp logicalOrOp) {
1186 Operation *operation = logicalOrOp.getOperation();
1196 auto requiresParentheses = [&](
Value value) {
1205 emitter.emitType(forOp.getLoc(), forOp.getInductionVar().getType())))
1208 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1210 if (failed(emitter.emitOperand(forOp.getLowerBound())))
1213 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1215 Value upperBound = forOp.getUpperBound();
1216 bool upperBoundRequiresParentheses = requiresParentheses(upperBound);
1217 if (upperBoundRequiresParentheses)
1219 if (failed(emitter.emitOperand(upperBound)))
1221 if (upperBoundRequiresParentheses)
1224 os << emitter.getOrCreateInductionVarName(forOp.getInductionVar());
1226 if (failed(emitter.emitOperand(forOp.getStep())))
1231 CppEmitter::LoopScope lScope(emitter);
1233 Region &forRegion = forOp.getRegion();
1234 auto regionOps = forRegion.
getOps();
1237 for (
auto it = regionOps.begin(); std::next(it) != regionOps.end(); ++it) {
1238 if (failed(emitter.emitOperation(*it,
true)))
1252 auto emitAllExceptLast = [&emitter](
Region ®ion) {
1254 for (; std::next(it) != end; ++it) {
1255 if (failed(emitter.emitOperation(*it,
true)))
1258 assert(isa<emitc::YieldOp>(*it) &&
1259 "Expected last operation in the region to be emitc::yield");
1264 if (failed(emitter.emitOperand(ifOp.getCondition())))
1268 if (failed(emitAllExceptLast(ifOp.getThenRegion())))
1272 Region &elseRegion = ifOp.getElseRegion();
1273 if (!elseRegion.
empty()) {
1276 if (failed(emitAllExceptLast(elseRegion)))
1285 func::ReturnOp returnOp) {
1288 switch (returnOp.getNumOperands()) {
1293 if (failed(emitter.emitOperand(returnOp.getOperand(0))))
1297 os <<
" std::make_tuple(";
1298 if (failed(emitter.emitOperandsAndAttributes(*returnOp.getOperation())))
1306 emitc::ReturnOp returnOp) {
1309 if (returnOp.getNumOperands() == 0)
1313 if (failed(emitter.emitOperand(returnOp.getOperand())))
1320 if (failed(emitter.emitOperation(op,
false)))
1328 ClassType classType = classOp.getClassType();
1329 os << stringifyClassType(classType) <<
" " << classOp.getSymName();
1330 if (classOp.getFinalSpecifier())
1334 if (classType == ClassType::class_)
1340 if (failed(emitter.emitOperation(op,
false)))
1351 if (failed(emitter.emitVariableDeclaration(
1352 fieldOp->getLoc(), fieldOp.getType(), fieldOp.getSymName())))
1354 std::optional<Attribute> initialValue = fieldOp.getInitialValue();
1357 if (failed(emitter.emitAttribute(fieldOp->getLoc(), *initialValue)))
1366 if (!emitter.shouldEmitFile(file))
1370 if (failed(emitter.emitOperation(op,
false)))
1383 return emitter.emitType(functionOp->
getLoc(), arg);
1394 return emitter.emitVariableDeclaration(
1395 functionOp->
getLoc(), arg.
getType(), emitter.getOrCreateName(arg));
1405 if (emitter.shouldDeclareVariablesAtTop()) {
1410 if (isa<emitc::ExpressionOp>(op->
getParentOp()) ||
1411 (isa<emitc::ExpressionOp>(op) &&
1415 if (failed(emitter.emitVariableDeclaration(
1418 op->
emitError(
"unable to declare result variable for op"));
1423 if (
result.wasInterrupted())
1428 for (
Block &block : blocks) {
1429 emitter.getOrCreateName(block);
1433 for (
Block &block : llvm::drop_begin(blocks)) {
1435 if (emitter.hasValueInScope(arg))
1436 return functionOp->
emitOpError(
" block argument #")
1437 << arg.getArgNumber() <<
" is out of scope";
1438 if (isa<ArrayType, LValueType>(arg.getType()))
1439 return functionOp->
emitOpError(
"cannot emit block argument #")
1440 << arg.getArgNumber() <<
" with type " << arg.getType();
1442 emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
1445 os <<
" " << emitter.getOrCreateName(arg) <<
";\n";
1449 for (
Block &block : blocks) {
1451 if (!block.hasNoPredecessors()) {
1452 if (failed(emitter.emitLabel(block)))
1455 for (
Operation &op : block.getOperations()) {
1456 if (failed(emitter.emitOperation(op,
true)))
1467 func::FuncOp functionOp) {
1469 if (!emitter.shouldDeclareVariablesAtTop() &&
1470 functionOp.getBlocks().size() > 1) {
1471 return functionOp.emitOpError(
1472 "with multiple blocks needs variables declared at top");
1475 if (llvm::any_of(functionOp.getArgumentTypes(), llvm::IsaPred<LValueType>)) {
1476 return functionOp.emitOpError()
1477 <<
"cannot emit lvalue type as argument type";
1480 if (llvm::any_of(functionOp.getResultTypes(), llvm::IsaPred<ArrayType>)) {
1481 return functionOp.emitOpError() <<
"cannot emit array type as result type";
1484 CppEmitter::FunctionScope scope(emitter);
1486 if (failed(emitter.emitTypes(functionOp.getLoc(),
1487 functionOp.getFunctionType().getResults())))
1489 os <<
" " << functionOp.getName();
1492 Operation *operation = functionOp.getOperation();
1504 emitc::FuncOp functionOp) {
1506 if (!emitter.shouldDeclareVariablesAtTop() &&
1507 functionOp.getBlocks().size() > 1) {
1508 return functionOp.emitOpError(
1509 "with multiple blocks needs variables declared at top");
1512 CppEmitter::FunctionScope scope(emitter);
1514 if (functionOp.getSpecifiers()) {
1515 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1516 os << cast<StringAttr>(specifier).str() <<
" ";
1520 if (failed(emitter.emitTypes(functionOp.getLoc(),
1521 functionOp.getFunctionType().getResults())))
1523 os <<
" " << functionOp.getName();
1526 Operation *operation = functionOp.getOperation();
1527 if (functionOp.isExternal()) {
1529 functionOp.getArgumentTypes())))
1545 DeclareFuncOp declareFuncOp) {
1548 CppEmitter::FunctionScope scope(emitter);
1550 declareFuncOp, declareFuncOp.getSymNameAttr());
1555 if (functionOp.getSpecifiers()) {
1556 for (
Attribute specifier : functionOp.getSpecifiersAttr()) {
1557 os << cast<StringAttr>(specifier).str() <<
" ";
1561 if (failed(emitter.emitTypes(functionOp.getLoc(),
1562 functionOp.getFunctionType().getResults())))
1564 os <<
" " << functionOp.getName();
1567 Operation *operation = functionOp.getOperation();
1575CppEmitter::CppEmitter(
raw_ostream &os,
bool declareVariablesAtTop,
1577 : os(os), declareVariablesAtTop(declareVariablesAtTop),
1578 fileId(fileId.str()), defaultValueMapperScope(valueMapper),
1579 defaultBlockMapperScope(blockMapper) {
1580 labelInScopeCount.push(0);
1584StringRef CppEmitter::getOrCreateName(
Value val) {
1585 if (!valueMapper.count(val)) {
1586 valueMapper.insert(val, formatv(
"v{0}", ++valueCount));
1588 return *valueMapper.begin(val);
1593StringRef CppEmitter::getOrCreateInductionVarName(Value val) {
1594 if (!valueMapper.count(val)) {
1596 int64_t identifier =
'i' + loopNestingLevel;
1598 if (identifier >=
'i' && identifier <=
't') {
1599 valueMapper.insert(val,
1600 formatv(
"{0}{1}", (
char)identifier, ++valueCount));
1603 valueMapper.insert(val, formatv(
"u{0}", ++valueCount));
1606 return *valueMapper.begin(val);
1610StringRef CppEmitter::getOrCreateName(
Block &block) {
1611 if (!blockMapper.count(&block))
1612 blockMapper.insert(&block, formatv(
"label{0}", ++labelInScopeCount.top()));
1613 return *blockMapper.begin(&block);
1616bool CppEmitter::shouldMapToUnsigned(IntegerType::SignednessSemantics val) {
1618 case IntegerType::Signless:
1620 case IntegerType::Signed:
1622 case IntegerType::Unsigned:
1625 llvm_unreachable(
"Unexpected IntegerType::SignednessSemantics");
1628bool CppEmitter::hasValueInScope(Value val) {
return valueMapper.count(val); }
1630bool CppEmitter::hasBlockLabel(
Block &block) {
1631 return blockMapper.count(&block);
1634LogicalResult CppEmitter::emitAttribute(Location loc, Attribute attr) {
1635 auto printInt = [&](
const APInt &val,
bool isUnsigned) {
1636 if (val.getBitWidth() == 1) {
1637 if (val.getBoolValue())
1642 SmallString<128> strValue;
1643 val.toString(strValue, 10, !isUnsigned,
false);
1648 auto printFloat = [&](
const APFloat &val) {
1649 if (val.isFinite()) {
1650 SmallString<128> strValue;
1652 val.toString(strValue, 0, 0,
false);
1654 switch (llvm::APFloatBase::SemanticsToEnum(val.getSemantics())) {
1655 case llvm::APFloatBase::S_IEEEhalf:
1658 case llvm::APFloatBase::S_BFloat:
1661 case llvm::APFloatBase::S_IEEEsingle:
1664 case llvm::APFloatBase::S_IEEEdouble:
1667 llvm_unreachable(
"unsupported floating point type");
1669 }
else if (val.isNaN()) {
1671 }
else if (val.isInfinity()) {
1672 if (val.isNegative())
1679 if (
auto fAttr = dyn_cast<FloatAttr>(attr)) {
1680 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1683 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1685 printFloat(fAttr.getValue());
1688 if (
auto dense = dyn_cast<DenseFPElementsAttr>(attr)) {
1689 if (!isa<Float16Type, BFloat16Type, Float32Type, Float64Type>(
1690 dense.getElementType())) {
1692 loc,
"expected floating point attribute to be f16, bf16, f32 or f64");
1695 interleaveComma(dense, os, [&](
const APFloat &val) { printFloat(val); });
1701 if (
auto iAttr = dyn_cast<IntegerAttr>(attr)) {
1702 if (
auto iType = dyn_cast<IntegerType>(iAttr.getType())) {
1703 printInt(iAttr.getValue(), shouldMapToUnsigned(iType.getSignedness()));
1706 if (
auto iType = dyn_cast<IndexType>(iAttr.getType())) {
1707 printInt(iAttr.getValue(),
false);
1711 if (
auto dense = dyn_cast<DenseIntElementsAttr>(attr)) {
1712 if (
auto iType = dyn_cast<IntegerType>(
1713 cast<ShapedType>(dense.getType()).getElementType())) {
1715 interleaveComma(dense, os, [&](
const APInt &val) {
1716 printInt(val, shouldMapToUnsigned(iType.getSignedness()));
1721 if (
auto iType = dyn_cast<IndexType>(
1722 cast<ShapedType>(dense.getType()).getElementType())) {
1724 interleaveComma(dense, os,
1725 [&](
const APInt &val) { printInt(val,
false); });
1732 if (
auto oAttr = dyn_cast<emitc::OpaqueAttr>(attr)) {
1733 os << oAttr.getValue();
1738 if (
auto sAttr = dyn_cast<SymbolRefAttr>(attr)) {
1739 if (sAttr.getNestedReferences().size() > 1)
1740 return emitError(loc,
"attribute has more than 1 nested reference");
1741 os << sAttr.getRootReference().getValue();
1746 if (
auto type = dyn_cast<TypeAttr>(attr))
1747 return emitType(loc, type.getValue());
1749 return emitError(loc,
"cannot emit attribute: ") << attr;
1752LogicalResult CppEmitter::emitExpression(Operation *op) {
1753 assert(emittedExpressionPrecedence.empty() &&
1754 "Expected precedence stack to be empty");
1755 Operation *rootOp =
nullptr;
1757 if (
auto expressionOp = dyn_cast<ExpressionOp>(op)) {
1758 rootOp = expressionOp.getRootOp();
1760 assert(cast<CExpressionInterface>(op).alwaysInline() &&
1761 "Expected an always-inline operation");
1763 "Expected operation to have no containing expression");
1769 pushExpressionPrecedence(precedence.value());
1771 if (
failed(emitOperation(*rootOp,
false)))
1774 popExpressionPrecedence();
1775 assert(emittedExpressionPrecedence.empty() &&
1776 "Expected precedence stack to be empty");
1781LogicalResult CppEmitter::emitOperand(Value value,
bool isInBrackets) {
1782 if (isPartOfCurrentExpression(value)) {
1784 assert(def &&
"Expected operand to be defined by an operation");
1785 if (
auto expressionOp = dyn_cast<ExpressionOp>(def))
1786 def = expressionOp.getRootOp();
1794 bool encloseInParenthesis =
1795 !isInBrackets && precedence.value() <= getExpressionPrecedence();
1797 if (encloseInParenthesis)
1799 pushExpressionPrecedence(precedence.value());
1801 if (
failed(emitOperation(*def,
false)))
1804 if (encloseInParenthesis)
1807 popExpressionPrecedence();
1812 return emitExpression(def);
1814 if (BlockArgument arg = dyn_cast<BlockArgument>(value)) {
1817 Operation *argOp = arg.getParentBlock()->getParentOp();
1818 if (
auto expressionOp = dyn_cast<ExpressionOp>(argOp))
1819 return emitOperand(expressionOp->getOperand(arg.getArgNumber()));
1822 os << getOrCreateName(value);
1826LogicalResult CppEmitter::emitOperands(Operation &op) {
1830 return emitOperand(operand, true);
1835CppEmitter::emitOperandsAndAttributes(Operation &op,
1836 ArrayRef<StringRef> exclude) {
1837 if (
failed(emitOperands(op)))
1841 for (NamedAttribute attr : op.
getAttrs()) {
1842 if (!llvm::is_contained(exclude, attr.getName().strref())) {
1849 auto emitNamedAttribute = [&](NamedAttribute attr) -> LogicalResult {
1850 if (llvm::is_contained(exclude, attr.getName().strref()))
1852 os <<
"/* " << attr.getName().getValue() <<
" */";
1853 if (
failed(emitAttribute(op.
getLoc(), attr.getValue())))
1860LogicalResult CppEmitter::emitVariableAssignment(OpResult
result) {
1861 if (!hasValueInScope(
result)) {
1862 return result.getDefiningOp()->emitOpError(
1863 "result variable for the operation has not been declared");
1865 os << getOrCreateName(
result) <<
" = ";
1869LogicalResult CppEmitter::emitVariableDeclaration(OpResult
result,
1870 bool trailingSemicolon) {
1871 if (
auto cExpression =
1872 dyn_cast<CExpressionInterface>(
result.getDefiningOp())) {
1873 if (cExpression.alwaysInline())
1876 if (hasValueInScope(
result)) {
1877 return result.getDefiningOp()->emitError(
1878 "result variable for the operation already declared");
1880 if (
failed(emitVariableDeclaration(
result.getOwner()->getLoc(),
1882 getOrCreateName(
result))))
1884 if (trailingSemicolon)
1889LogicalResult CppEmitter::emitGlobalVariable(GlobalOp op) {
1890 if (op.getExternSpecifier())
1892 else if (op.getStaticSpecifier())
1894 if (op.getConstSpecifier())
1897 if (
failed(emitVariableDeclaration(op->getLoc(), op.getType(),
1898 op.getSymName()))) {
1902 std::optional<Attribute> initialValue = op.getInitialValue();
1905 if (
failed(emitAttribute(op->getLoc(), *initialValue)))
1913LogicalResult CppEmitter::emitAssignPrefix(Operation &op) {
1915 if (isEmittingExpression())
1923 if (shouldDeclareVariablesAtTop()) {
1934 if (!shouldDeclareVariablesAtTop()) {
1942 [&](Value
result) { os << getOrCreateName(result); });
1948LogicalResult CppEmitter::emitLabel(
Block &block) {
1949 if (!hasBlockLabel(block))
1953 os.getOStream() << getOrCreateName(block) <<
":\n";
1957LogicalResult CppEmitter::emitOperation(Operation &op,
bool trailingSemicolon) {
1958 LogicalResult status =
1959 llvm::TypeSwitch<Operation *, LogicalResult>(&op)
1963 .Case<cf::BranchOp, cf::CondBranchOp>(
1966 .Case<emitc::AddAssignOp, emitc::AddressOfOp, emitc::AddOp,
1967 emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1968 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
1969 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
1970 emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
1971 emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1972 emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivAssignOp,
1973 emitc::DivOp, emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp,
1974 emitc::FileOp, emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
1975 emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
1976 emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
1977 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
1978 emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
1979 emitc::MemberOp, emitc::MulAssignOp, emitc::MulOp,
1980 emitc::PostDecrementOp, emitc::PostIncrementOp,
1981 emitc::PreDecrementOp, emitc::PreIncrementOp,
1982 emitc::RemAssignOp, emitc::RemOp, emitc::ReturnOp,
1983 emitc::SubAssignOp, emitc::SubscriptOp, emitc::SubOp,
1984 emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
1985 emitc::VariableOp, emitc::VerbatimOp>(
1989 .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
1991 .Default([&](Operation *) {
1992 return op.emitOpError(
"unable to find printer for op");
1998 if (
auto cExpression = dyn_cast<CExpressionInterface>(op)) {
1999 if (cExpression.alwaysInline())
2003 if (isEmittingExpression() ||
2004 (isa<emitc::ExpressionOp>(op) &&
2010 trailingSemicolon &=
2011 !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::DoOp, emitc::FileOp,
2012 emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp,
2013 emitc::VerbatimOp>(op);
2015 os << (trailingSemicolon ?
";\n" :
"\n");
2020LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
2022 if (
auto arrType = dyn_cast<emitc::ArrayType>(type)) {
2023 if (
failed(emitType(loc, arrType.getElementType())))
2026 for (
auto dim : arrType.getShape()) {
2027 os <<
"[" << dim <<
"]";
2031 if (
failed(emitType(loc, type)))
2037LogicalResult CppEmitter::emitType(Location loc, Type type) {
2038 if (
auto iType = dyn_cast<IntegerType>(type)) {
2039 switch (iType.getWidth()) {
2041 return (os <<
"bool"),
success();
2046 if (shouldMapToUnsigned(iType.getSignedness()))
2047 return (os <<
"uint" << iType.getWidth() <<
"_t"),
success();
2049 return (os <<
"int" << iType.getWidth() <<
"_t"),
success();
2051 return emitError(loc,
"cannot emit integer type ") << type;
2054 if (
auto fType = dyn_cast<FloatType>(type)) {
2055 switch (fType.getWidth()) {
2057 if (llvm::isa<Float16Type>(type))
2058 return (os <<
"_Float16"),
success();
2059 if (llvm::isa<BFloat16Type>(type))
2060 return (os <<
"__bf16"),
success();
2062 return emitError(loc,
"cannot emit float type ") << type;
2065 return (os <<
"float"),
success();
2067 return (os <<
"double"),
success();
2069 return emitError(loc,
"cannot emit float type ") << type;
2072 if (
auto iType = dyn_cast<IndexType>(type))
2073 return (os <<
"size_t"),
success();
2074 if (
auto sType = dyn_cast<emitc::SizeTType>(type))
2075 return (os <<
"size_t"),
success();
2076 if (
auto sType = dyn_cast<emitc::SignedSizeTType>(type))
2077 return (os <<
"ssize_t"),
success();
2078 if (
auto pType = dyn_cast<emitc::PtrDiffTType>(type))
2079 return (os <<
"ptrdiff_t"),
success();
2080 if (
auto tType = dyn_cast<TensorType>(type)) {
2081 if (!tType.hasRank())
2082 return emitError(loc,
"cannot emit unranked tensor type");
2083 if (!tType.hasStaticShape())
2084 return emitError(loc,
"cannot emit tensor type with non static shape");
2086 if (isa<ArrayType>(tType.getElementType()))
2087 return emitError(loc,
"cannot emit tensor of array type ") << type;
2088 if (
failed(emitType(loc, tType.getElementType())))
2090 auto shape = tType.getShape();
2091 for (
auto dimSize : shape) {
2098 if (
auto tType = dyn_cast<TupleType>(type))
2099 return emitTupleType(loc, tType.getTypes());
2100 if (
auto oType = dyn_cast<emitc::OpaqueType>(type)) {
2101 os << oType.getValue();
2104 if (
auto aType = dyn_cast<emitc::ArrayType>(type)) {
2105 if (
failed(emitType(loc, aType.getElementType())))
2107 for (
auto dim : aType.getShape())
2108 os <<
"[" << dim <<
"]";
2111 if (
auto lType = dyn_cast<emitc::LValueType>(type))
2112 return emitType(loc, lType.getValueType());
2113 if (
auto pType = dyn_cast<emitc::PointerType>(type)) {
2114 if (isa<ArrayType>(pType.getPointee()))
2115 return emitError(loc,
"cannot emit pointer to array type ") << type;
2116 if (
failed(emitType(loc, pType.getPointee())))
2121 return emitError(loc,
"cannot emit type ") << type;
2124LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
2125 switch (types.size()) {
2130 return emitType(loc, types.front());
2132 return emitTupleType(loc, types);
2136LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
2137 if (llvm::any_of(types, llvm::IsaPred<ArrayType>)) {
2138 return emitError(loc,
"cannot emit tuple of array type");
2140 os <<
"std::tuple<";
2142 types, os, [&](Type type) {
return emitType(loc, type); })))
2148void CppEmitter::resetValueCounter() { valueCount = 0; }
2150void CppEmitter::increaseLoopNestingLevel() { loopNestingLevel++; }
2152void CppEmitter::decreaseLoopNestingLevel() { loopNestingLevel--; }
2155 bool declareVariablesAtTop,
2157 CppEmitter emitter(os, declareVariablesAtTop, fileId);
2158 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)
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
unsigned getNumOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
operand_range getOperands()
Returns an iterator on the underlying Value's.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
unsigned getNumResults()
Return the number of results held by this operation.
This class provides iteration over the held operations of blocks directly within a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
llvm::iplist< Block > BlockListType
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
iterator_range< OpIterator > getOps()
MutableArrayRef< BlockArgument > BlockArgListType
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
raw_indented_ostream & unindent()
Decreases the indent and returning this raw_indented_ostream.
LogicalResult translateToCpp(Operation *op, raw_ostream &os, bool declareVariablesAtTop=false, StringRef fileId={})
Translates the given operation to C++ code.
std::variant< StringRef, Placeholder > ReplacementItem
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This iterator enumerates the elements in "forward" order.