Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -660,6 +660,23 @@ bit HasPositionOrder = false; } +class Inst16 : Instruction { + field bits<16> Inst; + let Size = 2; +} + +class Inst32 : Instruction { + field bits<32> Inst; + let Size = 4; +} + +class CompressPat { + dag Input = input; + dag Output = output; + list Predicates = []; + bit isCompressOnly = false; +} + /// Defines an additional encoding that disassembles to the given instruction /// Like Instruction, the Inst and SoftFail fields are omitted to allow targets // to specify their size. Index: llvm/lib/Target/CSKY/CMakeLists.txt =================================================================== --- llvm/lib/Target/CSKY/CMakeLists.txt +++ llvm/lib/Target/CSKY/CMakeLists.txt @@ -5,6 +5,7 @@ tablegen(LLVM CSKYGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv) +tablegen(LLVM CSKYGenCompressInstEmitter.inc -gen-compress-inst-emitter) tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel) tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info) tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter) Index: llvm/lib/Target/CSKY/CSKYAsmPrinter.h =================================================================== --- llvm/lib/Target/CSKY/CSKYAsmPrinter.h +++ llvm/lib/Target/CSKY/CSKYAsmPrinter.h @@ -19,6 +19,7 @@ CSKYMCInstLower MCInstLowering; const CSKYSubtarget *Subtarget; + void EmitToStreamer(MCStreamer &S, const MCInst &Inst); public: explicit CSKYAsmPrinter(TargetMachine &TM, Index: llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp =================================================================== --- llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp +++ llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp @@ -30,6 +30,9 @@ #define DEBUG_TYPE "csky-asm-printer" +STATISTIC(CSKYNumInstrsCompressed, + "Number of C-SKY Compressed instructions emitted"); + CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} @@ -39,6 +42,16 @@ return AsmPrinter::runOnMachineFunction(MF); } +#define GEN_COMPRESS_INSTR +#include "CSKYGenCompressInstEmitter.inc" +void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { + MCInst CInst; + bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext()); + if (Res) + ++CSKYNumInstrsCompressed; + AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); +} + // Simple pseudo-instructions have their lowering (with expansion to real // instructions) auto-generated. #include "CSKYGenMCPseudoLowering.inc" Index: llvm/lib/Target/CSKY/CSKYInstrFormats.td =================================================================== --- llvm/lib/Target/CSKY/CSKYInstrFormats.td +++ llvm/lib/Target/CSKY/CSKYInstrFormats.td @@ -19,10 +19,24 @@ def AddrMode16W : AddrMode<6>; // ld16.w, +128b or +1kb def AddrMode32SDF : AddrMode<7>; // flds, fldd, +1kb -class CSKYInst pattern> : Instruction { +class CSKY32Inst opcode, dag outs, dag ins, string asmstr, + list pattern> + : Inst32 { + let Namespace = "CSKY"; + AddrMode AM = am; + field bits<32> SoftFail = 0; + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = NoItinerary; + let TSFlags{4 - 0} = AM.Value; + let Inst{31 - 26} = opcode; +} + +class CSKY16Inst pattern> + : Inst16 { let Namespace = "CSKY"; - int Size = sz; AddrMode AM = am; field bits<32> SoftFail = 0; let OutOperandList = outs; @@ -34,23 +48,11 @@ } class CSKYPseudo pattern> - : CSKYInst { + : CSKY32Inst { let isCodeGenOnly = 1; let isPseudo = 1; } -class CSKY32Inst opcode, dag outs, dag ins, string asmstr, - list pattern> - : CSKYInst { - field bits<32> Inst; - let Inst{31 - 26} = opcode; -} - -class CSKY16Inst pattern> - : CSKYInst { - field bits<16> Inst; -} - // CSKY 32-bit instruction // Format< OP[6] | Offset[26] > // Instruction(1): bsr32 Index: llvm/lib/Target/CSKY/CSKYInstrInfo16Instr.td =================================================================== --- llvm/lib/Target/CSKY/CSKYInstrInfo16Instr.td +++ llvm/lib/Target/CSKY/CSKYInstrInfo16Instr.td @@ -450,3 +450,10 @@ let mayLoad = 1, Size = 2, isCodeGenOnly = 0 in def PseudoLRW16 : CSKYPseudo<(outs mGPR:$rz), (ins bare_symbol:$src), "lrw16 $rz, $src", []>; + +//===----------------------------------------------------------------------===// +// Compress Instruction tablegen backend. +//===----------------------------------------------------------------------===// + +def : CompressPat<(ADDU32 mGPR:$rd, mGPR:$rs1, mGPR:$rs2), + (ADDU16 mGPR:$rd, mGPR:$rs1, mGPR:$rs2)>; Index: llvm/lib/Target/RISCV/RISCVInstrFormats.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrFormats.td +++ llvm/lib/Target/RISCV/RISCVInstrFormats.td @@ -135,14 +135,12 @@ class RVInst pattern, InstFormat format> - : Instruction { - field bits<32> Inst; + : Inst32 { // SoftFail is a field the disassembler can use to provide a way for // instructions to not match without killing the whole decode process. It is // mainly used for ARM, but Tablegen expects this field to exist or it fails // to build the decode table. field bits<32> SoftFail = 0; - let Size = 4; bits<7> Opcode = 0; Index: llvm/lib/Target/RISCV/RISCVInstrFormatsC.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrFormatsC.td +++ llvm/lib/Target/RISCV/RISCVInstrFormatsC.td @@ -12,14 +12,12 @@ class RVInst16 pattern, InstFormat format> - : Instruction { - field bits<16> Inst; + : Inst16 { // SoftFail is a field the disassembler can use to provide a way for // instructions to not match without killing the whole decode process. It is // mainly used for ARM, but Tablegen expects this field to exist or it fails // to build the decode table. field bits<16> SoftFail = 0; - let Size = 2; bits<2> Opcode = 0; Index: llvm/lib/Target/RISCV/RISCVInstrInfoC.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoC.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoC.td @@ -745,13 +745,6 @@ // Compress Instruction tablegen backend. //===----------------------------------------------------------------------===// -class CompressPat { - dag Input = input; - dag Output = output; - list Predicates = []; - bit isCompressOnly = false; -} - // Patterns are defined in the same order the compressed instructions appear // on page 82 of the ISA manual. Index: llvm/test/TableGen/AsmPredicateCombiningRISCV.td =================================================================== --- llvm/test/TableGen/AsmPredicateCombiningRISCV.td +++ llvm/test/TableGen/AsmPredicateCombiningRISCV.td @@ -22,21 +22,17 @@ } def Regs : RegisterClass<"Regs", [i32], 32, (add R0)>; -class RVInst Preds> : Instruction { - let Size = 4; +class RVInst Preds> : Inst32 { let OutOperandList = (outs); let InOperandList = (ins Regs:$r); - field bits<32> Inst; let Inst = Opc; let AsmString = NAME # " $r"; field bits<32> SoftFail = 0; let Predicates = Preds; } -class RVInst16 Preds> : Instruction { - let Size = 2; +class RVInst16 Preds> : Inst16 { let OutOperandList = (outs); let InOperandList = (ins Regs:$r); - field bits<16> Inst; let Inst = Opc; let AsmString = NAME # " $r"; field bits<16> SoftFail = 0; Index: llvm/utils/TableGen/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/CMakeLists.txt +++ llvm/utils/TableGen/CMakeLists.txt @@ -40,7 +40,7 @@ OptRSTEmitter.cpp PredicateExpander.cpp PseudoLoweringEmitter.cpp - RISCVCompressInstEmitter.cpp + CompressInstEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SDNodeProperties.cpp Index: llvm/utils/TableGen/CompressInstEmitter.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/CompressInstEmitter.cpp @@ -0,0 +1,892 @@ +//===------ CompressInstEmitter.cpp - Generator for Compression Inst-------===// +// +// 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 +// +// CompressInstEmitter implements a tablegen-driven CompressPat based +// Instruction Compression mechanism. +// +//===----------------------------------------------------------------------===// +// +// CompressInstEmitter implements a tablegen-driven CompressPat Instruction +// Compression mechanism for generating compressed instructions from the +// expanded instruction form. + +// This tablegen backend processes CompressPat declarations in a +// td file and generates all the required checks to validate the pattern +// declarations; validate the input and output operands to generate the correct +// compressed instructions. The checks include validating different types of +// operands; register operands, immediate operands, fixed register and fixed +// immediate inputs. +// +// Example: +// class CompressPat { +// dag Input = input; +// dag Output = output; +// list Predicates = []; +// } +// +// let Predicates = [HasStdExtC] in { +// def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2), +// (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; +// } +// +// The result is an auto-generated header file which exports two functions +// for compressing/uncompressing MCInst instructions, plus +// some helper functions: +// +// bool compressInst(MCInst &OutInst, const MCInst &MI, +// const MCSubtargetInfo &STI, +// MCContext &Context); +// +// bool uncompressInst(MCInst &OutInst, const MCInst &MI, +// const MCRegisterInfo &MRI, +// const MCSubtargetInfo &STI); +// +// In addition, it exports a function for checking whether +// an instruction is compressable: +// +// bool isCompressibleInst(const MachineInstr& MI, +// const Subtarget *Subtarget, +// const MCRegisterInfo &MRI, +// const MCSubtargetInfo &STI); +// +// The clients that include this auto-generated header file and +// invoke these functions can compress an instruction before emitting +// it in the target-specific ASM or ELF streamer or can uncompress +// an instruction before printing it when the expanded instruction +// format aliases is favored. + +//===----------------------------------------------------------------------===// + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +using namespace llvm; + +#define DEBUG_TYPE "compress-inst-emitter" + +namespace { +class CompressInstEmitter { + struct OpData { + enum MapKind { Operand, Imm, Reg }; + MapKind Kind; + union { + unsigned Operand; // Operand number mapped to. + int64_t Imm; // Integer immediate value. + Record *Reg; // Physical register. + } Data; + int TiedOpIdx = -1; // Tied operand index within the instruction. + }; + struct CompressPat { + CodeGenInstruction Source; // The source instruction definition. + CodeGenInstruction Dest; // The destination instruction to transform to. + std::vector + PatReqFeatures; // Required target features to enable pattern. + IndexedMap + SourceOperandMap; // Maps operands in the Source Instruction to + // the corresponding Dest instruction operand. + IndexedMap + DestOperandMap; // Maps operands in the Dest Instruction + // to the corresponding Source instruction operand. + bool IsCompressOnly; + CompressPat(CodeGenInstruction &S, CodeGenInstruction &D, + std::vector RF, IndexedMap &SourceMap, + IndexedMap &DestMap, bool IsCompressOnly) + : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), + DestOperandMap(DestMap), IsCompressOnly(IsCompressOnly) {} + }; + enum EmitterType { Compress, Uncompress, CheckCompress }; + RecordKeeper &Records; + CodeGenTarget Target; + SmallVector CompressPatterns; + + void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap &OperandMap, bool IsSourceInst); + void evaluateCompressPat(Record *Compress); + void emitCompressInstEmitter(raw_ostream &o, EmitterType EType); + bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst); + bool validateRegister(Record *Reg, Record *RegClass); + void createDagOperandMapping(Record *Rec, StringMap &SourceOperands, + StringMap &DestOperands, + DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap); + + void createInstOperandMapping(Record *Rec, DagInit *SourceDag, + DagInit *DestDag, + IndexedMap &SourceOperandMap, + IndexedMap &DestOperandMap, + StringMap &SourceOperands, + CodeGenInstruction &DestInst); + +public: + CompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + void run(raw_ostream &o); +}; +} // End anonymous namespace. + +bool CompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) { + assert(Reg->isSubClassOf("Register") && "Reg record should be a Register"); + assert(RegClass->isSubClassOf("RegisterClass") && + "RegClass record should be a RegisterClass"); + const CodeGenRegisterClass &RC = Target.getRegisterClass(RegClass); + const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); + assert((R != nullptr) && "Register not defined!!"); + return RC.contains(R); +} + +bool CompressInstEmitter::validateTypes(Record *DagOpType, + Record *InstOpType, + bool IsSourceInst) { + if (DagOpType == InstOpType) + return true; + // Only source instruction operands are allowed to not match Input Dag + // operands. + if (!IsSourceInst) + return false; + + if (DagOpType->isSubClassOf("RegisterClass") && + InstOpType->isSubClassOf("RegisterClass")) { + const CodeGenRegisterClass &RC = Target.getRegisterClass(InstOpType); + const CodeGenRegisterClass &SubRC = Target.getRegisterClass(DagOpType); + return RC.hasSubClass(&SubRC); + } + + // At this point either or both types are not registers, reject the pattern. + if (DagOpType->isSubClassOf("RegisterClass") || + InstOpType->isSubClassOf("RegisterClass")) + return false; + + // Let further validation happen when compress()/uncompress() functions are + // invoked. + LLVM_DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") + << " Dag Operand Type: '" << DagOpType->getName() + << "' and " + << "Instruction Operand Type: '" << InstOpType->getName() + << "' can't be checked at pattern validation time!\n"); + return true; +} + +/// The patterns in the Dag contain different types of operands: +/// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate +/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function +/// maps Dag operands to its corresponding instruction operands. For register +/// operands and fixed registers it expects the Dag operand type to be contained +/// in the instantiated instruction operand type. For immediate operands and +/// immediates no validation checks are enforced at pattern validation time. +void CompressInstEmitter::addDagOperandMapping( + Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap &OperandMap, bool IsSourceInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. This is + // necessary because the number of operands in Inst might be greater + // than number of operands in the Dag due to how tied operands + // are represented. + unsigned TiedCount = 0; + for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) { + int TiedOpIdx = Inst.Operands[i].getTiedRegister(); + if (-1 != TiedOpIdx) { + // Set the entry in OperandMap for the tied operand we're skipping. + OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind; + OperandMap[i].Data = OperandMap[TiedOpIdx].Data; + TiedCount++; + continue; + } + if (DefInit *DI = dyn_cast(Dag->getArg(i - TiedCount))) { + if (DI->getDef()->isSubClassOf("Register")) { + // Check if the fixed register belongs to the Register class. + if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + + "'Register: '" + DI->getDef()->getName() + + "' is not in register class '" + + Inst.Operands[i].Rec->getName() + "'"); + OperandMap[i].Kind = OpData::Reg; + OperandMap[i].Data.Reg = DI->getDef(); + continue; + } + // Validate that Dag operand type matches the type defined in the + // corresponding instruction. Operands in the input Dag pattern are + // allowed to be a subclass of the type specified in corresponding + // instruction operand instead of being an exact match. + if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + "'. Operand '" + + Dag->getArgNameStr(i - TiedCount) + "' has type '" + + DI->getDef()->getName() + + "' which does not match the type '" + + Inst.Operands[i].Rec->getName() + + "' in the corresponding instruction operand!"); + + OperandMap[i].Kind = OpData::Operand; + } else if (IntInit *II = dyn_cast(Dag->getArg(i - TiedCount))) { + // Validate that corresponding instruction operand expects an immediate. + if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass")) + PrintFatalError( + Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + + II->getAsString() + + "' but corresponding instruction operand expected a register!"); + // No pattern validation check possible for values of fixed immediate. + OperandMap[i].Kind = OpData::Imm; + OperandMap[i].Data.Imm = II->getValue(); + LLVM_DEBUG( + dbgs() << " Found immediate '" << II->getValue() << "' at " + << (IsSourceInst ? "input " : "output ") + << "Dag. No validation time check possible for values of " + "fixed immediate.\n"); + } else + llvm_unreachable("Unhandled CompressPat argument type!"); + } +} + +// Verify the Dag operand count is enough to build an instruction. +static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag, + bool IsSource) { + if (Dag->getNumArgs() == Inst.Operands.size()) + return true; + // Source instructions are non compressed instructions and don't have tied + // operands. + if (IsSource) + PrintFatalError(Inst.TheDef->getLoc(), + "Input operands for Inst '" + Inst.TheDef->getName() + + "' and input Dag operand count mismatch"); + // The Dag can't have more arguments than the Instruction. + if (Dag->getNumArgs() > Inst.Operands.size()) + PrintFatalError(Inst.TheDef->getLoc(), + "Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + + // The Instruction might have tied operands so the Dag might have + // a fewer operand count. + unsigned RealCount = Inst.Operands.size(); + for (const auto &Operand : Inst.Operands) + if (Operand.getTiedRegister() != -1) + --RealCount; + + if (Dag->getNumArgs() != RealCount) + PrintFatalError(Inst.TheDef->getLoc(), + "Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + return true; +} + +static bool validateArgsTypes(Init *Arg1, Init *Arg2) { + return cast(Arg1)->getDef() == cast(Arg2)->getDef(); +} + +// Creates a mapping between the operand name in the Dag (e.g. $rs1) and +// its index in the list of Dag operands and checks that operands with the same +// name have the same types. For example in 'C_ADD $rs1, $rs2' we generate the +// mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied) +// same Dag we use the last occurrence for indexing. +void CompressInstEmitter::createDagOperandMapping( + Record *Rec, StringMap &SourceOperands, + StringMap &DestOperands, DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap) { + for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == DestDag->getArgNameStr(i)) + continue; + DestOperands[DestDag->getArgNameStr(i)] = i; + } + + for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == SourceDag->getArgNameStr(i)) + continue; + + StringMap::iterator it = + SourceOperands.find(SourceDag->getArgNameStr(i)); + if (it != SourceOperands.end()) { + // Operand sharing the same name in the Dag should be mapped as tied. + SourceOperandMap[i].TiedOpIdx = it->getValue(); + if (!validateArgsTypes(SourceDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), + "Input Operand '" + SourceDag->getArgNameStr(i) + + "' has a mismatched tied operand!\n"); + } + it = DestOperands.find(SourceDag->getArgNameStr(i)); + if (it == DestOperands.end()) + PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) + + " defined in Input Dag but not used in" + " Output Dag!\n"); + // Input Dag operand types must match output Dag operand type. + if (!validateArgsTypes(DestDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), "Type mismatch between Input and " + "Output Dag operand '" + + SourceDag->getArgNameStr(i) + "'!"); + SourceOperands[SourceDag->getArgNameStr(i)] = i; + } +} + +/// Map operand names in the Dag to their index in both corresponding input and +/// output instructions. Validate that operands defined in the input are +/// used in the output pattern while populating the maps. +void CompressInstEmitter::createInstOperandMapping( + Record *Rec, DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap, IndexedMap &DestOperandMap, + StringMap &SourceOperands, CodeGenInstruction &DestInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. + unsigned TiedCount = 0; + LLVM_DEBUG(dbgs() << " Operand mapping:\n Source Dest\n"); + for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) { + int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister(); + if (TiedInstOpIdx != -1) { + ++TiedCount; + DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data; + DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind; + if (DestOperandMap[i].Kind == OpData::Operand) + // No need to fill the SourceOperandMap here since it was mapped to + // destination operand 'TiedInstOpIdx' in a previous iteration. + LLVM_DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand + << " ====> " << i + << " Dest operand tied with operand '" + << TiedInstOpIdx << "'\n"); + continue; + } + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if (DestOperandMap[i].Kind != OpData::Operand) + continue; + + unsigned DagArgIdx = i - TiedCount; + StringMap::iterator SourceOp = + SourceOperands.find(DestDag->getArgNameStr(DagArgIdx)); + if (SourceOp == SourceOperands.end()) + PrintFatalError(Rec->getLoc(), + "Output Dag operand '" + + DestDag->getArgNameStr(DagArgIdx) + + "' has no matching input Dag operand."); + + assert(DestDag->getArgNameStr(DagArgIdx) == + SourceDag->getArgNameStr(SourceOp->getValue()) && + "Incorrect operand mapping detected!\n"); + DestOperandMap[i].Data.Operand = SourceOp->getValue(); + SourceOperandMap[SourceOp->getValue()].Data.Operand = i; + LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i + << "\n"); + } +} + +/// Validates the CompressPattern and create operand mapping. +/// These are the checks to validate a CompressPat pattern declarations. +/// Error out with message under these conditions: +/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a +/// compressed instruction. +/// - Operands in Dag Input must be all used in Dag Output. +/// Register Operand type in Dag Input Type must be contained in the +/// corresponding Source Instruction type. +/// - Register Operand type in Dag Input must be the same as in Dag Ouput. +/// - Register Operand type in Dag Output must be the same as the +/// corresponding Destination Inst type. +/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput. +/// - Immediate Operand type in Dag Ouput must be the same as the corresponding +/// Destination Instruction type. +/// - Fixed register must be contained in the corresponding Source Instruction +/// type. +/// - Fixed register must be contained in the corresponding Destination +/// Instruction type. Warning message printed under these conditions: +/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time +/// and generate warning. +/// - Immediate operand type in Dag Input differs from the corresponding Source +/// Instruction type and generate a warning. +void CompressInstEmitter::evaluateCompressPat(Record *Rec) { + // Validate input Dag operands. + DagInit *SourceDag = Rec->getValueAsDag("Input"); + assert(SourceDag && "Missing 'Input' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n"); + + // Checking we are transforming from compressed to uncompressed instructions. + Record *Operator = SourceDag->getOperatorAsDef(Rec->getLoc()); + if (!Operator->isSubClassOf("Inst32")) + PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() + + "' is not a 32 bit wide instruction!"); + CodeGenInstruction SourceInst(Operator); + verifyDagOpCount(SourceInst, SourceDag, true); + + // Validate output Dag operands. + DagInit *DestDag = Rec->getValueAsDag("Output"); + assert(DestDag && "Missing 'Output' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n"); + + Record *DestOperator = DestDag->getOperatorAsDef(Rec->getLoc()); + if (!DestOperator->isSubClassOf("Inst16")) + PrintFatalError(Rec->getLoc(), "Output instruction '" + + DestOperator->getName() + + "' is not a 16 bit wide instruction!"); + CodeGenInstruction DestInst(DestOperator); + verifyDagOpCount(DestInst, DestDag, false); + + // Fill the mapping from the source to destination instructions. + + IndexedMap SourceOperandMap; + SourceOperandMap.grow(SourceInst.Operands.size()); + // Create a mapping between source Dag operands and source Inst operands. + addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap, + /*IsSourceInst*/ true); + + IndexedMap DestOperandMap; + DestOperandMap.grow(DestInst.Operands.size()); + // Create a mapping between destination Dag operands and destination Inst + // operands. + addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, + /*IsSourceInst*/ false); + + StringMap SourceOperands; + StringMap DestOperands; + createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag, + SourceOperandMap); + // Create operand mapping between the source and destination instructions. + createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap, + DestOperandMap, SourceOperands, DestInst); + + // Get the target features for the CompressPat. + std::vector PatReqFeatures; + std::vector RF = Rec->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + + CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures, + SourceOperandMap, DestOperandMap, + Rec->getValueAsBit("isCompressOnly"))); +} + +static void +getReqFeatures(std::set> &FeaturesSet, + std::set>> &AnyOfFeatureSets, + const std::vector &ReqFeatures) { + for (auto &R : ReqFeatures) { + const DagInit *D = R->getValueAsDag("AssemblerCondDag"); + std::string CombineType = D->getOperator()->getAsString(); + if (CombineType != "any_of" && CombineType != "all_of") + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + if (D->getNumArgs() == 0) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + bool IsOr = CombineType == "any_of"; + std::set> AnyOfSet; + + for (auto *Arg : D->getArgs()) { + bool IsNot = false; + if (auto *NotArg = dyn_cast(Arg)) { + if (NotArg->getOperator()->getAsString() != "not" || + NotArg->getNumArgs() != 1) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + Arg = NotArg->getArg(0); + IsNot = true; + } + if (!isa(Arg) || + !cast(Arg)->getDef()->isSubClassOf("SubtargetFeature")) + PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); + if (IsOr) + AnyOfSet.insert({IsNot, cast(Arg)->getDef()->getName()}); + else + FeaturesSet.insert({IsNot, cast(Arg)->getDef()->getName()}); + } + + if (IsOr) + AnyOfFeatureSets.insert(AnyOfSet); + } +} + +static unsigned getPredicates(DenseMap &PredicateMap, + std::vector &Predicates, + Record *Rec, StringRef Name) { + unsigned &Entry = PredicateMap[Rec]; + if (Entry) + return Entry; + + if (!Rec->isValueUnset(Name)) { + Predicates.push_back(Rec); + Entry = Predicates.size(); + return Entry; + } + + PrintFatalError(Rec->getLoc(), "No " + Name + + " predicate on this operand at all: '" + + Rec->getName() + "'"); + return 0; +} + +static void printPredicates(const std::vector &Predicates, + StringRef Name, raw_ostream &o) { + for (unsigned i = 0; i < Predicates.size(); ++i) { + StringRef Pred = Predicates[i]->getValueAsString(Name); + o << " case " << i + 1 << ": {\n" + << " // " << Predicates[i]->getName() << "\n" + << " " << Pred << "\n" + << " }\n"; + } +} + +static void mergeCondAndCode(raw_ostream &CombinedStream, StringRef CondStr, + StringRef CodeStr) { + // Remove first indentation and last '&&'. + CondStr = CondStr.drop_front(6).drop_back(4); + CombinedStream.indent(4) << "if (" << CondStr << ") {\n"; + CombinedStream << CodeStr; + CombinedStream.indent(4) << " return true;\n"; + CombinedStream.indent(4) << "} // if\n"; +} + +void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, + EmitterType EType) { + Record *AsmWriter = Target.getAsmWriter(); + if (!AsmWriter->getValueAsInt("PassSubtarget")) + PrintFatalError(AsmWriter->getLoc(), + "'PassSubtarget' is false. SubTargetInfo object is needed " + "for target features.\n"); + + StringRef Namespace = Target.getName(); + + // Sort entries in CompressPatterns to handle instructions that can have more + // than one candidate for compression\uncompression, e.g ADD can be + // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the + // source and destination are flipped and the sort key needs to change + // accordingly. + llvm::stable_sort(CompressPatterns, [EType](const CompressPat &LHS, + const CompressPat &RHS) { + if (EType == EmitterType::Compress || EType == EmitterType::CheckCompress) + return (LHS.Source.TheDef->getName() < RHS.Source.TheDef->getName()); + else + return (LHS.Dest.TheDef->getName() < RHS.Dest.TheDef->getName()); + }); + + // A list of MCOperandPredicates for all operands in use, and the reverse map. + std::vector MCOpPredicates; + DenseMap MCOpPredicateMap; + // A list of ImmLeaf Predicates for all operands in use, and the reverse map. + std::vector ImmLeafPredicates; + DenseMap ImmLeafPredicateMap; + + std::string F; + std::string FH; + raw_string_ostream Func(F); + raw_string_ostream FuncH(FH); + bool NeedMRI = false; + + if (EType == EmitterType::Compress) + o << "\n#ifdef GEN_COMPRESS_INSTR\n" + << "#undef GEN_COMPRESS_INSTR\n\n"; + else if (EType == EmitterType::Uncompress) + o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n" + << "#undef GEN_UNCOMPRESS_INSTR\n\n"; + else if (EType == EmitterType::CheckCompress) + o << "\n#ifdef GEN_CHECK_COMPRESS_INSTR\n" + << "#undef GEN_CHECK_COMPRESS_INSTR\n\n"; + + if (EType == EmitterType::Compress) { + FuncH << "static bool compressInst(MCInst &OutInst,\n"; + FuncH.indent(25) << "const MCInst &MI,\n"; + FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; + FuncH.indent(25) << "MCContext &Context) {\n"; + } else if (EType == EmitterType::Uncompress){ + FuncH << "static bool uncompressInst(MCInst &OutInst,\n"; + FuncH.indent(27) << "const MCInst &MI,\n"; + FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; + FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; + } else if (EType == EmitterType::CheckCompress) { + FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n"; + FuncH.indent(27) << "const " << Namespace << "Subtarget *Subtarget,\n"; + FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; + FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; + } + + if (CompressPatterns.empty()) { + o << FuncH.str(); + o.indent(2) << "return false;\n}\n"; + if (EType == EmitterType::Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else if (EType == EmitterType::Uncompress) + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; + else if (EType == EmitterType::CheckCompress) + o << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n"; + return; + } + + std::string CaseString; + raw_string_ostream CaseStream(CaseString); + StringRef PrevOp; + StringRef CurOp; + CaseStream << " switch (MI.getOpcode()) {\n"; + CaseStream << " default: return false;\n"; + + bool CompressOrCheck = + EType == EmitterType::Compress || EType == EmitterType::CheckCompress; + bool CompressOrUncompress = + EType == EmitterType::Compress || EType == EmitterType::Uncompress; + + for (auto &CompressPat : CompressPatterns) { + if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly) + continue; + + std::string CondString; + std::string CodeString; + raw_string_ostream CondStream(CondString); + raw_string_ostream CodeStream(CodeString); + CodeGenInstruction &Source = + CompressOrCheck ? CompressPat.Source : CompressPat.Dest; + CodeGenInstruction &Dest = + CompressOrCheck ? CompressPat.Dest : CompressPat.Source; + IndexedMap SourceOperandMap = CompressOrCheck ? + CompressPat.SourceOperandMap : CompressPat.DestOperandMap; + IndexedMap &DestOperandMap = CompressOrCheck ? + CompressPat.DestOperandMap : CompressPat.SourceOperandMap; + + CurOp = Source.TheDef->getName(); + // Check current and previous opcode to decide to continue or end a case. + if (CurOp != PrevOp) { + if (!PrevOp.empty()) + CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n"; + CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; + } + + std::set> FeaturesSet; + std::set>> AnyOfFeatureSets; + // Add CompressPat required features. + getReqFeatures(FeaturesSet, AnyOfFeatureSets, CompressPat.PatReqFeatures); + + // Add Dest instruction required features. + std::vector ReqFeatures; + std::vector RF = Dest.TheDef->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + getReqFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures); + + // Emit checks for all required features. + for (auto &Op : FeaturesSet) { + StringRef Not = Op.first ? "!" : ""; + CondStream.indent(6) << Not << "STI.getFeatureBits()[" << Namespace + << "::" << Op.second << "]" + << " &&\n"; + } + + // Emit checks for all required feature groups. + for (auto &Set : AnyOfFeatureSets) { + CondStream.indent(6) << "("; + for (auto &Op : Set) { + bool isLast = &Op == &*Set.rbegin(); + StringRef Not = Op.first ? "!" : ""; + CondStream << Not << "STI.getFeatureBits()[" << Namespace + << "::" << Op.second << "]"; + if (!isLast) + CondStream << " || "; + } + CondStream << ") &&\n"; + } + + // Start Source Inst operands validation. + unsigned OpNo = 0; + for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) { + if (SourceOperandMap[OpNo].TiedOpIdx != -1) { + if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) + CondStream.indent(6) + << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand(" + << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n"; + else + PrintFatalError("Unexpected tied operand types!\n"); + } + // Check for fixed immediates\registers in the source instruction. + switch (SourceOperandMap[OpNo].Kind) { + case OpData::Operand: + // We don't need to do anything for source instruction operand checks. + break; + case OpData::Imm: + CondStream.indent(6) + << "(MI.getOperand(" << OpNo << ").isImm()) &&\n" + << " (MI.getOperand(" << OpNo + << ").getImm() == " << SourceOperandMap[OpNo].Data.Imm << ") &&\n"; + break; + case OpData::Reg: { + Record *Reg = SourceOperandMap[OpNo].Data.Reg; + CondStream.indent(6) + << "(MI.getOperand(" << OpNo << ").getReg() == " << Namespace + << "::" << Reg->getName() << ") &&\n"; + break; + } + } + } + CodeStream.indent(6) << "// " << Dest.AsmString << "\n"; + if (CompressOrUncompress) + CodeStream.indent(6) << "OutInst.setOpcode(" << Namespace + << "::" << Dest.TheDef->getName() << ");\n"; + OpNo = 0; + for (const auto &DestOperand : Dest.Operands) { + CodeStream.indent(6) << "// Operand: " << DestOperand.Name << "\n"; + switch (DestOperandMap[OpNo].Kind) { + case OpData::Operand: { + unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; + // Check that the operand in the Source instruction fits + // the type for the Dest instruction. + if (DestOperand.Rec->isSubClassOf("RegisterClass")) { + NeedMRI = true; + // This is a register operand. Check the register class. + // Don't check register class if this is a tied operand, it was done + // for the operand its tied to. + if (DestOperand.getTiedRegister() == -1) + CondStream.indent(6) << "(MRI.getRegClass(" << Namespace + << "::" << DestOperand.Rec->getName() + << "RegClassID).contains(MI.getOperand(" + << OpIdx << ").getReg())) &&\n"; + + if (CompressOrUncompress) + CodeStream.indent(6) + << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; + } else { + // Handling immediate operands. + if (CompressOrUncompress) { + unsigned Entry = + getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec, + "MCOperandPredicate"); + CondStream.indent(6) + << Namespace << "ValidateMCOperand(" + << "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n"; + } else { + unsigned Entry = + getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, + DestOperand.Rec, "ImmediateCode"); + CondStream.indent(6) + << "MI.getOperand(" << OpIdx << ").isImm() &&\n"; + CondStream.indent(6) << Namespace << "ValidateMachineOperand(" + << "MI.getOperand(" << OpIdx + << "), Subtarget, " << Entry << ") &&\n"; + } + if (CompressOrUncompress) + CodeStream.indent(6) + << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; + } + break; + } + case OpData::Imm: { + if (CompressOrUncompress) { + unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, + DestOperand.Rec, "MCOperandPredicate"); + CondStream.indent(6) + << Namespace << "ValidateMCOperand(" + << "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm + << "), STI, " << Entry << ") &&\n"; + } else { + unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, + DestOperand.Rec, "ImmediateCode"); + CondStream.indent(6) + << Namespace + << "ValidateMachineOperand(MachineOperand::CreateImm(" + << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry + << ") &&\n"; + } + if (CompressOrUncompress) + CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createImm(" + << DestOperandMap[OpNo].Data.Imm << "));\n"; + } break; + case OpData::Reg: { + if (CompressOrUncompress) { + // Fixed register has been validated at pattern validation time. + Record *Reg = DestOperandMap[OpNo].Data.Reg; + CodeStream.indent(6) + << "OutInst.addOperand(MCOperand::createReg(" << Namespace + << "::" << Reg->getName() << "));\n"; + } + } break; + } + ++OpNo; + } + if (CompressOrUncompress) + CodeStream.indent(6) << "OutInst.setLoc(MI.getLoc());\n"; + mergeCondAndCode(CaseStream, CondStream.str(), CodeStream.str()); + PrevOp = CurOp; + } + Func << CaseStream.str() << "\n"; + // Close brace for the last case. + Func.indent(4) << "} // case " << CurOp << "\n"; + Func.indent(2) << "} // switch\n"; + Func.indent(2) << "return false;\n}\n"; + + if (!MCOpPredicates.empty()) { + o << "static bool " << Namespace + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + printPredicates(MCOpPredicates, "MCOperandPredicate", o); + + o << " }\n" + << "}\n\n"; + } + + if (!ImmLeafPredicates.empty()) { + o << "static bool " << Namespace + << "ValidateMachineOperand(const MachineOperand &MO,\n" + << " const "<< Namespace << "Subtarget *Subtarget,\n" + << " unsigned PredicateIndex) {\n" + << " int64_t Imm = MO.getImm();\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown ImmLeaf Predicate kind\");\n" + << " break;\n"; + + printPredicates(ImmLeafPredicates, "ImmediateCode", o); + + o << " }\n" + << "}\n\n"; + } + + o << FuncH.str(); + if (NeedMRI && EType == EmitterType::Compress) + o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; + o << Func.str(); + + if (EType == EmitterType::Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else if (EType == EmitterType::Uncompress) + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; + else if (EType == EmitterType::CheckCompress) + o << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n"; +} + +void CompressInstEmitter::run(raw_ostream &o) { + std::vector Insts = Records.getAllDerivedDefinitions("CompressPat"); + + // Process the CompressPat definitions, validating them as we do so. + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + evaluateCompressPat(Insts[i]); + + // Emit file header. + emitSourceFileHeader("Compress instruction Source Fragment", o); + // Generate compressInst() function. + emitCompressInstEmitter(o, EmitterType::Compress); + // Generate uncompressInst() function. + emitCompressInstEmitter(o, EmitterType::Uncompress); + // Generate isCompressibleInst() function. + emitCompressInstEmitter(o, EmitterType::CheckCompress); +} + +namespace llvm { + +void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) { + CompressInstEmitter(RK).run(OS); +} + +} // namespace llvm Index: llvm/utils/TableGen/RISCVCompressInstEmitter.cpp =================================================================== --- llvm/utils/TableGen/RISCVCompressInstEmitter.cpp +++ /dev/null @@ -1,893 +0,0 @@ -//===- RISCVCompressInstEmitter.cpp - Generator for RISCV Compression -===// -// -// 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 -// -// RISCVCompressInstEmitter implements a tablegen-driven CompressPat based -// RISCV Instruction Compression mechanism. -// -//===--------------------------------------------------------------===// -// -// RISCVCompressInstEmitter implements a tablegen-driven CompressPat Instruction -// Compression mechanism for generating RISCV compressed instructions -// (C ISA Extension) from the expanded instruction form. - -// This tablegen backend processes CompressPat declarations in a -// td file and generates all the required checks to validate the pattern -// declarations; validate the input and output operands to generate the correct -// compressed instructions. The checks include validating different types of -// operands; register operands, immediate operands, fixed register and fixed -// immediate inputs. -// -// Example: -// class CompressPat { -// dag Input = input; -// dag Output = output; -// list Predicates = []; -// } -// -// let Predicates = [HasStdExtC] in { -// def : CompressPat<(ADD GPRNoX0:$rs1, GPRNoX0:$rs1, GPRNoX0:$rs2), -// (C_ADD GPRNoX0:$rs1, GPRNoX0:$rs2)>; -// } -// -// The result is an auto-generated header file -// 'RISCVGenCompressInstEmitter.inc' which exports two functions for -// compressing/uncompressing MCInst instructions, plus -// some helper functions: -// -// bool compressInst(MCInst &OutInst, const MCInst &MI, -// const MCSubtargetInfo &STI, -// MCContext &Context); -// -// bool uncompressInst(MCInst &OutInst, const MCInst &MI, -// const MCRegisterInfo &MRI, -// const MCSubtargetInfo &STI); -// -// In addition, it exports a function for checking whether -// an instruction is compressable: -// -// bool isCompressibleInst(const MachineInstr& MI, -// const RISCVSubtarget *Subtarget, -// const MCRegisterInfo &MRI, -// const MCSubtargetInfo &STI); -// -// The clients that include this auto-generated header file and -// invoke these functions can compress an instruction before emitting -// it in the target-specific ASM or ELF streamer or can uncompress -// an instruction before printing it when the expanded instruction -// format aliases is favored. - -//===----------------------------------------------------------------------===// - -#include "CodeGenInstruction.h" -#include "CodeGenTarget.h" -#include "llvm/ADT/IndexedMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include -#include -using namespace llvm; - -#define DEBUG_TYPE "compress-inst-emitter" - -namespace { -class RISCVCompressInstEmitter { - struct OpData { - enum MapKind { Operand, Imm, Reg }; - MapKind Kind; - union { - unsigned Operand; // Operand number mapped to. - int64_t Imm; // Integer immediate value. - Record *Reg; // Physical register. - } Data; - int TiedOpIdx = -1; // Tied operand index within the instruction. - }; - struct CompressPat { - CodeGenInstruction Source; // The source instruction definition. - CodeGenInstruction Dest; // The destination instruction to transform to. - std::vector - PatReqFeatures; // Required target features to enable pattern. - IndexedMap - SourceOperandMap; // Maps operands in the Source Instruction to - // the corresponding Dest instruction operand. - IndexedMap - DestOperandMap; // Maps operands in the Dest Instruction - // to the corresponding Source instruction operand. - bool IsCompressOnly; - CompressPat(CodeGenInstruction &S, CodeGenInstruction &D, - std::vector RF, IndexedMap &SourceMap, - IndexedMap &DestMap, bool IsCompressOnly) - : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), - DestOperandMap(DestMap), IsCompressOnly(IsCompressOnly) {} - }; - enum EmitterType { Compress, Uncompress, CheckCompress }; - RecordKeeper &Records; - CodeGenTarget Target; - SmallVector CompressPatterns; - - void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, - IndexedMap &OperandMap, bool IsSourceInst); - void evaluateCompressPat(Record *Compress); - void emitCompressInstEmitter(raw_ostream &o, EmitterType EType); - bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst); - bool validateRegister(Record *Reg, Record *RegClass); - void createDagOperandMapping(Record *Rec, StringMap &SourceOperands, - StringMap &DestOperands, - DagInit *SourceDag, DagInit *DestDag, - IndexedMap &SourceOperandMap); - - void createInstOperandMapping(Record *Rec, DagInit *SourceDag, - DagInit *DestDag, - IndexedMap &SourceOperandMap, - IndexedMap &DestOperandMap, - StringMap &SourceOperands, - CodeGenInstruction &DestInst); - -public: - RISCVCompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {} - - void run(raw_ostream &o); -}; -} // End anonymous namespace. - -bool RISCVCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) { - assert(Reg->isSubClassOf("Register") && "Reg record should be a Register"); - assert(RegClass->isSubClassOf("RegisterClass") && - "RegClass record should be a RegisterClass"); - const CodeGenRegisterClass &RC = Target.getRegisterClass(RegClass); - const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); - assert((R != nullptr) && "Register not defined!!"); - return RC.contains(R); -} - -bool RISCVCompressInstEmitter::validateTypes(Record *DagOpType, - Record *InstOpType, - bool IsSourceInst) { - if (DagOpType == InstOpType) - return true; - // Only source instruction operands are allowed to not match Input Dag - // operands. - if (!IsSourceInst) - return false; - - if (DagOpType->isSubClassOf("RegisterClass") && - InstOpType->isSubClassOf("RegisterClass")) { - const CodeGenRegisterClass &RC = Target.getRegisterClass(InstOpType); - const CodeGenRegisterClass &SubRC = Target.getRegisterClass(DagOpType); - return RC.hasSubClass(&SubRC); - } - - // At this point either or both types are not registers, reject the pattern. - if (DagOpType->isSubClassOf("RegisterClass") || - InstOpType->isSubClassOf("RegisterClass")) - return false; - - // Let further validation happen when compress()/uncompress() functions are - // invoked. - LLVM_DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") - << " Dag Operand Type: '" << DagOpType->getName() - << "' and " - << "Instruction Operand Type: '" << InstOpType->getName() - << "' can't be checked at pattern validation time!\n"); - return true; -} - -/// The patterns in the Dag contain different types of operands: -/// Register operands, e.g.: GPRC:$rs1; Fixed registers, e.g: X1; Immediate -/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function -/// maps Dag operands to its corresponding instruction operands. For register -/// operands and fixed registers it expects the Dag operand type to be contained -/// in the instantiated instruction operand type. For immediate operands and -/// immediates no validation checks are enforced at pattern validation time. -void RISCVCompressInstEmitter::addDagOperandMapping( - Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, - IndexedMap &OperandMap, bool IsSourceInst) { - // TiedCount keeps track of the number of operands skipped in Inst - // operands list to get to the corresponding Dag operand. This is - // necessary because the number of operands in Inst might be greater - // than number of operands in the Dag due to how tied operands - // are represented. - unsigned TiedCount = 0; - for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) { - int TiedOpIdx = Inst.Operands[i].getTiedRegister(); - if (-1 != TiedOpIdx) { - // Set the entry in OperandMap for the tied operand we're skipping. - OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind; - OperandMap[i].Data = OperandMap[TiedOpIdx].Data; - TiedCount++; - continue; - } - if (DefInit *DI = dyn_cast(Dag->getArg(i - TiedCount))) { - if (DI->getDef()->isSubClassOf("Register")) { - // Check if the fixed register belongs to the Register class. - if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec)) - PrintFatalError(Rec->getLoc(), - "Error in Dag '" + Dag->getAsString() + - "'Register: '" + DI->getDef()->getName() + - "' is not in register class '" + - Inst.Operands[i].Rec->getName() + "'"); - OperandMap[i].Kind = OpData::Reg; - OperandMap[i].Data.Reg = DI->getDef(); - continue; - } - // Validate that Dag operand type matches the type defined in the - // corresponding instruction. Operands in the input Dag pattern are - // allowed to be a subclass of the type specified in corresponding - // instruction operand instead of being an exact match. - if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst)) - PrintFatalError(Rec->getLoc(), - "Error in Dag '" + Dag->getAsString() + "'. Operand '" + - Dag->getArgNameStr(i - TiedCount) + "' has type '" + - DI->getDef()->getName() + - "' which does not match the type '" + - Inst.Operands[i].Rec->getName() + - "' in the corresponding instruction operand!"); - - OperandMap[i].Kind = OpData::Operand; - } else if (IntInit *II = dyn_cast(Dag->getArg(i - TiedCount))) { - // Validate that corresponding instruction operand expects an immediate. - if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass")) - PrintFatalError( - Rec->getLoc(), - "Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + - II->getAsString() + - "' but corresponding instruction operand expected a register!"); - // No pattern validation check possible for values of fixed immediate. - OperandMap[i].Kind = OpData::Imm; - OperandMap[i].Data.Imm = II->getValue(); - LLVM_DEBUG( - dbgs() << " Found immediate '" << II->getValue() << "' at " - << (IsSourceInst ? "input " : "output ") - << "Dag. No validation time check possible for values of " - "fixed immediate.\n"); - } else - llvm_unreachable("Unhandled CompressPat argument type!"); - } -} - -// Verify the Dag operand count is enough to build an instruction. -static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag, - bool IsSource) { - if (Dag->getNumArgs() == Inst.Operands.size()) - return true; - // Source instructions are non compressed instructions and don't have tied - // operands. - if (IsSource) - PrintFatalError(Inst.TheDef->getLoc(), - "Input operands for Inst '" + Inst.TheDef->getName() + - "' and input Dag operand count mismatch"); - // The Dag can't have more arguments than the Instruction. - if (Dag->getNumArgs() > Inst.Operands.size()) - PrintFatalError(Inst.TheDef->getLoc(), - "Inst '" + Inst.TheDef->getName() + - "' and Dag operand count mismatch"); - - // The Instruction might have tied operands so the Dag might have - // a fewer operand count. - unsigned RealCount = Inst.Operands.size(); - for (const auto &Operand : Inst.Operands) - if (Operand.getTiedRegister() != -1) - --RealCount; - - if (Dag->getNumArgs() != RealCount) - PrintFatalError(Inst.TheDef->getLoc(), - "Inst '" + Inst.TheDef->getName() + - "' and Dag operand count mismatch"); - return true; -} - -static bool validateArgsTypes(Init *Arg1, Init *Arg2) { - return cast(Arg1)->getDef() == cast(Arg2)->getDef(); -} - -// Creates a mapping between the operand name in the Dag (e.g. $rs1) and -// its index in the list of Dag operands and checks that operands with the same -// name have the same types. For example in 'C_ADD $rs1, $rs2' we generate the -// mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied) -// same Dag we use the last occurrence for indexing. -void RISCVCompressInstEmitter::createDagOperandMapping( - Record *Rec, StringMap &SourceOperands, - StringMap &DestOperands, DagInit *SourceDag, DagInit *DestDag, - IndexedMap &SourceOperandMap) { - for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) { - // Skip fixed immediates and registers, they were handled in - // addDagOperandMapping. - if ("" == DestDag->getArgNameStr(i)) - continue; - DestOperands[DestDag->getArgNameStr(i)] = i; - } - - for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) { - // Skip fixed immediates and registers, they were handled in - // addDagOperandMapping. - if ("" == SourceDag->getArgNameStr(i)) - continue; - - StringMap::iterator it = - SourceOperands.find(SourceDag->getArgNameStr(i)); - if (it != SourceOperands.end()) { - // Operand sharing the same name in the Dag should be mapped as tied. - SourceOperandMap[i].TiedOpIdx = it->getValue(); - if (!validateArgsTypes(SourceDag->getArg(it->getValue()), - SourceDag->getArg(i))) - PrintFatalError(Rec->getLoc(), - "Input Operand '" + SourceDag->getArgNameStr(i) + - "' has a mismatched tied operand!\n"); - } - it = DestOperands.find(SourceDag->getArgNameStr(i)); - if (it == DestOperands.end()) - PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) + - " defined in Input Dag but not used in" - " Output Dag!\n"); - // Input Dag operand types must match output Dag operand type. - if (!validateArgsTypes(DestDag->getArg(it->getValue()), - SourceDag->getArg(i))) - PrintFatalError(Rec->getLoc(), "Type mismatch between Input and " - "Output Dag operand '" + - SourceDag->getArgNameStr(i) + "'!"); - SourceOperands[SourceDag->getArgNameStr(i)] = i; - } -} - -/// Map operand names in the Dag to their index in both corresponding input and -/// output instructions. Validate that operands defined in the input are -/// used in the output pattern while populating the maps. -void RISCVCompressInstEmitter::createInstOperandMapping( - Record *Rec, DagInit *SourceDag, DagInit *DestDag, - IndexedMap &SourceOperandMap, IndexedMap &DestOperandMap, - StringMap &SourceOperands, CodeGenInstruction &DestInst) { - // TiedCount keeps track of the number of operands skipped in Inst - // operands list to get to the corresponding Dag operand. - unsigned TiedCount = 0; - LLVM_DEBUG(dbgs() << " Operand mapping:\n Source Dest\n"); - for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) { - int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister(); - if (TiedInstOpIdx != -1) { - ++TiedCount; - DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data; - DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind; - if (DestOperandMap[i].Kind == OpData::Operand) - // No need to fill the SourceOperandMap here since it was mapped to - // destination operand 'TiedInstOpIdx' in a previous iteration. - LLVM_DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand - << " ====> " << i - << " Dest operand tied with operand '" - << TiedInstOpIdx << "'\n"); - continue; - } - // Skip fixed immediates and registers, they were handled in - // addDagOperandMapping. - if (DestOperandMap[i].Kind != OpData::Operand) - continue; - - unsigned DagArgIdx = i - TiedCount; - StringMap::iterator SourceOp = - SourceOperands.find(DestDag->getArgNameStr(DagArgIdx)); - if (SourceOp == SourceOperands.end()) - PrintFatalError(Rec->getLoc(), - "Output Dag operand '" + - DestDag->getArgNameStr(DagArgIdx) + - "' has no matching input Dag operand."); - - assert(DestDag->getArgNameStr(DagArgIdx) == - SourceDag->getArgNameStr(SourceOp->getValue()) && - "Incorrect operand mapping detected!\n"); - DestOperandMap[i].Data.Operand = SourceOp->getValue(); - SourceOperandMap[SourceOp->getValue()].Data.Operand = i; - LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i - << "\n"); - } -} - -/// Validates the CompressPattern and create operand mapping. -/// These are the checks to validate a CompressPat pattern declarations. -/// Error out with message under these conditions: -/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a -/// compressed instruction. -/// - Operands in Dag Input must be all used in Dag Output. -/// Register Operand type in Dag Input Type must be contained in the -/// corresponding Source Instruction type. -/// - Register Operand type in Dag Input must be the same as in Dag Ouput. -/// - Register Operand type in Dag Output must be the same as the -/// corresponding Destination Inst type. -/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput. -/// - Immediate Operand type in Dag Ouput must be the same as the corresponding -/// Destination Instruction type. -/// - Fixed register must be contained in the corresponding Source Instruction -/// type. -/// - Fixed register must be contained in the corresponding Destination -/// Instruction type. Warning message printed under these conditions: -/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time -/// and generate warning. -/// - Immediate operand type in Dag Input differs from the corresponding Source -/// Instruction type and generate a warning. -void RISCVCompressInstEmitter::evaluateCompressPat(Record *Rec) { - // Validate input Dag operands. - DagInit *SourceDag = Rec->getValueAsDag("Input"); - assert(SourceDag && "Missing 'Input' in compress pattern!"); - LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n"); - - // Checking we are transforming from compressed to uncompressed instructions. - Record *Operator = SourceDag->getOperatorAsDef(Rec->getLoc()); - if (!Operator->isSubClassOf("RVInst")) - PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() + - "' is not a 32 bit wide instruction!"); - CodeGenInstruction SourceInst(Operator); - verifyDagOpCount(SourceInst, SourceDag, true); - - // Validate output Dag operands. - DagInit *DestDag = Rec->getValueAsDag("Output"); - assert(DestDag && "Missing 'Output' in compress pattern!"); - LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n"); - - Record *DestOperator = DestDag->getOperatorAsDef(Rec->getLoc()); - if (!DestOperator->isSubClassOf("RVInst16")) - PrintFatalError(Rec->getLoc(), "Output instruction '" + - DestOperator->getName() + - "' is not a 16 bit wide instruction!"); - CodeGenInstruction DestInst(DestOperator); - verifyDagOpCount(DestInst, DestDag, false); - - // Fill the mapping from the source to destination instructions. - - IndexedMap SourceOperandMap; - SourceOperandMap.grow(SourceInst.Operands.size()); - // Create a mapping between source Dag operands and source Inst operands. - addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap, - /*IsSourceInst*/ true); - - IndexedMap DestOperandMap; - DestOperandMap.grow(DestInst.Operands.size()); - // Create a mapping between destination Dag operands and destination Inst - // operands. - addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, - /*IsSourceInst*/ false); - - StringMap SourceOperands; - StringMap DestOperands; - createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag, - SourceOperandMap); - // Create operand mapping between the source and destination instructions. - createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap, - DestOperandMap, SourceOperands, DestInst); - - // Get the target features for the CompressPat. - std::vector PatReqFeatures; - std::vector RF = Rec->getValueAsListOfDefs("Predicates"); - copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) { - return R->getValueAsBit("AssemblerMatcherPredicate"); - }); - - CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures, - SourceOperandMap, DestOperandMap, - Rec->getValueAsBit("isCompressOnly"))); -} - -static void -getReqFeatures(std::set> &FeaturesSet, - std::set>> &AnyOfFeatureSets, - const std::vector &ReqFeatures) { - for (auto &R : ReqFeatures) { - const DagInit *D = R->getValueAsDag("AssemblerCondDag"); - std::string CombineType = D->getOperator()->getAsString(); - if (CombineType != "any_of" && CombineType != "all_of") - PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); - if (D->getNumArgs() == 0) - PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); - bool IsOr = CombineType == "any_of"; - std::set> AnyOfSet; - - for (auto *Arg : D->getArgs()) { - bool IsNot = false; - if (auto *NotArg = dyn_cast(Arg)) { - if (NotArg->getOperator()->getAsString() != "not" || - NotArg->getNumArgs() != 1) - PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); - Arg = NotArg->getArg(0); - IsNot = true; - } - if (!isa(Arg) || - !cast(Arg)->getDef()->isSubClassOf("SubtargetFeature")) - PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!"); - if (IsOr) - AnyOfSet.insert({IsNot, cast(Arg)->getDef()->getName()}); - else - FeaturesSet.insert({IsNot, cast(Arg)->getDef()->getName()}); - } - - if (IsOr) - AnyOfFeatureSets.insert(AnyOfSet); - } -} - -static unsigned getPredicates(DenseMap &PredicateMap, - std::vector &Predicates, - Record *Rec, StringRef Name) { - unsigned &Entry = PredicateMap[Rec]; - if (Entry) - return Entry; - - if (!Rec->isValueUnset(Name)) { - Predicates.push_back(Rec); - Entry = Predicates.size(); - return Entry; - } - - PrintFatalError(Rec->getLoc(), "No " + Name + - " predicate on this operand at all: '" + - Rec->getName() + "'"); - return 0; -} - -static void printPredicates(const std::vector &Predicates, - StringRef Name, raw_ostream &o) { - for (unsigned i = 0; i < Predicates.size(); ++i) { - StringRef Pred = Predicates[i]->getValueAsString(Name); - o << " case " << i + 1 << ": {\n" - << " // " << Predicates[i]->getName() << "\n" - << " " << Pred << "\n" - << " }\n"; - } -} - -static void mergeCondAndCode(raw_ostream &CombinedStream, StringRef CondStr, - StringRef CodeStr) { - // Remove first indentation and last '&&'. - CondStr = CondStr.drop_front(6).drop_back(4); - CombinedStream.indent(4) << "if (" << CondStr << ") {\n"; - CombinedStream << CodeStr; - CombinedStream.indent(4) << " return true;\n"; - CombinedStream.indent(4) << "} // if\n"; -} - -void RISCVCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, - EmitterType EType) { - Record *AsmWriter = Target.getAsmWriter(); - if (!AsmWriter->getValueAsInt("PassSubtarget")) - PrintFatalError(AsmWriter->getLoc(), - "'PassSubtarget' is false. SubTargetInfo object is needed " - "for target features.\n"); - - StringRef Namespace = Target.getName(); - - // Sort entries in CompressPatterns to handle instructions that can have more - // than one candidate for compression\uncompression, e.g ADD can be - // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the - // source and destination are flipped and the sort key needs to change - // accordingly. - llvm::stable_sort(CompressPatterns, [EType](const CompressPat &LHS, - const CompressPat &RHS) { - if (EType == EmitterType::Compress || EType == EmitterType::CheckCompress) - return (LHS.Source.TheDef->getName() < RHS.Source.TheDef->getName()); - else - return (LHS.Dest.TheDef->getName() < RHS.Dest.TheDef->getName()); - }); - - // A list of MCOperandPredicates for all operands in use, and the reverse map. - std::vector MCOpPredicates; - DenseMap MCOpPredicateMap; - // A list of ImmLeaf Predicates for all operands in use, and the reverse map. - std::vector ImmLeafPredicates; - DenseMap ImmLeafPredicateMap; - - std::string F; - std::string FH; - raw_string_ostream Func(F); - raw_string_ostream FuncH(FH); - bool NeedMRI = false; - - if (EType == EmitterType::Compress) - o << "\n#ifdef GEN_COMPRESS_INSTR\n" - << "#undef GEN_COMPRESS_INSTR\n\n"; - else if (EType == EmitterType::Uncompress) - o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n" - << "#undef GEN_UNCOMPRESS_INSTR\n\n"; - else if (EType == EmitterType::CheckCompress) - o << "\n#ifdef GEN_CHECK_COMPRESS_INSTR\n" - << "#undef GEN_CHECK_COMPRESS_INSTR\n\n"; - - if (EType == EmitterType::Compress) { - FuncH << "static bool compressInst(MCInst &OutInst,\n"; - FuncH.indent(25) << "const MCInst &MI,\n"; - FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; - FuncH.indent(25) << "MCContext &Context) {\n"; - } else if (EType == EmitterType::Uncompress){ - FuncH << "static bool uncompressInst(MCInst &OutInst,\n"; - FuncH.indent(27) << "const MCInst &MI,\n"; - FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; - FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; - } else if (EType == EmitterType::CheckCompress) { - FuncH << "static bool isCompressibleInst(const MachineInstr &MI,\n"; - FuncH.indent(27) << "const RISCVSubtarget *Subtarget,\n"; - FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; - FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; - } - - if (CompressPatterns.empty()) { - o << FuncH.str(); - o.indent(2) << "return false;\n}\n"; - if (EType == EmitterType::Compress) - o << "\n#endif //GEN_COMPRESS_INSTR\n"; - else if (EType == EmitterType::Uncompress) - o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; - else if (EType == EmitterType::CheckCompress) - o << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n"; - return; - } - - std::string CaseString; - raw_string_ostream CaseStream(CaseString); - StringRef PrevOp; - StringRef CurOp; - CaseStream << " switch (MI.getOpcode()) {\n"; - CaseStream << " default: return false;\n"; - - bool CompressOrCheck = - EType == EmitterType::Compress || EType == EmitterType::CheckCompress; - bool CompressOrUncompress = - EType == EmitterType::Compress || EType == EmitterType::Uncompress; - - for (auto &CompressPat : CompressPatterns) { - if (EType == EmitterType::Uncompress && CompressPat.IsCompressOnly) - continue; - - std::string CondString; - std::string CodeString; - raw_string_ostream CondStream(CondString); - raw_string_ostream CodeStream(CodeString); - CodeGenInstruction &Source = - CompressOrCheck ? CompressPat.Source : CompressPat.Dest; - CodeGenInstruction &Dest = - CompressOrCheck ? CompressPat.Dest : CompressPat.Source; - IndexedMap SourceOperandMap = CompressOrCheck ? - CompressPat.SourceOperandMap : CompressPat.DestOperandMap; - IndexedMap &DestOperandMap = CompressOrCheck ? - CompressPat.DestOperandMap : CompressPat.SourceOperandMap; - - CurOp = Source.TheDef->getName(); - // Check current and previous opcode to decide to continue or end a case. - if (CurOp != PrevOp) { - if (!PrevOp.empty()) - CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n"; - CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; - } - - std::set> FeaturesSet; - std::set>> AnyOfFeatureSets; - // Add CompressPat required features. - getReqFeatures(FeaturesSet, AnyOfFeatureSets, CompressPat.PatReqFeatures); - - // Add Dest instruction required features. - std::vector ReqFeatures; - std::vector RF = Dest.TheDef->getValueAsListOfDefs("Predicates"); - copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { - return R->getValueAsBit("AssemblerMatcherPredicate"); - }); - getReqFeatures(FeaturesSet, AnyOfFeatureSets, ReqFeatures); - - // Emit checks for all required features. - for (auto &Op : FeaturesSet) { - StringRef Not = Op.first ? "!" : ""; - CondStream.indent(6) << Not << "STI.getFeatureBits()[" << Namespace - << "::" << Op.second << "]" - << " &&\n"; - } - - // Emit checks for all required feature groups. - for (auto &Set : AnyOfFeatureSets) { - CondStream.indent(6) << "("; - for (auto &Op : Set) { - bool isLast = &Op == &*Set.rbegin(); - StringRef Not = Op.first ? "!" : ""; - CondStream << Not << "STI.getFeatureBits()[" << Namespace - << "::" << Op.second << "]"; - if (!isLast) - CondStream << " || "; - } - CondStream << ") &&\n"; - } - - // Start Source Inst operands validation. - unsigned OpNo = 0; - for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) { - if (SourceOperandMap[OpNo].TiedOpIdx != -1) { - if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) - CondStream.indent(6) - << "(MI.getOperand(" << OpNo << ").getReg() == MI.getOperand(" - << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n"; - else - PrintFatalError("Unexpected tied operand types!\n"); - } - // Check for fixed immediates\registers in the source instruction. - switch (SourceOperandMap[OpNo].Kind) { - case OpData::Operand: - // We don't need to do anything for source instruction operand checks. - break; - case OpData::Imm: - CondStream.indent(6) - << "(MI.getOperand(" << OpNo << ").isImm()) &&\n" - << " (MI.getOperand(" << OpNo - << ").getImm() == " << SourceOperandMap[OpNo].Data.Imm << ") &&\n"; - break; - case OpData::Reg: { - Record *Reg = SourceOperandMap[OpNo].Data.Reg; - CondStream.indent(6) - << "(MI.getOperand(" << OpNo << ").getReg() == " << Namespace - << "::" << Reg->getName() << ") &&\n"; - break; - } - } - } - CodeStream.indent(6) << "// " << Dest.AsmString << "\n"; - if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.setOpcode(" << Namespace - << "::" << Dest.TheDef->getName() << ");\n"; - OpNo = 0; - for (const auto &DestOperand : Dest.Operands) { - CodeStream.indent(6) << "// Operand: " << DestOperand.Name << "\n"; - switch (DestOperandMap[OpNo].Kind) { - case OpData::Operand: { - unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; - // Check that the operand in the Source instruction fits - // the type for the Dest instruction. - if (DestOperand.Rec->isSubClassOf("RegisterClass")) { - NeedMRI = true; - // This is a register operand. Check the register class. - // Don't check register class if this is a tied operand, it was done - // for the operand its tied to. - if (DestOperand.getTiedRegister() == -1) - CondStream.indent(6) << "(MRI.getRegClass(" << Namespace - << "::" << DestOperand.Rec->getName() - << "RegClassID).contains(MI.getOperand(" - << OpIdx << ").getReg())) &&\n"; - - if (CompressOrUncompress) - CodeStream.indent(6) - << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; - } else { - // Handling immediate operands. - if (CompressOrUncompress) { - unsigned Entry = - getPredicates(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec, - "MCOperandPredicate"); - CondStream.indent(6) - << Namespace << "ValidateMCOperand(" - << "MI.getOperand(" << OpIdx << "), STI, " << Entry << ") &&\n"; - } else { - unsigned Entry = - getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, - DestOperand.Rec, "ImmediateCode"); - CondStream.indent(6) - << "MI.getOperand(" << OpIdx << ").isImm() &&\n"; - CondStream.indent(6) << Namespace << "ValidateMachineOperand(" - << "MI.getOperand(" << OpIdx - << "), Subtarget, " << Entry << ") &&\n"; - } - if (CompressOrUncompress) - CodeStream.indent(6) - << "OutInst.addOperand(MI.getOperand(" << OpIdx << "));\n"; - } - break; - } - case OpData::Imm: { - if (CompressOrUncompress) { - unsigned Entry = getPredicates(MCOpPredicateMap, MCOpPredicates, - DestOperand.Rec, "MCOperandPredicate"); - CondStream.indent(6) - << Namespace << "ValidateMCOperand(" - << "MCOperand::createImm(" << DestOperandMap[OpNo].Data.Imm - << "), STI, " << Entry << ") &&\n"; - } else { - unsigned Entry = getPredicates(ImmLeafPredicateMap, ImmLeafPredicates, - DestOperand.Rec, "ImmediateCode"); - CondStream.indent(6) - << Namespace - << "ValidateMachineOperand(MachineOperand::CreateImm(" - << DestOperandMap[OpNo].Data.Imm << "), SubTarget, " << Entry - << ") &&\n"; - } - if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createImm(" - << DestOperandMap[OpNo].Data.Imm << "));\n"; - } break; - case OpData::Reg: { - if (CompressOrUncompress) { - // Fixed register has been validated at pattern validation time. - Record *Reg = DestOperandMap[OpNo].Data.Reg; - CodeStream.indent(6) - << "OutInst.addOperand(MCOperand::createReg(" << Namespace - << "::" << Reg->getName() << "));\n"; - } - } break; - } - ++OpNo; - } - if (CompressOrUncompress) - CodeStream.indent(6) << "OutInst.setLoc(MI.getLoc());\n"; - mergeCondAndCode(CaseStream, CondStream.str(), CodeStream.str()); - PrevOp = CurOp; - } - Func << CaseStream.str() << "\n"; - // Close brace for the last case. - Func.indent(4) << "} // case " << CurOp << "\n"; - Func.indent(2) << "} // switch\n"; - Func.indent(2) << "return false;\n}\n"; - - if (!MCOpPredicates.empty()) { - o << "static bool " << Namespace - << "ValidateMCOperand(const MCOperand &MCOp,\n" - << " const MCSubtargetInfo &STI,\n" - << " unsigned PredicateIndex) {\n" - << " switch (PredicateIndex) {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" - << " break;\n"; - - printPredicates(MCOpPredicates, "MCOperandPredicate", o); - - o << " }\n" - << "}\n\n"; - } - - if (!ImmLeafPredicates.empty()) { - o << "static bool " << Namespace - << "ValidateMachineOperand(const MachineOperand &MO,\n" - << " const RISCVSubtarget *Subtarget,\n" - << " unsigned PredicateIndex) {\n" - << " int64_t Imm = MO.getImm();\n" - << " switch (PredicateIndex) {\n" - << " default:\n" - << " llvm_unreachable(\"Unknown ImmLeaf Predicate kind\");\n" - << " break;\n"; - - printPredicates(ImmLeafPredicates, "ImmediateCode", o); - - o << " }\n" - << "}\n\n"; - } - - o << FuncH.str(); - if (NeedMRI && EType == EmitterType::Compress) - o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; - o << Func.str(); - - if (EType == EmitterType::Compress) - o << "\n#endif //GEN_COMPRESS_INSTR\n"; - else if (EType == EmitterType::Uncompress) - o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; - else if (EType == EmitterType::CheckCompress) - o << "\n#endif //GEN_CHECK_COMPRESS_INSTR\n\n"; -} - -void RISCVCompressInstEmitter::run(raw_ostream &o) { - std::vector Insts = Records.getAllDerivedDefinitions("CompressPat"); - - // Process the CompressPat definitions, validating them as we do so. - for (unsigned i = 0, e = Insts.size(); i != e; ++i) - evaluateCompressPat(Insts[i]); - - // Emit file header. - emitSourceFileHeader("Compress instruction Source Fragment", o); - // Generate compressInst() function. - emitCompressInstEmitter(o, EmitterType::Compress); - // Generate uncompressInst() function. - emitCompressInstEmitter(o, EmitterType::Uncompress); - // Generate isCompressibleInst() function. - emitCompressInstEmitter(o, EmitterType::CheckCompress); -} - -namespace llvm { - -void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS) { - RISCVCompressInstEmitter(RK).run(OS); -} - -} // namespace llvm