forked from OSchip/llvm-project
AArch64: TableGenerate system instruction operands.
The way the named arguments for various system instructions are handled at the moment has a few problems: - Large-scale duplication between AArch64BaseInfo.h and AArch64BaseInfo.cpp - That weird Mapping class that I have no idea what I was on when I thought it was a good idea. - Searches are performed linearly through the entire list. - We print absolutely all registers in upper-case, even though some are canonically mixed case (SPSel for example). - The ARM ARM specifies sysregs in terms of 5 fields, but those are relegated to comments in our implementation, with a slightly opaque hex value indicating the canonical encoding LLVM will use. This adds a new TableGen backend to produce efficiently searchable tables, and switches AArch64 over to using that infrastructure. llvm-svn: 274576
This commit is contained in:
parent
88403d7a84
commit
e6ae6767d9
|
@ -0,0 +1,41 @@
|
|||
//===- SearchableTable.td ----------------------------------*- tablegen -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the key top-level classes needed to produce a reasonably
|
||||
// generic table that can be binary-searched via int and string entries.
|
||||
//
|
||||
// Each table must instantiate "Mappingkind", listing the fields that should be
|
||||
// included and fields that shoould be searchable. Only two kinds of fields are
|
||||
// searchable at the moment: "strings" (which are compared case-insensitively),
|
||||
// and "bits".
|
||||
//
|
||||
// For each "MappingKind" the generated header will create GET_MAPPINGKIND_DECL
|
||||
// and GET_MAPPINGKIND_IMPL guards.
|
||||
//
|
||||
// Inside the DECL guard will be a set of function declarations:
|
||||
// "lookup{InstanceClass}By{SearchableField}", returning "const {InstanceClass}
|
||||
// *" and accepting either a StringRef or a uintN_t. Additionally, if
|
||||
// EnumNameField is still defined, there will be an "enum {InstanceClass}Values"
|
||||
// allowing C++ code to reference either the primary data table's entries (if
|
||||
// EnumValueField is not defined) or some other field (e.g. encoding) if it is.
|
||||
//
|
||||
// Inside the IMPL guard will be a primary data table "{InstanceClass}sList" and
|
||||
// as many searchable indexes as requested
|
||||
// ("{InstanceClass}sBy{SearchableField}"). Additionally implementations of the
|
||||
// lookup function will be provided.
|
||||
//
|
||||
// See AArch64SystemOperands.td and its generated header for example uses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class SearchableTable {
|
||||
list<string> SearchableFields;
|
||||
string EnumNameField = "Name";
|
||||
string EnumValueField;
|
||||
}
|
|
@ -131,6 +131,12 @@ include "AArch64InstrInfo.td"
|
|||
|
||||
def AArch64InstrInfo : InstrInfo;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Named operands for MRS/MSR/TLBI/...
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
include "AArch64SystemOperands.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AArch64 Processors supported.
|
||||
//
|
||||
|
|
|
@ -2438,12 +2438,14 @@ bool AArch64DAGToDAGISel::tryReadRegister(SDNode *N) {
|
|||
|
||||
// Use the sysreg mapper to map the remaining possible strings to the
|
||||
// value for the register to be used for the instruction operand.
|
||||
AArch64SysReg::MRSMapper mapper;
|
||||
bool IsValidSpecialReg;
|
||||
Reg = mapper.fromString(RegString->getString(),
|
||||
Subtarget->getFeatureBits(),
|
||||
IsValidSpecialReg);
|
||||
if (IsValidSpecialReg) {
|
||||
auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString());
|
||||
if (TheReg && TheReg->Readable &&
|
||||
TheReg->haveFeatures(Subtarget->getFeatureBits()))
|
||||
Reg = TheReg->Encoding;
|
||||
else
|
||||
Reg = AArch64SysReg::parseGenericRegister(RegString->getString());
|
||||
|
||||
if (Reg != -1) {
|
||||
ReplaceNode(N, CurDAG->getMachineNode(
|
||||
AArch64::MRS, DL, N->getSimpleValueType(0), MVT::Other,
|
||||
CurDAG->getTargetConstant(Reg, DL, MVT::i32),
|
||||
|
@ -2477,14 +2479,11 @@ bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) {
|
|||
// pstatefield for the MSR (immediate) instruction, we also require that an
|
||||
// immediate value has been provided as an argument, we know that this is
|
||||
// the case as it has been ensured by semantic checking.
|
||||
AArch64PState::PStateMapper PMapper;
|
||||
bool IsValidSpecialReg;
|
||||
Reg = PMapper.fromString(RegString->getString(),
|
||||
Subtarget->getFeatureBits(),
|
||||
IsValidSpecialReg);
|
||||
if (IsValidSpecialReg) {
|
||||
auto PMapper = AArch64PState::lookupPStateByName(RegString->getString());;
|
||||
if (PMapper) {
|
||||
assert (isa<ConstantSDNode>(N->getOperand(2))
|
||||
&& "Expected a constant integer expression.");
|
||||
unsigned Reg = PMapper->Encoding;
|
||||
uint64_t Immed = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
|
||||
unsigned State;
|
||||
if (Reg == AArch64PState::PAN || Reg == AArch64PState::UAO) {
|
||||
|
@ -2505,16 +2504,17 @@ bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) {
|
|||
// Use the sysreg mapper to attempt to map the remaining possible strings
|
||||
// to the value for the register to be used for the MSR (register)
|
||||
// instruction operand.
|
||||
AArch64SysReg::MSRMapper Mapper;
|
||||
Reg = Mapper.fromString(RegString->getString(),
|
||||
Subtarget->getFeatureBits(),
|
||||
IsValidSpecialReg);
|
||||
|
||||
if (IsValidSpecialReg) {
|
||||
ReplaceNode(
|
||||
N, CurDAG->getMachineNode(AArch64::MSR, DL, MVT::Other,
|
||||
CurDAG->getTargetConstant(Reg, DL, MVT::i32),
|
||||
N->getOperand(2), N->getOperand(0)));
|
||||
auto TheReg = AArch64SysReg::lookupSysRegByName(RegString->getString());
|
||||
if (TheReg && TheReg->Writeable &&
|
||||
TheReg->haveFeatures(Subtarget->getFeatureBits()))
|
||||
Reg = TheReg->Encoding;
|
||||
else
|
||||
Reg = AArch64SysReg::parseGenericRegister(RegString->getString());
|
||||
if (Reg != -1) {
|
||||
ReplaceNode(N, CurDAG->getMachineNode(
|
||||
AArch64::MSR, DL, MVT::Other,
|
||||
CurDAG->getTargetConstant(Reg, DL, MVT::i32),
|
||||
N->getOperand(2), N->getOperand(0)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -923,10 +923,7 @@ def psbhint_op : Operand<i32> {
|
|||
// "psb" is an alias to "hint" only for certain values of CRm:Op2 fields.
|
||||
if (!MCOp.isImm())
|
||||
return false;
|
||||
bool ValidNamed;
|
||||
(void)AArch64PSBHint::PSBHintMapper().toString(MCOp.getImm(),
|
||||
STI.getFeatureBits(), ValidNamed);
|
||||
return ValidNamed;
|
||||
return AArch64PSBHint::lookupPSBByEncoding(MCOp.getImm()) != nullptr;
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2073,12 +2073,9 @@ AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
|
|||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
bool Valid;
|
||||
auto Mapper = AArch64PRFM::PRFMMapper();
|
||||
StringRef Name =
|
||||
Mapper.toString(MCE->getValue(), getSTI().getFeatureBits(), Valid);
|
||||
Operands.push_back(AArch64Operand::CreatePrefetch(prfop, Name,
|
||||
S, getContext()));
|
||||
auto PRFM = AArch64PRFM::lookupPRFMByEncoding(MCE->getValue());
|
||||
Operands.push_back(AArch64Operand::CreatePrefetch(
|
||||
prfop, PRFM ? PRFM->Name : "", S, getContext()));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
|
@ -2087,18 +2084,15 @@ AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
|
|||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
bool Valid;
|
||||
auto Mapper = AArch64PRFM::PRFMMapper();
|
||||
unsigned prfop =
|
||||
Mapper.fromString(Tok.getString(), getSTI().getFeatureBits(), Valid);
|
||||
if (!Valid) {
|
||||
auto PRFM = AArch64PRFM::lookupPRFMByName(Tok.getString());
|
||||
if (!PRFM) {
|
||||
TokError("pre-fetch hint expected");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
Parser.Lex(); // Eat identifier token.
|
||||
Operands.push_back(AArch64Operand::CreatePrefetch(prfop, Tok.getString(),
|
||||
S, getContext()));
|
||||
Operands.push_back(AArch64Operand::CreatePrefetch(
|
||||
PRFM->Encoding, Tok.getString(), S, getContext()));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
|
@ -2113,18 +2107,15 @@ AArch64AsmParser::tryParsePSBHint(OperandVector &Operands) {
|
|||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
bool Valid;
|
||||
auto Mapper = AArch64PSBHint::PSBHintMapper();
|
||||
unsigned psbhint =
|
||||
Mapper.fromString(Tok.getString(), getSTI().getFeatureBits(), Valid);
|
||||
if (!Valid) {
|
||||
auto PSB = AArch64PSBHint::lookupPSBByName(Tok.getString());
|
||||
if (!PSB) {
|
||||
TokError("invalid operand for instruction");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
Parser.Lex(); // Eat identifier token.
|
||||
Operands.push_back(AArch64Operand::CreatePSBHint(psbhint, Tok.getString(),
|
||||
S, getContext()));
|
||||
Operands.push_back(AArch64Operand::CreatePSBHint(
|
||||
PSB->Encoding, Tok.getString(), S, getContext()));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
|
@ -2748,12 +2739,9 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
|
|||
Error(ExprLoc, "barrier operand out of range");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
bool Valid;
|
||||
auto Mapper = AArch64DB::DBarrierMapper();
|
||||
StringRef Name =
|
||||
Mapper.toString(MCE->getValue(), getSTI().getFeatureBits(), Valid);
|
||||
Operands.push_back( AArch64Operand::CreateBarrier(MCE->getValue(), Name,
|
||||
ExprLoc, getContext()));
|
||||
auto DB = AArch64DB::lookupDBByEncoding(MCE->getValue());
|
||||
Operands.push_back(AArch64Operand::CreateBarrier(
|
||||
MCE->getValue(), DB ? DB->Name : "", ExprLoc, getContext()));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
|
@ -2762,23 +2750,20 @@ AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
|
|||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
bool Valid;
|
||||
auto Mapper = AArch64DB::DBarrierMapper();
|
||||
unsigned Opt =
|
||||
Mapper.fromString(Tok.getString(), getSTI().getFeatureBits(), Valid);
|
||||
if (!Valid) {
|
||||
auto DB = AArch64DB::lookupDBByName(Tok.getString());
|
||||
if (!DB) {
|
||||
TokError("invalid barrier option name");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
// The only valid named option for ISB is 'sy'
|
||||
if (Mnemonic == "isb" && Opt != AArch64DB::SY) {
|
||||
if (Mnemonic == "isb" && DB->Encoding != AArch64DB::sy) {
|
||||
TokError("'sy' or #imm operand expected");
|
||||
return MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
Operands.push_back( AArch64Operand::CreateBarrier(Opt, Tok.getString(),
|
||||
getLoc(), getContext()));
|
||||
Operands.push_back(AArch64Operand::CreateBarrier(
|
||||
DB->Encoding, Tok.getString(), getLoc(), getContext()));
|
||||
Parser.Lex(); // Consume the option
|
||||
|
||||
return MatchOperand_Success;
|
||||
|
@ -2792,28 +2777,22 @@ AArch64AsmParser::tryParseSysReg(OperandVector &Operands) {
|
|||
if (Tok.isNot(AsmToken::Identifier))
|
||||
return MatchOperand_NoMatch;
|
||||
|
||||
bool IsKnown;
|
||||
auto MRSMapper = AArch64SysReg::MRSMapper();
|
||||
uint32_t MRSReg = MRSMapper.fromString(Tok.getString(),
|
||||
getSTI().getFeatureBits(), IsKnown);
|
||||
assert(IsKnown == (MRSReg != -1U) &&
|
||||
"register should be -1 if and only if it's unknown");
|
||||
int MRSReg, MSRReg;
|
||||
auto SysReg = AArch64SysReg::lookupSysRegByName(Tok.getString());
|
||||
if (SysReg && SysReg->haveFeatures(getSTI().getFeatureBits())) {
|
||||
MRSReg = SysReg->Readable ? SysReg->Encoding : -1;
|
||||
MSRReg = SysReg->Writeable ? SysReg->Encoding : -1;
|
||||
} else
|
||||
MRSReg = MSRReg = AArch64SysReg::parseGenericRegister(Tok.getString());
|
||||
|
||||
auto MSRMapper = AArch64SysReg::MSRMapper();
|
||||
uint32_t MSRReg = MSRMapper.fromString(Tok.getString(),
|
||||
getSTI().getFeatureBits(), IsKnown);
|
||||
assert(IsKnown == (MSRReg != -1U) &&
|
||||
"register should be -1 if and only if it's unknown");
|
||||
auto PState = AArch64PState::lookupPStateByName(Tok.getString());
|
||||
unsigned PStateImm = -1;
|
||||
if (PState && PState->haveFeatures(getSTI().getFeatureBits()))
|
||||
PStateImm = PState->Encoding;
|
||||
|
||||
auto PStateMapper = AArch64PState::PStateMapper();
|
||||
uint32_t PStateField =
|
||||
PStateMapper.fromString(Tok.getString(),
|
||||
getSTI().getFeatureBits(), IsKnown);
|
||||
assert(IsKnown == (PStateField != -1U) &&
|
||||
"register should be -1 if and only if it's unknown");
|
||||
|
||||
Operands.push_back(AArch64Operand::CreateSysReg(
|
||||
Tok.getString(), getLoc(), MRSReg, MSRReg, PStateField, getContext()));
|
||||
Operands.push_back(
|
||||
AArch64Operand::CreateSysReg(Tok.getString(), getLoc(), MRSReg, MSRReg,
|
||||
PStateImm, getContext()));
|
||||
Parser.Lex(); // Eat identifier
|
||||
|
||||
return MatchOperand_Success;
|
||||
|
|
|
@ -12,6 +12,8 @@ tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel)
|
|||
tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv)
|
||||
tablegen(LLVM AArch64GenSubtargetInfo.inc -gen-subtarget)
|
||||
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
|
||||
tablegen(LLVM AArch64GenSystemOperands.inc -gen-searchable-tables)
|
||||
|
||||
add_public_tablegen_target(AArch64CommonTableGen)
|
||||
|
||||
# List of all GlobalISel files.
|
||||
|
|
|
@ -1523,13 +1523,12 @@ static DecodeStatus DecodeSystemPStateInstruction(llvm::MCInst &Inst,
|
|||
Inst.addOperand(MCOperand::createImm(pstate_field));
|
||||
Inst.addOperand(MCOperand::createImm(crm));
|
||||
|
||||
bool ValidNamed;
|
||||
const AArch64Disassembler *Dis =
|
||||
const AArch64Disassembler *Dis =
|
||||
static_cast<const AArch64Disassembler *>(Decoder);
|
||||
(void)AArch64PState::PStateMapper().toString(pstate_field,
|
||||
Dis->getSubtargetInfo().getFeatureBits(), ValidNamed);
|
||||
|
||||
return ValidNamed ? Success : Fail;
|
||||
auto PState = AArch64PState::lookupPStateByEncoding(pstate_field);
|
||||
if (PState && PState->haveFeatures(Dis->getSubtargetInfo().getFeatureBits()))
|
||||
return Success;
|
||||
return Fail;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeTestAndBranch(llvm::MCInst &Inst, uint32_t insn,
|
||||
|
|
|
@ -1191,11 +1191,9 @@ void AArch64InstPrinter::printPrefetchOp(const MCInst *MI, unsigned OpNum,
|
|||
const MCSubtargetInfo &STI,
|
||||
raw_ostream &O) {
|
||||
unsigned prfop = MI->getOperand(OpNum).getImm();
|
||||
bool Valid;
|
||||
StringRef Name =
|
||||
AArch64PRFM::PRFMMapper().toString(prfop, STI.getFeatureBits(), Valid);
|
||||
if (Valid)
|
||||
O << Name;
|
||||
auto PRFM = AArch64PRFM::lookupPRFMByEncoding(prfop);
|
||||
if (PRFM)
|
||||
O << PRFM->Name;
|
||||
else
|
||||
O << '#' << formatImm(prfop);
|
||||
}
|
||||
|
@ -1204,11 +1202,9 @@ void AArch64InstPrinter::printPSBHintOp(const MCInst *MI, unsigned OpNum,
|
|||
const MCSubtargetInfo &STI,
|
||||
raw_ostream &O) {
|
||||
unsigned psbhintop = MI->getOperand(OpNum).getImm();
|
||||
bool Valid;
|
||||
StringRef Name =
|
||||
AArch64PSBHint::PSBHintMapper().toString(psbhintop, STI.getFeatureBits(), Valid);
|
||||
if (Valid)
|
||||
O << Name;
|
||||
auto PSB = AArch64PSBHint::lookupPSBByEncoding(psbhintop);
|
||||
if (PSB)
|
||||
O << PSB->Name;
|
||||
else
|
||||
O << '#' << formatImm(psbhintop);
|
||||
}
|
||||
|
@ -1404,15 +1400,15 @@ void AArch64InstPrinter::printBarrierOption(const MCInst *MI, unsigned OpNo,
|
|||
unsigned Val = MI->getOperand(OpNo).getImm();
|
||||
unsigned Opcode = MI->getOpcode();
|
||||
|
||||
bool Valid;
|
||||
StringRef Name;
|
||||
if (Opcode == AArch64::ISB)
|
||||
Name = AArch64ISB::ISBMapper().toString(Val, STI.getFeatureBits(),
|
||||
Valid);
|
||||
else
|
||||
Name = AArch64DB::DBarrierMapper().toString(Val, STI.getFeatureBits(),
|
||||
Valid);
|
||||
if (Valid)
|
||||
if (Opcode == AArch64::ISB) {
|
||||
auto ISB = AArch64ISB::lookupISBByEncoding(Val);
|
||||
Name = ISB ? ISB->Name : "";
|
||||
} else {
|
||||
auto DB = AArch64DB::lookupDBByEncoding(Val);
|
||||
Name = DB ? DB->Name : "";
|
||||
}
|
||||
if (!Name.empty())
|
||||
O << Name;
|
||||
else
|
||||
O << "#" << Val;
|
||||
|
@ -1423,10 +1419,19 @@ void AArch64InstPrinter::printMRSSystemRegister(const MCInst *MI, unsigned OpNo,
|
|||
raw_ostream &O) {
|
||||
unsigned Val = MI->getOperand(OpNo).getImm();
|
||||
|
||||
auto Mapper = AArch64SysReg::MRSMapper();
|
||||
std::string Name = Mapper.toString(Val, STI.getFeatureBits());
|
||||
// Horrible hack for the one register that has identical encodings but
|
||||
// different names in MSR and MRS. Because of this, one of MRS and MSR is
|
||||
// going to get the wrong entry
|
||||
if (Val == AArch64SysReg::DBGDTRRX_EL0) {
|
||||
O << "DBGDTRRX_EL0";
|
||||
return;
|
||||
}
|
||||
|
||||
O << StringRef(Name).upper();
|
||||
const AArch64SysReg::SysReg *Reg = AArch64SysReg::lookupSysRegByEncoding(Val);
|
||||
if (Reg && Reg->Readable && Reg->haveFeatures(STI.getFeatureBits()))
|
||||
O << Reg->Name;
|
||||
else
|
||||
O << AArch64SysReg::genericRegisterString(Val);
|
||||
}
|
||||
|
||||
void AArch64InstPrinter::printMSRSystemRegister(const MCInst *MI, unsigned OpNo,
|
||||
|
@ -1434,10 +1439,19 @@ void AArch64InstPrinter::printMSRSystemRegister(const MCInst *MI, unsigned OpNo,
|
|||
raw_ostream &O) {
|
||||
unsigned Val = MI->getOperand(OpNo).getImm();
|
||||
|
||||
auto Mapper = AArch64SysReg::MSRMapper();
|
||||
std::string Name = Mapper.toString(Val, STI.getFeatureBits());
|
||||
// Horrible hack for the one register that has identical encodings but
|
||||
// different names in MSR and MRS. Because of this, one of MRS and MSR is
|
||||
// going to get the wrong entry
|
||||
if (Val == AArch64SysReg::DBGDTRTX_EL0) {
|
||||
O << "DBGDTRTX_EL0";
|
||||
return;
|
||||
}
|
||||
|
||||
O << StringRef(Name).upper();
|
||||
const AArch64SysReg::SysReg *Reg = AArch64SysReg::lookupSysRegByEncoding(Val);
|
||||
if (Reg && Reg->Writeable && Reg->haveFeatures(STI.getFeatureBits()))
|
||||
O << Reg->Name;
|
||||
else
|
||||
O << AArch64SysReg::genericRegisterString(Val);
|
||||
}
|
||||
|
||||
void AArch64InstPrinter::printSystemPStateField(const MCInst *MI, unsigned OpNo,
|
||||
|
@ -1445,11 +1459,9 @@ void AArch64InstPrinter::printSystemPStateField(const MCInst *MI, unsigned OpNo,
|
|||
raw_ostream &O) {
|
||||
unsigned Val = MI->getOperand(OpNo).getImm();
|
||||
|
||||
bool Valid;
|
||||
StringRef Name =
|
||||
AArch64PState::PStateMapper().toString(Val, STI.getFeatureBits(), Valid);
|
||||
if (Valid)
|
||||
O << Name.upper();
|
||||
auto PState = AArch64PState::lookupPStateByEncoding(Val);
|
||||
if (PState && PState->haveFeatures(STI.getFeatureBits()))
|
||||
O << PState->Name;
|
||||
else
|
||||
O << "#" << formatImm(Val);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -35,7 +35,7 @@ entry:
|
|||
define void @write_daifset() nounwind {
|
||||
entry:
|
||||
; CHECK-LABEL: write_daifset:
|
||||
; CHECK: msr DAIFSET, #2
|
||||
; CHECK: msr DAIFSet, #2
|
||||
call void @llvm.write_register.i64(metadata !2, i64 2)
|
||||
ret void
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ msr ESR_EL1, x0
|
|||
mrs x0, SPSel
|
||||
mrs x0, ESR_EL1
|
||||
|
||||
// CHECK: msr SPSEL, #0 // encoding: [0xbf,0x40,0x00,0xd5]
|
||||
// CHECK: msr SPSEL, x0 // encoding: [0x00,0x42,0x18,0xd5]
|
||||
// CHECK: msr DAIFSET, #0 // encoding: [0xdf,0x40,0x03,0xd5]
|
||||
// CHECK: msr SPSel, #0 // encoding: [0xbf,0x40,0x00,0xd5]
|
||||
// CHECK: msr SPSel, x0 // encoding: [0x00,0x42,0x18,0xd5]
|
||||
// CHECK: msr DAIFSet, #0 // encoding: [0xdf,0x40,0x03,0xd5]
|
||||
// CHECK: msr ESR_EL1, x0 // encoding: [0x00,0x52,0x18,0xd5]
|
||||
// CHECK: mrs x0, SPSEL // encoding: [0x00,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x0, SPSel // encoding: [0x00,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x0, ESR_EL1 // encoding: [0x00,0x52,0x38,0xd5]
|
||||
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ foo:
|
|||
; CHECK: msr CPTR_EL2, x3 ; encoding: [0x43,0x11,0x1c,0xd5]
|
||||
; CHECK: msr CPTR_EL3, x3 ; encoding: [0x43,0x11,0x1e,0xd5]
|
||||
; CHECK: msr CSSELR_EL1, x3 ; encoding: [0x03,0x00,0x1a,0xd5]
|
||||
; CHECK: msr CURRENTEL, x3 ; encoding: [0x43,0x42,0x18,0xd5]
|
||||
; CHECK: msr CurrentEL, x3 ; encoding: [0x43,0x42,0x18,0xd5]
|
||||
; CHECK: msr DACR32_EL2, x3 ; encoding: [0x03,0x30,0x1c,0xd5]
|
||||
; CHECK: msr ESR_EL1, x3 ; encoding: [0x03,0x52,0x18,0xd5]
|
||||
; CHECK: msr ESR_EL2, x3 ; encoding: [0x03,0x52,0x1c,0xd5]
|
||||
|
@ -213,7 +213,7 @@ foo:
|
|||
; CHECK: msr VPIDR_EL2, x3 ; encoding: [0x03,0x00,0x1c,0xd5]
|
||||
; CHECK: msr VTCR_EL2, x3 ; encoding: [0x43,0x21,0x1c,0xd5]
|
||||
; CHECK: msr VTTBR_EL2, x3 ; encoding: [0x03,0x21,0x1c,0xd5]
|
||||
; CHECK: msr SPSEL, x3 ; encoding: [0x03,0x42,0x18,0xd5]
|
||||
; CHECK: msr SPSel, x3 ; encoding: [0x03,0x42,0x18,0xd5]
|
||||
; CHECK: msr S3_2_C11_C6_4, x1 ; encoding: [0x81,0xb6,0x1a,0xd5]
|
||||
; CHECK: msr S0_0_C0_C0_0, x0 ; encoding: [0x00,0x00,0x00,0xd5]
|
||||
; CHECK: msr S1_2_C3_C4_5, x2 ; encoding: [0xa2,0x34,0x0a,0xd5]
|
||||
|
@ -439,7 +439,7 @@ foo:
|
|||
; CHECK: mrs x3, CPTR_EL3 ; encoding: [0x43,0x11,0x3e,0xd5]
|
||||
; CHECK: mrs x3, CSSELR_EL1 ; encoding: [0x03,0x00,0x3a,0xd5]
|
||||
; CHECK: mrs x3, CTR_EL0 ; encoding: [0x23,0x00,0x3b,0xd5]
|
||||
; CHECK: mrs x3, CURRENTEL ; encoding: [0x43,0x42,0x38,0xd5]
|
||||
; CHECK: mrs x3, CurrentEL ; encoding: [0x43,0x42,0x38,0xd5]
|
||||
; CHECK: mrs x3, DACR32_EL2 ; encoding: [0x03,0x30,0x3c,0xd5]
|
||||
; CHECK: mrs x3, DCZID_EL0 ; encoding: [0xe3,0x00,0x3b,0xd5]
|
||||
; CHECK: mrs x3, REVIDR_EL1 ; encoding: [0xc3,0x00,0x38,0xd5]
|
||||
|
|
|
@ -3571,9 +3571,9 @@ _func:
|
|||
msr spsel, #0
|
||||
msr daifset, #15
|
||||
msr daifclr, #12
|
||||
// CHECK: msr {{spsel|SPSEL}}, #0 // encoding: [0xbf,0x40,0x00,0xd5]
|
||||
// CHECK: msr {{daifset|DAIFSET}}, #15 // encoding: [0xdf,0x4f,0x03,0xd5]
|
||||
// CHECK: msr {{daifclr|DAIFCLR}}, #12 // encoding: [0xff,0x4c,0x03,0xd5]
|
||||
// CHECK: msr {{SPSel|SPSEL}}, #0 // encoding: [0xbf,0x40,0x00,0xd5]
|
||||
// CHECK: msr {{DAIFSet|DAIFSET}}, #15 // encoding: [0xdf,0x4f,0x03,0xd5]
|
||||
// CHECK: msr {{DAIFClr|DAIFCLR}}, #12 // encoding: [0xff,0x4c,0x03,0xd5]
|
||||
|
||||
sys #7, c5, c9, #7, x5
|
||||
sys #0, c15, c15, #2
|
||||
|
@ -4070,14 +4070,14 @@ _func:
|
|||
// CHECK: msr {{sp_el0|SP_EL0}}, x12 // encoding: [0x0c,0x41,0x18,0xd5]
|
||||
// CHECK: msr {{sp_el1|SP_EL1}}, x12 // encoding: [0x0c,0x41,0x1c,0xd5]
|
||||
// CHECK: msr {{sp_el2|SP_EL2}}, x12 // encoding: [0x0c,0x41,0x1e,0xd5]
|
||||
// CHECK: msr {{spsel|SPSEL}}, x12 // encoding: [0x0c,0x42,0x18,0xd5]
|
||||
// CHECK: msr {{SPSel|SPSEL}}, x12 // encoding: [0x0c,0x42,0x18,0xd5]
|
||||
// CHECK: msr {{nzcv|NZCV}}, x12 // encoding: [0x0c,0x42,0x1b,0xd5]
|
||||
// CHECK: msr {{daif|DAIF}}, x12 // encoding: [0x2c,0x42,0x1b,0xd5]
|
||||
// CHECK: msr {{currentel|CURRENTEL}}, x12 // encoding: [0x4c,0x42,0x18,0xd5]
|
||||
// CHECK: msr {{spsr_irq|SPSR_IRQ}}, x12 // encoding: [0x0c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{spsr_abt|SPSR_ABT}}, x12 // encoding: [0x2c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{spsr_und|SPSR_UND}}, x12 // encoding: [0x4c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{spsr_fiq|SPSR_FIQ}}, x12 // encoding: [0x6c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{CurrentEL|CURRENTEL}}, x12 // encoding: [0x4c,0x42,0x18,0xd5]
|
||||
// CHECK: msr {{SPSR_irq|SPSR_IRQ}}, x12 // encoding: [0x0c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{SPSR_abt|SPSR_ABT}}, x12 // encoding: [0x2c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{SPSR_und|SPSR_UND}}, x12 // encoding: [0x4c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{SPSR_fiq|SPSR_FIQ}}, x12 // encoding: [0x6c,0x43,0x1c,0xd5]
|
||||
// CHECK: msr {{fpcr|FPCR}}, x12 // encoding: [0x0c,0x44,0x1b,0xd5]
|
||||
// CHECK: msr {{fpsr|FPSR}}, x12 // encoding: [0x2c,0x44,0x1b,0xd5]
|
||||
// CHECK: msr {{dspsr_el0|DSPSR_EL0}}, x12 // encoding: [0x0c,0x45,0x1b,0xd5]
|
||||
|
@ -4665,14 +4665,14 @@ _func:
|
|||
// CHECK: mrs x9, {{sp_el0|SP_EL0}} // encoding: [0x09,0x41,0x38,0xd5]
|
||||
// CHECK: mrs x9, {{sp_el1|SP_EL1}} // encoding: [0x09,0x41,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{sp_el2|SP_EL2}} // encoding: [0x09,0x41,0x3e,0xd5]
|
||||
// CHECK: mrs x9, {{spsel|SPSEL}} // encoding: [0x09,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x9, {{SPSel|SPSEL}} // encoding: [0x09,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x9, {{nzcv|NZCV}} // encoding: [0x09,0x42,0x3b,0xd5]
|
||||
// CHECK: mrs x9, {{daif|DAIF}} // encoding: [0x29,0x42,0x3b,0xd5]
|
||||
// CHECK: mrs x9, {{currentel|CURRENTEL}} // encoding: [0x49,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x9, {{spsr_irq|SPSR_IRQ}} // encoding: [0x09,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{spsr_abt|SPSR_ABT}} // encoding: [0x29,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{spsr_und|SPSR_UND}} // encoding: [0x49,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{spsr_fiq|SPSR_FIQ}} // encoding: [0x69,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{CurrentEL|CURRENTEL}} // encoding: [0x49,0x42,0x38,0xd5]
|
||||
// CHECK: mrs x9, {{SPSR_irq|SPSR_IRQ}} // encoding: [0x09,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{SPSR_abt|SPSR_ABT}} // encoding: [0x29,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{SPSR_und|SPSR_UND}} // encoding: [0x49,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{SPSR_fiq|SPSR_FIQ}} // encoding: [0x69,0x43,0x3c,0xd5]
|
||||
// CHECK: mrs x9, {{fpcr|FPCR}} // encoding: [0x09,0x44,0x3b,0xd5]
|
||||
// CHECK: mrs x9, {{fpsr|FPSR}} // encoding: [0x29,0x44,0x3b,0xd5]
|
||||
// CHECK: mrs x9, {{dspsr_el0|DSPSR_EL0}} // encoding: [0x09,0x45,0x3b,0xd5]
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
# CHECK: sys #2, c0, c5, #7
|
||||
# CHECK: sys #7, c6, c10, #7, x7
|
||||
# CHECK: sysl x20, #6, c3, c15, #7
|
||||
# CHECK: msr SPSEL, #0
|
||||
# CHECK: msr SPSel, #0
|
||||
# CHECK: msr S3_0_C11_C0_0, x0
|
||||
# CHECK: mrs x0, S3_0_C11_C0_0
|
||||
|
||||
|
|
|
@ -3131,9 +3131,9 @@
|
|||
0xdf 0x3f 0x3 0xd5
|
||||
0xdf 0x3c 0x3 0xd5
|
||||
|
||||
# CHECK: msr {{spsel|SPSEL}}, #0
|
||||
# CHECK: msr {{daifset|DAIFSET}}, #15
|
||||
# CHECK: msr {{daifclr|DAIFCLR}}, #12
|
||||
# CHECK: msr {{SPSel|SPSEL}}, #0
|
||||
# CHECK: msr {{DAIFSet|DAIFSET}}, #15
|
||||
# CHECK: msr {{DAIFClr|DAIFCLR}}, #12
|
||||
0xbf 0x40 0x0 0xd5
|
||||
0xdf 0x4f 0x3 0xd5
|
||||
0xff 0x4c 0x3 0xd5
|
||||
|
@ -3289,14 +3289,14 @@
|
|||
# CHECK: msr {{sp_el0|SP_EL0}}, x12
|
||||
# CHECK: msr {{sp_el1|SP_EL1}}, x12
|
||||
# CHECK: msr {{sp_el2|SP_EL2}}, x12
|
||||
# CHECK: msr {{spsel|SPSEL}}, x12
|
||||
# CHECK: msr {{SPSel|SPSEL}}, x12
|
||||
# CHECK: msr {{nzcv|NZCV}}, x12
|
||||
# CHECK: msr {{daif|DAIF}}, x12
|
||||
# CHECK: msr {{currentel|CURRENTEL}}, x12
|
||||
# CHECK: msr {{spsr_irq|SPSR_IRQ}}, x12
|
||||
# CHECK: msr {{spsr_abt|SPSR_ABT}}, x12
|
||||
# CHECK: msr {{spsr_und|SPSR_UND}}, x12
|
||||
# CHECK: msr {{spsr_fiq|SPSR_FIQ}}, x12
|
||||
# CHECK: msr {{CurrentEL|CURRENTEL}}, x12
|
||||
# CHECK: msr {{SPSR_irq|SPSR_IRQ}}, x12
|
||||
# CHECK: msr {{SPSR_abt|SPSR_ABT}}, x12
|
||||
# CHECK: msr {{SPSR_und|SPSR_UND}}, x12
|
||||
# CHECK: msr {{SPSR_fiq|SPSR_FIQ}}, x12
|
||||
# CHECK: msr {{fpcr|FPCR}}, x12
|
||||
# CHECK: msr {{fpsr|FPSR}}, x12
|
||||
# CHECK: msr {{dspsr_el0|DSPSR_EL0}}, x12
|
||||
|
@ -3581,14 +3581,14 @@
|
|||
# CHECK: mrs x9, {{sp_el0|SP_EL0}}
|
||||
# CHECK: mrs x9, {{sp_el1|SP_EL1}}
|
||||
# CHECK: mrs x9, {{sp_el2|SP_EL2}}
|
||||
# CHECK: mrs x9, {{spsel|SPSEL}}
|
||||
# CHECK: mrs x9, {{SPSel|SPSEL}}
|
||||
# CHECK: mrs x9, {{nzcv|NZCV}}
|
||||
# CHECK: mrs x9, {{daif|DAIF}}
|
||||
# CHECK: mrs x9, {{currentel|CURRENTEL}}
|
||||
# CHECK: mrs x9, {{spsr_irq|SPSR_IRQ}}
|
||||
# CHECK: mrs x9, {{spsr_abt|SPSR_ABT}}
|
||||
# CHECK: mrs x9, {{spsr_und|SPSR_UND}}
|
||||
# CHECK: mrs x9, {{spsr_fiq|SPSR_FIQ}}
|
||||
# CHECK: mrs x9, {{CurrentEL|CURRENTEL}}
|
||||
# CHECK: mrs x9, {{SPSR_irq|SPSR_IRQ}}
|
||||
# CHECK: mrs x9, {{SPSR_abt|SPSR_ABT}}
|
||||
# CHECK: mrs x9, {{SPSR_und|SPSR_UND}}
|
||||
# CHECK: mrs x9, {{SPSR_fiq|SPSR_FIQ}}
|
||||
# CHECK: mrs x9, {{fpcr|FPCR}}
|
||||
# CHECK: mrs x9, {{fpsr|FPSR}}
|
||||
# CHECK: mrs x9, {{dspsr_el0|DSPSR_EL0}}
|
||||
|
|
|
@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
|
|||
OptParserEmitter.cpp
|
||||
PseudoLoweringEmitter.cpp
|
||||
RegisterInfoEmitter.cpp
|
||||
SearchableTableEmitter.cpp
|
||||
SubtargetEmitter.cpp
|
||||
TableGen.cpp
|
||||
X86DisassemblerTables.cpp
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tablegen backend emits a generic array initialized by specified fields,
|
||||
// together with companion index tables and lookup functions (binary search,
|
||||
// currently).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "searchable-table-emitter"
|
||||
|
||||
namespace {
|
||||
|
||||
class SearchableTableEmitter {
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
|
||||
private:
|
||||
typedef std::pair<Init *, int> SearchTableEntry;
|
||||
|
||||
int getAsInt(BitsInit *B) {
|
||||
return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
|
||||
}
|
||||
int getInt(Record *R, StringRef Field) {
|
||||
return getAsInt(R->getValueAsBitsInit(Field));
|
||||
}
|
||||
|
||||
std::string primaryRepresentation(Init *I) {
|
||||
if (StringInit *SI = dyn_cast<StringInit>(I))
|
||||
return SI->getAsString();
|
||||
else if (BitsInit *BI = dyn_cast<BitsInit>(I))
|
||||
return "0x" + utohexstr(getAsInt(BI));
|
||||
else if (BitInit *BI = dyn_cast<BitInit>(I))
|
||||
return BI->getValue() ? "true" : "false";
|
||||
else if (CodeInit *CI = dyn_cast<CodeInit>(I)) {
|
||||
return CI->getValue();
|
||||
}
|
||||
PrintFatalError(SMLoc(),
|
||||
"invalid field type, expected: string, bits, bit or code");
|
||||
}
|
||||
|
||||
std::string searchRepresentation(Init *I) {
|
||||
std::string PrimaryRep = primaryRepresentation(I);
|
||||
if (!isa<StringInit>(I))
|
||||
return PrimaryRep;
|
||||
return StringRef(PrimaryRep).upper();
|
||||
}
|
||||
|
||||
std::string searchableFieldType(Init *I) {
|
||||
if (isa<StringInit>(I))
|
||||
return "const char *";
|
||||
else if (BitsInit *BI = dyn_cast<BitsInit>(I)) {
|
||||
unsigned NumBits = BI->getNumBits();
|
||||
if (NumBits <= 8)
|
||||
NumBits = 8;
|
||||
else if (NumBits <= 16)
|
||||
NumBits = 16;
|
||||
else if (NumBits <= 32)
|
||||
NumBits = 32;
|
||||
else if (NumBits <= 64)
|
||||
NumBits = 64;
|
||||
else
|
||||
PrintFatalError(SMLoc(), "bitfield too large to search");
|
||||
return "uint" + utostr(NumBits) + "_t";
|
||||
}
|
||||
PrintFatalError(SMLoc(), "Unknown type to search by");
|
||||
}
|
||||
|
||||
void emitMapping(Record *MappingDesc, raw_ostream &OS);
|
||||
void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass,
|
||||
raw_ostream &OS);
|
||||
void
|
||||
emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames,
|
||||
std::vector<std::string> &SearchFieldNames,
|
||||
std::vector<std::vector<SearchTableEntry>> &SearchTables,
|
||||
std::vector<Record *> &Items, raw_ostream &OS);
|
||||
void emitSearchTable(StringRef Name, StringRef Field,
|
||||
std::vector<SearchTableEntry> &SearchTable,
|
||||
raw_ostream &OS);
|
||||
void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I,
|
||||
raw_ostream &OS);
|
||||
void emitLookupFunction(StringRef Name, StringRef Field, Init *I,
|
||||
raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
/// Emit an enum providing symbolic access to some preferred field from
|
||||
/// C++.
|
||||
void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items,
|
||||
Record *InstanceClass,
|
||||
raw_ostream &OS) {
|
||||
std::string EnumNameField = InstanceClass->getValueAsString("EnumNameField");
|
||||
std::string EnumValueField;
|
||||
if (!InstanceClass->isValueUnset("EnumValueField"))
|
||||
EnumValueField = InstanceClass->getValueAsString("EnumValueField");
|
||||
|
||||
OS << "enum " << InstanceClass->getName() << "Values {\n";
|
||||
for (auto Item : Items) {
|
||||
OS << " " << Item->getValueAsString(EnumNameField);
|
||||
if (EnumValueField != StringRef())
|
||||
OS << " = " << getInt(Item, EnumValueField);
|
||||
OS << ",\n";
|
||||
}
|
||||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::emitPrimaryTable(
|
||||
StringRef Name, std::vector<std::string> &FieldNames,
|
||||
std::vector<std::string> &SearchFieldNames,
|
||||
std::vector<std::vector<SearchTableEntry>> &SearchTables,
|
||||
std::vector<Record *> &Items, raw_ostream &OS) {
|
||||
OS << "const " << Name << " " << Name << "sList[] = {\n";
|
||||
|
||||
for (auto Item : Items) {
|
||||
OS << " { ";
|
||||
for (unsigned i = 0; i < FieldNames.size(); ++i) {
|
||||
OS << primaryRepresentation(Item->getValueInit(FieldNames[i]));
|
||||
if (i != FieldNames.size() - 1)
|
||||
OS << ", ";
|
||||
}
|
||||
OS << "},\n";
|
||||
}
|
||||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::emitSearchTable(
|
||||
StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable,
|
||||
raw_ostream &OS) {
|
||||
OS << "const std::pair<" << searchableFieldType(SearchTable[0].first)
|
||||
<< ", int> " << Name << "sBy" << Field << "[] = {\n";
|
||||
|
||||
if (isa<BitsInit>(SearchTable[0].first)) {
|
||||
std::stable_sort(SearchTable.begin(), SearchTable.end(),
|
||||
[this](const SearchTableEntry &LHS,
|
||||
const SearchTableEntry &RHS) {
|
||||
return getAsInt(cast<BitsInit>(LHS.first)) <
|
||||
getAsInt(cast<BitsInit>(RHS.first));
|
||||
});
|
||||
} else {
|
||||
std::stable_sort(SearchTable.begin(), SearchTable.end(),
|
||||
[this](const SearchTableEntry &LHS,
|
||||
const SearchTableEntry &RHS) {
|
||||
return searchRepresentation(LHS.first) <
|
||||
searchRepresentation(RHS.first);
|
||||
});
|
||||
}
|
||||
|
||||
for (auto Entry : SearchTable) {
|
||||
OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second
|
||||
<< " },\n";
|
||||
}
|
||||
OS << "};\n\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field,
|
||||
Init *I, raw_ostream &OS) {
|
||||
bool IsIntegral = isa<BitsInit>(I);
|
||||
std::string FieldType = searchableFieldType(I);
|
||||
std::string PairType = "std::pair<" + FieldType + ", int>";
|
||||
|
||||
// const SysRegs *lookupSysRegByName(const char *Name) {
|
||||
OS << "const " << Name << " *"
|
||||
<< "lookup" << Name << "By" << Field;
|
||||
OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
|
||||
<< ") {\n";
|
||||
|
||||
if (IsIntegral) {
|
||||
OS << " auto CanonicalVal = " << Field << ";\n";
|
||||
OS << " " << PairType << " Val = {CanonicalVal, 0};\n";
|
||||
} else {
|
||||
// Make sure the result is null terminated because it's going via "char *".
|
||||
OS << " std::string CanonicalVal = " << Field << ".upper();\n";
|
||||
OS << " " << PairType << " Val = {CanonicalVal.data(), 0};\n";
|
||||
}
|
||||
|
||||
OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field
|
||||
<< ");\n";
|
||||
OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val";
|
||||
|
||||
if (IsIntegral)
|
||||
OS << ");\n";
|
||||
else {
|
||||
OS << ",\n ";
|
||||
OS << "[](const " << PairType << " &LHS, const " << PairType
|
||||
<< " &RHS) {\n";
|
||||
OS << " return StringRef(LHS.first) < StringRef(RHS.first);\n";
|
||||
OS << " });\n\n";
|
||||
}
|
||||
|
||||
OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n";
|
||||
OS << " return nullptr;\n";
|
||||
|
||||
OS << " return &" << Name << "sList[Idx->second];\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::emitLookupDeclaration(StringRef Name,
|
||||
StringRef Field, Init *I,
|
||||
raw_ostream &OS) {
|
||||
bool IsIntegral = isa<BitsInit>(I);
|
||||
std::string FieldType = searchableFieldType(I);
|
||||
OS << "const " << Name << " *"
|
||||
<< "lookup" << Name << "By" << Field;
|
||||
OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
|
||||
<< ");\n\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::emitMapping(Record *InstanceClass,
|
||||
raw_ostream &OS) {
|
||||
std::string TableName = InstanceClass->getName();
|
||||
std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
|
||||
|
||||
// Gather all the records we're going to need for this particular mapping.
|
||||
std::vector<std::vector<SearchTableEntry>> SearchTables;
|
||||
std::vector<std::string> SearchFieldNames;
|
||||
|
||||
std::vector<std::string> FieldNames;
|
||||
for (const RecordVal &Field : InstanceClass->getValues()) {
|
||||
std::string FieldName = Field.getName();
|
||||
|
||||
// Skip uninteresting fields: either built-in, special to us, or injected
|
||||
// template parameters (if they contain a ':').
|
||||
if (FieldName.find(':') != std::string::npos || FieldName == "NAME" ||
|
||||
FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
|
||||
FieldName == "EnumValueField")
|
||||
continue;
|
||||
|
||||
FieldNames.push_back(FieldName);
|
||||
}
|
||||
|
||||
for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) {
|
||||
SearchTables.emplace_back();
|
||||
SearchFieldNames.push_back(Field->getAsUnquotedString());
|
||||
}
|
||||
|
||||
int Idx = 0;
|
||||
for (Record *Item : Items) {
|
||||
for (unsigned i = 0; i < SearchFieldNames.size(); ++i) {
|
||||
Init *SearchVal = Item->getValueInit(SearchFieldNames[i]);
|
||||
SearchTables[i].emplace_back(SearchVal, Idx);
|
||||
}
|
||||
++Idx;
|
||||
}
|
||||
|
||||
OS << "#ifdef GET_" << StringRef(TableName).upper() << "_DECL\n";
|
||||
OS << "#undef GET_" << StringRef(TableName).upper() << "_DECL\n";
|
||||
|
||||
// Next emit the enum containing the top-level names for use in C++ code if
|
||||
// requested
|
||||
if (!InstanceClass->isValueUnset("EnumNameField")) {
|
||||
emitMappingEnum(Items, InstanceClass, OS);
|
||||
}
|
||||
|
||||
// And the declarations for the functions that will perform lookup.
|
||||
for (unsigned i = 0; i < SearchFieldNames.size(); ++i)
|
||||
emitLookupDeclaration(TableName, SearchFieldNames[i],
|
||||
SearchTables[i][0].first, OS);
|
||||
|
||||
OS << "#endif\n\n";
|
||||
|
||||
OS << "#ifdef GET_" << StringRef(TableName).upper() << "_IMPL\n";
|
||||
OS << "#undef GET_" << StringRef(TableName).upper() << "_IMPL\n";
|
||||
|
||||
// The primary data table contains all the fields defined for this map.
|
||||
emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items,
|
||||
OS);
|
||||
|
||||
// Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
|
||||
// search can be performed by "Thing".
|
||||
for (unsigned i = 0; i < SearchTables.size(); ++i) {
|
||||
emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS);
|
||||
emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first,
|
||||
OS);
|
||||
}
|
||||
|
||||
OS << "#endif\n";
|
||||
}
|
||||
|
||||
void SearchableTableEmitter::run(raw_ostream &OS) {
|
||||
// Tables are defined to be the direct descendents of "SearchableEntry".
|
||||
Record *SearchableTable = Records.getClass("SearchableTable");
|
||||
for (auto &NameRec : Records.getClasses()) {
|
||||
Record *Class = NameRec.second.get();
|
||||
if (Class->getSuperClasses().size() != 1 ||
|
||||
!Class->isSubClassOf(SearchableTable))
|
||||
continue;
|
||||
emitMapping(Class, OS);
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
|
||||
SearchableTableEmitter(RK).run(OS);
|
||||
}
|
||||
|
||||
} // End llvm namespace.
|
|
@ -43,7 +43,8 @@ enum ActionType {
|
|||
PrintSets,
|
||||
GenOptParserDefs,
|
||||
GenCTags,
|
||||
GenAttributes
|
||||
GenAttributes,
|
||||
GenSearchableTables,
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
@ -89,6 +90,8 @@ namespace {
|
|||
"Generate ctags-compatible index"),
|
||||
clEnumValN(GenAttributes, "gen-attrs",
|
||||
"Generate attributes"),
|
||||
clEnumValN(GenSearchableTables, "gen-searchable-tables",
|
||||
"Generate generic binary-searchable table"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<std::string>
|
||||
|
@ -172,6 +175,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
|||
case GenAttributes:
|
||||
EmitAttributes(Records, OS);
|
||||
break;
|
||||
case GenSearchableTables:
|
||||
EmitSearchableTables(Records, OS);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -79,6 +79,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
|
|||
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
|
Loading…
Reference in New Issue