summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td10
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp20
-rw-r--r--test/MC/ARM/basic-thumb2-instructions.s4
-rw-r--r--test/MC/Disassembler/ARM/thumb2.txt2
4 files changed, 36 insertions, 0 deletions
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 8e5e8c1735..842f3372d0 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -3599,6 +3599,16 @@ def t2RFEIA : T2RFE<0b111010011001,
(outs), (ins GPR:$Rn), NoItinerary, "rfeia", "\t$Rn",
[/* For disassembly only; pattern left blank */]>;
+// B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction.
+let Defs = [PC], Uses = [LR] in
+def t2SUBS_PC_LR : T2I <(outs), (ins imm0_255:$imm), NoItinerary,
+ "subs", "\tpc, lr, $imm", []>, Requires<[IsThumb2]> {
+ let Inst{31-8} = 0b111100111101111010001111;
+
+ bits<8> imm;
+ let Inst{7-0} = imm;
+}
+
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 6d885a0d91..8e56a1ab94 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -5138,6 +5138,26 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
}
+ // FIXME: As said above, this is all a pretty gross hack. This instruction
+ // does not fit with other "subs" and tblgen.
+ // Adjust operands of B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction
+ // so the Mnemonic is the original name "subs" and delete the predicate
+ // operand so it will match the table entry.
+ if (isThumbTwo() && Mnemonic == "sub" && Operands.size() == 6 &&
+ static_cast<ARMOperand*>(Operands[3])->isReg() &&
+ static_cast<ARMOperand*>(Operands[3])->getReg() == ARM::PC &&
+ static_cast<ARMOperand*>(Operands[4])->isReg() &&
+ static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::LR &&
+ static_cast<ARMOperand*>(Operands[5])->isImm()) {
+ ARMOperand *Op0 = static_cast<ARMOperand*>(Operands[0]);
+ Operands.erase(Operands.begin());
+ delete Op0;
+ Operands.insert(Operands.begin(), ARMOperand::CreateToken(Name, NameLoc));
+
+ ARMOperand *Op1 = static_cast<ARMOperand*>(Operands[1]);
+ Operands.erase(Operands.begin() + 1);
+ delete Op1;
+ }
return false;
}
diff --git a/test/MC/ARM/basic-thumb2-instructions.s b/test/MC/ARM/basic-thumb2-instructions.s
index 43e03c9833..f3a1c6a9f9 100644
--- a/test/MC/ARM/basic-thumb2-instructions.s
+++ b/test/MC/ARM/basic-thumb2-instructions.s
@@ -3588,3 +3588,7 @@ _func:
@ rdar://12596361
ldr r1, [pc, #12]
@ CHECK: ldr r1, [pc, #12] @ encoding: [0x03,0x49]
+
+@ rdar://14214063
+ subs pc, lr, #4
+@ CHECK: subs pc, lr, #4 @ encoding: [0xde,0xf3,0x04,0x8f]
diff --git a/test/MC/Disassembler/ARM/thumb2.txt b/test/MC/Disassembler/ARM/thumb2.txt
index 110a4c0530..9fc166f066 100644
--- a/test/MC/Disassembler/ARM/thumb2.txt
+++ b/test/MC/Disassembler/ARM/thumb2.txt
@@ -2051,6 +2051,7 @@
# CHECK: sub.w r12, r6, #256
# CHECK: subw r12, r6, #256
# CHECK: subs.w r1, r2, #496
+# CHECK: subs pc, lr, #4
0x0a 0xbf
0x11 0x1f
@@ -2062,6 +2063,7 @@
0xa6 0xf5 0x80 0x7c
0xa6 0xf2 0x00 0x1c
0xb2 0xf5 0xf8 0x71
+0xde 0xf3 0x04 0x8f
#------------------------------------------------------------------------------