From 0b4c6738868e11ba06047a406f79489cb1db8c5a Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Wed, 18 Jan 2012 22:46:46 +0000 Subject: [PATCH] Thumb2 alternate syntax for LDR(literal) and friends. Explicit pc-relative syntax. For example, "ldrb r2, [pc, #-22]". rdar://10250964 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148432 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstrThumb2.td | 29 ++++++++++++++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 39 +++++++++++++++++++ .../ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 1 + test/MC/ARM/basic-thumb2-instructions.s | 27 +++++++++++++ 4 files changed, 96 insertions(+) diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index da58146ec27..142ab222b88 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -136,6 +136,12 @@ def t2ldrlabel : Operand { let PrintMethod = "printT2LdrLabelOperand"; } +def t2ldr_pcrel_imm12_asmoperand : AsmOperandClass {let Name = "MemPCRelImm12";} +def t2ldr_pcrel_imm12 : Operand { + let ParserMatchClass = t2ldr_pcrel_imm12_asmoperand; + // used for assembler pseudo instruction and maps to t2ldrlabel, so + // doesn't need encoder or print methods of its own. +} // ADR instruction labels. def t2adrlabel : Operand { @@ -4151,3 +4157,26 @@ def t2MOVSsr: t2AsmPseudo<"movs${p} $Rd, $shift", // ADR w/o the .w suffix def : t2InstAlias<"adr${p} $Rd, $addr", (t2ADR rGPR:$Rd, t2adrlabel:$addr, pred:$p)>; + +// LDR(literal) w/ alternate [pc, #imm] syntax. +def t2LDRpcrel : t2AsmPseudo<"ldr${p} $Rt, $addr", + (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def t2LDRBpcrel : t2AsmPseudo<"ldrb${p} $Rt, $addr", + (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def t2LDRHpcrel : t2AsmPseudo<"ldrh${p} $Rt, $addr", + (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def t2LDRSBpcrel : t2AsmPseudo<"ldrsb${p} $Rt, $addr", + (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def t2LDRSHpcrel : t2AsmPseudo<"ldrsh${p} $Rt, $addr", + (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; + // Version w/ the .w suffix. +def : t2InstAlias<"ldr${p}.w $Rt, $addr", + (t2LDRpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def : t2InstAlias<"ldrb${p}.w $Rt, $addr", + (t2LDRBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def : t2InstAlias<"ldrh${p}.w $Rt, $addr", + (t2LDRHpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def : t2InstAlias<"ldrsb${p}.w $Rt, $addr", + (t2LDRSBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; +def : t2InstAlias<"ldrsh${p}.w $Rt, $addr", + (t2LDRSHpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 021803de711..29a02f69590 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -838,6 +838,17 @@ public: return Memory.OffsetRegNum == 0 && Memory.OffsetImm == 0 && (alignOK || Memory.Alignment == 0); } + bool isMemPCRelImm12() const { + if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) + return false; + // Base register must be PC. + if (Memory.BaseRegNum != ARM::PC) + return false; + // Immediate offset in range [-4095, 4095]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return (Val > -4096 && Val < 4096) || (Val == INT32_MIN); + } bool isAlignedMemory() const { return isMemNoOffset(true); } @@ -999,6 +1010,8 @@ public: bool isMemImm8Offset() const { if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; + // Base reg of PC isn't allowed for these encodings. + if (Memory.BaseRegNum == ARM::PC) return false; // Immediate offset in range [-255, 255]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); @@ -1015,6 +1028,8 @@ public: bool isMemNegImm8Offset() const { if (!isMemory() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; + // Base reg of PC isn't allowed for these encodings. + if (Memory.BaseRegNum == ARM::PC) return false; // Immediate offset in range [-255, -1]. if (!Memory.OffsetImm) return false; int64_t Val = Memory.OffsetImm->getValue(); @@ -1482,6 +1497,14 @@ public: Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); } + void addMemPCRelImm12Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + int32_t Imm = Memory.OffsetImm->getValue(); + // FIXME: Handle #-0 + if (Imm == INT32_MIN) Imm = 0; + Inst.addOperand(MCOperand::CreateImm(Imm)); + } + void addAlignedMemoryOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(Memory.BaseRegNum)); @@ -5389,6 +5412,22 @@ bool ARMAsmParser:: processInstruction(MCInst &Inst, const SmallVectorImpl &Operands) { switch (Inst.getOpcode()) { + // Aliases for alternate PC+imm syntax of LDR instructions. + case ARM::t2LDRpcrel: + Inst.setOpcode(ARM::t2LDRpci); + return true; + case ARM::t2LDRBpcrel: + Inst.setOpcode(ARM::t2LDRBpci); + return true; + case ARM::t2LDRHpcrel: + Inst.setOpcode(ARM::t2LDRHpci); + return true; + case ARM::t2LDRSBpcrel: + Inst.setOpcode(ARM::t2LDRSBpci); + return true; + case ARM::t2LDRSHpcrel: + Inst.setOpcode(ARM::t2LDRSHpci); + return true; // Handle NEON VST complex aliases. case ARM::VST1LNdWB_register_Asm_8: case ARM::VST1LNdWB_register_Asm_P8: case ARM::VST1LNdWB_register_Asm_I8: case ARM::VST1LNdWB_register_Asm_S8: diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index 1bfefa7c0e8..768eaea1896 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -723,6 +723,7 @@ getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx, } else { Reg = ARM::PC; int32_t Offset = MO.getImm(); + // FIXME: Handle #-0. if (Offset < 0) { Offset *= -1; isAdd = false; diff --git a/test/MC/ARM/basic-thumb2-instructions.s b/test/MC/ARM/basic-thumb2-instructions.s index 9daeb9d2c40..78311af9b60 100644 --- a/test/MC/ARM/basic-thumb2-instructions.s +++ b/test/MC/ARM/basic-thumb2-instructions.s @@ -3323,3 +3323,30 @@ _func: @ CHECK: wfelt @ encoding: [0x20,0xbf] @ CHECK: wfige @ encoding: [0x30,0xbf] @ CHECK: yieldlt @ encoding: [0x10,0xbf] + + +@------------------------------------------------------------------------------ +@ Alternate syntax for LDR*(literal) encodings +@------------------------------------------------------------------------------ + ldr r11, [pc, #-22] + ldrb r11, [pc, #-22] + ldrh r11, [pc, #-22] + ldrsb r11, [pc, #-22] + ldrsh r11, [pc, #-22] + + ldr.w r11, [pc, #-22] + ldrb.w r11, [pc, #-22] + ldrh.w r11, [pc, #-22] + ldrsb.w r11, [pc, #-22] + ldrsh.w r11, [pc, #-22] + +@ CHECK: ldr.w r11, [pc, #-22] @ encoding: [0x5f,0xf8,0x16,0xb0] +@ CHECK: ldrb.w r11, [pc, #-22] @ encoding: [0x1f,0xf8,0x16,0xb0] +@ CHECK: ldrh.w r11, [pc, #-22] @ encoding: [0x3f,0xf8,0x16,0xb0] +@ CHECK: ldrsb.w r11, [pc, #-22] @ encoding: [0x1f,0xf9,0x16,0xb0] +@ CHECK: ldrsh.w r11, [pc, #-22] @ encoding: [0x3f,0xf9,0x16,0xb0] +@ CHECK: ldr.w r11, [pc, #-22] @ encoding: [0x5f,0xf8,0x16,0xb0] +@ CHECK: ldrb.w r11, [pc, #-22] @ encoding: [0x1f,0xf8,0x16,0xb0] +@ CHECK: ldrh.w r11, [pc, #-22] @ encoding: [0x3f,0xf8,0x16,0xb0] +@ CHECK: ldrsb.w r11, [pc, #-22] @ encoding: [0x1f,0xf9,0x16,0xb0] +@ CHECK: ldrsh.w r11, [pc, #-22] @ encoding: [0x3f,0xf9,0x16,0xb0] -- 2.34.1