mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-04 18:06:49 +00:00
Fix encoding and add parsing support for the arm/thumb CPS instruction:
- Add custom operand matching for imod and iflags. - Rename SplitMnemonicAndCC to SplitMnemonic since it splits more than CC from mnemonic. - While adding ".w" as an operand, don't change "Head" to avoid passing the wrong mnemonic to ParseOperand. - Add asm parser tests. - Add disassembler tests just to make sure it can catch all cps versions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@125489 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
283c8caccd
commit
a2b6e4151b
@ -97,6 +97,36 @@ inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace ARM_PROC {
|
||||
enum IMod {
|
||||
IE = 2,
|
||||
ID = 3
|
||||
};
|
||||
|
||||
enum IFlags {
|
||||
F = 1,
|
||||
I = 2,
|
||||
A = 4
|
||||
};
|
||||
|
||||
inline static const char *IFlagsToString(unsigned val) {
|
||||
switch (val) {
|
||||
default: llvm_unreachable("Unknown iflags operand");
|
||||
case F: return "f";
|
||||
case I: return "i";
|
||||
case A: return "a";
|
||||
}
|
||||
}
|
||||
|
||||
inline static const char *IModToString(unsigned val) {
|
||||
switch (val) {
|
||||
default: llvm_unreachable("Unknown imod operand");
|
||||
case IE: return "ie";
|
||||
case ID: return "id";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace ARM_MB {
|
||||
// The Memory Barrier Option constants map directly to the 4-bit encoding of
|
||||
// the option field for memory barrier operations.
|
||||
|
@ -155,6 +155,22 @@ def MemBarrierOptOperand : AsmOperandClass {
|
||||
let ParserMethod = "tryParseMemBarrierOptOperand";
|
||||
}
|
||||
|
||||
def ProcIFlagsOperand : AsmOperandClass {
|
||||
let Name = "ProcIFlags";
|
||||
let SuperClasses = [];
|
||||
let ParserMethod = "tryParseProcIFlagsOperand";
|
||||
}
|
||||
|
||||
// ARM imod and iflag operands, used only by the CPS instruction.
|
||||
def imod_op : Operand<i32> {
|
||||
let PrintMethod = "printCPSIMod";
|
||||
}
|
||||
|
||||
def iflags_op : Operand<i32> {
|
||||
let PrintMethod = "printCPSIFlag";
|
||||
let ParserMatchClass = ProcIFlagsOperand;
|
||||
}
|
||||
|
||||
// ARM Predicate operand. Default to 14 = always (AL). Second part is CC
|
||||
// register whose default is 0 (no register).
|
||||
def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),
|
||||
|
@ -1102,22 +1102,38 @@ def BKPT : AI<(outs), (ins i32imm:$val), MiscFrm, NoItinerary, "bkpt", "\t$val",
|
||||
let Inst{7-4} = 0b0111;
|
||||
}
|
||||
|
||||
// Change Processor State is a system instruction -- for disassembly only.
|
||||
// The singleton $opt operand contains the following information:
|
||||
// opt{4-0} = mode from Inst{4-0}
|
||||
// opt{5} = changemode from Inst{17}
|
||||
// opt{8-6} = AIF from Inst{8-6}
|
||||
// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
|
||||
// FIXME: Integrated assembler will need these split out.
|
||||
def CPS : AXI<(outs), (ins cps_opt:$opt), MiscFrm, NoItinerary, "cps$opt",
|
||||
[/* For disassembly only; pattern left blank */]>,
|
||||
Requires<[IsARM]> {
|
||||
// Change Processor State is a system instruction -- for disassembly and
|
||||
// parsing only.
|
||||
// FIXME: Since the asm parser has currently no clean way to handle optional
|
||||
// operands, create 3 versions of the same instruction. Once there's a clean
|
||||
// framework to represent optional operands, change this behavior.
|
||||
class CPS<dag iops, string asm_ops>
|
||||
: AXI<(outs), iops, MiscFrm, NoItinerary, !strconcat("cps", asm_ops),
|
||||
[/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> {
|
||||
bits<2> imod;
|
||||
bits<3> iflags;
|
||||
bits<5> mode;
|
||||
bit M;
|
||||
|
||||
let Inst{31-28} = 0b1111;
|
||||
let Inst{27-20} = 0b00010000;
|
||||
let Inst{16} = 0;
|
||||
let Inst{5} = 0;
|
||||
let Inst{19-18} = imod;
|
||||
let Inst{17} = M; // Enabled if mode is set;
|
||||
let Inst{16} = 0;
|
||||
let Inst{8-6} = iflags;
|
||||
let Inst{5} = 0;
|
||||
let Inst{4-0} = mode;
|
||||
}
|
||||
|
||||
let M = 1 in
|
||||
def CPS3p : CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode),
|
||||
"$imod\t$iflags, $mode">;
|
||||
let mode = 0, M = 0 in
|
||||
def CPS2p : CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod\t$iflags">;
|
||||
|
||||
let imod = 0, iflags = 0, M = 1 in
|
||||
def CPS1p : CPS<(ins i32imm:$mode), "\t$mode">;
|
||||
|
||||
// Preload signals the memory system of possible future data/instruction access.
|
||||
// These are for disassembly only.
|
||||
multiclass APreLoad<bits<1> read, bits<1> data, string opc> {
|
||||
|
@ -266,21 +266,17 @@ def tSETENDLE : T1I<(outs), (ins), NoItinerary, "setend\tle",
|
||||
}
|
||||
|
||||
// Change Processor State is a system instruction -- for disassembly only.
|
||||
// The singleton $opt operand contains the following information:
|
||||
//
|
||||
// opt{4-0} = mode ==> don't care
|
||||
// opt{5} = changemode ==> 0 (false for 16-bit Thumb instr)
|
||||
// opt{8-6} = AIF from Inst{2-0}
|
||||
// opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable
|
||||
//
|
||||
// The opt{4-0} and opt{5} sub-fields are to accommodate 32-bit Thumb and ARM
|
||||
// CPS which has more options.
|
||||
def tCPS : T1I<(outs), (ins cps_opt:$opt), NoItinerary, "cps$opt",
|
||||
[/* For disassembly only; pattern left blank */]>,
|
||||
def tCPS : T1I<(outs), (ins imod_op:$imod, iflags_op:$iflags),
|
||||
NoItinerary, "cps$imod $iflags",
|
||||
[/* For disassembly only; pattern left blank */]>,
|
||||
T1Misc<0b0110011> {
|
||||
// A8.6.38 & B6.1.1
|
||||
let Inst{3} = 0;
|
||||
// FIXME: Finish encoding.
|
||||
bit imod;
|
||||
bits<3> iflags;
|
||||
|
||||
let Inst{4} = imod;
|
||||
let Inst{3} = 0;
|
||||
let Inst{2-0} = iflags;
|
||||
}
|
||||
|
||||
// For both thumb1 and thumb2.
|
||||
|
@ -3127,41 +3127,40 @@ def t2BXJ : T2I<(outs), (ins rGPR:$func), NoItinerary, "bxj", "\t$func",
|
||||
let Inst{19-16} = func;
|
||||
}
|
||||
|
||||
// Change Processor State is a system instruction -- for disassembly only.
|
||||
// The singleton $opt operand contains the following information:
|
||||
// opt{4-0} = mode from Inst{4-0}
|
||||
// opt{5} = changemode from Inst{17}
|
||||
// opt{8-6} = AIF from Inst{8-6}
|
||||
// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
|
||||
def t2CPS : T2XI<(outs),(ins cps_opt:$opt), NoItinerary, "cps$opt",
|
||||
[/* For disassembly only; pattern left blank */]> {
|
||||
// Change Processor State is a system instruction -- for disassembly and
|
||||
// parsing only.
|
||||
// FIXME: Since the asm parser has currently no clean way to handle optional
|
||||
// operands, create 3 versions of the same instruction. Once there's a clean
|
||||
// framework to represent optional operands, change this behavior.
|
||||
class t2CPS<dag iops, string asm_op> : T2XI<(outs), iops, NoItinerary,
|
||||
!strconcat("cps", asm_op),
|
||||
[/* For disassembly only; pattern left blank */]> {
|
||||
bits<2> imod;
|
||||
bits<3> iflags;
|
||||
bits<5> mode;
|
||||
bit M;
|
||||
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{26} = 0;
|
||||
let Inst{26} = 0;
|
||||
let Inst{25-20} = 0b111010;
|
||||
let Inst{19-16} = 0b1111;
|
||||
let Inst{15-14} = 0b10;
|
||||
let Inst{12} = 0;
|
||||
|
||||
bits<11> opt;
|
||||
|
||||
// mode number
|
||||
let Inst{4-0} = opt{4-0};
|
||||
|
||||
// M flag
|
||||
let Inst{8} = opt{5};
|
||||
|
||||
// F flag
|
||||
let Inst{5} = opt{6};
|
||||
|
||||
// I flag
|
||||
let Inst{6} = opt{7};
|
||||
|
||||
// A flag
|
||||
let Inst{7} = opt{8};
|
||||
|
||||
// imod flag
|
||||
let Inst{10-9} = opt{10-9};
|
||||
let Inst{12} = 0;
|
||||
let Inst{10-9} = imod;
|
||||
let Inst{8} = M;
|
||||
let Inst{7-5} = iflags;
|
||||
let Inst{4-0} = mode;
|
||||
}
|
||||
|
||||
let M = 1 in
|
||||
def t2CPS3p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode),
|
||||
"$imod.w\t$iflags, $mode">;
|
||||
let mode = 0, M = 0 in
|
||||
def t2CPS2p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags),
|
||||
"$imod.w\t$iflags">;
|
||||
let imod = 0, iflags = 0, M = 1 in
|
||||
def t2CPS1p : t2CPS<(ins i32imm:$mode), "\t$mode">;
|
||||
|
||||
// A6.3.4 Branches and miscellaneous control
|
||||
// Table A6-14 Change Processor State, and hint instructions
|
||||
// Helper class for disassembly only.
|
||||
|
@ -98,6 +98,8 @@ class ARMAsmParser : public TargetAsmParser {
|
||||
SmallVectorImpl<MCParsedAsmOperand*>&);
|
||||
OperandMatchResultTy tryParseMemBarrierOptOperand(
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
OperandMatchResultTy tryParseProcIFlagsOperand(
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||
|
||||
public:
|
||||
ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
|
||||
@ -126,6 +128,7 @@ class ARMOperand : public MCParsedAsmOperand {
|
||||
Immediate,
|
||||
MemBarrierOpt,
|
||||
Memory,
|
||||
ProcIFlags,
|
||||
Register,
|
||||
RegisterList,
|
||||
DPRRegisterList,
|
||||
@ -149,6 +152,10 @@ class ARMOperand : public MCParsedAsmOperand {
|
||||
unsigned Val;
|
||||
} Cop;
|
||||
|
||||
struct {
|
||||
ARM_PROC::IFlags Val;
|
||||
} IFlags;
|
||||
|
||||
struct {
|
||||
const char *Data;
|
||||
unsigned Length;
|
||||
@ -215,6 +222,8 @@ public:
|
||||
case Memory:
|
||||
Mem = o.Mem;
|
||||
break;
|
||||
case ProcIFlags:
|
||||
IFlags = o.IFlags;
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,6 +268,11 @@ public:
|
||||
return MBOpt.Val;
|
||||
}
|
||||
|
||||
ARM_PROC::IFlags getProcIFlags() const {
|
||||
assert(Kind == ProcIFlags && "Invalid access!");
|
||||
return IFlags.Val;
|
||||
}
|
||||
|
||||
/// @name Memory Operand Accessors
|
||||
/// @{
|
||||
|
||||
@ -333,6 +347,7 @@ public:
|
||||
uint64_t Value = CE->getValue();
|
||||
return ((Value & 0x3) == 0 && Value <= 124);
|
||||
}
|
||||
bool isProcIFlags() const { return Kind == ProcIFlags; }
|
||||
|
||||
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
|
||||
// Add as immediates when possible. Null MCExpr = 0.
|
||||
@ -433,6 +448,11 @@ public:
|
||||
Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
|
||||
}
|
||||
|
||||
void addProcIFlagsOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags())));
|
||||
}
|
||||
|
||||
virtual void dump(raw_ostream &OS) const;
|
||||
|
||||
static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) {
|
||||
@ -556,6 +576,14 @@ public:
|
||||
Op->EndLoc = S;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) {
|
||||
ARMOperand *Op = new ARMOperand(ProcIFlags);
|
||||
Op->IFlags.Val = IFlags;
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = S;
|
||||
return Op;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace.
|
||||
@ -604,6 +632,15 @@ void ARMOperand::dump(raw_ostream &OS) const {
|
||||
OS << " (writeback)";
|
||||
OS << ">";
|
||||
break;
|
||||
case ProcIFlags: {
|
||||
OS << "<ARM_PROC::";
|
||||
unsigned IFlags = getProcIFlags();
|
||||
for (int i=2; i >= 0; --i)
|
||||
if (IFlags & (1 << i))
|
||||
OS << ARM_PROC::IFlagsToString(1 << i);
|
||||
OS << ">";
|
||||
break;
|
||||
}
|
||||
case Register:
|
||||
OS << "<register " << getReg() << ">";
|
||||
break;
|
||||
@ -885,6 +922,35 @@ tryParseMemBarrierOptOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
/// ParseProcIFlagsOperand - Try to parse iflags from CPS instruction.
|
||||
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
|
||||
tryParseProcIFlagsOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||
SMLoc S = Parser.getTok().getLoc();
|
||||
const AsmToken &Tok = Parser.getTok();
|
||||
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
|
||||
StringRef IFlagsStr = Tok.getString();
|
||||
|
||||
unsigned IFlags = 0;
|
||||
for (int i = 0, e = IFlagsStr.size(); i != e; ++i) {
|
||||
unsigned Flag = StringSwitch<unsigned>(IFlagsStr.substr(i, 1))
|
||||
.Case("a", ARM_PROC::A)
|
||||
.Case("i", ARM_PROC::I)
|
||||
.Case("f", ARM_PROC::F)
|
||||
.Default(~0U);
|
||||
|
||||
// If some specific iflag is already set, it means that some letter is
|
||||
// present more than once, this is not acceptable.
|
||||
if (Flag == ~0U || (IFlags & Flag))
|
||||
return MatchOperand_NoMatch;
|
||||
|
||||
IFlags |= Flag;
|
||||
}
|
||||
|
||||
Parser.Lex(); // Eat identifier token.
|
||||
Operands.push_back(ARMOperand::CreateProcIFlags((ARM_PROC::IFlags)IFlags, S));
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
/// Parse an ARM memory expression, return false if successful else return true
|
||||
/// or an error. The first token must be a '[' when called.
|
||||
///
|
||||
@ -1254,11 +1320,13 @@ ARMAsmParser::ApplyPrefixToExpr(const MCExpr *E,
|
||||
/// setting letters to form a canonical mnemonic and flags.
|
||||
//
|
||||
// FIXME: Would be nice to autogen this.
|
||||
static StringRef SplitMnemonicAndCC(StringRef Mnemonic,
|
||||
unsigned &PredicationCode,
|
||||
bool &CarrySetting) {
|
||||
static StringRef SplitMnemonic(StringRef Mnemonic,
|
||||
unsigned &PredicationCode,
|
||||
bool &CarrySetting,
|
||||
unsigned &ProcessorIMod) {
|
||||
PredicationCode = ARMCC::AL;
|
||||
CarrySetting = false;
|
||||
ProcessorIMod = 0;
|
||||
|
||||
// Ignore some mnemonics we know aren't predicated forms.
|
||||
//
|
||||
@ -1312,6 +1380,21 @@ static StringRef SplitMnemonicAndCC(StringRef Mnemonic,
|
||||
CarrySetting = true;
|
||||
}
|
||||
|
||||
// The "cps" instruction can have a interrupt mode operand which is glued into
|
||||
// the mnemonic. Check if this is the case, split it and parse the imod op
|
||||
if (Mnemonic.startswith("cps")) {
|
||||
// Split out any imod code.
|
||||
unsigned IMod =
|
||||
StringSwitch<unsigned>(Mnemonic.substr(Mnemonic.size()-2, 2))
|
||||
.Case("ie", ARM_PROC::IE)
|
||||
.Case("id", ARM_PROC::ID)
|
||||
.Default(~0U);
|
||||
if (IMod != ~0U) {
|
||||
Mnemonic = Mnemonic.slice(0, Mnemonic.size()-2);
|
||||
ProcessorIMod = IMod;
|
||||
}
|
||||
}
|
||||
|
||||
return Mnemonic;
|
||||
}
|
||||
|
||||
@ -1342,7 +1425,7 @@ GetMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
|
||||
Mnemonic == "mcrr2" || Mnemonic == "cbz" || Mnemonic == "cdp2" ||
|
||||
Mnemonic == "trap" || Mnemonic == "mrc2" || Mnemonic == "mrrc2" ||
|
||||
Mnemonic == "dsb" || Mnemonic == "movs" || Mnemonic == "isb" ||
|
||||
Mnemonic == "clrex") {
|
||||
Mnemonic == "clrex" || Mnemonic.startswith("cps")) {
|
||||
CanAcceptPredicationCode = false;
|
||||
} else {
|
||||
CanAcceptPredicationCode = true;
|
||||
@ -1363,8 +1446,10 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||
|
||||
// Split out the predication code and carry setting flag from the mnemonic.
|
||||
unsigned PredicationCode;
|
||||
unsigned ProcessorIMod;
|
||||
bool CarrySetting;
|
||||
Head = SplitMnemonicAndCC(Head, PredicationCode, CarrySetting);
|
||||
Head = SplitMnemonic(Head, PredicationCode, CarrySetting,
|
||||
ProcessorIMod);
|
||||
|
||||
Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
|
||||
|
||||
@ -1404,13 +1489,25 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||
// FIXME: Issue a nice error.
|
||||
}
|
||||
|
||||
// Add the processor imod operand, if necessary.
|
||||
if (ProcessorIMod) {
|
||||
Operands.push_back(ARMOperand::CreateImm(
|
||||
MCConstantExpr::Create(ProcessorIMod, getContext()),
|
||||
NameLoc, NameLoc));
|
||||
} else {
|
||||
// This mnemonic can't ever accept a imod, but the user wrote
|
||||
// one (or misspelled another mnemonic).
|
||||
|
||||
// FIXME: Issue a nice error.
|
||||
}
|
||||
|
||||
// Add the remaining tokens in the mnemonic.
|
||||
while (Next != StringRef::npos) {
|
||||
Start = Next;
|
||||
Next = Name.find('.', Start + 1);
|
||||
Head = Name.slice(Start, Next);
|
||||
StringRef ExtraToken = Name.slice(Start, Next);
|
||||
|
||||
Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
|
||||
Operands.push_back(ARMOperand::CreateToken(ExtraToken, NameLoc));
|
||||
}
|
||||
|
||||
// Read the remaining operands.
|
||||
|
@ -2942,15 +2942,25 @@ static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
|
||||
return true;
|
||||
}
|
||||
|
||||
// CPS has a singleton $opt operand that contains the following information:
|
||||
// opt{4-0} = mode from Inst{4-0}
|
||||
// opt{5} = changemode from Inst{17}
|
||||
// opt{8-6} = AIF from Inst{8-6}
|
||||
// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
|
||||
if (Opcode == ARM::CPS) {
|
||||
unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 |
|
||||
slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9;
|
||||
MI.addOperand(MCOperand::CreateImm(Option));
|
||||
// FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
|
||||
// opcodes which match the same real instruction. This is needed since there's
|
||||
// no current handling of optional arguments. Fix here when a better handling
|
||||
// of optional arguments is implemented.
|
||||
if (Opcode == ARM::CPS3p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
|
||||
NumOpsAdded = 3;
|
||||
return true;
|
||||
}
|
||||
if (Opcode == ARM::CPS2p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags
|
||||
NumOpsAdded = 2;
|
||||
return true;
|
||||
}
|
||||
if (Opcode == ARM::CPS1p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
|
||||
NumOpsAdded = 1;
|
||||
return true;
|
||||
}
|
||||
|
@ -828,14 +828,13 @@ static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn,
|
||||
}
|
||||
|
||||
// CPS has a singleton $opt operand that contains the following information:
|
||||
// opt{4-0} = don't care
|
||||
// opt{5} = 0 (false)
|
||||
// opt{8-6} = AIF from Inst{2-0}
|
||||
// opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable
|
||||
// The first op would be 0b10 as enable and 0b11 as disable in regular ARM,
|
||||
// but in Thumb it's is 0 as enable and 1 as disable. So map it to ARM's
|
||||
// default one. The second get the AIF flags from Inst{2-0}.
|
||||
if (Opcode == ARM::tCPS) {
|
||||
unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10;
|
||||
MI.addOperand(MCOperand::CreateImm(Option));
|
||||
NumOpsAdded = 1;
|
||||
MI.addOperand(MCOperand::CreateImm(2 + slice(insn, 4, 4)));
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 2, 0)));
|
||||
NumOpsAdded = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1659,15 +1658,25 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode,
|
||||
break;
|
||||
}
|
||||
|
||||
// CPS has a singleton $opt operand that contains the following information:
|
||||
// opt{4-0} = mode from Inst{4-0}
|
||||
// opt{5} = changemode from Inst{8}
|
||||
// opt{8-6} = AIF from Inst{7-5}
|
||||
// opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable
|
||||
if (Opcode == ARM::t2CPS) {
|
||||
unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 |
|
||||
slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9;
|
||||
MI.addOperand(MCOperand::CreateImm(Option));
|
||||
// FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
|
||||
// opcodes which match the same real instruction. This is needed since there's
|
||||
// no current handling of optional arguments. Fix here when a better handling
|
||||
// of optional arguments is implemented.
|
||||
if (Opcode == ARM::t2CPS3p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
|
||||
NumOpsAdded = 3;
|
||||
return true;
|
||||
}
|
||||
if (Opcode == ARM::t2CPS2p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags
|
||||
NumOpsAdded = 2;
|
||||
return true;
|
||||
}
|
||||
if (Opcode == ARM::t2CPS1p) {
|
||||
MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
|
||||
NumOpsAdded = 1;
|
||||
return true;
|
||||
}
|
||||
|
@ -379,27 +379,19 @@ void ARMInstPrinter::printSetendOperand(const MCInst *MI, unsigned OpNum,
|
||||
O << "le";
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum,
|
||||
raw_ostream &O) {
|
||||
void ARMInstPrinter::printCPSIMod(const MCInst *MI, unsigned OpNum,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
unsigned option = Op.getImm();
|
||||
unsigned mode = option & 31;
|
||||
bool changemode = option >> 5 & 1;
|
||||
unsigned AIF = option >> 6 & 7;
|
||||
unsigned imod = option >> 9 & 3;
|
||||
if (imod == 2)
|
||||
O << "ie";
|
||||
else if (imod == 3)
|
||||
O << "id";
|
||||
O << '\t';
|
||||
if (imod > 1) {
|
||||
if (AIF & 4) O << 'a';
|
||||
if (AIF & 2) O << 'i';
|
||||
if (AIF & 1) O << 'f';
|
||||
if (AIF > 0 && changemode) O << ", ";
|
||||
}
|
||||
if (changemode)
|
||||
O << '#' << mode;
|
||||
O << ARM_PROC::IModToString(Op.getImm());
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printCPSIFlag(const MCInst *MI, unsigned OpNum,
|
||||
raw_ostream &O) {
|
||||
const MCOperand &Op = MI->getOperand(OpNum);
|
||||
unsigned IFlags = Op.getImm();
|
||||
for (int i=2; i >= 0; --i)
|
||||
if (IFlags & (1 << i))
|
||||
O << ARM_PROC::IFlagsToString(1 << i);
|
||||
}
|
||||
|
||||
void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum,
|
||||
|
@ -85,6 +85,8 @@ public:
|
||||
raw_ostream &O);
|
||||
|
||||
void printSetendOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printCPSIMod(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printCPSIFlag(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printCPSOptionOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printMSRMaskOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
void printNegZeroOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
|
||||
|
@ -237,3 +237,12 @@
|
||||
@ CHECK: dsb oshst @ encoding: [0x42,0xf0,0x7f,0xf5]
|
||||
dsb oshst
|
||||
|
||||
@ CHECK: cpsie aif @ encoding: [0xc0,0x01,0x08,0xf1]
|
||||
cpsie aif
|
||||
|
||||
@ CHECK: cps #15 @ encoding: [0x0f,0x00,0x02,0xf1]
|
||||
cps #15
|
||||
|
||||
@ CHECK: cpsie if, #10 @ encoding: [0xca,0x00,0x0a,0xf1]
|
||||
cpsie if, #10
|
||||
|
||||
|
@ -65,3 +65,6 @@
|
||||
|
||||
@ CHECK: wfi @ encoding: [0x30,0xbf]
|
||||
wfi
|
||||
|
||||
@ CHECK: cpsie aif @ encoding: [0x67,0xb6]
|
||||
cpsie aif
|
||||
|
@ -252,3 +252,10 @@
|
||||
@ CHECK: dsb oshst @ encoding: [0xbf,0xf3,0x42,0x8f]
|
||||
dsb oshst
|
||||
|
||||
@ CHECK: cpsie.w aif @ encoding: [0xaf,0xf3,0xe0,0x84]
|
||||
cpsie.w aif
|
||||
@ CHECK: cps #15 @ encoding: [0xaf,0xf3,0x0f,0x81]
|
||||
cps #15
|
||||
@ CHECK: cpsie.w if, #10 @ encoding: [0xaf,0xf3,0x6a,0x85]
|
||||
cpsie.w if, #10
|
||||
|
||||
|
@ -118,3 +118,12 @@
|
||||
|
||||
# CHECK: setend le
|
||||
0x00 0x00 0x01 0xf1
|
||||
|
||||
# CHECK: cpsie aif
|
||||
0xc0 0x01 0x08 0xf1
|
||||
|
||||
# CHECK: cps #15
|
||||
0x0f 0x00 0x02 0xf1
|
||||
|
||||
# CHECK: cpsie if, #10
|
||||
0xca 0x00 0x0a 0xf1
|
||||
|
@ -103,3 +103,15 @@
|
||||
# IT block end
|
||||
# CHECK: rsbs r1, r2, #0
|
||||
0x51 0x42
|
||||
|
||||
# CHECK: cpsid.w f
|
||||
0xaf 0xf3 0x20 0x86
|
||||
|
||||
# CHECK: cps #15
|
||||
0xaf 0xf3 0x0f 0x81
|
||||
|
||||
# CHECK: cpsie.w if, #10
|
||||
0xaf 0xf3 0x6a 0x85
|
||||
|
||||
# CHECK: cpsie aif
|
||||
0x67 0xb6
|
||||
|
@ -576,6 +576,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
|
||||
IMM("nohash_imm");
|
||||
IMM("p_imm");
|
||||
IMM("c_imm");
|
||||
IMM("imod_op");
|
||||
IMM("iflags_op");
|
||||
IMM("cpinst_operand");
|
||||
IMM("setend_op");
|
||||
IMM("cps_opt");
|
||||
|
Loading…
Reference in New Issue
Block a user