From 1fb27eccf5b7eabde9678d84411eb1df8a693683 Mon Sep 17 00:00:00 2001 From: Jiangning Liu Date: Thu, 2 Aug 2012 08:13:13 +0000 Subject: [PATCH] Fix #13241, a bug around shift immediate operand for ARM instruction ADR. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161159 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrInfo.td | 3 +++ lib/Target/ARM/ARMInstrThumb2.td | 1 + lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 23 ++++++++++++++++++ lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp | 19 +++++++++++++++ lib/Target/ARM/InstPrinter/ARMInstPrinter.h | 1 + .../ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 24 +++++++++++++------ test/MC/ARM/basic-arm-instructions.s | 8 +++++++ test/MC/ARM/basic-thumb2-instructions.s | 2 ++ .../ARM/basic-arm-instructions.txt | 6 +++++ test/MC/Disassembler/ARM/thumb2.txt | 2 ++ 10 files changed, 82 insertions(+), 7 deletions(-) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 4da90c8bec0..754beb35cad 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -416,8 +416,11 @@ def pclabel : Operand { } // ADR instruction labels. +def AdrLabelAsmOperand : AsmOperandClass { let Name = "AdrLabel"; } def adrlabel : Operand { let EncoderMethod = "getAdrLabelOpValue"; + let ParserMatchClass = AdrLabelAsmOperand; + let PrintMethod = "printAdrLabelOperand"; } def neon_vcvt_imm32 : Operand { diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index d83530a902f..d64e12f2876 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -172,6 +172,7 @@ def t2ldr_pcrel_imm12 : Operand { // ADR instruction labels. def t2adrlabel : Operand { let EncoderMethod = "getT2AdrLabelOpValue"; + let PrintMethod = "printAdrLabelOperand"; } diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 44977201abd..6fe6356c931 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -796,6 +796,13 @@ public: int64_t Value = CE->getValue(); return Value > 0 && Value <= 32; } + bool isAdrLabel() const { + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, but it can't fit + // into shift immediate encoding, we reject it. + if (isImm() && !isa(getImm())) return true; + else return (isARMSOImm() || isARMSOImmNeg()); + } bool isARMSOImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); @@ -1644,6 +1651,22 @@ public: Inst.addOperand(MCOperand::CreateImm(Imm)); } + void addAdrLabelOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + assert(isImm() && "Not an immediate!"); + + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. + if (!isa(getImm())) { + Inst.addOperand(MCOperand::CreateExpr(getImm())); + return; + } + + const MCConstantExpr *CE = dyn_cast(getImm()); + int Val = CE->getValue(); + Inst.addOperand(MCOperand::CreateImm(Val)); + } + void addAlignedMemoryOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index 2f6b1b02cca..ad99c14ceed 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -792,6 +792,25 @@ void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum, llvm_unreachable("Unhandled PC-relative pseudo-instruction!"); } +void ARMInstPrinter::printAdrLabelOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + + if (MO.isExpr()) { + O << *MO.getExpr(); + return; + } + + int32_t OffImm = (int32_t)MO.getImm(); + + if (OffImm == INT32_MIN) + O << "#-0"; + else if (OffImm < 0) + O << "#-" << -OffImm; + else + O << "#" << OffImm; +} + void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { O << "#" << MI->getOperand(OpNum).getImm() * 4; diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h index 8acb7eef019..73d7bfd2850 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h @@ -73,6 +73,7 @@ public: void printPKHLSLShiftImm(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printPKHASRShiftImm(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printAdrLabelOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbSRImm(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbITMask(const MCInst *MI, unsigned OpNum, raw_ostream &O); diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index 1964bcd81fa..424b06d7fa8 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -641,8 +641,8 @@ getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx, return Val; } -/// getAdrLabelOpValue - Return encoding info for 12-bit immediate ADR label -/// target. +/// getAdrLabelOpValue - Return encoding info for 12-bit shifted-immediate +/// ADR label target. uint32_t ARMMCCodeEmitter:: getAdrLabelOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups) const { @@ -652,15 +652,23 @@ getAdrLabelOpValue(const MCInst &MI, unsigned OpIdx, Fixups); int32_t offset = MO.getImm(); uint32_t Val = 0x2000; - if (offset < 0) { + + if (offset == INT32_MIN) { + Val = 0x1000; + offset = 0; + } else if (offset < 0) { Val = 0x1000; offset *= -1; } - Val |= offset; + + int SoImmVal = ARM_AM::getSOImmVal(offset); + assert(SoImmVal != -1 && "Not a valid so_imm value!"); + + Val |= SoImmVal; return Val; } -/// getAdrLabelOpValue - Return encoding info for 12-bit immediate ADR label +/// getT2AdrLabelOpValue - Return encoding info for 12-bit immediate ADR label /// target. uint32_t ARMMCCodeEmitter:: getT2AdrLabelOpValue(const MCInst &MI, unsigned OpIdx, @@ -670,14 +678,16 @@ getT2AdrLabelOpValue(const MCInst &MI, unsigned OpIdx, return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_adr_pcrel_12, Fixups); int32_t Val = MO.getImm(); - if (Val < 0) { + if (Val == INT32_MIN) + Val = 0x1000; + else if (Val < 0) { Val *= -1; Val |= 0x1000; } return Val; } -/// getAdrLabelOpValue - Return encoding info for 8-bit immediate ADR label +/// getThumbAdrLabelOpValue - Return encoding info for 8-bit immediate ADR label /// target. uint32_t ARMMCCodeEmitter:: getThumbAdrLabelOpValue(const MCInst &MI, unsigned OpIdx, diff --git a/test/MC/ARM/basic-arm-instructions.s b/test/MC/ARM/basic-arm-instructions.s index e682db5273e..45f5247bce6 100644 --- a/test/MC/ARM/basic-arm-instructions.s +++ b/test/MC/ARM/basic-arm-instructions.s @@ -141,6 +141,14 @@ Lforward: @ CHECK: adr r2, #3 @ encoding: [0x03,0x20,0x8f,0xe2] @ CHECK: adr r2, #-3 @ encoding: [0x03,0x20,0x4f,0xe2] + adr r1, #-0x0 + adr r1, #-0x12000000 + adr r1, #0x12000000 + +@ CHECK: adr r1, #-0 @ encoding: [0x00,0x10,0x4f,0xe2] +@ CHECK: adr r1, #-301989888 @ encoding: [0x12,0x14,0x4f,0xe2] +@ CHECK: adr r1, #301989888 @ encoding: [0x12,0x14,0x8f,0xe2] + @------------------------------------------------------------------------------ @ ADD diff --git a/test/MC/ARM/basic-thumb2-instructions.s b/test/MC/ARM/basic-thumb2-instructions.s index 4cfe2f21112..6a048cf43f1 100644 --- a/test/MC/ARM/basic-thumb2-instructions.s +++ b/test/MC/ARM/basic-thumb2-instructions.s @@ -135,9 +135,11 @@ _func: subw r11, pc, #3270 adr.w r11, #-826 + adr.w r1, #-0x0 @ CHECK: subw r11, pc, #3270 @ encoding: [0xaf,0xf6,0xc6,0x4b] @ CHECK: adr.w r11, #-826 @ encoding: [0xaf,0xf2,0x3a,0x3b] +@ CHECK: adr.w r1, #-0 @ encoding: [0xaf,0xf2,0x00,0x01] @------------------------------------------------------------------------------ @ AND (immediate) diff --git a/test/MC/Disassembler/ARM/basic-arm-instructions.txt b/test/MC/Disassembler/ARM/basic-arm-instructions.txt index 40eb4cdbf2f..7ef7bca539d 100644 --- a/test/MC/Disassembler/ARM/basic-arm-instructions.txt +++ b/test/MC/Disassembler/ARM/basic-arm-instructions.txt @@ -169,9 +169,15 @@ #------------------------------------------------------------------------------ # CHECK: add r2, pc, #3 # CHECK: sub r2, pc, #3 +# CHECK: sub r1, pc, #0 +# CHECK: sub r1, pc, #301989888 +# CHECK: add r1, pc, #301989888 0x03 0x20 0x8f 0xe2 0x03 0x20 0x4f 0xe2 +0x00 0x10 0x4f 0xe2 +0x12 0x14 0x4f 0xe2 +0x12 0x14 0x8f 0xe2 #------------------------------------------------------------------------------ # AND diff --git a/test/MC/Disassembler/ARM/thumb2.txt b/test/MC/Disassembler/ARM/thumb2.txt index 4d1b398dbf9..380983fc224 100644 --- a/test/MC/Disassembler/ARM/thumb2.txt +++ b/test/MC/Disassembler/ARM/thumb2.txt @@ -92,9 +92,11 @@ #------------------------------------------------------------------------------ # CHECK: subw r11, pc, #3270 # CHECK: subw r11, pc, #826 +# CHECK: subw r1, pc, #0 0xaf 0xf6 0xc6 0x4b 0xaf 0xf2 0x3a 0x3b +0xaf 0xf2 0x00 0x01 #------------------------------------------------------------------------------ # AND (immediate)