Index: lib/Target/ARM/ARMConstantIslandPass.cpp =================================================================== --- lib/Target/ARM/ARMConstantIslandPass.cpp +++ lib/Target/ARM/ARMConstantIslandPass.cpp @@ -1762,8 +1762,13 @@ bool ARMConstantIslands::optimizeThumb2Branches() { bool MadeChange = false; - for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) { - ImmBranch &Br = ImmBranches[i]; + // The order in which branches appear in ImmBranches is approximately their + // order within the function body. By visiting later branches first, we reduce + // the distance between earlier forward branches and their targets, making it + // more likely that the cbn?z optimization, which can only apply to forward + // branches, will succeed. + for (unsigned i = ImmBranches.size(); i != 0; --i) { + ImmBranch &Br = ImmBranches[i-1]; unsigned Opcode = Br.MI->getOpcode(); unsigned NewOpc = 0; unsigned Scale = 1; Index: test/CodeGen/Thumb2/cbnz.ll =================================================================== --- /dev/null +++ test/CodeGen/Thumb2/cbnz.ll @@ -0,0 +1,54 @@ +; RUN: llc -mtriple thumbv7-unknown-linux -o - %s | FileCheck %s + +declare void @x() +declare void @y() + +define void @f(i32 %x, i32 %y) { + ; CHECK-LABEL: f: + ; CHECK: cbnz + %p = icmp eq i32 %x, 0 + br i1 %p, label %t, label %f + +t: + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + ; CHECK: cbnz + %q = icmp eq i32 %y, 0 + br i1 %q, label %t2, label %f + +t2: + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + call void @x() + br label %f + +f: + call void @y() + ret void +}