//===--------------------- 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::expandCheckFunctionPredicateWithTII( raw_ostream &OS, StringRef MCInstFn, StringRef MachineInstrFn, StringRef TIIPtr) { if (!shouldExpandForMC()) { OS << (TIIPtr.empty() ? "TII" : TIIPtr) << "->" << MachineInstrFn; OS << (isByRef() ? "(MI)" : "(*MI)"); return; } OS << MCInstFn << (isByRef() ? "(MI" : "(*MI") << ", MCII)"; } 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("CheckFunctionPredicateWithTII")) { return expandCheckFunctionPredicateWithTII( OS, Rec->getValueAsString("MCInstFnName"), Rec->getValueAsString("MachineInstrFnName"), Rec->getValueAsString("TIIPtrName")); } 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