diff options
author | Craig Topper <craig.topper@sifive.com> | 2025-07-25 14:15:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-25 14:15:02 -0700 |
commit | 18397f60633efefcee413d68a1e80cb726bb4d16 (patch) | |
tree | 43ac949cff60bba0bb25b087cc6c66b3937aa956 | |
parent | 9e09c4dd52a093501fe361890bd2924daf79e50e (diff) | |
download | llvm-18397f60633efefcee413d68a1e80cb726bb4d16.zip llvm-18397f60633efefcee413d68a1e80cb726bb4d16.tar.gz llvm-18397f60633efefcee413d68a1e80cb726bb4d16.tar.bz2 |
[RISCV] Use Record from CompressPat in compress/uncompress functions. (#150664)
Instead of using the Record from the instruction definition, use the
Record specified in the CompressPat DAG. This will allow us to use
Records that are subsets of both the source and destination.
I want to use this to merge the C_*_HINT instructions back into their
regular non-HINT versions, but prevent those encodings from being part
of compress/uncompress. For example, we will use GPRNoX0 for the C_ADDI
CompressPat while both C_ADDI and ADDI will use GPR in their instruction
definitions.
To do this I've recorded the original DAG Record in the OperandMap using
a struct in the union to represent the 3 fields needed for an Operand.
Previously we stored TiedOpIdx outside the union, but only used it for
Operand.
There is a verification hole here where we don't have any way to check
that an immediate predicate is a subset of an instruction predicate at
tablegen time. Prior to #148660 we had this hole in one direction, but
that patch made it in two directions. I'm not sure if this patch makes
it any worse. Now we're using what is in the CompressPat where before we
were using whatever was in the instructions and ignoring the predicate
in the CompressPat.
-rw-r--r-- | llvm/test/TableGen/CompressInstEmitter/suboperands.td | 16 | ||||
-rw-r--r-- | llvm/utils/TableGen/CompressInstEmitter.cpp | 102 |
2 files changed, 65 insertions, 53 deletions
diff --git a/llvm/test/TableGen/CompressInstEmitter/suboperands.td b/llvm/test/TableGen/CompressInstEmitter/suboperands.td index d83cc04..cd724e9 100644 --- a/llvm/test/TableGen/CompressInstEmitter/suboperands.td +++ b/llvm/test/TableGen/CompressInstEmitter/suboperands.td @@ -161,15 +161,15 @@ def : CompressPat<(BigInst3 RegsC:$dst, RegsC:$src, simm6:$imm), // CHECK-NEXT: } // if // CHECK-LABEL: ArchValidateMCOperandForUncompress -// CHECK: // simm12 -// CHECK: return isInt<12>(Imm); +// CHECK: // simm6 +// CHECK: return isInt<6>(Imm); // CHECK-LABEL: uncompressInst // CHECK: case Arch::SmallInst: // CHECK-NEXT: if (MI.getOperand(0).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(0).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) && // CHECK-NEXT: MI.getOperand(1).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(1).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) && // CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1)) { // CHECK-NEXT: // big $dst, $addr // CHECK-NEXT: OutInst.setOpcode(Arch::BigInst); @@ -183,9 +183,9 @@ def : CompressPat<(BigInst3 RegsC:$dst, RegsC:$src, simm6:$imm), // CHECK-NEXT: } // if // CHECK: case Arch::SmallInst2: // CHECK-NEXT: if (MI.getOperand(0).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(0).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) && // CHECK-NEXT: MI.getOperand(1).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(1).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) && // CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1)) { // CHECK-NEXT: // big $dst, $addr // CHECK-NEXT: OutInst.setOpcode(Arch::BigInst2); @@ -199,9 +199,9 @@ def : CompressPat<(BigInst3 RegsC:$dst, RegsC:$src, simm6:$imm), // CHECK-NEXT: } // if // CHECK: case Arch::SmallInst3: // CHECK-NEXT: if (MI.getOperand(0).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(0).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(0).getReg()) && // CHECK-NEXT: MI.getOperand(1).isReg() && -// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsRegClassID].contains(MI.getOperand(1).getReg()) && +// CHECK-NEXT: ArchMCRegisterClasses[Arch::RegsCRegClassID].contains(MI.getOperand(1).getReg()) && // CHECK-NEXT: ArchValidateMCOperandForUncompress(MI.getOperand(2), STI, 1)) { // CHECK-NEXT: // big $dst, $src, $imm // CHECK-NEXT: OutInst.setOpcode(Arch::BigInst3); diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp index 8889406..af119c3 100644 --- a/llvm/utils/TableGen/CompressInstEmitter.cpp +++ b/llvm/utils/TableGen/CompressInstEmitter.cpp @@ -86,16 +86,22 @@ namespace { class CompressInstEmitter { struct OpData { enum MapKind { Operand, Imm, Reg } Kind; - union { + // Info for an operand. + struct OpndInfo { + // Record from the Dag. + const Record *DagRec; // Operand number mapped to. - unsigned OpNo; + unsigned Idx; + // Tied operand index within the instruction. + int TiedOpIdx; + }; + union { + OpndInfo OpInfo; // Integer immediate value. int64_t ImmVal; // Physical register. const Record *RegRec; }; - // Tied operand index within the instruction. - int TiedOpIdx = -1; }; struct ArgData { unsigned DAGOpNo; @@ -273,6 +279,31 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec, "' in the corresponding instruction operand!"); OperandMap[OpNo].Kind = OpData::Operand; + OperandMap[OpNo].OpInfo.DagRec = DI->getDef(); + OperandMap[OpNo].OpInfo.TiedOpIdx = -1; + + // Create a mapping between the operand name in the Dag (e.g. $rs1) and + // its index in the list of Dag operands and check that operands with + // the same name have the same type. For example in 'C_ADD $rs1, $rs2' + // we generate the mapping $rs1 --> 0, $rs2 ---> 1. If the operand + // appears twice in the same Dag (tied in the compressed instruction), + // we note the previous index in the TiedOpIdx field. + StringRef ArgName = Dag->getArgNameStr(DAGOpNo); + if (ArgName.empty()) + continue; + + if (IsSourceInst) { + auto It = Operands.find(ArgName); + if (It != Operands.end()) { + OperandMap[OpNo].OpInfo.TiedOpIdx = It->getValue().MIOpNo; + if (OperandMap[It->getValue().MIOpNo].OpInfo.DagRec != DI->getDef()) + PrintFatalError(Rec->getLoc(), + "Input Operand '" + ArgName + + "' has a mismatched tied operand!"); + } + } + + Operands[ArgName] = {DAGOpNo, OpNo}; } else if (const auto *II = dyn_cast<IntInit>(Dag->getArg(DAGOpNo))) { // Validate that corresponding instruction operand expects an immediate. if (!OpndRec->isSubClassOf("Operand")) @@ -292,30 +323,6 @@ void CompressInstEmitter::addDagOperandMapping(const Record *Rec, } else { llvm_unreachable("Unhandled CompressPat argument type!"); } - - // Create a mapping between the operand name in the Dag (e.g. $rs1) and - // its index in the list of Dag operands and check that operands with the - // same name have the same type. For example in 'C_ADD $rs1, $rs2' we - // generate the mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears - // twice in the same Dag (tied in the compressed instruction), we note - // the previous index in the TiedOpIdx field. - StringRef ArgName = Dag->getArgNameStr(DAGOpNo); - if (ArgName.empty()) - continue; - - if (IsSourceInst) { - auto It = Operands.find(ArgName); - if (It != Operands.end()) { - OperandMap[OpNo].TiedOpIdx = It->getValue().MIOpNo; - if (!validateArgsTypes(Dag->getArg(It->getValue().DAGOpNo), - Dag->getArg(DAGOpNo))) - PrintFatalError(Rec->getLoc(), - "Input Operand '" + ArgName + - "' has a mismatched tied operand!"); - } - } - - Operands[ArgName] = {DAGOpNo, OpNo}; } } @@ -372,8 +379,9 @@ void CompressInstEmitter::createInstOperandMapping( if (DestOperandMap[OpNo].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[OpNo].OpNo << " ====> " - << OpNo << " Dest operand tied with operand '" + LLVM_DEBUG(dbgs() << " " << DestOperandMap[OpNo].OpInfo.Idx + << " ====> " << OpNo + << " Dest operand tied with operand '" << TiedInstOpIdx << "'\n"); ++OpNo; continue; @@ -398,8 +406,8 @@ void CompressInstEmitter::createInstOperandMapping( "Incorrect operand mapping detected!\n"); unsigned SourceOpNo = SourceOp->getValue().MIOpNo; - DestOperandMap[OpNo].OpNo = SourceOpNo; - SourceOperandMap[SourceOpNo].OpNo = OpNo; + DestOperandMap[OpNo].OpInfo.Idx = SourceOpNo; + SourceOperandMap[SourceOpNo].OpInfo.Idx = OpNo; LLVM_DEBUG(dbgs() << " " << SourceOpNo << " ====> " << OpNo << "\n"); } } @@ -721,21 +729,24 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS, // Start Source Inst operands validation. unsigned OpNo = 0; for (const auto &SourceOperand : Source.Operands) { - if (SourceOperandMap[OpNo].TiedOpIdx != -1) { - if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) - CondStream.indent(8) - << "(MI.getOperand(" << OpNo << ").isReg()) && (MI.getOperand(" - << SourceOperandMap[OpNo].TiedOpIdx << ").isReg()) &&\n" - << indent(8) << "(MI.getOperand(" << OpNo - << ").getReg() == MI.getOperand(" - << SourceOperandMap[OpNo].TiedOpIdx << ").getReg()) &&\n"; - else - PrintFatalError("Unexpected tied operand types!"); - } for (unsigned SubOp = 0; SubOp != SourceOperand.MINumOperands; ++SubOp) { // Check for fixed immediates\registers in the source instruction. switch (SourceOperandMap[OpNo].Kind) { case OpData::Operand: + if (SourceOperandMap[OpNo].OpInfo.TiedOpIdx != -1) { + if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) + CondStream.indent(8) << "(MI.getOperand(" << OpNo + << ").isReg()) && (MI.getOperand(" + << SourceOperandMap[OpNo].OpInfo.TiedOpIdx + << ").isReg()) &&\n" + << indent(8) << "(MI.getOperand(" << OpNo + << ").getReg() == MI.getOperand(" + << SourceOperandMap[OpNo].OpInfo.TiedOpIdx + << ").getReg()) &&\n"; + else + PrintFatalError("Unexpected tied operand types!"); + } + // We don't need to do anything for source instruction operand checks. break; case OpData::Imm: @@ -773,7 +784,8 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS, switch (DestOperandMap[OpNo].Kind) { case OpData::Operand: { - unsigned OpIdx = DestOperandMap[OpNo].OpNo; + unsigned OpIdx = DestOperandMap[OpNo].OpInfo.Idx; + DestRec = DestOperandMap[OpNo].OpInfo.DagRec; // Check that the operand in the Source instruction fits // the type for the Dest instruction. if (DestRec->isSubClassOf("RegisterClass") || @@ -783,7 +795,7 @@ void CompressInstEmitter::emitCompressInstEmitter(raw_ostream &OS, : DestRec->getValueAsDef("RegClass"); // 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. + // for the operand it's tied to. if (DestOperand.getTiedRegister() == -1) { CondStream.indent(8) << "MI.getOperand(" << OpIdx << ").isReg()"; if (EType == EmitterType::CheckCompress) |