llvm.org GIT mirror llvm / 1f1f6a6
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275116 91177308-0d34-0410-b5e6-96231b3b80d8 Tim Northover 4 years ago
9 changed file(s) with 170 addition(s) and 57 deletion(s). Raw diff Collapse all Expand all
417417 let DecoderMethod = "DecodeT2BROperand";
418418 }
419419
420 // FIXME: get rid of this one?
421 def uncondbrtarget : Operand {
422 let EncoderMethod = "getUnconditionalBranchTargetOpValue";
423 let OperandType = "OPERAND_PCREL";
424 }
425
426 // Branch target for ARM. Handles conditional/unconditional
427 def br_target : Operand {
420 // Branches targeting ARM-mode must be divisible by 4 if they're a raw
421 // immediate.
422 def ARMBranchTarget : AsmOperandClass {
423 let Name = "ARMBranchTarget";
424 }
425
426 // Branches targeting Thumb-mode must be divisible by 2 if they're a raw
427 // immediate.
428 def ThumbBranchTarget : AsmOperandClass {
429 let Name = "ThumbBranchTarget";
430 }
431
432 def arm_br_target : Operand {
433 let ParserMatchClass = ARMBranchTarget;
428434 let EncoderMethod = "getARMBranchTargetOpValue";
429435 let OperandType = "OPERAND_PCREL";
430436 }
431437
432 // Call target.
433 // FIXME: rename bltarget to t2_bl_target?
434 def bltarget : Operand {
435 // Encoded the same as branch targets.
436 let EncoderMethod = "getBranchTargetOpValue";
437 let OperandType = "OPERAND_PCREL";
438 }
439
440438 // Call target for ARM. Handles conditional/unconditional
441439 // FIXME: rename bl_target to t2_bltarget?
442 def bl_target : Operand {
440 def arm_bl_target : Operand {
441 let ParserMatchClass = ARMBranchTarget;
443442 let EncoderMethod = "getARMBLTargetOpValue";
444443 let OperandType = "OPERAND_PCREL";
445444 }
446445
447 def blx_target : Operand {
446 // Target for BLX *from* ARM mode.
447 def arm_blx_target : Operand {
448 let ParserMatchClass = ThumbBranchTarget;
448449 let EncoderMethod = "getARMBLXTargetOpValue";
449450 let OperandType = "OPERAND_PCREL";
450451 }
22072208 // at least be a pseudo instruction expanding to the predicated version
22082209 // at MC lowering time.
22092210 Defs = [LR], Uses = [SP] in {
2210 def BL : ABXI<0b1011, (outs), (ins bl_target:$func),
2211 def BL : ABXI<0b1011, (outs), (ins arm_bl_target:$func),
22112212 IIC_Br, "bl\t$func",
22122213 [(ARMcall tglobaladdr:$func)]>,
22132214 Requires<[IsARM]>, Sched<[WriteBrL]> {
22172218 let DecoderMethod = "DecodeBranchImmInstruction";
22182219 }
22192220
2220 def BL_pred : ABI<0b1011, (outs), (ins bl_target:$func),
2221 def BL_pred : ABI<0b1011, (outs), (ins arm_bl_target:$func),
22212222 IIC_Br, "bl", "\t$func",
22222223 [(ARMcall_pred tglobaladdr:$func)]>,
22232224 Requires<[IsARM]>, Sched<[WriteBrL]> {
22582259
22592260 // mov lr, pc; b if callee is marked noreturn to avoid confusing the
22602261 // return stack predictor.
2261 def BMOVPCB_CALL : ARMPseudoInst<(outs), (ins bl_target:$func),
2262 def BMOVPCB_CALL : ARMPseudoInst<(outs), (ins arm_bl_target:$func),
22622263 8, IIC_Br, [(ARMcall_nolink tglobaladdr:$func)]>,
22632264 Requires<[IsARM]>, Sched<[WriteBr]>;
22642265 }
22662267 let isBranch = 1, isTerminator = 1 in {
22672268 // FIXME: should be able to write a pattern for ARMBrcond, but can't use
22682269 // a two-value operand where a dag node expects two operands. :(
2269 def Bcc : ABI<0b1010, (outs), (ins br_target:$target),
2270 def Bcc : ABI<0b1010, (outs), (ins arm_br_target:$target),
22702271 IIC_Br, "b", "\t$target",
22712272 [/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]>,
22722273 Sched<[WriteBr]> {
22812282 // FIXME: We shouldn't need this pseudo at all. Just using Bcc directly
22822283 // should be sufficient.
22832284 // FIXME: Is B really a Barrier? That doesn't seem right.
2284 def B : ARMPseudoExpand<(outs), (ins br_target:$target), 4, IIC_Br,
2285 [(br bb:$target)], (Bcc br_target:$target, (ops 14, zero_reg))>,
2285 def B : ARMPseudoExpand<(outs), (ins arm_br_target:$target), 4, IIC_Br,
2286 [(br bb:$target)], (Bcc arm_br_target:$target,
2287 (ops 14, zero_reg))>,
22862288 Sched<[WriteBr]>;
22872289
22882290 let Size = 4, isNotDuplicable = 1, isIndirectBranch = 1 in {
23092311 }
23102312
23112313 // BLX (immediate)
2312 def BLXi : AXI<(outs), (ins blx_target:$target), BrMiscFrm, NoItinerary,
2314 def BLXi : AXI<(outs), (ins arm_blx_target:$target), BrMiscFrm, NoItinerary,
23132315 "blx\t$target", []>,
23142316 Requires<[IsARM, HasV5T]>, Sched<[WriteBrL]> {
23152317 let Inst{31-25} = 0b1111101;
23392341 def TCRETURNri : PseudoInst<(outs), (ins tcGPR:$dst), IIC_Br, []>,
23402342 Sched<[WriteBr]>;
23412343
2342 def TAILJMPd : ARMPseudoExpand<(outs), (ins br_target:$dst),
2344 def TAILJMPd : ARMPseudoExpand<(outs), (ins arm_br_target:$dst),
23432345 4, IIC_Br, [],
2344 (Bcc br_target:$dst, (ops 14, zero_reg))>,
2346 (Bcc arm_br_target:$dst, (ops 14, zero_reg))>,
23452347 Requires<[IsARM]>, Sched<[WriteBr]>;
23462348
23472349 def TAILJMPr : ARMPseudoExpand<(outs), (ins tcGPR:$dst),
124124 let ParserMatchClass = UnsignedOffset_b8s2;
125125 }
126126
127 def t_bcctarget : Operand {
127
128 def thumb_br_target : Operand {
129 let ParserMatchClass = ThumbBranchTarget;
130 let EncoderMethod = "getThumbBranchTargetOpValue";
131 let OperandType = "OPERAND_PCREL";
132 }
133
134 def thumb_bl_target : Operand {
135 let ParserMatchClass = ThumbBranchTarget;
136 let EncoderMethod = "getThumbBLTargetOpValue";
137 let DecoderMethod = "DecodeThumbBLTargetOperand";
138 }
139
140 // Target for BLX *from* thumb mode.
141 def thumb_blx_target : Operand {
142 let ParserMatchClass = ARMBranchTarget;
143 let EncoderMethod = "getThumbBLXTargetOpValue";
144 let DecoderMethod = "DecodeThumbBLXOffset";
145 }
146
147 def thumb_bcc_target : Operand {
148 let ParserMatchClass = ThumbBranchTarget;
128149 let EncoderMethod = "getThumbBCCTargetOpValue";
129150 let DecoderMethod = "DecodeThumbBCCTargetOperand";
130151 }
131152
132 def t_cbtarget : Operand> {
153 def thumb_cb_target : Operand> {
154 let ParserMatchClass = ThumbBranchTarget;
133155 let EncoderMethod = "getThumbCBTargetOpValue";
134156 let DecoderMethod = "DecodeThumbCmpBROperand";
135 }
136
137 def t_bltarget : Operand {
138 let EncoderMethod = "getThumbBLTargetOpValue";
139 let DecoderMethod = "DecodeThumbBLTargetOperand";
140 }
141
142 def t_blxtarget : Operand {
143 let EncoderMethod = "getThumbBLXTargetOpValue";
144 let DecoderMethod = "DecodeThumbBLXOffset";
145157 }
146158
147159 // t_addrmode_pc :=
470482 Defs = [LR], Uses = [SP] in {
471483 // Also used for Thumb2
472484 def tBL : TIx2<0b11110, 0b11, 1,
473 (outs), (ins pred:$p, t_bltarget:$func), IIC_Br,
485 (outs), (ins pred:$p, thumb_bl_target:$func), IIC_Br,
474486 "bl${p}\t$func",
475487 [(ARMcall tglobaladdr:$func)]>,
476488 Requires<[IsThumb]>, Sched<[WriteBrL]> {
484496
485497 // ARMv5T and above, also used for Thumb2
486498 def tBLXi : TIx2<0b11110, 0b11, 0,
487 (outs), (ins pred:$p, t_blxtarget:$func), IIC_Br,
499 (outs), (ins pred:$p, thumb_blx_target:$func), IIC_Br,
488500 "blx${p}\t$func", []>,
489501 Requires<[IsThumb, HasV5T, IsNotMClass]>, Sched<[WriteBrL]> {
490502 bits<24> func;
539551 // Just a pseudo for a tBL instruction. Needed to let regalloc know about
540552 // the clobber of LR.
541553 let Defs = [LR] in
542 def tBfar : tPseudoExpand<(outs), (ins t_bltarget:$target, pred:$p),
543 4, IIC_Br, [], (tBL pred:$p, t_bltarget:$target)>,
554 def tBfar : tPseudoExpand<(outs), (ins thumb_bl_target:$target, pred:$p),
555 4, IIC_Br, [],
556 (tBL pred:$p, thumb_bl_target:$target)>,
544557 Sched<[WriteBrTbl]>;
545558
546559 def tBR_JTr : tPseudoInst<(outs),
556569 // FIXME: should be able to write a pattern for ARMBrcond, but can't use
557570 // a two-value operand where a dag node expects two operands. :(
558571 let isBranch = 1, isTerminator = 1 in
559 def tBcc : T1I<(outs), (ins t_bcctarget:$target, pred:$p), IIC_Br,
572 def tBcc : T1I<(outs), (ins thumb_bcc_target:$target, pred:$p), IIC_Br,
560573 "b${p}\t$target",
561574 [/*(ARMbrcond bb:$target, imm:$cc)*/]>,
562575 T1BranchCond<{1,1,0,1}>, Sched<[WriteBr]> {
35233523
35243524 let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
35253525 let isPredicable = 1 in
3526 def t2B : T2I<(outs), (ins uncondbrtarget:$target), IIC_Br,
3526 def t2B : T2I<(outs), (ins thumb_br_target:$target), IIC_Br,
35273527 "b", ".w\t$target",
35283528 [(br bb:$target)]>, Sched<[WriteBr]>,
35293529 Requires<[IsThumb, HasV8MBaseline]> {
36163616 // IOS version.
36173617 let Uses = [SP] in
36183618 def tTAILJMPd: tPseudoExpand<(outs),
3619 (ins uncondbrtarget:$dst, pred:$p),
3619 (ins thumb_br_target:$dst, pred:$p),
36203620 4, IIC_Br, [],
3621 (t2B uncondbrtarget:$dst, pred:$p)>,
3621 (t2B thumb_br_target:$dst, pred:$p)>,
36223622 Requires<[IsThumb2, IsMachO]>, Sched<[WriteBr]>;
36233623 }
36243624
36543654
36553655 // Compare and branch on zero / non-zero
36563656 let isBranch = 1, isTerminator = 1 in {
3657 def tCBZ : T1I<(outs), (ins tGPR:$Rn, t_cbtarget:$target), IIC_Br,
3657 def tCBZ : T1I<(outs), (ins tGPR:$Rn, thumb_cb_target:$target), IIC_Br,
36583658 "cbz\t$Rn, $target", []>,
36593659 T1Misc<{0,0,?,1,?,?,?}>,
36603660 Requires<[IsThumb, HasV8MBaseline]>, Sched<[WriteBr]> {
36663666 let Inst{2-0} = Rn;
36673667 }
36683668
3669 def tCBNZ : T1I<(outs), (ins tGPR:$Rn, t_cbtarget:$target), IIC_Br,
3669 def tCBNZ : T1I<(outs), (ins tGPR:$Rn, thumb_cb_target:$target), IIC_Br,
36703670 "cbnz\t$Rn, $target", []>,
36713671 T1Misc<{1,0,?,1,?,?,?}>,
36723672 Requires<[IsThumb, HasV8MBaseline]>, Sched<[WriteBr]> {
675675 bool isImm() const override {
676676 return Kind == k_Immediate;
677677 }
678
679 bool isARMBranchTarget() const {
680 if (!isImm()) return false;
681
682 if (const MCConstantExpr *CE = dyn_cast(getImm()))
683 return CE->getValue() % 4 == 0;
684 return true;
685 }
686
687
688 bool isThumbBranchTarget() const {
689 if (!isImm()) return false;
690
691 if (const MCConstantExpr *CE = dyn_cast(getImm()))
692 return CE->getValue() % 2 == 0;
693 return true;
694 }
695
678696 // checks whether this operand is an unsigned offset which fits is a field
679697 // of specified width and scaled by a specific number of bits
680698 template
17251743 Inst.addOperand(MCOperand::createImm(CE->getValue()));
17261744 else
17271745 Inst.addOperand(MCOperand::createExpr(Expr));
1746 }
1747
1748 void addARMBranchTargetOperands(MCInst &Inst, unsigned N) const {
1749 assert(N == 1 && "Invalid number of operands!");
1750 addExpr(Inst, getImm());
1751 }
1752
1753 void addThumbBranchTargetOperands(MCInst &Inst, unsigned N) const {
1754 assert(N == 1 && "Invalid number of operands!");
1755 addExpr(Inst, getImm());
17281756 }
17291757
17301758 void addCondCodeOperands(MCInst &Inst, unsigned N) const {
119119 SmallVectorImpl &Fixups,
120120 const MCSubtargetInfo &STI) const;
121121
122 /// getUnconditionalBranchTargetOpValue - Return encoding info for 24-bit
122 /// getThumbBranchTargetOpValue - Return encoding info for 24-bit
123123 /// immediate Thumb2 direct branch target.
124 uint32_t getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
125 SmallVectorImpl &Fixups,
126 const MCSubtargetInfo &STI) const;
124 uint32_t getThumbBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
125 SmallVectorImpl &Fixups,
126 const MCSubtargetInfo &STI) const;
127127
128128 /// getARMBranchTargetOpValue - Return encoding info for 24-bit immediate
129129 /// branch target.
749749
750750 /// getUnconditionalBranchTargetOpValue - Return encoding info for 24-bit
751751 /// immediate branch target.
752 uint32_t ARMMCCodeEmitter::
753 getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
754 SmallVectorImpl &Fixups,
755 const MCSubtargetInfo &STI) const {
752 uint32_t ARMMCCodeEmitter::getThumbBranchTargetOpValue(
753 const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups,
754 const MCSubtargetInfo &STI) const {
756755 unsigned Val = 0;
757756 const MCOperand MO = MI.getOperand(OpIdx);
758757
0 @ RUN: not llvm-mc -triple=armv7-apple-darwin < %s 2>&1 | FileCheck %s
1
2 @------------------------------------------------------------------------------
3 @ Branch targets destined for ARM mode must == 0 (mod 4), otherwise (mod 2).
4 @------------------------------------------------------------------------------
5
6 b #2
7 bl #2
8 beq #2
9
10 @ CHECK: error: instruction requires: thumb
11 @ CHECK: b #2
12 @ CHECK: error: instruction requires: thumb
13 @ CHECK: bl #2
14 @ CHECK: error: instruction requires: thumb
15 @ CHECK: beq #2
0 @ RUN: llvm-mc -triple=armv7-apple-darwin -show-encoding < %s | FileCheck %s
1
2 @------------------------------------------------------------------------------
3 @ Branch targets destined for ARM mode must == 0 (mod 4), otherwise (mod 2).
4 @------------------------------------------------------------------------------
5
6 b #4
7 bl #4
8 beq #4
9 blx #2
10
11 @ CHECK: b #4 @ encoding: [0x01,0x00,0x00,0xea]
12 @ CHECK: bl #4 @ encoding: [0x01,0x00,0x00,0xeb]
13 @ CHECK: beq #4 @ encoding: [0x01,0x00,0x00,0x0a]
14 @ CHECK: blx #2 @ encoding: [0x00,0x00,0x00,0xfb]
0 @ RUN: not llvm-mc -triple=thumbv7-apple-darwin < %s 2>&1 | FileCheck %s
1
2 @------------------------------------------------------------------------------
3 @ Branch targets destined for ARM mode must == 0 (mod 4), otherwise (mod 2).
4 @------------------------------------------------------------------------------
5
6 b #1
7 bl #1
8 cbnz r2, #1
9 beq #1
10 blx #2
11
12 @ CHECK: error: branch target out of range
13 @ CHECK: b #1
14 @ CHECK: error: invalid operand for instruction
15 @ CHECK: bl #1
16 @ CHECK: error: invalid operand for instruction
17 @ CHECK: cbnz r2, #1
18 @ CHECK: error: branch target out of range
19 @ CHECK: beq #1
20 @ CHECK: error: invalid operand for instruction
21 @ CHECK: blx #2
283283 @ CHECK: addeq r0, r1 @ encoding: [0x08,0x44]
284284 @ CHECK: bne #128 @ encoding: [0x40,0xe0]
285285
286
287 @------------------------------------------------------------------------------
288 @ Branch targets destined for ARM mode must == 0 (mod 4), otherwise (mod 2).
289 @------------------------------------------------------------------------------
290
291 b #2
292 bl #2
293 beq #2
294 cbz r0, #2
295 @ N.b. destination is "align(PC, 4) + imm" so imm is still 4-byte
296 @ aligned even though current PC may not and destination must be.
297 blx #4
298
299 @ CHECK: b #2 @ encoding: [0x01,0xe0]
300 @ CHECK: bl #2 @ encoding: [0x00,0xf0,0x01,0xf8]
301 @ CHECK: beq #2 @ encoding: [0x01,0xd0]
302 @ CHECK: cbz r0, #2 @ encoding: [0x08,0xb1]
303 @ CHECK: blx #4 @ encoding: [0x00,0xf0,0x02,0xe8]