summaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/PredicateExpander.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen/PredicateExpander.cpp')
-rw-r--r--llvm/utils/TableGen/PredicateExpander.cpp529
1 files changed, 529 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp
new file mode 100644
index 000000000000..9f7f40db2626
--- /dev/null
+++ b/llvm/utils/TableGen/PredicateExpander.cpp
@@ -0,0 +1,529 @@
+//===--------------------- PredicateExpander.cpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Functionalities used by the Tablegen backends to expand machine predicates.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PredicateExpander.h"
+#include "CodeGenSchedule.h" // Definition of STIPredicateFunction.
+
+namespace llvm {
+
+void PredicateExpander::expandTrue(raw_ostream &OS) { OS << "true"; }
+void PredicateExpander::expandFalse(raw_ostream &OS) { OS << "false"; }
+
+void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex,
+ int ImmVal,
+ StringRef FunctionMapper) {
+ if (!FunctionMapper.empty())
+ OS << FunctionMapper << "(";
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getImm()";
+ if (!FunctionMapper.empty())
+ OS << ")";
+ OS << (shouldNegate() ? " != " : " == ") << ImmVal;
+}
+
+void PredicateExpander::expandCheckImmOperand(raw_ostream &OS, int OpIndex,
+ StringRef ImmVal,
+ StringRef FunctionMapper) {
+ if (ImmVal.empty())
+ expandCheckImmOperandSimple(OS, OpIndex, FunctionMapper);
+
+ if (!FunctionMapper.empty())
+ OS << FunctionMapper << "(";
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getImm()";
+ if (!FunctionMapper.empty())
+ OS << ")";
+ OS << (shouldNegate() ? " != " : " == ") << ImmVal;
+}
+
+void PredicateExpander::expandCheckImmOperandSimple(raw_ostream &OS,
+ int OpIndex,
+ StringRef FunctionMapper) {
+ if (shouldNegate())
+ OS << "!";
+ if (!FunctionMapper.empty())
+ OS << FunctionMapper << "(";
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getImm()";
+ if (!FunctionMapper.empty())
+ OS << ")";
+}
+
+void PredicateExpander::expandCheckRegOperand(raw_ostream &OS, int OpIndex,
+ const Record *Reg,
+ StringRef FunctionMapper) {
+ assert(Reg->isSubClassOf("Register") && "Expected a register Record!");
+
+ if (!FunctionMapper.empty())
+ OS << FunctionMapper << "(";
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getReg()";
+ if (!FunctionMapper.empty())
+ OS << ")";
+ OS << (shouldNegate() ? " != " : " == ");
+ const StringRef Str = Reg->getValueAsString("Namespace");
+ if (!Str.empty())
+ OS << Str << "::";
+ OS << Reg->getName();
+}
+
+
+void PredicateExpander::expandCheckRegOperandSimple(raw_ostream &OS,
+ int OpIndex,
+ StringRef FunctionMapper) {
+ if (shouldNegate())
+ OS << "!";
+ if (!FunctionMapper.empty())
+ OS << FunctionMapper << "(";
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getReg()";
+ if (!FunctionMapper.empty())
+ OS << ")";
+}
+
+void PredicateExpander::expandCheckInvalidRegOperand(raw_ostream &OS,
+ int OpIndex) {
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex
+ << ").getReg() " << (shouldNegate() ? "!= " : "== ") << "0";
+}
+
+void PredicateExpander::expandCheckSameRegOperand(raw_ostream &OS, int First,
+ int Second) {
+ OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First
+ << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI"
+ << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()";
+}
+
+void PredicateExpander::expandCheckNumOperands(raw_ostream &OS, int NumOps) {
+ OS << "MI" << (isByRef() ? "." : "->") << "getNumOperands() "
+ << (shouldNegate() ? "!= " : "== ") << NumOps;
+}
+
+void PredicateExpander::expandCheckOpcode(raw_ostream &OS, const Record *Inst) {
+ OS << "MI" << (isByRef() ? "." : "->") << "getOpcode() "
+ << (shouldNegate() ? "!= " : "== ") << Inst->getValueAsString("Namespace")
+ << "::" << Inst->getName();
+}
+
+void PredicateExpander::expandCheckOpcode(raw_ostream &OS,
+ const RecVec &Opcodes) {
+ assert(!Opcodes.empty() && "Expected at least one opcode to check!");
+ bool First = true;
+
+ if (Opcodes.size() == 1) {
+ OS << "( ";
+ expandCheckOpcode(OS, Opcodes[0]);
+ OS << " )";
+ return;
+ }
+
+ OS << '(';
+ increaseIndentLevel();
+ for (const Record *Rec : Opcodes) {
+ OS << '\n';
+ OS.indent(getIndentLevel() * 2);
+ if (!First)
+ OS << (shouldNegate() ? "&& " : "|| ");
+
+ expandCheckOpcode(OS, Rec);
+ First = false;
+ }
+
+ OS << '\n';
+ decreaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ OS << ')';
+}
+
+void PredicateExpander::expandCheckPseudo(raw_ostream &OS,
+ const RecVec &Opcodes) {
+ if (shouldExpandForMC())
+ expandFalse(OS);
+ else
+ expandCheckOpcode(OS, Opcodes);
+}
+
+void PredicateExpander::expandPredicateSequence(raw_ostream &OS,
+ const RecVec &Sequence,
+ bool IsCheckAll) {
+ assert(!Sequence.empty() && "Found an invalid empty predicate set!");
+ if (Sequence.size() == 1)
+ return expandPredicate(OS, Sequence[0]);
+
+ // Okay, there is more than one predicate in the set.
+ bool First = true;
+ OS << (shouldNegate() ? "!(" : "(");
+ increaseIndentLevel();
+
+ bool OldValue = shouldNegate();
+ setNegatePredicate(false);
+ for (const Record *Rec : Sequence) {
+ OS << '\n';
+ OS.indent(getIndentLevel() * 2);
+ if (!First)
+ OS << (IsCheckAll ? "&& " : "|| ");
+ expandPredicate(OS, Rec);
+ First = false;
+ }
+ OS << '\n';
+ decreaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ OS << ')';
+ setNegatePredicate(OldValue);
+}
+
+void PredicateExpander::expandTIIFunctionCall(raw_ostream &OS,
+ StringRef MethodName) {
+ OS << (shouldNegate() ? "!" : "");
+ OS << TargetName << (shouldExpandForMC() ? "_MC::" : "InstrInfo::");
+ OS << MethodName << (isByRef() ? "(MI)" : "(*MI)");
+}
+
+void PredicateExpander::expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) {
+ OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->")
+ << "getOperand(" << OpIndex << ").isReg() ";
+}
+
+void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) {
+ OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->")
+ << "getOperand(" << OpIndex << ").isImm() ";
+}
+
+void PredicateExpander::expandCheckFunctionPredicate(raw_ostream &OS,
+ StringRef MCInstFn,
+ StringRef MachineInstrFn) {
+ OS << (shouldExpandForMC() ? MCInstFn : MachineInstrFn)
+ << (isByRef() ? "(MI)" : "(*MI)");
+}
+
+void PredicateExpander::expandCheckNonPortable(raw_ostream &OS,
+ StringRef Code) {
+ if (shouldExpandForMC())
+ return expandFalse(OS);
+
+ OS << '(' << Code << ')';
+}
+
+void PredicateExpander::expandReturnStatement(raw_ostream &OS,
+ const Record *Rec) {
+ std::string Buffer;
+ raw_string_ostream SS(Buffer);
+
+ SS << "return ";
+ expandPredicate(SS, Rec);
+ SS << ";";
+ SS.flush();
+ OS << Buffer;
+}
+
+void PredicateExpander::expandOpcodeSwitchCase(raw_ostream &OS,
+ const Record *Rec) {
+ const RecVec &Opcodes = Rec->getValueAsListOfDefs("Opcodes");
+ for (const Record *Opcode : Opcodes) {
+ OS.indent(getIndentLevel() * 2);
+ OS << "case " << Opcode->getValueAsString("Namespace")
+ << "::" << Opcode->getName() << ":\n";
+ }
+
+ increaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ expandStatement(OS, Rec->getValueAsDef("CaseStmt"));
+ decreaseIndentLevel();
+}
+
+void PredicateExpander::expandOpcodeSwitchStatement(raw_ostream &OS,
+ const RecVec &Cases,
+ const Record *Default) {
+ std::string Buffer;
+ raw_string_ostream SS(Buffer);
+
+ SS << "switch(MI" << (isByRef() ? "." : "->") << "getOpcode()) {\n";
+ for (const Record *Rec : Cases) {
+ expandOpcodeSwitchCase(SS, Rec);
+ SS << '\n';
+ }
+
+ // Expand the default case.
+ SS.indent(getIndentLevel() * 2);
+ SS << "default:\n";
+
+ increaseIndentLevel();
+ SS.indent(getIndentLevel() * 2);
+ expandStatement(SS, Default);
+ decreaseIndentLevel();
+ SS << '\n';
+
+ SS.indent(getIndentLevel() * 2);
+ SS << "} // end of switch-stmt";
+ SS.flush();
+ OS << Buffer;
+}
+
+void PredicateExpander::expandStatement(raw_ostream &OS, const Record *Rec) {
+ // Assume that padding has been added by the caller.
+ if (Rec->isSubClassOf("MCOpcodeSwitchStatement")) {
+ expandOpcodeSwitchStatement(OS, Rec->getValueAsListOfDefs("Cases"),
+ Rec->getValueAsDef("DefaultCase"));
+ return;
+ }
+
+ if (Rec->isSubClassOf("MCReturnStatement")) {
+ expandReturnStatement(OS, Rec->getValueAsDef("Pred"));
+ return;
+ }
+
+ llvm_unreachable("No known rules to expand this MCStatement");
+}
+
+void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) {
+ // Assume that padding has been added by the caller.
+ if (Rec->isSubClassOf("MCTrue")) {
+ if (shouldNegate())
+ return expandFalse(OS);
+ return expandTrue(OS);
+ }
+
+ if (Rec->isSubClassOf("MCFalse")) {
+ if (shouldNegate())
+ return expandTrue(OS);
+ return expandFalse(OS);
+ }
+
+ if (Rec->isSubClassOf("CheckNot")) {
+ flipNegatePredicate();
+ expandPredicate(OS, Rec->getValueAsDef("Pred"));
+ flipNegatePredicate();
+ return;
+ }
+
+ if (Rec->isSubClassOf("CheckIsRegOperand"))
+ return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex"));
+
+ if (Rec->isSubClassOf("CheckIsImmOperand"))
+ return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex"));
+
+ if (Rec->isSubClassOf("CheckRegOperand"))
+ return expandCheckRegOperand(OS, Rec->getValueAsInt("OpIndex"),
+ Rec->getValueAsDef("Reg"),
+ Rec->getValueAsString("FunctionMapper"));
+
+ if (Rec->isSubClassOf("CheckRegOperandSimple"))
+ return expandCheckRegOperandSimple(OS, Rec->getValueAsInt("OpIndex"),
+ Rec->getValueAsString("FunctionMapper"));
+
+ if (Rec->isSubClassOf("CheckInvalidRegOperand"))
+ return expandCheckInvalidRegOperand(OS, Rec->getValueAsInt("OpIndex"));
+
+ if (Rec->isSubClassOf("CheckImmOperand"))
+ return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"),
+ Rec->getValueAsInt("ImmVal"),
+ Rec->getValueAsString("FunctionMapper"));
+
+ if (Rec->isSubClassOf("CheckImmOperand_s"))
+ return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"),
+ Rec->getValueAsString("ImmVal"),
+ Rec->getValueAsString("FunctionMapper"));
+
+ if (Rec->isSubClassOf("CheckImmOperandSimple"))
+ return expandCheckImmOperandSimple(OS, Rec->getValueAsInt("OpIndex"),
+ Rec->getValueAsString("FunctionMapper"));
+
+ if (Rec->isSubClassOf("CheckSameRegOperand"))
+ return expandCheckSameRegOperand(OS, Rec->getValueAsInt("FirstIndex"),
+ Rec->getValueAsInt("SecondIndex"));
+
+ if (Rec->isSubClassOf("CheckNumOperands"))
+ return expandCheckNumOperands(OS, Rec->getValueAsInt("NumOps"));
+
+ if (Rec->isSubClassOf("CheckPseudo"))
+ return expandCheckPseudo(OS, Rec->getValueAsListOfDefs("ValidOpcodes"));
+
+ if (Rec->isSubClassOf("CheckOpcode"))
+ return expandCheckOpcode(OS, Rec->getValueAsListOfDefs("ValidOpcodes"));
+
+ if (Rec->isSubClassOf("CheckAll"))
+ return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"),
+ /* AllOf */ true);
+
+ if (Rec->isSubClassOf("CheckAny"))
+ return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"),
+ /* AllOf */ false);
+
+ if (Rec->isSubClassOf("CheckFunctionPredicate"))
+ return expandCheckFunctionPredicate(
+ OS, Rec->getValueAsString("MCInstFnName"),
+ Rec->getValueAsString("MachineInstrFnName"));
+
+ if (Rec->isSubClassOf("CheckNonPortable"))
+ return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock"));
+
+ if (Rec->isSubClassOf("TIIPredicate"))
+ return expandTIIFunctionCall(OS, Rec->getValueAsString("FunctionName"));
+
+ llvm_unreachable("No known rules to expand this MCInstPredicate");
+}
+
+void STIPredicateExpander::expandHeader(raw_ostream &OS,
+ const STIPredicateFunction &Fn) {
+ const Record *Rec = Fn.getDeclaration();
+ StringRef FunctionName = Rec->getValueAsString("Name");
+
+ OS.indent(getIndentLevel() * 2);
+ OS << "bool ";
+ if (shouldExpandDefinition())
+ OS << getClassPrefix() << "::";
+ OS << FunctionName << "(";
+ if (shouldExpandForMC())
+ OS << "const MCInst " << (isByRef() ? "&" : "*") << "MI";
+ else
+ OS << "const MachineInstr " << (isByRef() ? "&" : "*") << "MI";
+ if (Rec->getValueAsBit("UpdatesOpcodeMask"))
+ OS << ", APInt &Mask";
+ OS << (shouldExpandForMC() ? ", unsigned ProcessorID) const " : ") const ");
+ if (shouldExpandDefinition()) {
+ OS << "{\n";
+ return;
+ }
+
+ if (Rec->getValueAsBit("OverridesBaseClassMember"))
+ OS << "override";
+ OS << ";\n";
+}
+
+void STIPredicateExpander::expandPrologue(raw_ostream &OS,
+ const STIPredicateFunction &Fn) {
+ RecVec Delegates = Fn.getDeclaration()->getValueAsListOfDefs("Delegates");
+ bool UpdatesOpcodeMask =
+ Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask");
+
+ increaseIndentLevel();
+ unsigned IndentLevel = getIndentLevel();
+ for (const Record *Delegate : Delegates) {
+ OS.indent(IndentLevel * 2);
+ OS << "if (" << Delegate->getValueAsString("Name") << "(MI";
+ if (UpdatesOpcodeMask)
+ OS << ", Mask";
+ if (shouldExpandForMC())
+ OS << ", ProcessorID";
+ OS << "))\n";
+ OS.indent((1 + IndentLevel) * 2);
+ OS << "return true;\n\n";
+ }
+
+ if (shouldExpandForMC())
+ return;
+
+ OS.indent(IndentLevel * 2);
+ OS << "unsigned ProcessorID = getSchedModel().getProcessorID();\n";
+}
+
+void STIPredicateExpander::expandOpcodeGroup(raw_ostream &OS, const OpcodeGroup &Group,
+ bool ShouldUpdateOpcodeMask) {
+ const OpcodeInfo &OI = Group.getOpcodeInfo();
+ for (const PredicateInfo &PI : OI.getPredicates()) {
+ const APInt &ProcModelMask = PI.ProcModelMask;
+ bool FirstProcID = true;
+ for (unsigned I = 0, E = ProcModelMask.getActiveBits(); I < E; ++I) {
+ if (!ProcModelMask[I])
+ continue;
+
+ if (FirstProcID) {
+ OS.indent(getIndentLevel() * 2);
+ OS << "if (ProcessorID == " << I;
+ } else {
+ OS << " || ProcessorID == " << I;
+ }
+ FirstProcID = false;
+ }
+
+ OS << ") {\n";
+
+ increaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ if (ShouldUpdateOpcodeMask) {
+ if (PI.OperandMask.isNullValue())
+ OS << "Mask.clearAllBits();\n";
+ else
+ OS << "Mask = " << PI.OperandMask << ";\n";
+ OS.indent(getIndentLevel() * 2);
+ }
+ OS << "return ";
+ expandPredicate(OS, PI.Predicate);
+ OS << ";\n";
+ decreaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ OS << "}\n";
+ }
+}
+
+void STIPredicateExpander::expandBody(raw_ostream &OS,
+ const STIPredicateFunction &Fn) {
+ bool UpdatesOpcodeMask =
+ Fn.getDeclaration()->getValueAsBit("UpdatesOpcodeMask");
+
+ unsigned IndentLevel = getIndentLevel();
+ OS.indent(IndentLevel * 2);
+ OS << "switch(MI" << (isByRef() ? "." : "->") << "getOpcode()) {\n";
+ OS.indent(IndentLevel * 2);
+ OS << "default:\n";
+ OS.indent(IndentLevel * 2);
+ OS << " break;";
+
+ for (const OpcodeGroup &Group : Fn.getGroups()) {
+ for (const Record *Opcode : Group.getOpcodes()) {
+ OS << '\n';
+ OS.indent(IndentLevel * 2);
+ OS << "case " << getTargetName() << "::" << Opcode->getName() << ":";
+ }
+
+ OS << '\n';
+ increaseIndentLevel();
+ expandOpcodeGroup(OS, Group, UpdatesOpcodeMask);
+
+ OS.indent(getIndentLevel() * 2);
+ OS << "break;\n";
+ decreaseIndentLevel();
+ }
+
+ OS.indent(IndentLevel * 2);
+ OS << "}\n";
+}
+
+void STIPredicateExpander::expandEpilogue(raw_ostream &OS,
+ const STIPredicateFunction &Fn) {
+ OS << '\n';
+ OS.indent(getIndentLevel() * 2);
+ OS << "return ";
+ expandPredicate(OS, Fn.getDefaultReturnPredicate());
+ OS << ";\n";
+
+ decreaseIndentLevel();
+ OS.indent(getIndentLevel() * 2);
+ StringRef FunctionName = Fn.getDeclaration()->getValueAsString("Name");
+ OS << "} // " << ClassPrefix << "::" << FunctionName << "\n\n";
+}
+
+void STIPredicateExpander::expandSTIPredicate(raw_ostream &OS,
+ const STIPredicateFunction &Fn) {
+ const Record *Rec = Fn.getDeclaration();
+ if (shouldExpandForMC() && !Rec->getValueAsBit("ExpandForMC"))
+ return;
+
+ expandHeader(OS, Fn);
+ if (shouldExpandDefinition()) {
+ expandPrologue(OS, Fn);
+ expandBody(OS, Fn);
+ expandEpilogue(OS, Fn);
+ }
+}
+
+} // namespace llvm