Skip to content

Commit f26360f

Browse files
authored
[IR] Don't store switch case values as operands (#166842)
SwitchInst case values must be ConstantInt, which have no use list. Therefore it is not necessary to store these as Use, instead store them more efficiently as a simple array of pointers after the uses, similar to how PHINode stores basic blocks. After this change, the successors of all terminators are stored consecutively in the operand list. This is preparatory work for improving the performance of successor access.
1 parent 80760b0 commit f26360f

File tree

13 files changed

+141
-55
lines changed

13 files changed

+141
-55
lines changed

llvm/docs/ReleaseNotes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Changes to the LLVM IR
7474
format string function implementations from statically-linked libc's based on
7575
the requirements of each call. Currently only `float` is supported; this can
7676
keep floating point support out of printf if it can be proven unused.
77+
* Case values are no longer operands of `SwitchInst`.
7778

7879
Changes to LLVM infrastructure
7980
------------------------------
@@ -178,6 +179,7 @@ Changes to the C API
178179
* Add `LLVMGetOrInsertFunction` to get or insert a function, replacing the combination of `LLVMGetNamedFunction` and `LLVMAddFunction`.
179180
* Allow `LLVMGetVolatile` to work with any kind of Instruction.
180181
* Add `LLVMConstFPFromBits` to get a constant floating-point value from an array of 64 bit values.
182+
* Add `LLVMGetSwitchCaseValue` and `LLVMSetSwitchCaseValue` to get and set switch case values; switch case values are no longer operands of the instruction.
181183

182184
Changes to the CodeGen infrastructure
183185
-------------------------------------

llvm/include/llvm-c/Core.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4213,6 +4213,30 @@ LLVM_C_ABI void LLVMSetCondition(LLVMValueRef Branch, LLVMValueRef Cond);
42134213
*/
42144214
LLVM_C_ABI LLVMBasicBlockRef LLVMGetSwitchDefaultDest(LLVMValueRef SwitchInstr);
42154215

4216+
/**
4217+
* Obtain the case value for a successor of a switch instruction. i corresponds
4218+
* to the successor index. The first successor is the default destination, so i
4219+
* must be greater than zero.
4220+
*
4221+
* This only works on llvm::SwitchInst instructions.
4222+
*
4223+
* @see llvm::SwitchInst::CaseHandle::getCaseValue()
4224+
*/
4225+
LLVM_C_ABI LLVMValueRef LLVMGetSwitchCaseValue(LLVMValueRef SwitchInstr,
4226+
unsigned i);
4227+
4228+
/**
4229+
* Set the case value for a successor of a switch instruction. i corresponds to
4230+
* the successor index. The first successor is the default destination, so i
4231+
* must be greater than zero.
4232+
*
4233+
* This only works on llvm::SwitchInst instructions.
4234+
*
4235+
* @see llvm::SwitchInst::CaseHandle::setValue()
4236+
*/
4237+
LLVM_C_ABI void LLVMSetSwitchCaseValue(LLVMValueRef SwitchInstr, unsigned i,
4238+
LLVMValueRef CaseValue);
4239+
42164240
/**
42174241
* @}
42184242
*/

