1,018 changes: 1,018 additions & 0 deletions llvm/lib/Target/AArch64/AArch64SystemOperands.td

Large diffs are not rendered by default.

91 changes: 35 additions & 56 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

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

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

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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");

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 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()));
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 PState = AArch64PState::lookupPStateByName(Tok.getString());
unsigned PStateImm = -1;
if (PState && PState->haveFeatures(getSTI().getFeatureBits()))
PStateImm = PState->Encoding;

Operands.push_back(
AArch64Operand::CreateSysReg(Tok.getString(), getLoc(), MRSReg, MSRReg,
PStateImm, getContext()));
Parser.Lex(); // Eat identifier

return MatchOperand_Success;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 5 additions & 6 deletions llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
70 changes: 41 additions & 29 deletions llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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;
Expand All @@ -1423,33 +1419,49 @@ 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,
const MCSubtargetInfo &STI,
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,
const MCSubtargetInfo &STI,
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);
}
Expand Down
956 changes: 59 additions & 897 deletions llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp

Large diffs are not rendered by default.

1,011 changes: 66 additions & 945 deletions llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion llvm/test/CodeGen/AArch64/special-reg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/MC/AArch64/arm64-spsel-sysreg.s
Original file line number Diff line number Diff line change
Expand Up @@ -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]


Expand Down
6 changes: 3 additions & 3 deletions llvm/test/MC/AArch64/arm64-system-encoding.s
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
30 changes: 15 additions & 15 deletions llvm/test/MC/AArch64/basic-a64-instructions.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/Disassembler/AArch64/arm64-system.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
30 changes: 15 additions & 15 deletions llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}}
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/TableGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
SearchableTableEmitter.cpp
SubtargetEmitter.cpp
TableGen.cpp
X86DisassemblerTables.cpp
Expand Down
320 changes: 320 additions & 0 deletions llvm/utils/TableGen/SearchableTableEmitter.cpp
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 7 additions & 1 deletion llvm/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ enum ActionType {
PrintSets,
GenOptParserDefs,
GenCTags,
GenAttributes
GenAttributes,
GenSearchableTables,
};

namespace {
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/TableGen/TableGenBackends.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down