[ARM] LSL #0 is an alias of MOV
Currently we handle this correctly in arm, but in thumb we don't which leads to
an unpredictable instruction being emitted for LSL #0 in an IT block and SP not
being permitted in some cases when it should be.
For the thumb2 LSL we can handle this by making LSL #0 an alias of MOV in the
.td file, but for thumb1 we need to handle it in checkTargetMatchPredicate to
get the IT handling right. We also need to adjust the handling of
MOV rd, rn, LSL #0 to avoid generating the 16-bit encoding in an IT block. We
should also adjust it to allow SP in the same way that it is allowed in
MOV rd, rn, but I haven't done that here because it looks like it would take
quite a lot of work to get right.
Additionally correct the selection of the 16-bit shift instructions in
processInstruction, where it was checking if the two registers were equal when
it should have been checking if they were low. It appears that previously this
code was never executed and the 16-bit encoding was selected by default, but
the other changes I've done here have somehow made it start being used.
Differential Revision: https://reviews.llvm.org/D30294
llvm-svn: 296342
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index f27957c..03e1d44 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -8236,7 +8236,7 @@
case ARM::t2LSRri:
case ARM::t2ASRri: {
if (isARMLowRegister(Inst.getOperand(0).getReg()) &&
- Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg() &&
+ isARMLowRegister(Inst.getOperand(1).getReg()) &&
Inst.getOperand(5).getReg() == (inITBlock() ? 0 : ARM::CPSR) &&
!(static_cast<ARMOperand &>(*Operands[3]).isToken() &&
static_cast<ARMOperand &>(*Operands[3]).getToken() == ".w")) {
@@ -8311,23 +8311,38 @@
isNarrow = true;
MCInst TmpInst;
unsigned newOpc;
- switch(ARM_AM::getSORegShOp(Inst.getOperand(2).getImm())) {
- default: llvm_unreachable("unexpected opcode!");
- case ARM_AM::asr: newOpc = isNarrow ? ARM::tASRri : ARM::t2ASRri; break;
- case ARM_AM::lsr: newOpc = isNarrow ? ARM::tLSRri : ARM::t2LSRri; break;
- case ARM_AM::lsl: newOpc = isNarrow ? ARM::tLSLri : ARM::t2LSLri; break;
- case ARM_AM::ror: newOpc = ARM::t2RORri; isNarrow = false; break;
- case ARM_AM::rrx: isNarrow = false; newOpc = ARM::t2RRX; break;
- }
+ unsigned Shift = ARM_AM::getSORegShOp(Inst.getOperand(2).getImm());
unsigned Amount = ARM_AM::getSORegOffset(Inst.getOperand(2).getImm());
+ bool isMov = false;
+ // MOV rd, rm, LSL #0 is actually a MOV instruction
+ if (Shift == ARM_AM::lsl && Amount == 0) {
+ isMov = true;
+ // The 16-bit encoding of MOV rd, rm, LSL #N is explicitly encoding T2 of
+ // MOV (register) in the ARMv8-A and ARMv8-M manuals, and immediate 0 is
+ // unpredictable in an IT block so the 32-bit encoding T3 has to be used
+ // instead.
+ if (inITBlock()) {
+ isNarrow = false;
+ }
+ newOpc = isNarrow ? ARM::tMOVSr : ARM::t2MOVr;
+ } else {
+ switch(Shift) {
+ default: llvm_unreachable("unexpected opcode!");
+ case ARM_AM::asr: newOpc = isNarrow ? ARM::tASRri : ARM::t2ASRri; break;
+ case ARM_AM::lsr: newOpc = isNarrow ? ARM::tLSRri : ARM::t2LSRri; break;
+ case ARM_AM::lsl: newOpc = isNarrow ? ARM::tLSLri : ARM::t2LSLri; break;
+ case ARM_AM::ror: newOpc = ARM::t2RORri; isNarrow = false; break;
+ case ARM_AM::rrx: isNarrow = false; newOpc = ARM::t2RRX; break;
+ }
+ }
if (Amount == 32) Amount = 0;
TmpInst.setOpcode(newOpc);
TmpInst.addOperand(Inst.getOperand(0)); // Rd
- if (isNarrow)
+ if (isNarrow && !isMov)
TmpInst.addOperand(MCOperand::createReg(
Inst.getOpcode() == ARM::t2MOVSsi ? ARM::CPSR : 0));
TmpInst.addOperand(Inst.getOperand(1)); // Rn
- if (newOpc != ARM::t2RRX)
+ if (newOpc != ARM::t2RRX && !isMov)
TmpInst.addOperand(MCOperand::createImm(Amount));
TmpInst.addOperand(Inst.getOperand(3)); // CondCode
TmpInst.addOperand(Inst.getOperand(4));
@@ -8922,6 +8937,9 @@
if (isThumbTwo() && Inst.getOperand(OpNo).getReg() == ARM::CPSR &&
inITBlock())
return Match_RequiresNotITBlock;
+ // LSL with zero immediate is not allowed in an IT block
+ if (Opc == ARM::tLSLri && Inst.getOperand(4).getImm() == 0 && inITBlock())
+ return Match_RequiresNotITBlock;
} else if (isThumbOne()) {
// Some high-register supporting Thumb1 encodings only allow both registers
// to be from r0-r7 when in Thumb2.