llvm/include/llvm/IR/Instructions.h

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,7 +2665,7 @@ class PHINode : public Instruction {
26652665
// User::allocHungoffUses, because we have to allocate Uses for the incoming
26662666
// values and pointers to the incoming blocks, all in one allocation.
26672667
void allocHungoffUses(unsigned N) {
2668-
User::allocHungoffUses(N, /* IsPhi */ true);
2668+
User::allocHungoffUses(N, /*WithExtraValues=*/true);
26692669
}
26702670

26712671
public:
@@ -3198,10 +3198,10 @@ class SwitchInst : public Instruction {
31983198

31993199
unsigned ReservedSpace;
32003200

3201-
// Operand[0] = Value to switch on
3202-
// Operand[1] = Default basic block destination
3203-
// Operand[2n ] = Value to match
3204-
// Operand[2n+1] = BasicBlock to go to on match
3201+
// Operand[0] = Value to switch on
3202+
// Operand[1] = Default basic block destination
3203+
// Operand[n] = BasicBlock to go to on match
3204+
// Values are stored after the Uses similar to PHINode's basic blocks.
32053205
SwitchInst(const SwitchInst &SI);
32063206

32073207
/// Create a new switch instruction, specifying a value to switch on and a
@@ -3223,6 +3223,17 @@ class SwitchInst : public Instruction {
32233223

32243224
LLVM_ABI SwitchInst *cloneImpl() const;
32253225

3226+
void allocHungoffUses(unsigned N) {
3227+
User::allocHungoffUses(N, /*WithExtraValues=*/true);
3228+
}
3229+
3230+
ConstantInt *const *case_values() const {
3231+
return reinterpret_cast<ConstantInt *const *>(op_begin() + ReservedSpace);
3232+
}
3233+
ConstantInt **case_values() {
3234+
return reinterpret_cast<ConstantInt **>(op_begin() + ReservedSpace);
3235+
}
3236+
32263237
public:
32273238
void operator delete(void *Ptr) { User::operator delete(Ptr); }
32283239

@@ -3257,7 +3268,7 @@ class SwitchInst : public Instruction {
32573268
ConstantIntT *getCaseValue() const {
32583269
assert((unsigned)Index < SI->getNumCases() &&
32593270
"Index out the number of cases.");
3260-
return reinterpret_cast<ConstantIntT *>(SI->getOperand(2 + Index * 2));
3271+
return SI->case_values()[Index];
32613272
}
32623273

32633274
/// Resolves successor for current case.
@@ -3299,7 +3310,7 @@ class SwitchInst : public Instruction {
32993310
void setValue(ConstantInt *V) const {
33003311
assert((unsigned)Index < SI->getNumCases() &&
33013312
"Index out the number of cases.");
3302-
SI->setOperand(2 + Index*2, reinterpret_cast<Value*>(V));
3313+
SI->case_values()[Index] = V;
33033314
}
33043315

33053316
/// Sets the new successor for current case.
@@ -3406,9 +3417,7 @@ class SwitchInst : public Instruction {
34063417

34073418
/// Return the number of 'cases' in this switch instruction, excluding the
34083419
/// default case.
3409-
unsigned getNumCases() const {
3410-
return getNumOperands()/2 - 1;
3411-
}
3420+
unsigned getNumCases() const { return getNumOperands() - 2; }
34123421

34133422
/// Returns a read/write iterator that points to the first case in the
34143423
/// SwitchInst.
@@ -3510,14 +3519,14 @@ class SwitchInst : public Instruction {
35103519
/// case.
35113520
LLVM_ABI CaseIt removeCase(CaseIt I);
35123521

3513-
unsigned getNumSuccessors() const { return getNumOperands()/2; }
3522+
unsigned getNumSuccessors() const { return getNumOperands() - 1; }
35143523
BasicBlock *getSuccessor(unsigned idx) const {
35153524
assert(idx < getNumSuccessors() &&"Successor idx out of range for switch!");
3516-
return cast<BasicBlock>(getOperand(idx*2+1));
3525+
return cast<BasicBlock>(getOperand(idx + 1));
35173526
}
35183527
void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
35193528
assert(idx < getNumSuccessors() && "Successor # out of range for switch!");
3520-
setOperand(idx * 2 + 1, NewSucc);
3529+
setOperand(idx + 1, NewSucc);
35213530
}
35223531

35233532
// Methods for support type inquiry through isa, cast, and dyn_cast:

llvm/include/llvm/IR/User.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ class User : public Value {
132132

133133
/// Allocate the array of Uses, followed by a pointer
134134
/// (with bottom bit set) to the User.
135-
/// \param IsPhi identifies callers which are phi nodes and which need
136-
/// N BasicBlock* allocated along with N
137-
LLVM_ABI void allocHungoffUses(unsigned N, bool IsPhi = false);
135+
/// \param WithExtraValues identifies callers which need N Value* allocated
136+
/// along the N operands.
137+
LLVM_ABI void allocHungoffUses(unsigned N, bool WithExtraValues = false);
138138

139139
/// Grow the number of hung off uses. Note that allocHungoffUses
140140
/// should be called if there are no uses.
141-
LLVM_ABI void growHungoffUses(unsigned N, bool IsPhi = false);
141+
LLVM_ABI void growHungoffUses(unsigned N, bool WithExtraValues = false);
142142

143143
protected:
144144
~User() = default; // Use deleteValue() to delete a generic Instruction.

llvm/lib/Bitcode/Writer/ValueEnumerator.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ static OrderMap orderModule(const Module &M) {
164164
orderConstantValue(Op);
165165
if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I))
166166
orderValue(SVI->getShuffleMaskForBitcode(), OM);
167+
if (auto *SI = dyn_cast<SwitchInst>(&I)) {
168+
for (const auto &Case : SI->cases())
169+
orderValue(Case.getCaseValue(), OM);
170+
}
167171
orderValue(&I, OM);
168172
}
169173
}
@@ -1092,6 +1096,10 @@ void ValueEnumerator::incorporateFunction(const Function &F) {
10921096
}
10931097
if (auto *SVI = dyn_cast<ShuffleVectorInst>(&I))
10941098
EnumerateValue(SVI->getShuffleMaskForBitcode());
1099+
if (auto *SI = dyn_cast<SwitchInst>(&I)) {
1100+
for (const auto &Case : SI->cases())
1101+
EnumerateValue(Case.getCaseValue());
1102+
}
10951103
}
10961104
BasicBlocks.push_back(&BB);
10971105
ValueMap[&BB] = BasicBlocks.size();

llvm/lib/CodeGen/TypePromotion.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,14 @@ void IRPromoter::PromoteTree() {
512512
I->setOperand(i, ConstantInt::get(ExtTy, 0));
513513
}
514514

515+
// For switch, also mutate case values, which are not operands.
516+
if (auto *SI = dyn_cast<SwitchInst>(I)) {
517+
for (auto Case : SI->cases()) {
518+
APInt NewConst = Case.getCaseValue()->getValue().zext(PromotedWidth);
519+
Case.setValue(ConstantInt::get(SI->getContext(), NewConst));
520+
}
521+
}
522+
515523
// Mutate the result type, unless this is an icmp or switch.
516524
if (!isa<ICmpInst>(I) && !isa<SwitchInst>(I)) {
517525
I->mutateType(ExtTy);

llvm/lib/IR/Core.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3257,6 +3257,19 @@ LLVMBasicBlockRef LLVMGetSwitchDefaultDest(LLVMValueRef Switch) {
32573257
return wrap(unwrap<SwitchInst>(Switch)->getDefaultDest());
32583258
}
32593259

3260+
LLVMValueRef LLVMGetSwitchCaseValue(LLVMValueRef Switch, unsigned i) {
3261+
assert(i > 0 && i <= unwrap<SwitchInst>(Switch)->getNumCases());
3262+
auto It = unwrap<SwitchInst>(Switch)->case_begin() + (i - 1);
3263+
return wrap(It->getCaseValue());
3264+
}
3265+
3266+
void LLVMSetSwitchCaseValue(LLVMValueRef Switch, unsigned i,
3267+
LLVMValueRef CaseValue) {
3268+
assert(i > 0 && i <= unwrap<SwitchInst>(Switch)->getNumCases());
3269+
auto It = unwrap<SwitchInst>(Switch)->case_begin() + (i - 1);
3270+
It->setValue(unwrap<ConstantInt>(CaseValue));
3271+
}
3272+
32603273
/*--.. Operations on alloca instructions (only) ............................--*/
32613274

32623275
LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca) {

llvm/lib/IR/Instructions.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ void PHINode::growOperands() {
202202
if (NumOps < 2) NumOps = 2; // 2 op PHI nodes are VERY common.
203203

204204
ReservedSpace = NumOps;
205-
growHungoffUses(ReservedSpace, /* IsPhi */ true);
205+
growHungoffUses(ReservedSpace, /*WithExtraValues=*/true);
206206
}
207207

208208
/// hasConstantValue - If the specified PHI node always merges together the same
@@ -4076,18 +4076,20 @@ SwitchInst::SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases,
40764076
InsertPosition InsertBefore)
40774077
: Instruction(Type::getVoidTy(Value->getContext()), Instruction::Switch,
40784078
AllocMarker, InsertBefore) {
4079-
init(Value, Default, 2+NumCases*2);
4079+
init(Value, Default, 2 + NumCases);
40804080
}
40814081

40824082
SwitchInst::SwitchInst(const SwitchInst &SI)
40834083
: Instruction(SI.getType(), Instruction::Switch, AllocMarker) {
40844084
init(SI.getCondition(), SI.getDefaultDest(), SI.getNumOperands());
40854085
setNumHungOffUseOperands(SI.getNumOperands());
40864086
Use *OL = getOperandList();
4087+
ConstantInt **VL = case_values();
40874088
const Use *InOL = SI.getOperandList();
4088-
for (unsigned i = 2, E = SI.getNumOperands(); i != E; i += 2) {
4089+
ConstantInt *const *InVL = SI.case_values();
4090+
for (unsigned i = 2, E = SI.getNumOperands(); i != E; ++i) {
40894091
OL[i] = InOL[i];
4090-
OL[i+1] = InOL[i+1];
4092+
VL[i - 2] = InVL[i - 2];
40914093
}
40924094
SubclassOptionalData = SI.SubclassOptionalData;
40934095
}
@@ -4097,11 +4099,11 @@ SwitchInst::SwitchInst(const SwitchInst &SI)
40974099
void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) {
40984100
unsigned NewCaseIdx = getNumCases();
40994101
unsigned OpNo = getNumOperands();
4100-
if (OpNo+2 > ReservedSpace)
4102+
if (OpNo + 1 > ReservedSpace)
41014103
growOperands(); // Get more space!
41024104
// Initialize some new operands.
4103-
assert(OpNo+1 < ReservedSpace && "Growing didn't work!");
4104-
setNumHungOffUseOperands(OpNo+2);
4105+
assert(OpNo < ReservedSpace && "Growing didn't work!");
4106+
setNumHungOffUseOperands(OpNo + 1);
41054107
CaseHandle Case(this, NewCaseIdx);
41064108
Case.setValue(OnVal);
41074109
Case.setSuccessor(Dest);
@@ -4112,21 +4114,22 @@ void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) {
41124114
SwitchInst::CaseIt SwitchInst::removeCase(CaseIt I) {
41134115
unsigned idx = I->getCaseIndex();
41144116

4115-
assert(2 + idx*2 < getNumOperands() && "Case index out of range!!!");
4117+
assert(2 + idx < getNumOperands() && "Case index out of range!!!");
41164118

41174119
unsigned NumOps = getNumOperands();
41184120
Use *OL = getOperandList();
4121+
ConstantInt **VL = case_values();
41194122

41204123
// Overwrite this case with the end of the list.
4121-
if (2 + (idx + 1) * 2 != NumOps) {
4122-
OL[2 + idx * 2] = OL[NumOps - 2];
4123-
OL[2 + idx * 2 + 1] = OL[NumOps - 1];
4124+
if (2 + idx + 1 != NumOps) {
4125+
OL[2 + idx] = OL[NumOps - 1];
4126+
VL[idx] = VL[NumOps - 2 - 1];
41244127
}
41254128

41264129
// Nuke the last value.
4127-
OL[NumOps-2].set(nullptr);
4128-
OL[NumOps-2+1].set(nullptr);
4129-
setNumHungOffUseOperands(NumOps-2);
4130+
OL[NumOps - 1].set(nullptr);
4131+
VL[NumOps - 2 - 1] = nullptr;
4132+
setNumHungOffUseOperands(NumOps - 1);
41304133

41314134
return CaseIt(this, idx);
41324135
}
@@ -4139,7 +4142,7 @@ void SwitchInst::growOperands() {
41394142
unsigned NumOps = e*3;
41404143

41414144
ReservedSpace = NumOps;
4142-
growHungoffUses(ReservedSpace);
4145+
growHungoffUses(ReservedSpace, /*WithExtraValues=*/true);
41434146
}
41444147

41454148
void SwitchInstProfUpdateWrapper::init() {

llvm/lib/IR/User.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,24 @@ bool User::replaceUsesOfWith(Value *From, Value *To) {
5050
// User allocHungoffUses Implementation
5151
//===----------------------------------------------------------------------===//
5252

53-
void User::allocHungoffUses(unsigned N, bool IsPhi) {
53+
void User::allocHungoffUses(unsigned N, bool WithExtraValues) {
5454
assert(HasHungOffUses && "alloc must have hung off uses");
5555

56-
static_assert(alignof(Use) >= alignof(BasicBlock *),
56+
static_assert(alignof(Use) >= alignof(Value *),
5757
"Alignment is insufficient for 'hung-off-uses' pieces");
5858

5959
// Allocate the array of Uses
6060
size_t size = N * sizeof(Use);
61-
if (IsPhi)
62-
size += N * sizeof(BasicBlock *);
61+
if (WithExtraValues)
62+
size += N * sizeof(Value *);
6363
Use *Begin = static_cast<Use*>(::operator new(size));
6464
Use *End = Begin + N;
6565
setOperandList(Begin);
6666
for (; Begin != End; Begin++)
6767
new (Begin) Use(this);
6868
}
6969

70-
void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
70+
void User::growHungoffUses(unsigned NewNumUses, bool WithExtraValues) {
7171
assert(HasHungOffUses && "realloc must have hung off uses");
7272

7373
unsigned OldNumUses = getNumOperands();
@@ -77,22 +77,22 @@ void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
7777
assert(NewNumUses > OldNumUses && "realloc must grow num uses");
7878

7979
Use *OldOps = getOperandList();
80-
allocHungoffUses(NewNumUses, IsPhi);
80+
allocHungoffUses(NewNumUses, WithExtraValues);
8181
Use *NewOps = getOperandList();
8282

8383
// Now copy from the old operands list to the new one.
8484
std::copy(OldOps, OldOps + OldNumUses, NewOps);
8585

86-
// If this is a Phi, then we need to copy the BB pointers too.
87-
if (IsPhi) {
86+
// If the User has extra values (phi basic blocks, switch case values), then
87+
// we need to copy these, too.
88+
if (WithExtraValues) {
8889
auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
8990
auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
90-
std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr);
91+
std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(Value *)), NewPtr);
9192
}
9293
Use::zap(OldOps, OldOps + OldNumUses, true);
9394
}
9495

95-
9696
// This is a private struct used by `User` to track the co-allocated descriptor
9797
// section.
9898
struct DescriptorInfo {

llvm/lib/IR/Verifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3424,7 +3424,7 @@ void Verifier::visitSwitchInst(SwitchInst &SI) {
34243424
Type *SwitchTy = SI.getCondition()->getType();
34253425
SmallPtrSet<ConstantInt*, 32> Constants;
34263426
for (auto &Case : SI.cases()) {
3427-
Check(isa<ConstantInt>(SI.getOperand(Case.getCaseIndex() * 2 + 2)),
3427+
Check(isa<ConstantInt>(Case.getCaseValue()),
34283428
"Case value is not a constant integer.", &SI);
34293429
Check(Case.getCaseValue()->getType() == SwitchTy,
34303430
"Switch constants must all be same type as switch value!", &SI);

0 commit comments

Comments
 (0)