Skip to content

Commit c1dc267

Browse files
committed
MachineBasicBlock: add liveout iterator aware of which liveins are defined by the runtime.
Using this in RegAlloc fast reduces register pressure, and in some cases allows x86 code to compile that wouldn't before.
1 parent 4f86aa6 commit c1dc267

File tree

6 files changed

+167
-6
lines changed

6 files changed

+167
-6
lines changed

llvm/include/llvm/CodeGen/MachineBasicBlock.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,97 @@ class MachineBasicBlock
416416
/// Remove entry from the livein set and return iterator to the next.
417417
livein_iterator removeLiveIn(livein_iterator I);
418418

419+
class liveout_iterator {
420+
public:
421+
using iterator_category = std::input_iterator_tag;
422+
using difference_type = std::ptrdiff_t;
423+
using value_type = RegisterMaskPair;
424+
using pointer = const RegisterMaskPair *;
425+
using reference = const RegisterMaskPair &;
426+
427+
liveout_iterator(const MachineBasicBlock &MBB, MCPhysReg ExceptionPointer,
428+
MCPhysReg ExceptionSelector, bool End)
429+
: ExceptionPointer(ExceptionPointer),
430+
ExceptionSelector(ExceptionSelector), BlockI(MBB.succ_begin()),
431+
BlockEnd(MBB.succ_end()) {
432+
if (End)
433+
BlockI = BlockEnd;
434+
else if (BlockI != BlockEnd) {
435+
LiveRegI = (*BlockI)->livein_begin();
436+
if (!advanceToValidPosition())
437+
return;
438+
if (LiveRegI->PhysReg == ExceptionPointer ||
439+
LiveRegI->PhysReg == ExceptionSelector)
440+
++(*this);
441+
}
442+
}
443+
444+
liveout_iterator &operator++() {
445+
do {
446+
++LiveRegI;
447+
if (!advanceToValidPosition())
448+
return *this;
449+
} while ((*BlockI)->isEHPad() &&
450+
(LiveRegI->PhysReg == ExceptionPointer ||
451+
LiveRegI->PhysReg == ExceptionSelector));
452+
return *this;
453+
}
454+
455+
liveout_iterator operator++(int) {
456+
liveout_iterator Tmp = *this;
457+
++(*this);
458+
return Tmp;
459+
}
460+
461+
reference operator*() const {
462+
return *LiveRegI;
463+
}
464+
465+
pointer operator->() const {
466+
return &*LiveRegI;
467+
}
468+
469+
bool operator==(const liveout_iterator &RHS) const {
470+
if (BlockI != BlockEnd)
471+
return BlockI == RHS.BlockI && LiveRegI == RHS.LiveRegI;
472+
return RHS.BlockI == BlockEnd;
473+
}
474+
475+
bool operator!=(const liveout_iterator &RHS) const {
476+
return !(*this == RHS);
477+
}
478+
private:
479+
bool advanceToValidPosition() {
480+
if (LiveRegI != (*BlockI)->livein_end())
481+
return true;
482+
483+
do {
484+
++BlockI;
485+
} while (BlockI != BlockEnd && (*BlockI)->livein_empty());
486+
if (BlockI == BlockEnd)
487+
return false;
488+
489+
LiveRegI = (*BlockI)->livein_begin();
490+
return true;
491+
}
492+
493+
MCPhysReg ExceptionPointer, ExceptionSelector;
494+
const_succ_iterator BlockI;
495+
const_succ_iterator BlockEnd;
496+
livein_iterator LiveRegI;
497+
};
498+
499+
/// Iterator scanning successor basic blocks' liveins to determine the
500+
/// registers potentially live at the end of this block. There may be
501+
/// duplicates or overlapping registers in the list returned.
502+
liveout_iterator liveout_begin() const;
503+
liveout_iterator liveout_end() const {
504+
return liveout_iterator(*this, 0, 0, true);
505+
}
506+
iterator_range<liveout_iterator> liveouts() const {
507+
return make_range(liveout_begin(), liveout_end());
508+
}
509+
419510
/// Get the clobber mask for the start of this basic block. Funclets use this
420511
/// to prevent register allocation across funclet transitions.
421512
const uint32_t *getBeginClobberMask(const TargetRegisterInfo *TRI) const;

llvm/lib/CodeGen/MachineBasicBlock.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/CodeGen/MachineRegisterInfo.h"
2222
#include "llvm/CodeGen/SlotIndexes.h"
2323
#include "llvm/CodeGen/TargetInstrInfo.h"
24+
#include "llvm/CodeGen/TargetLowering.h"
2425
#include "llvm/CodeGen/TargetRegisterInfo.h"
2526
#include "llvm/CodeGen/TargetSubtargetInfo.h"
2627
#include "llvm/Config/llvm-config.h"
@@ -1629,6 +1630,23 @@ MachineBasicBlock::livein_iterator MachineBasicBlock::livein_begin() const {
16291630
return LiveIns.begin();
16301631
}
16311632

