Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/PseudoLoweringEmitter.cpp
35258 views
//===- PseudoLoweringEmitter.cpp - PseudoLowering Generator -----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Common/CodeGenInstruction.h"9#include "Common/CodeGenTarget.h"10#include "llvm/ADT/IndexedMap.h"11#include "llvm/ADT/SmallVector.h"12#include "llvm/ADT/StringMap.h"13#include "llvm/Support/Debug.h"14#include "llvm/Support/ErrorHandling.h"15#include "llvm/TableGen/Error.h"16#include "llvm/TableGen/Record.h"17#include "llvm/TableGen/TableGenBackend.h"18#include <vector>19using namespace llvm;2021#define DEBUG_TYPE "pseudo-lowering"2223namespace {24class PseudoLoweringEmitter {25struct OpData {26enum MapKind { Operand, Imm, Reg };27MapKind Kind;28union {29unsigned Operand; // Operand number mapped to.30uint64_t Imm; // Integer immedate value.31Record *Reg; // Physical register.32} Data;33};34struct PseudoExpansion {35CodeGenInstruction Source; // The source pseudo instruction definition.36CodeGenInstruction Dest; // The destination instruction to lower to.37IndexedMap<OpData> OperandMap;3839PseudoExpansion(CodeGenInstruction &s, CodeGenInstruction &d,40IndexedMap<OpData> &m)41: Source(s), Dest(d), OperandMap(m) {}42};4344RecordKeeper &Records;4546// It's overkill to have an instance of the full CodeGenTarget object,47// but it loads everything on demand, not in the constructor, so it's48// lightweight in performance, so it works out OK.49CodeGenTarget Target;5051SmallVector<PseudoExpansion, 64> Expansions;5253unsigned addDagOperandMapping(Record *Rec, DagInit *Dag,54CodeGenInstruction &Insn,55IndexedMap<OpData> &OperandMap,56unsigned BaseIdx);57void evaluateExpansion(Record *Pseudo);58void emitLoweringEmitter(raw_ostream &o);5960public:61PseudoLoweringEmitter(RecordKeeper &R) : Records(R), Target(R) {}6263/// run - Output the pseudo-lowerings.64void run(raw_ostream &o);65};66} // End anonymous namespace6768// FIXME: This pass currently can only expand a pseudo to a single instruction.69// The pseudo expansion really should take a list of dags, not just70// a single dag, so we can do fancier things.7172unsigned PseudoLoweringEmitter::addDagOperandMapping(73Record *Rec, DagInit *Dag, CodeGenInstruction &Insn,74IndexedMap<OpData> &OperandMap, unsigned BaseIdx) {75unsigned OpsAdded = 0;76for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) {77if (DefInit *DI = dyn_cast<DefInit>(Dag->getArg(i))) {78// Physical register reference. Explicit check for the special case79// "zero_reg" definition.80if (DI->getDef()->isSubClassOf("Register") ||81DI->getDef()->getName() == "zero_reg") {82OperandMap[BaseIdx + i].Kind = OpData::Reg;83OperandMap[BaseIdx + i].Data.Reg = DI->getDef();84++OpsAdded;85continue;86}8788// Normal operands should always have the same type, or we have a89// problem.90// FIXME: We probably shouldn't ever get a non-zero BaseIdx here.91assert(BaseIdx == 0 && "Named subargument in pseudo expansion?!");92// FIXME: Are the message operand types backward?93if (DI->getDef() != Insn.Operands[BaseIdx + i].Rec) {94PrintError(Rec, "In pseudo instruction '" + Rec->getName() +95"', operand type '" + DI->getDef()->getName() +96"' does not match expansion operand type '" +97Insn.Operands[BaseIdx + i].Rec->getName() + "'");98PrintFatalNote(DI->getDef(),99"Value was assigned at the following location:");100}101// Source operand maps to destination operand. The Data element102// will be filled in later, just set the Kind for now. Do it103// for each corresponding MachineInstr operand, not just the first.104for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)105OperandMap[BaseIdx + i + I].Kind = OpData::Operand;106OpsAdded += Insn.Operands[i].MINumOperands;107} else if (IntInit *II = dyn_cast<IntInit>(Dag->getArg(i))) {108OperandMap[BaseIdx + i].Kind = OpData::Imm;109OperandMap[BaseIdx + i].Data.Imm = II->getValue();110++OpsAdded;111} else if (auto *BI = dyn_cast<BitsInit>(Dag->getArg(i))) {112auto *II =113cast<IntInit>(BI->convertInitializerTo(IntRecTy::get(Records)));114OperandMap[BaseIdx + i].Kind = OpData::Imm;115OperandMap[BaseIdx + i].Data.Imm = II->getValue();116++OpsAdded;117} else if (DagInit *SubDag = dyn_cast<DagInit>(Dag->getArg(i))) {118// Just add the operands recursively. This is almost certainly119// a constant value for a complex operand (> 1 MI operand).120unsigned NewOps =121addDagOperandMapping(Rec, SubDag, Insn, OperandMap, BaseIdx + i);122OpsAdded += NewOps;123// Since we added more than one, we also need to adjust the base.124BaseIdx += NewOps - 1;125} else126llvm_unreachable("Unhandled pseudo-expansion argument type!");127}128return OpsAdded;129}130131void PseudoLoweringEmitter::evaluateExpansion(Record *Rec) {132LLVM_DEBUG(dbgs() << "Pseudo definition: " << Rec->getName() << "\n");133134// Validate that the result pattern has the corrent number and types135// of arguments for the instruction it references.136DagInit *Dag = Rec->getValueAsDag("ResultInst");137assert(Dag && "Missing result instruction in pseudo expansion!");138LLVM_DEBUG(dbgs() << " Result: " << *Dag << "\n");139140DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());141if (!OpDef) {142PrintError(Rec, "In pseudo instruction '" + Rec->getName() +143"', result operator is not a record");144PrintFatalNote(Rec->getValue("ResultInst"),145"Result was assigned at the following location:");146}147Record *Operator = OpDef->getDef();148if (!Operator->isSubClassOf("Instruction")) {149PrintError(Rec, "In pseudo instruction '" + Rec->getName() +150"', result operator '" + Operator->getName() +151"' is not an instruction");152PrintFatalNote(Rec->getValue("ResultInst"),153"Result was assigned at the following location:");154}155156CodeGenInstruction Insn(Operator);157158if (Insn.isCodeGenOnly || Insn.isPseudo) {159PrintError(Rec, "In pseudo instruction '" + Rec->getName() +160"', result operator '" + Operator->getName() +161"' cannot be a pseudo instruction");162PrintFatalNote(Rec->getValue("ResultInst"),163"Result was assigned at the following location:");164}165166if (Insn.Operands.size() != Dag->getNumArgs()) {167PrintError(Rec, "In pseudo instruction '" + Rec->getName() +168"', result operator '" + Operator->getName() +169"' has the wrong number of operands");170PrintFatalNote(Rec->getValue("ResultInst"),171"Result was assigned at the following location:");172}173174unsigned NumMIOperands = 0;175for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i)176NumMIOperands += Insn.Operands[i].MINumOperands;177IndexedMap<OpData> OperandMap;178OperandMap.grow(NumMIOperands);179180addDagOperandMapping(Rec, Dag, Insn, OperandMap, 0);181182// If there are more operands that weren't in the DAG, they have to183// be operands that have default values, or we have an error. Currently,184// Operands that are a subclass of OperandWithDefaultOp have default values.185186// Validate that each result pattern argument has a matching (by name)187// argument in the source instruction, in either the (outs) or (ins) list.188// Also check that the type of the arguments match.189//190// Record the mapping of the source to result arguments for use by191// the lowering emitter.192CodeGenInstruction SourceInsn(Rec);193StringMap<unsigned> SourceOperands;194for (unsigned i = 0, e = SourceInsn.Operands.size(); i != e; ++i)195SourceOperands[SourceInsn.Operands[i].Name] = i;196197LLVM_DEBUG(dbgs() << " Operand mapping:\n");198for (unsigned i = 0, e = Insn.Operands.size(); i != e; ++i) {199// We've already handled constant values. Just map instruction operands200// here.201if (OperandMap[Insn.Operands[i].MIOperandNo].Kind != OpData::Operand)202continue;203StringMap<unsigned>::iterator SourceOp =204SourceOperands.find(Dag->getArgNameStr(i));205if (SourceOp == SourceOperands.end()) {206PrintError(Rec, "In pseudo instruction '" + Rec->getName() +207"', output operand '" + Dag->getArgNameStr(i) +208"' has no matching source operand");209PrintFatalNote(Rec->getValue("ResultInst"),210"Value was assigned at the following location:");211}212// Map the source operand to the destination operand index for each213// MachineInstr operand.214for (unsigned I = 0, E = Insn.Operands[i].MINumOperands; I != E; ++I)215OperandMap[Insn.Operands[i].MIOperandNo + I].Data.Operand =216SourceOp->getValue();217218LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ==> " << i219<< "\n");220}221222Expansions.push_back(PseudoExpansion(SourceInsn, Insn, OperandMap));223}224225void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) {226// Emit file header.227emitSourceFileHeader("Pseudo-instruction MC lowering Source Fragment", o);228229o << "bool " << Target.getName() + "AsmPrinter"230<< "::\n"231<< "emitPseudoExpansionLowering(MCStreamer &OutStreamer,\n"232<< " const MachineInstr *MI) {\n";233234if (!Expansions.empty()) {235o << " switch (MI->getOpcode()) {\n"236<< " default: return false;\n";237for (auto &Expansion : Expansions) {238CodeGenInstruction &Source = Expansion.Source;239CodeGenInstruction &Dest = Expansion.Dest;240o << " case " << Source.Namespace << "::" << Source.TheDef->getName()241<< ": {\n"242<< " MCInst TmpInst;\n"243<< " MCOperand MCOp;\n"244<< " TmpInst.setOpcode(" << Dest.Namespace245<< "::" << Dest.TheDef->getName() << ");\n";246247// Copy the operands from the source instruction.248// FIXME: Instruction operands with defaults values (predicates and cc_out249// in ARM, for example shouldn't need explicit values in the250// expansion DAG.251unsigned MIOpNo = 0;252for (const auto &DestOperand : Dest.Operands) {253o << " // Operand: " << DestOperand.Name << "\n";254for (unsigned i = 0, e = DestOperand.MINumOperands; i != e; ++i) {255switch (Expansion.OperandMap[MIOpNo + i].Kind) {256case OpData::Operand:257o << " lowerOperand(MI->getOperand("258<< Source.Operands[Expansion.OperandMap[MIOpNo].Data.Operand]259.MIOperandNo +260i261<< "), MCOp);\n"262<< " TmpInst.addOperand(MCOp);\n";263break;264case OpData::Imm:265o << " TmpInst.addOperand(MCOperand::createImm("266<< Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n";267break;268case OpData::Reg: {269Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg;270o << " TmpInst.addOperand(MCOperand::createReg(";271// "zero_reg" is special.272if (Reg->getName() == "zero_reg")273o << "0";274else275o << Reg->getValueAsString("Namespace") << "::" << Reg->getName();276o << "));\n";277break;278}279}280}281MIOpNo += DestOperand.MINumOperands;282}283if (Dest.Operands.isVariadic) {284MIOpNo = Source.Operands.size() + 1;285o << " // variable_ops\n";286o << " for (unsigned i = " << MIOpNo287<< ", e = MI->getNumOperands(); i != e; ++i)\n"288<< " if (lowerOperand(MI->getOperand(i), MCOp))\n"289<< " TmpInst.addOperand(MCOp);\n";290}291o << " EmitToStreamer(OutStreamer, TmpInst);\n"292<< " break;\n"293<< " }\n";294}295o << " }\n return true;";296} else297o << " return false;";298299o << "\n}\n\n";300}301302void PseudoLoweringEmitter::run(raw_ostream &o) {303StringRef Classes[] = {"PseudoInstExpansion", "Instruction"};304std::vector<Record *> Insts = Records.getAllDerivedDefinitions(Classes);305306// Process the pseudo expansion definitions, validating them as we do so.307Records.startTimer("Process definitions");308for (unsigned i = 0, e = Insts.size(); i != e; ++i)309evaluateExpansion(Insts[i]);310311// Generate expansion code to lower the pseudo to an MCInst of the real312// instruction.313Records.startTimer("Emit expansion code");314emitLoweringEmitter(o);315}316317static TableGen::Emitter::OptClass<PseudoLoweringEmitter>318X("gen-pseudo-lowering", "Generate pseudo instruction lowering");319320321