summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2011-02-14 13:09:44 +0000
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>2011-02-14 13:09:44 +0000
commita2b6e4151b75248f9dbf8067186cba673520f8f4 (patch)
treec4aaaa817865ec6d4759a038002da3ec84e11ec2
parent283c8caccd093f8e1d4f0bdd01ac240b4edbd20a (diff)
downloadllvm-a2b6e4151b75248f9dbf8067186cba673520f8f4.tar.gz
llvm-a2b6e4151b75248f9dbf8067186cba673520f8f4.tar.bz2
llvm-a2b6e4151b75248f9dbf8067186cba673520f8f4.tar.xz
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
-rw-r--r--lib/Target/ARM/ARMBaseInfo.h30
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td16
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td42
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td22
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td61
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp111
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp28
-rw-r--r--lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h41
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp32
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.h2
-rw-r--r--test/MC/ARM/arm_instructions.s9
-rw-r--r--test/MC/ARM/thumb.s3
-rw-r--r--test/MC/ARM/thumb2.s7
-rw-r--r--test/MC/Disassembler/ARM/arm-tests.txt9
-rw-r--r--test/MC/Disassembler/ARM/thumb-tests.txt12
-rw-r--r--utils/TableGen/EDEmitter.cpp2
16 files changed, 318 insertions, 109 deletions
diff --git a/lib/Target/ARM/ARMBaseInfo.h b/lib/Target/ARM/ARMBaseInfo.h
index 6054bb773e..a56cc1a9f2 100644
--- a/lib/Target/ARM/ARMBaseInfo.h
+++ b/lib/Target/ARM/ARMBaseInfo.h
@@ -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.
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index e018ab53ca..b602712a23 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -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),
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index 2fd25328d3..c66bc13915 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -1102,21 +1102,37 @@ 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.
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index 6dc07eb7b6..826ef46bcd 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -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.
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index c61c88f8cf..2c2cf46f96 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -3127,40 +3127,39 @@ 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
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 089a08c405..fd7e7734ad 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -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,
@@ -150,6 +153,10 @@ class ARMOperand : public MCParsedAsmOperand {
} Cop;
struct {
+ ARM_PROC::IFlags Val;
+ } IFlags;
+
+ struct {
const char *Data;
unsigned Length;
} Tok;
@@ -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.
diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
index 45c6c300aa..06ad61e9b3 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
+++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
@@ -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;
}
diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
index 8a38507a5a..d1428169f7 100644
--- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
+++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
@@ -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;
}
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
index 4f03b8497b..aace2f9723 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
@@ -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,
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
index 3c94b6eaba..679d3135ea 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
@@ -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);
diff --git a/test/MC/ARM/arm_instructions.s b/test/MC/ARM/arm_instructions.s
index f5bf236ab2..291a76131c 100644
--- a/test/MC/ARM/arm_instructions.s
+++ b/test/MC/ARM/arm_instructions.s
@@ -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
+
diff --git a/test/MC/ARM/thumb.s b/test/MC/ARM/thumb.s
index 5d284c31fe..342a390d81 100644
--- a/test/MC/ARM/thumb.s
+++ b/test/MC/ARM/thumb.s
@@ -65,3 +65,6 @@
@ CHECK: wfi @ encoding: [0x30,0xbf]
wfi
+
+@ CHECK: cpsie aif @ encoding: [0x67,0xb6]
+ cpsie aif
diff --git a/test/MC/ARM/thumb2.s b/test/MC/ARM/thumb2.s
index b8b068fd90..be4e555dc4 100644
--- a/test/MC/ARM/thumb2.s
+++ b/test/MC/ARM/thumb2.s
@@ -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
+
diff --git a/test/MC/Disassembler/ARM/arm-tests.txt b/test/MC/Disassembler/ARM/arm-tests.txt
index 07d349fc3b..26bd182d78 100644
--- a/test/MC/Disassembler/ARM/arm-tests.txt
+++ b/test/MC/Disassembler/ARM/arm-tests.txt
@@ -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
diff --git a/test/MC/Disassembler/ARM/thumb-tests.txt b/test/MC/Disassembler/ARM/thumb-tests.txt
index 29c67e7a03..4e8bc9baa2 100644
--- a/test/MC/Disassembler/ARM/thumb-tests.txt
+++ b/test/MC/Disassembler/ARM/thumb-tests.txt
@@ -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
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index f00f79d56a..020a4a312d 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -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");