From b2bffb2bad5c37dacae09013ce640e502f52e93a Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 11 Jul 2016 22:29:37 +0000 Subject: [PATCH] ARM: validate immediate branch targets in AsmParser. Immediate branch targets aren't commonly used, but if they are we should make sure they can actually be encoded. This means they must be divisible by 2 when targeting Thumb mode, and by 4 when targeting ARM mode. Also do a little naming cleanup while I was changing everything around anyway. llvm-svn: 275116 --- lib/Target/ARM/ARMInstrInfo.td | 52 ++++++++++--------- lib/Target/ARM/ARMInstrThumb.td | 43 +++++++++------ lib/Target/ARM/ARMInstrThumb2.td | 10 ++-- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 28 ++++++++++ .../ARM/MCTargetDesc/ARMMCCodeEmitter.cpp | 15 +++--- test/MC/ARM/arm-branch-errors.s | 16 ++++++ test/MC/ARM/arm-branches.s | 15 ++++++ test/MC/ARM/thumb-branch-errors.s | 22 ++++++++ test/MC/ARM/thumb2-branches.s | 18 +++++++ 9 files changed, 166 insertions(+), 53 deletions(-) create mode 100644 test/MC/ARM/arm-branch-errors.s create mode 100644 test/MC/ARM/arm-branches.s create mode 100644 test/MC/ARM/thumb-branch-errors.s diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index e2a66eb56cf..060376b0a27 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -418,34 +418,35 @@ def brtarget : Operand { let DecoderMethod = "DecodeT2BROperand"; } -// FIXME: get rid of this one? -def uncondbrtarget : Operand { - let EncoderMethod = "getUnconditionalBranchTargetOpValue"; - let OperandType = "OPERAND_PCREL"; +// Branches targeting ARM-mode must be divisible by 4 if they're a raw +// immediate. +def ARMBranchTarget : AsmOperandClass { + let Name = "ARMBranchTarget"; } -// Branch target for ARM. Handles conditional/unconditional -def br_target : Operand { +// Branches targeting Thumb-mode must be divisible by 2 if they're a raw +// immediate. +def ThumbBranchTarget : AsmOperandClass { + let Name = "ThumbBranchTarget"; +} + +def arm_br_target : Operand { + let ParserMatchClass = ARMBranchTarget; let EncoderMethod = "getARMBranchTargetOpValue"; let OperandType = "OPERAND_PCREL"; } -// Call target. -// FIXME: rename bltarget to t2_bl_target? -def bltarget : Operand { - // Encoded the same as branch targets. - let EncoderMethod = "getBranchTargetOpValue"; - let OperandType = "OPERAND_PCREL"; -} - // Call target for ARM. Handles conditional/unconditional // FIXME: rename bl_target to t2_bltarget? -def bl_target : Operand { +def arm_bl_target : Operand { + let ParserMatchClass = ARMBranchTarget; let EncoderMethod = "getARMBLTargetOpValue"; let OperandType = "OPERAND_PCREL"; } -def blx_target : Operand { +// Target for BLX *from* ARM mode. +def arm_blx_target : Operand { + let ParserMatchClass = ThumbBranchTarget; let EncoderMethod = "getARMBLXTargetOpValue"; let OperandType = "OPERAND_PCREL"; } @@ -2208,7 +2209,7 @@ let isCall = 1, // at least be a pseudo instruction expanding to the predicated version // at MC lowering time. Defs = [LR], Uses = [SP] in { - def BL : ABXI<0b1011, (outs), (ins bl_target:$func), + def BL : ABXI<0b1011, (outs), (ins arm_bl_target:$func), IIC_Br, "bl\t$func", [(ARMcall tglobaladdr:$func)]>, Requires<[IsARM]>, Sched<[WriteBrL]> { @@ -2218,7 +2219,7 @@ let isCall = 1, let DecoderMethod = "DecodeBranchImmInstruction"; } - def BL_pred : ABI<0b1011, (outs), (ins bl_target:$func), + def BL_pred : ABI<0b1011, (outs), (ins arm_bl_target:$func), IIC_Br, "bl", "\t$func", [(ARMcall_pred tglobaladdr:$func)]>, Requires<[IsARM]>, Sched<[WriteBrL]> { @@ -2259,7 +2260,7 @@ let isCall = 1, // mov lr, pc; b if callee is marked noreturn to avoid confusing the // return stack predictor. - def BMOVPCB_CALL : ARMPseudoInst<(outs), (ins bl_target:$func), + def BMOVPCB_CALL : ARMPseudoInst<(outs), (ins arm_bl_target:$func), 8, IIC_Br, [(ARMcall_nolink tglobaladdr:$func)]>, Requires<[IsARM]>, Sched<[WriteBr]>; } @@ -2267,7 +2268,7 @@ let isCall = 1, let isBranch = 1, isTerminator = 1 in { // FIXME: should be able to write a pattern for ARMBrcond, but can't use // a two-value operand where a dag node expects two operands. :( - def Bcc : ABI<0b1010, (outs), (ins br_target:$target), + def Bcc : ABI<0b1010, (outs), (ins arm_br_target:$target), IIC_Br, "b", "\t$target", [/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]>, Sched<[WriteBr]> { @@ -2282,8 +2283,9 @@ let isBranch = 1, isTerminator = 1 in { // FIXME: We shouldn't need this pseudo at all. Just using Bcc directly // should be sufficient. // FIXME: Is B really a Barrier? That doesn't seem right. - def B : ARMPseudoExpand<(outs), (ins br_target:$target), 4, IIC_Br, - [(br bb:$target)], (Bcc br_target:$target, (ops 14, zero_reg))>, + def B : ARMPseudoExpand<(outs), (ins arm_br_target:$target), 4, IIC_Br, + [(br bb:$target)], (Bcc arm_br_target:$target, + (ops 14, zero_reg))>, Sched<[WriteBr]>; let Size = 4, isNotDuplicable = 1, isIndirectBranch = 1 in { @@ -2310,7 +2312,7 @@ let isBranch = 1, isTerminator = 1 in { } // BLX (immediate) -def BLXi : AXI<(outs), (ins blx_target:$target), BrMiscFrm, NoItinerary, +def BLXi : AXI<(outs), (ins arm_blx_target:$target), BrMiscFrm, NoItinerary, "blx\t$target", []>, Requires<[IsARM, HasV5T]>, Sched<[WriteBrL]> { let Inst{31-25} = 0b1111101; @@ -2340,9 +2342,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in { def TCRETURNri : PseudoInst<(outs), (ins tcGPR:$dst), IIC_Br, []>, Sched<[WriteBr]>; - def TAILJMPd : ARMPseudoExpand<(outs), (ins br_target:$dst), + def TAILJMPd : ARMPseudoExpand<(outs), (ins arm_br_target:$dst), 4, IIC_Br, [], - (Bcc br_target:$dst, (ops 14, zero_reg))>, + (Bcc arm_br_target:$dst, (ops 14, zero_reg))>, Requires<[IsARM]>, Sched<[WriteBr]>; def TAILJMPr : ARMPseudoExpand<(outs), (ins tcGPR:$dst), diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index 5d4698f6a8b..bec1ea8763d 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -125,26 +125,38 @@ def t_adrlabel : Operand { let ParserMatchClass = UnsignedOffset_b8s2; } -def t_bcctarget : Operand { - let EncoderMethod = "getThumbBCCTargetOpValue"; - let DecoderMethod = "DecodeThumbBCCTargetOperand"; + +def thumb_br_target : Operand { + let ParserMatchClass = ThumbBranchTarget; + let EncoderMethod = "getThumbBranchTargetOpValue"; + let OperandType = "OPERAND_PCREL"; } -def t_cbtarget : Operand { - let EncoderMethod = "getThumbCBTargetOpValue"; - let DecoderMethod = "DecodeThumbCmpBROperand"; -} - -def t_bltarget : Operand { +def thumb_bl_target : Operand { + let ParserMatchClass = ThumbBranchTarget; let EncoderMethod = "getThumbBLTargetOpValue"; let DecoderMethod = "DecodeThumbBLTargetOperand"; } -def t_blxtarget : Operand { +// Target for BLX *from* thumb mode. +def thumb_blx_target : Operand { + let ParserMatchClass = ARMBranchTarget; let EncoderMethod = "getThumbBLXTargetOpValue"; let DecoderMethod = "DecodeThumbBLXOffset"; } +def thumb_bcc_target : Operand { + let ParserMatchClass = ThumbBranchTarget; + let EncoderMethod = "getThumbBCCTargetOpValue"; + let DecoderMethod = "DecodeThumbBCCTargetOperand"; +} + +def thumb_cb_target : Operand { + let ParserMatchClass = ThumbBranchTarget; + let EncoderMethod = "getThumbCBTargetOpValue"; + let DecoderMethod = "DecodeThumbCmpBROperand"; +} + // t_addrmode_pc :=