1633+
MachineBasicBlock::liveout_iterator MachineBasicBlock::liveout_begin() const {
1634+
const MachineFunction &MF = *getParent();
1635+
assert(MF.getProperties().hasProperty(
1636+
MachineFunctionProperties::Property::TracksLiveness) &&
1637+
"Liveness information is accurate");
1638+
1639+
const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
1640+
MCPhysReg ExceptionPointer = 0, ExceptionSelector = 0;
1641+
if (MF.getFunction().hasPersonalityFn()) {
1642+
auto PersonalityFn = MF.getFunction().getPersonalityFn();
1643+
ExceptionPointer = TLI.getExceptionPointerRegister(PersonalityFn);
1644+
ExceptionSelector = TLI.getExceptionSelectorRegister(PersonalityFn);
1645+
}
1646+
1647+
return liveout_iterator(*this, ExceptionPointer, ExceptionSelector, false);
1648+
}
1649+
16321650
const MBBSectionID MBBSectionID::ColdSectionID(MBBSectionID::SectionType::Cold);
16331651
const MBBSectionID
16341652
MBBSectionID::ExceptionSectionID(MBBSectionID::SectionType::Exception);

llvm/lib/CodeGen/RegAllocFast.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,10 +1452,8 @@ void RegAllocFast::allocateBasicBlock(MachineBasicBlock &MBB) {
14521452
RegUnitStates.assign(TRI->getNumRegUnits(), regFree);
14531453
assert(LiveVirtRegs.empty() && "Mapping not cleared from last block?");
14541454

1455-
for (MachineBasicBlock *Succ : MBB.successors()) {
1456-
for (const MachineBasicBlock::RegisterMaskPair &LI : Succ->liveins())
1457-
setPhysRegState(LI.PhysReg, regPreAssigned);
1458-
}
1455+
for (auto &LiveReg : MBB.liveouts())
1456+
setPhysRegState(LiveReg.PhysReg, regPreAssigned);
14591457

14601458
Coalesced.clear();
14611459

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26700,7 +26700,8 @@ Register X86TargetLowering::getExceptionPointerRegister(
2670026700
Register X86TargetLowering::getExceptionSelectorRegister(
2670126701
const Constant *PersonalityFn) const {
2670226702
// Funclet personalities don't use selectors (the runtime does the selection).
26703-
assert(!isFuncletEHPersonality(classifyEHPersonality(PersonalityFn)));
26703+
if (isFuncletEHPersonality(classifyEHPersonality(PersonalityFn)))
26704+
return X86::NoRegister;
2670426705
return Subtarget.isTarget64BitLP64() ? X86::RDX : X86::EDX;
2670526706
}
2670626707

llvm/test/CodeGen/X86/fast-isel-cmp-branch.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ exit:
1919
; different basic block, so its operands aren't necessarily exported
2020
; for cross-block usage.
2121

22-
; CHECK: movb %cl, [[OFS:[0-9]*]](%rsp)
22+
; CHECK: movb %al, [[OFS:[0-9]*]](%rsp)
2323
; CHECK: callq {{_?}}bar
2424
; CHECK: movb [[OFS]](%rsp), %al
2525

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o - | FileCheck %s
2+
declare void @foo(i32, ...)
3+
4+
declare i32 @__gxx_personality_v0(...)
5+
6+
; We were running out of registers for this invoke, because:
7+
8+
; 1. The lshr/and pattern gets matched to a no-REX MOV so that ah/bh/... can
9+
; be used instead, cutting available registers for %b.arg down to eax, ebx,
10+
; ecx, edx, esi, edi.
11+
; 2. We have a base pointer taking ebx out of contention.
12+
; 3. The landingpad block convinced us we should be defining rax here.
13+
; 3. The al fiddling for the varargs call only noted down that al was spillable,
14+
; not ah or hax.
15+
;
16+
; So by the time we need to allocate a register for the call all registers are
17+
; tied up and unspillable.
18+
19+
; CHECK-LABEL: bar:
20+
; CHECK: xorl %edi, %edi
21+
; CHECK: movb %dil, {{[0-9]+}}(%rbx)
22+
; CHECK: movb {{[0-9]+}}(%rbx), %al
23+
24+
define i32 @bar(i32 %a, i32 %b, i32 %c, i32 %d, ...) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
25+
%mem = alloca i32, i32 %a, align 32 ; Force rbx to be used as a base pointer
26+
%b.tmp = lshr i32 %b, 8
27+
%b.arg = and i32 %b.tmp, 255
28+
invoke void(i32, ...) @foo(i32 42, i32* %mem, i32 %c, i32 %d, i32 %b.arg) to label %success unwind label %fail
29+
30+
success:
31+
ret i32 0
32+
fail:
33+
%exc = landingpad { i8*, i32 } cleanup
34+
%res = extractvalue { i8*, i32 } %exc, 1
35+
ret i32 %res
36+
}
37+
38+
; CHECK-LABEL: live:
39+
; CHECK: movl {{%.*}}, %eax
40+
41+
define i32 @live(i32 %a, i32 %b, i32 %c, i32 %d, ...) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
42+
%mem = alloca i32, i32 %a, align 32 ; Force rbx to be used as a base pointer
43+
%b.tmp = lshr i32 %b, 8
44+
%b.arg = and i32 %b.tmp, 255
45+
invoke void(i32, ...) @foo(i32 42) to label %success unwind label %fail
46+
47+
success:
48+
ret i32 0
49+
fail:
50+
%exc = landingpad { i8*, i32 } cleanup
51+
%res = extractvalue { i8*, i32 } %exc, 1
52+
ret i32 %b.arg
53+
}

0 commit comments

Comments
 (0)