From 9ab0f25fc194b4315db1b87d38d4024054120bf6 Mon Sep 17 00:00:00 2001 From: Owen Anderson Date: Fri, 26 Aug 2011 20:43:14 +0000 Subject: [PATCH] invalid-LDR_PRE-arm.txt was already passing, but for the wrong reasons. We were failing to specify enough fixed bits of LDR_PRE/LDRB_PRE, resulting in decoding conflicts. Separate them into immediate vs. register versions, allowing us to specify the necessary fixed bits. This in turn results in the test being decoded properly, and being rejected as UNPREDICTABLE rather than a hard failure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138653 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMISelDAGToDAG.cpp | 8 +-- lib/Target/ARM/ARMInstrInfo.cpp | 6 ++- lib/Target/ARM/ARMInstrInfo.td | 29 +++++++---- lib/Target/ARM/ARMLoadStoreOptimizer.cpp | 2 +- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 19 +++++++ .../ARM/Disassembler/ARMDisassembler.cpp | 51 ++++++++++++++++++- .../Disassembler/ARM/invalid-LDR_PRE-arm.txt | 2 +- 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 7e4450fced2..5e60cc42c39 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -1321,11 +1321,11 @@ SDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDNode *N) { bool Match = false; if (LoadedVT == MVT::i32 && SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) { - Opcode = isPre ? ARM::LDR_PRE : ARM::LDR_POST_IMM; + Opcode = isPre ? ARM::LDR_PRE_IMM : ARM::LDR_POST_IMM; Match = true; } else if (LoadedVT == MVT::i32 && SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) { - Opcode = isPre ? ARM::LDR_PRE : ARM::LDR_POST_REG; + Opcode = isPre ? ARM::LDR_PRE_REG : ARM::LDR_POST_REG; Match = true; } else if (LoadedVT == MVT::i16 && @@ -1343,10 +1343,10 @@ SDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDNode *N) { } else { if (SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) { Match = true; - Opcode = isPre ? ARM::LDRB_PRE : ARM::LDRB_POST_IMM; + Opcode = isPre ? ARM::LDRB_PRE_IMM : ARM::LDRB_POST_IMM; } else if (SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) { Match = true; - Opcode = isPre ? ARM::LDRB_PRE : ARM::LDRB_POST_REG; + Opcode = isPre ? ARM::LDRB_PRE_REG : ARM::LDRB_POST_REG; } } } diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index f8880ea4e0e..48da03f63bb 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -30,14 +30,16 @@ ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI) unsigned ARMInstrInfo::getUnindexedOpcode(unsigned Opc) const { switch (Opc) { default: break; - case ARM::LDR_PRE: + case ARM::LDR_PRE_IMM: + case ARM::LDR_PRE_REG: case ARM::LDR_POST_IMM: case ARM::LDR_POST_REG: return ARM::LDRi12; case ARM::LDRH_PRE: case ARM::LDRH_POST: return ARM::LDRH; - case ARM::LDRB_PRE: + case ARM::LDRB_PRE_IMM: + case ARM::LDRB_PRE_REG: case ARM::LDRB_POST_IMM: case ARM::LDRB_POST_REG: return ARM::LDRBi12; diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index ec123cbc176..d20e944ddf5 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -1997,19 +1997,28 @@ def LDRD : AI3ld<0b1101, 0, (outs GPR:$Rd, GPR:$dst2), // Indexed loads multiclass AI2_ldridx { - def _PRE : AI2ldstidx<1, isByte, 1, (outs GPR:$Rt, GPR:$Rn_wb), - (ins addrmode2:$addr), IndexModePre, LdFrm, itin, + def _PRE_IMM : AI2ldstidx<1, isByte, 1, (outs GPR:$Rt, GPR:$Rn_wb), + (ins addrmode_imm12:$addr), IndexModePre, LdFrm, itin, opc, "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { - // {17-14} Rn - // {13} reg vs. imm - // {12} isAdd - // {11-0} imm12/Rm - bits<18> addr; - let Inst{25} = addr{13}; + bits<17> addr; + let Inst{25} = 0; let Inst{23} = addr{12}; - let Inst{19-16} = addr{17-14}; + let Inst{19-16} = addr{16-13}; let Inst{11-0} = addr{11-0}; - let DecoderMethod = "DecodeAddrMode2IdxInstruction"; + let DecoderMethod = "DecodeLDRPreImm"; + let AsmMatchConverter = "cvtLdWriteBackRegAddrModeImm12"; + } + + def _PRE_REG : AI2ldstidx<1, isByte, 1, (outs GPR:$Rt, GPR:$Rn_wb), + (ins ldst_so_reg:$addr), IndexModePre, LdFrm, itin, + opc, "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { + bits<17> addr; + let Inst{25} = 1; + let Inst{23} = addr{12}; + let Inst{19-16} = addr{16-13}; + let Inst{11-0} = addr{11-0}; + let Inst{4} = 0; + let DecoderMethod = "DecodeLDRPreReg"; let AsmMatchConverter = "cvtLdWriteBackRegAddrMode2"; } diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp index 96e40cd24f9..246f6c231e3 100644 --- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -764,7 +764,7 @@ static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc, ARM_AM::AddrOpc Mode) { switch (Opc) { case ARM::LDRi12: - return ARM::LDR_PRE; + return ARM::LDR_PRE_IMM; case ARM::STRi12: return ARM::STR_PRE_IMM; case ARM::VLDRS: diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index f0d74f3345d..a1054250c4c 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -127,6 +127,8 @@ class ARMAsmParser : public MCTargetAsmParser { // Asm Match Converter Methods bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); + bool cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &); bool cvtStWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, const SmallVectorImpl &); bool cvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, @@ -2233,6 +2235,23 @@ cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, return true; } +/// cvtLdWriteBackRegAddrModeImm12 - Convert parsed operands to MCInst. +/// Needed here because the Asm Gen Matcher can't handle properly tied operands +/// when they refer multiple MIOperands inside a single one. +bool ARMAsmParser:: +cvtLdWriteBackRegAddrModeImm12(MCInst &Inst, unsigned Opcode, + const SmallVectorImpl &Operands) { + ((ARMOperand*)Operands[2])->addRegOperands(Inst, 1); + + // Create a writeback register dummy placeholder. + Inst.addOperand(MCOperand::CreateImm(0)); + + ((ARMOperand*)Operands[3])->addMemImm12OffsetOperands(Inst, 2); + ((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2); + return true; +} + + /// cvtStWriteBackRegAddrModeImm12 - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index b58cca32afe..3cdcb050596 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -157,6 +157,10 @@ static DecodeStatus DecodeDoubleRegLoad(llvm::MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeDoubleRegStore(llvm::MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeLDRPreImm(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); +static DecodeStatus DecodeLDRPreReg(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeSTRPreImm(llvm::MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSTRPreReg(llvm::MCInst &Inst, unsigned Insn, @@ -1055,8 +1059,6 @@ DecodeAddrMode2IdxInstruction(llvm::MCInst &Inst, unsigned Insn, case ARM::LDR_POST_REG: case ARM::LDRB_POST_IMM: case ARM::LDRB_POST_REG: - case ARM::LDR_PRE: - case ARM::LDRB_PRE: case ARM::LDRBT_POST_REG: case ARM::LDRBT_POST_IMM: case ARM::LDRT_POST_REG: @@ -2756,6 +2758,51 @@ static DecodeStatus DecodeDoubleRegStore(llvm::MCInst &Inst, unsigned Insn, return S; } +static DecodeStatus DecodeLDRPreImm(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = Success; + + unsigned Rn = fieldFromInstruction32(Insn, 16, 4); + unsigned Rt = fieldFromInstruction32(Insn, 12, 4); + unsigned imm = fieldFromInstruction32(Insn, 0, 12); + imm |= fieldFromInstruction32(Insn, 16, 4) << 13; + imm |= fieldFromInstruction32(Insn, 23, 1) << 12; + unsigned pred = fieldFromInstruction32(Insn, 28, 4); + + if (Rn == 0xF || Rn == Rt) CHECK(S, Unpredictable); + + CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)); + CHECK(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)); + CHECK(S, DecodeAddrModeImm12Operand(Inst, imm, Address, Decoder)); + CHECK(S, DecodePredicateOperand(Inst, pred, Address, Decoder)); + + return S; +} + +static DecodeStatus DecodeLDRPreReg(llvm::MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + DecodeStatus S = Success; + + unsigned Rn = fieldFromInstruction32(Insn, 16, 4); + unsigned Rt = fieldFromInstruction32(Insn, 12, 4); + unsigned imm = fieldFromInstruction32(Insn, 0, 12); + imm |= fieldFromInstruction32(Insn, 16, 4) << 13; + imm |= fieldFromInstruction32(Insn, 23, 1) << 12; + unsigned pred = fieldFromInstruction32(Insn, 28, 4); + unsigned Rm = fieldFromInstruction32(Insn, 0, 4); + + if (Rn == 0xF || Rn == Rt) CHECK(S, Unpredictable); + if (Rm == 0xF) CHECK(S, Unpredictable); + + CHECK(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder)); + CHECK(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)); + CHECK(S, DecodeSORegMemOperand(Inst, imm, Address, Decoder)); + CHECK(S, DecodePredicateOperand(Inst, pred, Address, Decoder)); + + return S; +} + + static DecodeStatus DecodeSTRPreImm(llvm::MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { DecodeStatus S = Success; diff --git a/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt b/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt index e22f8444139..e42e0de9b9d 100644 --- a/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt +++ b/test/MC/Disassembler/ARM/invalid-LDR_PRE-arm.txt @@ -1,4 +1,4 @@ -# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {invalid instruction encoding} +# RUN: llvm-mc --disassemble %s -triple=arm-apple-darwin9 |& grep {potentially undefined instruction encoding} # Opcode=165 Name=LDR_PRE Format=ARM_FORMAT_LDFRM(6) # 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0