summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/ARM/ARMInstrThumb.td4
-rw-r--r--llvm/lib/Target/ARM/ARMInstrThumb2.td10
-rw-r--r--llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp107
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp10
-rw-r--r--llvm/test/MC/ARM/basic-thumb-instructions.s4
-rw-r--r--llvm/test/MC/ARM/basic-thumb2-instructions.s4
-rw-r--r--llvm/test/MC/ARM/thumb-diagnostics.s21
-rw-r--r--llvm/test/MC/ARM/thumb2-b.w-encodingT4.s2
-rw-r--r--llvm/test/MC/ARM/thumb2-branches.s286
-rw-r--r--llvm/test/MC/ARM/thumb2-diagnostics.s19
10 files changed, 451 insertions, 16 deletions
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td
index e7218c66586..d5b65631704 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb.td
@@ -491,7 +491,8 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
T1Encoding<{1,1,1,0,0,?}>, Sched<[WriteBr]> {
bits<11> target;
let Inst{10-0} = target;
- }
+ let AsmMatchConverter = "cvtThumbBranches";
+ }
// Far jump
// Just a pseudo for a tBL instruction. Needed to let regalloc know about
@@ -521,6 +522,7 @@ let isBranch = 1, isTerminator = 1 in
bits<8> target;
let Inst{11-8} = p;
let Inst{7-0} = target;
+ let AsmMatchConverter = "cvtThumbBranches";
}
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index 7de0901f1c1..ccca41a1d36 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -3336,13 +3336,14 @@ def t2B : T2I<(outs), (ins uncondbrtarget:$target), IIC_Br,
let Inst{12} = 1;
bits<24> target;
- let Inst{26} = target{19};
- let Inst{11} = target{18};
- let Inst{13} = target{17};
+ let Inst{26} = target{23};
+ let Inst{13} = target{22};
+ let Inst{11} = target{21};
let Inst{25-16} = target{20-11};
let Inst{10-0} = target{10-0};
let DecoderMethod = "DecodeT2BInstruction";
-}
+ let AsmMatchConverter = "cvtThumbBranches";
+}
let isNotDuplicable = 1, isIndirectBranch = 1 in {
def t2BR_JT : t2PseudoInst<(outs),
@@ -3410,6 +3411,7 @@ def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br,
let Inst{10-0} = target{11-1};
let DecoderMethod = "DecodeThumb2BCCInstruction";
+ let AsmMatchConverter = "cvtThumbBranches";
}
// Tail calls. The IOS version of thumb tail calls uses a t2 branch, so
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 80e5c6edb4c..03d3a48f210 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -221,6 +221,9 @@ class ARMAsmParser : public MCTargetAsmParser {
// Asm Match Converter Methods
void cvtThumbMultiply(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &);
+ void cvtThumbBranches(MCInst &Inst,
+ const SmallVectorImpl<MCParsedAsmOperand*> &);
+
bool validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool processInstruction(MCInst &Inst,
@@ -601,7 +604,7 @@ public:
template<unsigned width, unsigned scale>
bool isUnsignedOffset() const {
if (!isImm()) return false;
- if (dyn_cast<MCSymbolRefExpr>(Imm.Val)) return true;
+ if (isa<MCSymbolRefExpr>(Imm.Val)) return true;
if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
int64_t Val = CE->getValue();
int64_t Align = 1LL << scale;
@@ -610,6 +613,22 @@ public:
}
return false;
}
+ // checks whether this operand is an signed offset which fits is a field
+ // of specified width and scaled by a specific number of bits
+ template<unsigned width, unsigned scale>
+ bool isSignedOffset() const {
+ if (!isImm()) return false;
+ if (isa<MCSymbolRefExpr>(Imm.Val)) return true;
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
+ int64_t Val = CE->getValue();
+ int64_t Align = 1LL << scale;
+ int64_t Max = Align * ((1LL << (width-1)) - 1);
+ int64_t Min = -Align * (1LL << (width-1));
+ return ((Val % Align) == 0) && (Val >= Min) && (Val <= Max);
+ }
+ return false;
+ }
+
// checks whether this operand is a memory operand computed as an offset
// applied to PC. the offset may have 8 bits of magnitude and is represented
// with two bits of shift. textually it may be either [pc, #imm], #imm or
@@ -4102,6 +4121,65 @@ cvtThumbMultiply(MCInst &Inst,
((ARMOperand*)Operands[2])->addCondCodeOperands(Inst, 2);
}
+void ARMAsmParser::
+cvtThumbBranches(MCInst &Inst,
+ const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ int CondOp = -1, ImmOp = -1;
+ switch(Inst.getOpcode()) {
+ case ARM::tB:
+ case ARM::tBcc: CondOp = 1; ImmOp = 2; break;
+
+ case ARM::t2B:
+ case ARM::t2Bcc: CondOp = 1; ImmOp = 3; break;
+
+ default: llvm_unreachable("Unexpected instruction in cvtThumbBranches");
+ }
+ // first decide whether or not the branch should be conditional
+ // by looking at it's location relative to an IT block
+ if(inITBlock()) {
+ // inside an IT block we cannot have any conditional branches. any
+ // such instructions needs to be converted to unconditional form
+ switch(Inst.getOpcode()) {
+ case ARM::tBcc: Inst.setOpcode(ARM::tB); break;
+ case ARM::t2Bcc: Inst.setOpcode(ARM::t2B); break;
+ }
+ } else {
+ // outside IT blocks we can only have unconditional branches with AL
+ // condition code or conditional branches with non-AL condition code
+ unsigned Cond = static_cast<ARMOperand*>(Operands[CondOp])->getCondCode();
+ switch(Inst.getOpcode()) {
+ case ARM::tB:
+ case ARM::tBcc:
+ Inst.setOpcode(Cond == ARMCC::AL ? ARM::tB : ARM::tBcc);
+ break;
+ case ARM::t2B:
+ case ARM::t2Bcc:
+ Inst.setOpcode(Cond == ARMCC::AL ? ARM::t2B : ARM::t2Bcc);
+ break;
+ }
+ }
+
+ // now decide on encoding size based on branch target range
+ switch(Inst.getOpcode()) {
+ // classify tB as either t2B or t1B based on range of immediate operand
+ case ARM::tB: {
+ ARMOperand* op = static_cast<ARMOperand*>(Operands[ImmOp]);
+ if(!op->isSignedOffset<11, 1>() && isThumbTwo())
+ Inst.setOpcode(ARM::t2B);
+ break;
+ }
+ // classify tBcc as either t2Bcc or t1Bcc based on range of immediate operand
+ case ARM::tBcc: {
+ ARMOperand* op = static_cast<ARMOperand*>(Operands[ImmOp]);
+ if(!op->isSignedOffset<8, 1>() && isThumbTwo())
+ Inst.setOpcode(ARM::t2Bcc);
+ break;
+ }
+ }
+ ((ARMOperand*)Operands[ImmOp])->addImmOperands(Inst, 1);
+ ((ARMOperand*)Operands[CondOp])->addCondCodeOperands(Inst, 2);
+}
+
/// Parse an ARM memory expression, return false if successful else return true
/// or an error. The first token must be a '[' when called.
bool ARMAsmParser::
@@ -5216,6 +5294,7 @@ validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
SMLoc Loc = Operands[0]->getStartLoc();
+
// Check the IT block state first.
// NOTE: BKPT instruction has the interesting property of being
// allowed in IT blocks, but not being predicable. It just always
@@ -5247,8 +5326,8 @@ validateInstruction(MCInst &Inst,
// Check for non-'al' condition codes outside of the IT block.
} else if (isThumbTwo() && MCID.isPredicable() &&
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
- ARMCC::AL && Inst.getOpcode() != ARM::tB &&
- Inst.getOpcode() != ARM::t2B)
+ ARMCC::AL && Inst.getOpcode() != ARM::tBcc &&
+ Inst.getOpcode() != ARM::t2Bcc)
return Error(Loc, "predicated instructions must be in IT block");
switch (Inst.getOpcode()) {
@@ -5383,6 +5462,28 @@ validateInstruction(MCInst &Inst,
}
break;
}
+ // final range checking for Thumb unconditional branch instructions
+ case ARM::tB:
+ if(!(static_cast<ARMOperand*>(Operands[2]))->isSignedOffset<11, 1>())
+ return Error(Operands[2]->getStartLoc(), "Branch target out of range");
+ break;
+ case ARM::t2B: {
+ int op = (Operands[2]->isImm()) ? 2 : 3;
+ if(!(static_cast<ARMOperand*>(Operands[op]))->isSignedOffset<24, 1>())
+ return Error(Operands[op]->getStartLoc(), "Branch target out of range");
+ break;
+ }
+ // final range checking for Thumb conditional branch instructions
+ case ARM::tBcc:
+ if(!(static_cast<ARMOperand*>(Operands[2]))->isSignedOffset<8, 1>())
+ return Error(Operands[2]->getStartLoc(), "Branch target out of range");
+ break;
+ case ARM::t2Bcc: {
+ int op = (Operands[2]->isImm()) ? 2 : 3;
+ if(!(static_cast<ARMOperand*>(Operands[op]))->isSignedOffset<20, 1>())
+ return Error(Operands[op]->getStartLoc(), "Branch target out of range");
+ break;
+ }
}
StringRef DepInfo;
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
index a18d465f042..08732201b51 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -638,8 +638,14 @@ getARMBLXTargetOpValue(const MCInst &MI, unsigned OpIdx,
uint32_t ARMMCCodeEmitter::
getUnconditionalBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const {
- unsigned Val =
- ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_uncondbranch, Fixups);
+ unsigned Val = 0;
+ const MCOperand MO = MI.getOperand(OpIdx);
+
+ if(MO.isExpr())
+ Val = ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_t2_uncondbranch, Fixups);
+ else
+ Val = MO.getImm() >> 1;
+
bool I = (Val & 0x800000);
bool J1 = (Val & 0x400000);
bool J2 = (Val & 0x200000);
diff --git a/llvm/test/MC/ARM/basic-thumb-instructions.s b/llvm/test/MC/ARM/basic-thumb-instructions.s
index b48db9a4d8e..aba03f9f18d 100644
--- a/llvm/test/MC/ARM/basic-thumb-instructions.s
+++ b/llvm/test/MC/ARM/basic-thumb-instructions.s
@@ -128,7 +128,7 @@ _func:
beq _bar
b #1838
b #-420
- beq #336
+ beq #-256
beq #160
@ CHECK: b _baz @ encoding: [A,0xe0'A']
@@ -137,7 +137,7 @@ _func:
@ fixup A - offset: 0, value: _bar, kind: fixup_arm_thumb_bcc
@ CHECK: b #1838 @ encoding: [0x97,0xe3]
@ CHECK: b #-420 @ encoding: [0x2e,0xe7]
-@ CHECK: beq #336 @ encoding: [0xa8,0xd0]
+@ CHECK: beq #-256 @ encoding: [0x80,0xd0]
@ CHECK: beq #160 @ encoding: [0x50,0xd0]
@------------------------------------------------------------------------------
diff --git a/llvm/test/MC/ARM/basic-thumb2-instructions.s b/llvm/test/MC/ARM/basic-thumb2-instructions.s
index b5d3966b1fb..4c51cd9ee7c 100644
--- a/llvm/test/MC/ARM/basic-thumb2-instructions.s
+++ b/llvm/test/MC/ARM/basic-thumb2-instructions.s
@@ -221,12 +221,12 @@ _func:
beq.w _bar
bmi.w #-183396
-@ CHECK: b.w _bar @ encoding: [A,0xf0'A',A,0x90'A']
+@ CHECK: b.w _bar @ encoding: [A,0xf0'A',A,0xb8'A']
@ fixup A - offset: 0, value: _bar, kind: fixup_t2_uncondbranch
@ CHECK: beq.w _bar @ encoding: [A,0xf0'A',A,0x80'A']
@ fixup A - offset: 0, value: _bar, kind: fixup_t2_condbranch
@ CHECK: it eq @ encoding: [0x08,0xbf]
-@ CHECK: beq.w _bar @ encoding: [A,0xf0'A',A,0x90'A']
+@ CHECK: beq.w _bar @ encoding: [A,0xf0'A',A,0xb8'A']
@ fixup A - offset: 0, value: _bar, kind: fixup_t2_uncondbranch
@ CHECK: bmi.w #-183396 @ encoding: [0x13,0xf5,0xce,0xa9]
diff --git a/llvm/test/MC/ARM/thumb-diagnostics.s b/llvm/test/MC/ARM/thumb-diagnostics.s
index a194ab4f22e..3604fc5f1ba 100644
--- a/llvm/test/MC/ARM/thumb-diagnostics.s
+++ b/llvm/test/MC/ARM/thumb-diagnostics.s
@@ -138,7 +138,26 @@ error: invalid operand for instruction
@ CHECK-ERRORS: error: source register must be the same as destination
@ CHECK-ERRORS: add r2, sp, ip
@ CHECK-ERRORS: ^
-
+
+
+@------------------------------------------------------------------------------
+@ WFE/WFI/YIELD - out of range immediates for Thumb1 branches
+@------------------------------------------------------------------------------
+
+ beq #-258
+ bne #256
+ bgt #13
+ b #-1048578
+ b #1048576
+ b #10323
+
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+
@------------------------------------------------------------------------------
@ WFE/WFI/YIELD - are not supported pre v6T2
@------------------------------------------------------------------------------
diff --git a/llvm/test/MC/ARM/thumb2-b.w-encodingT4.s b/llvm/test/MC/ARM/thumb2-b.w-encodingT4.s
index be77b06267a..aff02e1e151 100644
--- a/llvm/test/MC/ARM/thumb2-b.w-encodingT4.s
+++ b/llvm/test/MC/ARM/thumb2-b.w-encodingT4.s
@@ -9,4 +9,4 @@ _foo:
@------------------------------------------------------------------------------
b.w 0x3680c
-@ CHECK: b.w #223244 @ encoding: [0x6d,0xf0,0x0c,0xb0]
+@ CHECK: b.w #223244 @ encoding: [0x36,0xf0,0x06,0xbc]
diff --git a/llvm/test/MC/ARM/thumb2-branches.s b/llvm/test/MC/ARM/thumb2-branches.s
new file mode 100644
index 00000000000..9148233a79c
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb2-branches.s
@@ -0,0 +1,286 @@
+@ RUN: llvm-mc -triple=thumbv7-apple-darwin -mcpu=cortex-a8 -show-encoding < %s | FileCheck %s
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept narrow suffix and encode to short encodings
+@------------------------------------------------------------------------------
+
+ b.n #-2048
+ b.n #2046
+
+@ CHECK: b #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: b #2046 @ encoding: [0xff,0xe3]
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept wide suffix and encode to wide encodings
+@------------------------------------------------------------------------------
+
+ b.w #-2048
+ b.w #2046
+ b.w #-1677216
+ b.w #1677214
+
+@ CHECK: b.w #-2048 @ encoding: [0xff,0xf7,0x00,0xbc]
+@ CHECK: b.w #2046 @ encoding: [0x00,0xf0,0xff,0xbb]
+@ CHECK: b.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: b.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ unconditional branches without width suffix encode depending of offset size
+@------------------------------------------------------------------------------
+
+ b #-2048
+ b #2046
+ b #-2050
+ b #2048
+ b #-1677216
+ b #1677214
+
+@ CHECK: b #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: b #2046 @ encoding: [0xff,0xe3]
+@ CHECK: b.w #-2050 @ encoding: [0xff,0xf7,0xff,0xbb]
+@ CHECK: b.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
+@ CHECK: b.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: b.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ unconditional branches with width narrow suffix in IT block
+@------------------------------------------------------------------------------
+
+ it eq
+ beq.n #-2048
+ it ne
+ bne.n #-2046
+
+@ CHECK: it eq @ encoding: [0x08,0xbf]
+@ CHECK: beq #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: it ne @ encoding: [0x18,0xbf]
+@ CHECK: bne #-2046 @ encoding: [0x01,0xe4]
+
+@------------------------------------------------------------------------------
+@ unconditional branches with wide suffix in IT block
+@------------------------------------------------------------------------------
+
+ it gt
+ bgt.w #-2048
+ it le
+ ble.w #2046
+ it ge
+ bge.w #-1677216
+ it lt
+ blt.w #1677214
+
+@ CHECK: it gt @ encoding: [0xc8,0xbf]
+@ CHECK: bgt.w #-2048 @ encoding: [0xff,0xf7,0x00,0xbc]
+@ CHECK: it le @ encoding: [0xd8,0xbf]
+@ CHECK: ble.w #2046 @ encoding: [0x00,0xf0,0xff,0xbb]
+@ CHECK: it ge @ encoding: [0xa8,0xbf]
+@ CHECK: bge.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: it lt @ encoding: [0xb8,0xbf]
+@ CHECK: blt.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ conditional branches accept narrow suffix and encode to short encodings
+@------------------------------------------------------------------------------
+
+ beq.n #-256
+ bne.n #254
+
+@ CHECK: beq #-256 @ encoding: [0x80,0xd0]
+@ CHECK: bne #254 @ encoding: [0x7f,0xd1]
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept wide suffix and encode to wide encodings
+@------------------------------------------------------------------------------
+
+ bmi.w #-256
+ bne.w #254
+ blt.w #-1048576
+ bge.w #1048574
+
+@ CHECK: bmi.w #-256 @ encoding: [0x3f,0xf5,0x80,0xaf]
+@ CHECK: bne.w #254 @ encoding: [0x40,0xf0,0x7f,0x80]
+@ CHECK: blt.w #-1048576 @ encoding: [0xc0,0xf6,0x00,0x80]
+@ CHECK: bge.w #1048574 @ encoding: [0xbf,0xf2,0xff,0xaf]
+
+@------------------------------------------------------------------------------
+@ unconditional branches without width suffix encode depending of offset size
+@------------------------------------------------------------------------------
+
+ bne #-256
+ bgt #254
+ bne #-258
+ bgt #256
+ bne #-1048576
+ bgt #1048574
+
+@ CHECK: bne #-256 @ encoding: [0x80,0xd1]
+@ CHECK: bgt #254 @ encoding: [0x7f,0xdc]
+@ CHECK: bne.w #-258 @ encoding: [0x7f,0xf4,0x7f,0xaf]
+@ CHECK: bgt.w #256 @ encoding: [0x00,0xf3,0x80,0x80]
+@ CHECK: bne.w #-1048576 @ encoding: [0x40,0xf4,0x00,0x80]
+@ CHECK: bgt.w #1048574 @ encoding: [0x3f,0xf3,0xff,0xaf]
+
+@------------------------------------------------------------------------------
+@ same branch insturction encoding to conditional or unconditional depending
+@ on whether it is in an IT block or not
+@------------------------------------------------------------------------------
+
+ it eq
+ addeq r0, r1
+ bne #128
+
+@ CHECK: it eq @ encoding: [0x08,0xbf]
+@ CHECK: addeq r0, r1 @ encoding: [0x08,0x44]
+@ CHECK: bne #128 @ encoding: [0x40,0xd1]
+
+ ite eq
+ addeq r0, r1
+ bne #128
+
+@ CHECK: ite eq @ encoding: [0x0c,0xbf]
+@ CHECK: addeq r0, r1 @ encoding: [0x08,0x44]
+@ CHECK: bne #128 @ encoding: [0x40,0xe0]
+
+@ RUN: llvm-mc -triple=thumbv7-apple-darwin -mcpu=cortex-a8 -show-encoding < %s | FileCheck %s
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept narrow suffix and encode to short encodings
+@------------------------------------------------------------------------------
+
+ b.n #-2048
+ b.n #2046
+
+@ CHECK: b #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: b #2046 @ encoding: [0xff,0xe3]
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept wide suffix and encode to wide encodings
+@------------------------------------------------------------------------------
+
+ b.w #-2048
+ b.w #2046
+ b.w #-1677216
+ b.w #1677214
+
+@ CHECK: b.w #-2048 @ encoding: [0xff,0xf7,0x00,0xbc]
+@ CHECK: b.w #2046 @ encoding: [0x00,0xf0,0xff,0xbb]
+@ CHECK: b.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: b.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ unconditional branches without width suffix encode depending of offset size
+@------------------------------------------------------------------------------
+
+ b #-2048
+ b #2046
+ b #-2050
+ b #2048
+ b #-1677216
+ b #1677214
+
+@ CHECK: b #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: b #2046 @ encoding: [0xff,0xe3]
+@ CHECK: b.w #-2050 @ encoding: [0xff,0xf7,0xff,0xbb]
+@ CHECK: b.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
+@ CHECK: b.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: b.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ unconditional branches with width narrow suffix in IT block
+@------------------------------------------------------------------------------
+
+ it eq
+ beq.n #-2048
+ it ne
+ bne.n #-2046
+
+@ CHECK: it eq @ encoding: [0x08,0xbf]
+@ CHECK: beq #-2048 @ encoding: [0x00,0xe4]
+@ CHECK: it ne @ encoding: [0x18,0xbf]
+@ CHECK: bne #-2046 @ encoding: [0x01,0xe4]
+
+@------------------------------------------------------------------------------
+@ unconditional branches with wide suffix in IT block
+@------------------------------------------------------------------------------
+
+ it gt
+ bgt.w #-2048
+ it le
+ ble.w #2046
+ it ge
+ bge.w #-1677216
+ it lt
+ blt.w #1677214
+
+@ CHECK: it gt @ encoding: [0xc8,0xbf]
+@ CHECK: bgt.w #-2048 @ encoding: [0xff,0xf7,0x00,0xbc]
+@ CHECK: it le @ encoding: [0xd8,0xbf]
+@ CHECK: ble.w #2046 @ encoding: [0x00,0xf0,0xff,0xbb]
+@ CHECK: it ge @ encoding: [0xa8,0xbf]
+@ CHECK: bge.w #-1677216 @ encoding: [0x66,0xf6,0x30,0xbc]
+@ CHECK: it lt @ encoding: [0xb8,0xbf]
+@ CHECK: blt.w #1677214 @ encoding: [0x99,0xf1,0xcf,0xbb]
+
+@------------------------------------------------------------------------------
+@ conditional branches accept narrow suffix and encode to short encodings
+@------------------------------------------------------------------------------
+
+ beq.n #-256
+ bne.n #254
+
+@ CHECK: beq #-256 @ encoding: [0x80,0xd0]
+@ CHECK: bne #254 @ encoding: [0x7f,0xd1]
+
+@------------------------------------------------------------------------------
+@ unconditional branches accept wide suffix and encode to wide encodings
+@------------------------------------------------------------------------------
+
+ bmi.w #-256
+ bne.w #254
+ blt.w #-1048576
+ bge.w #1048574
+
+@ CHECK: bmi.w #-256 @ encoding: [0x3f,0xf5,0x80,0xaf]
+@ CHECK: bne.w #254 @ encoding: [0x40,0xf0,0x7f,0x80]
+@ CHECK: blt.w #-1048576 @ encoding: [0xc0,0xf6,0x00,0x80]
+@ CHECK: bge.w #1048574 @ encoding: [0xbf,0xf2,0xff,0xaf]
+
+@------------------------------------------------------------------------------
+@ unconditional branches without width suffix encode depending of offset size
+@------------------------------------------------------------------------------
+
+ bne #-256
+ bgt #254
+ bne #-258
+ bgt #256
+ bne #-1048576
+ bgt #1048574
+
+@ CHECK: bne #-256 @ encoding: [0x80,0xd1]
+@ CHECK: bgt #254 @ encoding: [0x7f,0xdc]
+@ CHECK: bne.w #-258 @ encoding: [0x7f,0xf4,0x7f,0xaf]
+@ CHECK: bgt.w #256 @ encoding: [0x00,0xf3,0x80,0x80]
+@ CHECK: bne.w #-1048576 @ encoding: [0x40,0xf4,0x00,0x80]
+@ CHECK: bgt.w #1048574 @ encoding: [0x3f,0xf3,0xff,0xaf]
+
+@------------------------------------------------------------------------------
+@ same branch insturction encoding to conditional or unconditional depending
+@ on whether it is in an IT block or not
+@------------------------------------------------------------------------------
+
+ it eq
+ addeq r0, r1
+ bne #128
+
+@ CHECK: it eq @ encoding: [0x08,0xbf]
+@ CHECK: addeq r0, r1 @ encoding: [0x08,0x44]
+@ CHECK: bne #128 @ encoding: [0x40,0xd1]
+
+ ite eq
+ addeq r0, r1
+ bne #128
+
+@ CHECK: ite eq @ encoding: [0x0c,0xbf]
+@ CHECK: addeq r0, r1 @ encoding: [0x08,0x44]
+@ CHECK: bne #128 @ encoding: [0x40,0xe0]
+
diff --git a/llvm/test/MC/ARM/thumb2-diagnostics.s b/llvm/test/MC/ARM/thumb2-diagnostics.s
index e1c005872f0..7450e745c82 100644
--- a/llvm/test/MC/ARM/thumb2-diagnostics.s
+++ b/llvm/test/MC/ARM/thumb2-diagnostics.s
@@ -51,3 +51,22 @@
itt eq
bkpteq #1
@ CHECK-ERRORS: error: instruction 'bkpt' is not predicable, but condition code specified
+
+ nopeq
+ nopeq
+
+@ out of range operands for Thumb2 targets
+
+ beq.w #-1048578
+ bne.w #1048576
+ blt.w #1013411
+ b.w #-16777218
+ b.w #16777216
+ b.w #1592313
+
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
+@ CHECK-ERRORS: error: Branch target out of range
OpenPOWER on IntegriCloud