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:
Tim Northover 2016-07-05 21:23:04 +00:00
parent 88403d7a84
commit e6ae6767d9
21 changed files with 1669 additions and 2004 deletions

View File

@ -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;
}

View File

@ -131,6 +131,12 @@ include "AArch64InstrInfo.td"
def AArch64InstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
// Named operands for MRS/MSR/TLBI/...
//===----------------------------------------------------------------------===//
include "AArch64SystemOperands.td"
//===----------------------------------------------------------------------===//
// AArch64 Processors supported.
//

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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,

View File

@ -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

View File

@ -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
}

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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}}

View File

@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
SearchableTableEmitter.cpp
SubtargetEmitter.cpp
TableGen.cpp
X86DisassemblerTables.cpp

View File

@ -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.

View File

@ -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;

View File

@ -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