[llvm] d7bca8e - [AArch64] Relax cross-section branches
Daniel Hoekwater via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 15 18:43:42 PDT 2023
Author: Daniel Hoekwater
Date: 2023-08-16T01:43:07Z
New Revision: d7bca8e4942b97a6442425d5f741cb4665582446
URL: https://github.com/llvm/llvm-project/commit/d7bca8e4942b97a6442425d5f741cb4665582446
DIFF: https://github.com/llvm/llvm-project/commit/d7bca8e4942b97a6442425d5f741cb4665582446.diff
LOG: [AArch64] Relax cross-section branches
Because the code layout is not known during compilation, the distance of
cross-section jumps is not knowable at compile-time. Because of this, we
should assume that any cross-sectional jumps are out of range. This
assumption is necessary for machine function splitting on AArch64, which
introduces cross-section branches in the middle of functions. The linker
relaxes out-of-range unconditional branches, but it clobbers X16 to do
so; it doesn't relax conditional branches, which must be manually
relaxed by the compiler.
Differential Revision: https://reviews.llvm.org/D145211
Added:
llvm/test/CodeGen/AArch64/branch-relax-b.ll
llvm/test/CodeGen/AArch64/branch-relax-cross-section.mir
Modified:
llvm/include/llvm/Target/TargetMachine.h
llvm/lib/CodeGen/BranchRelaxation.cpp
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
llvm/lib/Target/AArch64/AArch64InstrInfo.h
llvm/lib/Target/TargetMachine.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index b6ba36fb09b1bc..5838758748fa82 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -232,6 +232,9 @@ class TargetMachine {
/// target default.
CodeModel::Model getCodeModel() const { return CMModel; }
+ /// Returns the maximum code size possible under the code model.
+ uint64_t getMaxCodeSize() const;
+
/// Set the code model.
void setCodeModel(CodeModel::Model CM) { CMModel = CM; }
diff --git a/llvm/lib/CodeGen/BranchRelaxation.cpp b/llvm/lib/CodeGen/BranchRelaxation.cpp
index 05494f1ddc67ea..378f8bfda20361 100644
--- a/llvm/lib/CodeGen/BranchRelaxation.cpp
+++ b/llvm/lib/CodeGen/BranchRelaxation.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
#include <cassert>
#include <cstdint>
#include <iterator>
@@ -84,6 +85,7 @@ class BranchRelaxation : public MachineFunctionPass {
MachineFunction *MF = nullptr;
const TargetRegisterInfo *TRI = nullptr;
const TargetInstrInfo *TII = nullptr;
+ const TargetMachine *TM = nullptr;
bool relaxBranchInstructions();
void scanFunction();
@@ -232,6 +234,11 @@ BranchRelaxation::createNewBlockAfter(MachineBasicBlock &OrigMBB,
MachineBasicBlock *NewBB = MF->CreateMachineBasicBlock(BB);
MF->insert(++OrigMBB.getIterator(), NewBB);
+ // Place the new block in the same section as OrigBB
+ NewBB->setSectionID(OrigMBB.getSectionID());
+ NewBB->setIsEndSection(OrigMBB.isEndSection());
+ OrigMBB.setIsEndSection(false);
+
// Insert an entry into BlockInfo to align it properly with the block numbers.
BlockInfo.insert(BlockInfo.begin() + NewBB->getNumber(), BasicBlockInfo());
@@ -241,8 +248,9 @@ BranchRelaxation::createNewBlockAfter(MachineBasicBlock &OrigMBB,
/// Split the basic block containing MI into two blocks, which are joined by
/// an unconditional branch. Update data structures and renumber blocks to
/// account for this change and returns the newly created block.
-MachineBasicBlock *BranchRelaxation::splitBlockBeforeInstr(MachineInstr &MI,
- MachineBasicBlock *DestBB) {
+MachineBasicBlock *
+BranchRelaxation::splitBlockBeforeInstr(MachineInstr &MI,
+ MachineBasicBlock *DestBB) {
MachineBasicBlock *OrigBB = MI.getParent();
// Create a new MBB for the code after the OrigBB.
@@ -250,6 +258,11 @@ MachineBasicBlock *BranchRelaxation::splitBlockBeforeInstr(MachineInstr &MI,
MF->CreateMachineBasicBlock(OrigBB->getBasicBlock());
MF->insert(++OrigBB->getIterator(), NewBB);
+ // Place the new block in the same section as OrigBB.
+ NewBB->setSectionID(OrigBB->getSectionID());
+ NewBB->setIsEndSection(OrigBB->isEndSection());
+ OrigBB->setIsEndSection(false);
+
// Splice the instructions starting with MI over to NewBB.
NewBB->splice(NewBB->end(), OrigBB, MI.getIterator(), OrigBB->end());
@@ -300,7 +313,12 @@ bool BranchRelaxation::isBlockInRange(
int64_t BrOffset = getInstrOffset(MI);
int64_t DestOffset = BlockInfo[DestBB.getNumber()].Offset;
- if (TII->isBranchOffsetInRange(MI.getOpcode(), DestOffset - BrOffset))
+ const MachineBasicBlock *SrcBB = MI.getParent();
+
+ if (TII->isBranchOffsetInRange(MI.getOpcode(),
+ SrcBB->getSectionID() != DestBB.getSectionID()
+ ? TM->getMaxCodeSize()
+ : DestOffset - BrOffset))
return true;
LLVM_DEBUG(dbgs() << "Out of range branch to destination "
@@ -462,7 +480,10 @@ bool BranchRelaxation::fixupUnconditionalBranch(MachineInstr &MI) {
int64_t DestOffset = BlockInfo[DestBB->getNumber()].Offset;
int64_t SrcOffset = getInstrOffset(MI);
- assert(!TII->isBranchOffsetInRange(MI.getOpcode(), DestOffset - SrcOffset));
+ assert(!TII->isBranchOffsetInRange(
+ MI.getOpcode(), MBB->getSectionID() != DestBB->getSectionID()
+ ? TM->getMaxCodeSize()
+ : DestOffset - SrcOffset));
BlockInfo[MBB->getNumber()].Size -= OldBrSize;
@@ -492,9 +513,15 @@ bool BranchRelaxation::fixupUnconditionalBranch(MachineInstr &MI) {
// be erased.
MachineBasicBlock *RestoreBB = createNewBlockAfter(MF->back(),
DestBB->getBasicBlock());
+ std::prev(RestoreBB->getIterator())
+ ->setIsEndSection(RestoreBB->isEndSection());
+ RestoreBB->setIsEndSection(false);
TII->insertIndirectBranch(*BranchBB, *DestBB, *RestoreBB, DL,
- DestOffset - SrcOffset, RS.get());
+ BranchBB->getSectionID() != DestBB->getSectionID()
+ ? TM->getMaxCodeSize()
+ : DestOffset - SrcOffset,
+ RS.get());
BlockInfo[BranchBB->getNumber()].Size = computeBlockSize(*BranchBB);
adjustBlockOffsets(*MBB);
@@ -525,6 +552,11 @@ bool BranchRelaxation::fixupUnconditionalBranch(MachineInstr &MI) {
BlockInfo[RestoreBB->getNumber()].Size = computeBlockSize(*RestoreBB);
// Update the offset starting from the previous block.
adjustBlockOffsets(*PrevBB);
+
+ // Fix up section information for RestoreBB and DestBB
+ RestoreBB->setSectionID(DestBB->getSectionID());
+ RestoreBB->setIsBeginSection(DestBB->isBeginSection());
+ DestBB->setIsBeginSection(false);
} else {
// Remove restore block if it's not required.
MF->erase(RestoreBB);
@@ -553,7 +585,7 @@ bool BranchRelaxation::relaxBranchInstructions() {
// Unconditional branch destination might be unanalyzable, assume these
// are OK.
if (MachineBasicBlock *DestBB = TII->getBranchDestBlock(*Last)) {
- if (!isBlockInRange(*Last, *DestBB)) {
+ if (!isBlockInRange(*Last, *DestBB) && !TII->isTailCall(*Last)) {
fixupUnconditionalBranch(*Last);
++NumUnconditionalRelaxed;
Changed = true;
@@ -607,6 +639,7 @@ bool BranchRelaxation::runOnMachineFunction(MachineFunction &mf) {
const TargetSubtargetInfo &ST = MF->getSubtarget();
TII = ST.getInstrInfo();
+ TM = &MF->getTarget();
TRI = ST.getRegisterInfo();
if (TRI->trackLivenessAfterRegAlloc(*MF))
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index ff7b50f4c4c1fd..433f8ad84d3afd 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -30,6 +30,7 @@
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
@@ -70,6 +71,10 @@ static cl::opt<unsigned>
BCCDisplacementBits("aarch64-bcc-offset-bits", cl::Hidden, cl::init(19),
cl::desc("Restrict range of Bcc instructions (DEBUG)"));
+static cl::opt<unsigned>
+ BDisplacementBits("aarch64-b-offset-bits", cl::Hidden, cl::init(26),
+ cl::desc("Restrict range of B instructions (DEBUG)"));
+
AArch64InstrInfo::AArch64InstrInfo(const AArch64Subtarget &STI)
: AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP,
AArch64::CATCHRET),
@@ -203,7 +208,7 @@ static unsigned getBranchDisplacementBits(unsigned Opc) {
default:
llvm_unreachable("unexpected opcode!");
case AArch64::B:
- return 64;
+ return BDisplacementBits;
case AArch64::TBNZW:
case AArch64::TBZW:
case AArch64::TBNZX:
@@ -248,6 +253,68 @@ AArch64InstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
}
}
+void AArch64InstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock &NewDestBB,
+ MachineBasicBlock &RestoreBB,
+ const DebugLoc &DL,
+ int64_t BrOffset,
+ RegScavenger *RS) const {
+ assert(RS && "RegScavenger required for long branching");
+ assert(MBB.empty() &&
+ "new block should be inserted for expanding unconditional branch");
+ assert(MBB.pred_size() == 1);
+ assert(RestoreBB.empty() &&
+ "restore block should be inserted for restoring clobbered registers");
+
+ auto buildIndirectBranch = [&](Register Reg, MachineBasicBlock &DestBB) {
+ // Offsets outside of the signed 33-bit range are not supported for ADRP +
+ // ADD.
+ if (!isInt<33>(BrOffset))
+ report_fatal_error(
+ "Branch offsets outside of the signed 33-bit range not supported");
+
+ BuildMI(MBB, MBB.end(), DL, get(AArch64::ADRP), Reg)
+ .addSym(DestBB.getSymbol(), AArch64II::MO_PAGE);
+ BuildMI(MBB, MBB.end(), DL, get(AArch64::ADDXri), Reg)
+ .addReg(Reg)
+ .addSym(DestBB.getSymbol(), AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
+ .addImm(0);
+ BuildMI(MBB, MBB.end(), DL, get(AArch64::BR)).addReg(Reg);
+ };
+
+ RS->enterBasicBlockEnd(MBB);
+ Register Reg = RS->FindUnusedReg(&AArch64::GPR64RegClass);
+
+ // If there's a free register, manually insert the indirect branch using it.
+ if (Reg != AArch64::NoRegister) {
+ buildIndirectBranch(Reg, NewDestBB);
+ RS->setRegUsed(Reg);
+ return;
+ }
+
+ // Otherwise, spill and use X16. This briefly moves the stack pointer, making
+ // it incompatible with red zones.
+ AArch64FunctionInfo *AFI = MBB.getParent()->getInfo<AArch64FunctionInfo>();
+ if (!AFI || AFI->hasRedZone().value_or(true))
+ report_fatal_error(
+ "Unable to insert indirect branch inside function that has red zone");
+
+ Reg = AArch64::X16;
+ BuildMI(MBB, MBB.end(), DL, get(AArch64::STRXpre))
+ .addReg(AArch64::SP, RegState::Define)
+ .addReg(Reg)
+ .addReg(AArch64::SP)
+ .addImm(-16);
+
+ buildIndirectBranch(Reg, RestoreBB);
+
+ BuildMI(RestoreBB, RestoreBB.end(), DL, get(AArch64::LDRXpost))
+ .addReg(AArch64::SP, RegState::Define)
+ .addReg(Reg, RegState::Define)
+ .addReg(AArch64::SP)
+ .addImm(16);
+}
+
// Branch analysis.
bool AArch64InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index 4d964e79096ea2..fe59d8f72f0b05 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -213,6 +213,11 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
+ void insertIndirectBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock &NewDestBB,
+ MachineBasicBlock &RestoreBB, const DebugLoc &DL,
+ int64_t BrOffset, RegScavenger *RS) const override;
+
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp
index bc465168f1dbaf..4ee7328dc2ed55 100644
--- a/llvm/lib/Target/TargetMachine.cpp
+++ b/llvm/lib/Target/TargetMachine.cpp
@@ -78,6 +78,19 @@ void TargetMachine::resetTargetOptions(const Function &F) const {
/// and dynamic-no-pic.
Reloc::Model TargetMachine::getRelocationModel() const { return RM; }
+uint64_t TargetMachine::getMaxCodeSize() const {
+ switch (getCodeModel()) {
+ case CodeModel::Tiny:
+ return llvm::maxUIntN(10);
+ case CodeModel::Small:
+ case CodeModel::Kernel:
+ case CodeModel::Medium:
+ return llvm::maxUIntN(31);
+ case CodeModel::Large:
+ return llvm::maxUIntN(64);
+ }
+}
+
/// Get the IR-specified TLS model for Var.
static TLSModel::Model getSelectedTLSModel(const GlobalValue *GV) {
switch (GV->getThreadLocalMode()) {
diff --git a/llvm/test/CodeGen/AArch64/branch-relax-b.ll b/llvm/test/CodeGen/AArch64/branch-relax-b.ll
new file mode 100644
index 00000000000000..cbf0152d811d56
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/branch-relax-b.ll
@@ -0,0 +1,139 @@
+; RUN: llc < %s -mtriple=aarch64-none-linux-gnu --verify-machineinstrs -aarch64-b-offset-bits=9 -aarch64-tbz-offset-bits=6 -aarch64-cbz-offset-bits=6 -aarch64-bcc-offset-bits=6 | FileCheck %s
+
+define void @relax_b_nospill(i1 zeroext %0) {
+; CHECK-LABEL: relax_b_nospill:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: tbnz w0,
+; CHECK-SAME: LBB0_1
+; CHECK-NEXT: // %bb.3: // %entry
+; CHECK-NEXT: adrp [[SCAVENGED_REGISTER:x[0-9]+]], .LBB0_2
+; CHECK-NEXT: add [[SCAVENGED_REGISTER]], [[SCAVENGED_REGISTER]], :lo12:.LBB0_2
+; CHECK-NEXT: br [[SCAVENGED_REGISTER]]
+; CHECK-NEXT: .LBB0_1: // %iftrue
+; CHECK-NEXT: //APP
+; CHECK-NEXT: .zero 2048
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB0_2: // %iffalse
+; CHECK-NEXT: //APP
+; CHECK-NEXT: .zero 8
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: ret
+entry:
+ br i1 %0, label %iftrue, label %iffalse
+
+iftrue:
+ call void asm sideeffect ".space 2048", ""()
+ ret void
+
+iffalse:
+ call void asm sideeffect ".space 8", ""()
+ ret void
+}
+
+define void @relax_b_spill() {
+; CHECK-LABEL: relax_b_spill: // @relax_b_spill
+; CHECK: // %bb.0: // %entry
+; CHECK-COUNT-5: // 16-byte Folded Spill
+; CHECK-NOT: // 16-byte Folded Spill
+; CHECK: //APP
+; CHECK-COUNT-29: mov {{x[0-9]+}},
+; CHECK-NOT: mov {{x[0-9]+}},
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: b.eq .LBB1_1
+; CHECK-NEXT: // %bb.4: // %entry
+; CHECK-NEXT: str [[SPILL_REGISTER:x[0-9]+]], [sp,
+; CHECK-SAME: -16]!
+; CHECK-NEXT: adrp [[SPILL_REGISTER:x[0-9]+]], .LBB1_5
+; CHECK-NEXT: add [[SPILL_REGISTER:x[0-9]+]], [[SPILL_REGISTER:x[0-9]+]], :lo12:.LBB1_5
+; CHECK-NEXT: br [[SPILL_REGISTER:x[0-9]+]]
+; CHECK-NEXT: .LBB1_1: // %iftrue
+; CHECK-NEXT: //APP
+; CHECK-NEXT: .zero 2048
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: b .LBB1_3
+; CHECK-NEXT: .LBB1_5: // %iffalse
+; CHECK-NEXT: ldr [[SPILL_REGISTER:x[0-9]+]], [sp],
+; CHECK-SAME: 16
+; CHECK-NEXT: // %bb.2: // %iffalse
+; CHECK-NEXT: //APP
+; CHECK-COUNT-29: // reg use {{x[0-9]+}}
+; CHECK-NOT: // reg use {{x[0-9]+}}
+; CHECK-NEXT: //NO_APP
+; CHECK-NEXT: .LBB1_3: // %common.ret
+; CHECK-COUNT-5: // 16-byte Folded Reload
+; CHECK-NOT: // 16-byte Folded Reload
+; CHECK-NEXT: ret
+entry:
+ %x0 = call i64 asm sideeffect "mov x0, 1", "={x0}"()
+ %x1 = call i64 asm sideeffect "mov x1, 1", "={x1}"()
+ %x2 = call i64 asm sideeffect "mov x2, 1", "={x2}"()
+ %x3 = call i64 asm sideeffect "mov x3, 1", "={x3}"()
+ %x4 = call i64 asm sideeffect "mov x4, 1", "={x4}"()
+ %x5 = call i64 asm sideeffect "mov x5, 1", "={x5}"()
+ %x6 = call i64 asm sideeffect "mov x6, 1", "={x6}"()
+ %x7 = call i64 asm sideeffect "mov x7, 1", "={x7}"()
+ %x8 = call i64 asm sideeffect "mov x8, 1", "={x8}"()
+ %x9 = call i64 asm sideeffect "mov x9, 1", "={x9}"()
+ %x10 = call i64 asm sideeffect "mov x10, 1", "={x10}"()
+ %x11 = call i64 asm sideeffect "mov x11, 1", "={x11}"()
+ %x12 = call i64 asm sideeffect "mov x12, 1", "={x12}"()
+ %x13 = call i64 asm sideeffect "mov x13, 1", "={x13}"()
+ %x14 = call i64 asm sideeffect "mov x14, 1", "={x14}"()
+ %x15 = call i64 asm sideeffect "mov x15, 1", "={x15}"()
+ %x16 = call i64 asm sideeffect "mov x16, 1", "={x16}"()
+ %x17 = call i64 asm sideeffect "mov x17, 1", "={x17}"()
+ %x18 = call i64 asm sideeffect "mov x18, 1", "={x18}"()
+ %x19 = call i64 asm sideeffect "mov x19, 1", "={x19}"()
+ %x20 = call i64 asm sideeffect "mov x20, 1", "={x20}"()
+ %x21 = call i64 asm sideeffect "mov x21, 1", "={x21}"()
+ %x22 = call i64 asm sideeffect "mov x22, 1", "={x22}"()
+ %x23 = call i64 asm sideeffect "mov x23, 1", "={x23}"()
+ %x24 = call i64 asm sideeffect "mov x24, 1", "={x24}"()
+ %x25 = call i64 asm sideeffect "mov x25, 1", "={x25}"()
+ %x26 = call i64 asm sideeffect "mov x26, 1", "={x26}"()
+ %x27 = call i64 asm sideeffect "mov x27, 1", "={x27}"()
+ %x28 = call i64 asm sideeffect "mov x28, 1", "={x28}"()
+
+ %cmp = icmp eq i64 %x16, %x15
+ br i1 %cmp, label %iftrue, label %iffalse
+
+iftrue:
+ call void asm sideeffect ".space 2048", ""()
+ ret void
+
+iffalse:
+ call void asm sideeffect "# reg use $0", "{x0}"(i64 %x0)
+ call void asm sideeffect "# reg use $0", "{x1}"(i64 %x1)
+ call void asm sideeffect "# reg use $0", "{x2}"(i64 %x2)
+ call void asm sideeffect "# reg use $0", "{x3}"(i64 %x3)
+ call void asm sideeffect "# reg use $0", "{x4}"(i64 %x4)
+ call void asm sideeffect "# reg use $0", "{x5}"(i64 %x5)
+ call void asm sideeffect "# reg use $0", "{x6}"(i64 %x6)
+ call void asm sideeffect "# reg use $0", "{x7}"(i64 %x7)
+ call void asm sideeffect "# reg use $0", "{x8}"(i64 %x8)
+ call void asm sideeffect "# reg use $0", "{x9}"(i64 %x9)
+ call void asm sideeffect "# reg use $0", "{x10}"(i64 %x10)
+ call void asm sideeffect "# reg use $0", "{x11}"(i64 %x11)
+ call void asm sideeffect "# reg use $0", "{x12}"(i64 %x12)
+ call void asm sideeffect "# reg use $0", "{x13}"(i64 %x13)
+ call void asm sideeffect "# reg use $0", "{x14}"(i64 %x14)
+ call void asm sideeffect "# reg use $0", "{x15}"(i64 %x15)
+ call void asm sideeffect "# reg use $0", "{x16}"(i64 %x16)
+ call void asm sideeffect "# reg use $0", "{x17}"(i64 %x17)
+ call void asm sideeffect "# reg use $0", "{x18}"(i64 %x18)
+ call void asm sideeffect "# reg use $0", "{x19}"(i64 %x19)
+ call void asm sideeffect "# reg use $0", "{x20}"(i64 %x20)
+ call void asm sideeffect "# reg use $0", "{x21}"(i64 %x21)
+ call void asm sideeffect "# reg use $0", "{x22}"(i64 %x22)
+ call void asm sideeffect "# reg use $0", "{x23}"(i64 %x23)
+ call void asm sideeffect "# reg use $0", "{x24}"(i64 %x24)
+ call void asm sideeffect "# reg use $0", "{x25}"(i64 %x25)
+ call void asm sideeffect "# reg use $0", "{x26}"(i64 %x26)
+ call void asm sideeffect "# reg use $0", "{x27}"(i64 %x27)
+ call void asm sideeffect "# reg use $0", "{x28}"(i64 %x28)
+ ret void
+}
+
+declare i32 @bar()
+declare i32 @baz()
\ No newline at end of file
diff --git a/llvm/test/CodeGen/AArch64/branch-relax-cross-section.mir b/llvm/test/CodeGen/AArch64/branch-relax-cross-section.mir
new file mode 100644
index 00000000000000..1cf307cd16ecff
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/branch-relax-cross-section.mir
@@ -0,0 +1,71 @@
+# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass branch-relaxation -aarch64-b-offset-bits=64 %s -o - | FileCheck %s
+
+--- |
+ declare i32 @bar()
+ declare i32 @baz()
+ declare i32 @qux()
+
+ define void @relax_tbz(i1 zeroext %0) {
+ br i1 %0, label %false_block, label %true_block
+
+ false_block: ; preds = %1
+ %2 = call i32 @baz()
+ br label %end
+
+ end: ; preds = %true_block, %false_block
+ %3 = tail call i32 @qux()
+ ret void
+
+ true_block: ; preds = %1
+ %4 = call i32 @bar()
+ br label %end
+ }
+
+...
+---
+name: relax_tbz
+tracksRegLiveness: true
+liveins:
+ - { reg: '$w0', virtual-reg: '' }
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
+ stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ ; CHECK-LABEL: name: relax_tbz
+ ; COM: Check that cross-section conditional branches are
+ ; COM: relaxed.
+ ; CHECK: bb.0 (%ir-block.1, bbsections 1):
+ ; CHECK-NEXT: successors: %bb.3(0x40000000)
+ ; CHECK: TBNZW
+ ; CHECK-SAME: %bb.3
+ ; CHECK: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3 (%ir-block.1, bbsections 1):
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: B %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1.false_block (bbsections 2):
+ ; CHECK: TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2.true_block (bbsections 3):
+ ; CHECK: TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
+ bb.0 (%ir-block.1, bbsections 1):
+ successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ liveins: $w0, $lr
+
+ early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
+ TBZW killed renamable $w0, 0, %bb.2
+ B %bb.1
+
+ bb.1.false_block (bbsections 2):
+ BL @baz, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
+ early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+ TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
+
+ bb.2.true_block (bbsections 3):
+ BL @bar, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $w0
+ early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
+ TCRETURNdi @qux, 0, csr_aarch64_aapcs, implicit $sp
+...
More information about the llvm-commits
mailing list