Skip to content

Commit e031718

Browse files
committedMay 19, 2015
[RewriteStatepointsForGC] For some values (like gep's and bitcasts) it's cheaper to clone them after statepoint than to emit proper relocates for them. This change implements this logic. There is alredy similar optimization in CodeGenPrepare, but doing so during RewriteStatepointsForGC allows to capture more opprtunities such as relocates in loops and longer instruction chains.
Differential Revision: http://reviews.llvm.org/D9774 llvm-svn: 237701
1 parent deb3033 commit e031718

File tree

5 files changed

+503
-9
lines changed

5 files changed

+503
-9
lines changed
 

Diff for: ‎llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp

+278-6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "llvm/Pass.h"
1616
#include "llvm/Analysis/CFG.h"
17+
#include "llvm/Analysis/TargetTransformInfo.h"
1718
#include "llvm/ADT/SetOperations.h"
1819
#include "llvm/ADT/Statistic.h"
1920
#include "llvm/ADT/DenseSet.h"
@@ -56,6 +57,12 @@ static cl::opt<bool> PrintLiveSetSize("spp-print-liveset-size", cl::Hidden,
5657
static cl::opt<bool> PrintBasePointers("spp-print-base-pointers", cl::Hidden,
5758
cl::init(false));
5859

60+
// Cost threshold measuring when it is profitable to rematerialize value instead
61+
// of relocating it
62+
static cl::opt<unsigned>
63+
RematerializationThreshold("spp-rematerialization-threshold", cl::Hidden,
64+
cl::init(6));
65+
5966
#ifdef XDEBUG
6067
static bool ClobberNonLive = true;
6168
#else
@@ -78,6 +85,7 @@ struct RewriteStatepointsForGC : public FunctionPass {
7885
// We add and rewrite a bunch of instructions, but don't really do much
7986
// else. We could in theory preserve a lot more analyses here.
8087
AU.addRequired<DominatorTreeWrapperPass>();
88+
AU.addRequired<TargetTransformInfoWrapperPass>();
8189
}
8290
};
8391
} // namespace
@@ -123,6 +131,7 @@ struct GCPtrLivenessData {
123131
// types, then update all the second type to the first type
124132
typedef DenseMap<Value *, Value *> DefiningValueMapTy;
125133
typedef DenseSet<llvm::Value *> StatepointLiveSetTy;
134+
typedef DenseMap<Instruction *, Value *> RematerializedValueMapTy;
126135

127136
struct PartiallyConstructedSafepointRecord {
128137
/// The set of values known to be live accross this safepoint
@@ -138,6 +147,11 @@ struct PartiallyConstructedSafepointRecord {
138147
/// Instruction to which exceptional gc relocates are attached
139148
/// Makes it easier to iterate through them during relocationViaAlloca.
140149
Instruction *UnwindToken;
150+
151+
/// Record live values we are rematerialized instead of relocating.
152+
/// They are not included into 'liveset' field.
153+
/// Maps rematerialized copy to it's original value.
154+
RematerializedValueMapTy RematerializedValues;
141155
};
142156
}
143157

@@ -1389,6 +1403,31 @@ insertRelocationStores(iterator_range<Value::user_iterator> GCRelocs,
13891403
}
13901404
}
13911405

1406+
// Helper function for the "relocationViaAlloca". Similar to the
1407+
// "insertRelocationStores" but works for rematerialized values.
1408+
static void
1409+
insertRematerializationStores(
1410+
RematerializedValueMapTy RematerializedValues,
1411+
DenseMap<Value *, Value *> &AllocaMap,
1412+
DenseSet<Value *> &VisitedLiveValues) {
1413+
1414+
for (auto RematerializedValuePair: RematerializedValues) {
1415+
Instruction *RematerializedValue = RematerializedValuePair.first;
1416+
Value *OriginalValue = RematerializedValuePair.second;
1417+
1418+
assert(AllocaMap.count(OriginalValue) &&
1419+
"Can not find alloca for rematerialized value");
1420+
Value *Alloca = AllocaMap[OriginalValue];
1421+
1422+
StoreInst *Store = new StoreInst(RematerializedValue, Alloca);
1423+
Store->insertAfter(RematerializedValue);
1424+
1425+
#ifndef NDEBUG
1426+
VisitedLiveValues.insert(OriginalValue);
1427+
#endif
1428+
}
1429+
}
1430+
13921431
/// do all the relocation update via allocas and mem2reg
13931432
static void relocationViaAlloca(
13941433
Function &F, DominatorTree &DT, ArrayRef<Value *> live,
@@ -1406,17 +1445,38 @@ static void relocationViaAlloca(
14061445
// TODO-PERF: change data structures, reserve
14071446
DenseMap<Value *, Value *> allocaMap;
14081447
SmallVector<AllocaInst *, 200> PromotableAllocas;
1448+
// Used later to chack that we have enough allocas to store all values
1449+
std::size_t NumRematerializedValues = 0;
14091450
PromotableAllocas.reserve(live.size());
14101451

1452+
// Emit alloca for "LiveValue" and record it in "allocaMap" and
1453+
// "PromotableAllocas"
1454+
auto emitAllocaFor = [&](Value *LiveValue) {
1455+
AllocaInst *Alloca = new AllocaInst(LiveValue->getType(), "",
1456+
F.getEntryBlock().getFirstNonPHI());
1457+
allocaMap[LiveValue] = Alloca;
1458+
PromotableAllocas.push_back(Alloca);
1459+
};
1460+
14111461
// emit alloca for each live gc pointer
14121462
for (unsigned i = 0; i < live.size(); i++) {
1413-
Value *liveValue = live[i];
1414-
AllocaInst *alloca = new AllocaInst(liveValue->getType(), "",
1415-
F.getEntryBlock().getFirstNonPHI());
1416-
allocaMap[liveValue] = alloca;
1417-
PromotableAllocas.push_back(alloca);
1463+
emitAllocaFor(live[i]);
14181464
}
14191465

1466+
// emit allocas for rematerialized values
1467+
for (size_t i = 0; i < records.size(); i++) {
1468+
const struct PartiallyConstructedSafepointRecord &Info = records[i];
1469+
1470+
for (auto RematerializedValuePair: Info.RematerializedValues) {
1471+
Value *OriginalValue = RematerializedValuePair.second;
1472+
if (allocaMap.count(OriginalValue) != 0)
1473+
continue;
1474+
1475+
emitAllocaFor(OriginalValue);
1476+
++NumRematerializedValues;
1477+
}
1478+
}
1479+
14201480
// The next two loops are part of the same conceptual operation. We need to
14211481
// insert a store to the alloca after the original def and at each
14221482
// redefinition. We need to insert a load before each use. These are split
@@ -1444,6 +1504,10 @@ static void relocationViaAlloca(
14441504
visitedLiveValues);
14451505
}
14461506

1507+
// Do similar thing with rematerialized values
1508+
insertRematerializationStores(info.RematerializedValues, allocaMap,
1509+
visitedLiveValues);
1510+
14471511
if (ClobberNonLive) {
14481512
// As a debuging aid, pretend that an unrelocated pointer becomes null at
14491513
// the gc.statepoint. This will turn some subtle GC problems into
@@ -1548,7 +1612,7 @@ static void relocationViaAlloca(
15481612
}
15491613
}
15501614

1551-
assert(PromotableAllocas.size() == live.size() &&
1615+
assert(PromotableAllocas.size() == live.size() + NumRematerializedValues &&
15521616
"we must have the same allocas with lives");
15531617
if (!PromotableAllocas.empty()) {
15541618
// apply mem2reg to promote alloca to SSA
@@ -1732,6 +1796,201 @@ static void splitVectorValues(Instruction *StatepointInst,
17321796
PromoteMemToReg(Allocas, DT);
17331797
}
17341798

1799+
// Helper function for the "rematerializeLiveValues". It walks use chain
1800+
// starting from the "CurrentValue" until it meets "BaseValue". Only "simple"
1801+
// values are visited (currently it is GEP's and casts). Returns true if it
1802+
// sucessfully reached "BaseValue" and false otherwise.
1803+
// Fills "ChainToBase" array with all visited values. "BaseValue" is not
1804+
// recorded.
1805+
static bool findRematerializableChainToBasePointer(
1806+
SmallVectorImpl<Instruction*> &ChainToBase,
1807+
Value *CurrentValue, Value *BaseValue) {
1808+
1809+
// We have found a base value
1810+
if (CurrentValue == BaseValue) {
1811+
return true;
1812+
}
1813+
1814+
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(CurrentValue)) {
1815+
ChainToBase.push_back(GEP);
1816+
return findRematerializableChainToBasePointer(ChainToBase,
1817+
GEP->getPointerOperand(),
1818+
BaseValue);
1819+
}
1820+
1821+
if (CastInst *CI = dyn_cast<CastInst>(CurrentValue)) {
1822+
Value *Def = CI->stripPointerCasts();
1823+
1824+
// This two checks are basically similar. First one is here for the
1825+
// consistency with findBasePointers logic.
1826+
assert(!isa<CastInst>(Def) && "not a pointer cast found");
1827+
if (!CI->isNoopCast(CI->getModule()->getDataLayout()))
1828+
return false;
1829+
1830+
ChainToBase.push_back(CI);
1831+
return findRematerializableChainToBasePointer(ChainToBase, Def, BaseValue);
1832+
}
1833+
1834+
// Not supported instruction in the chain
1835+
return false;
1836+
}
1837+
1838+
// Helper function for the "rematerializeLiveValues". Compute cost of the use
1839+
// chain we are going to rematerialize.
1840+
static unsigned
1841+
chainToBasePointerCost(SmallVectorImpl<Instruction*> &Chain,
1842+
TargetTransformInfo &TTI) {
1843+
unsigned Cost = 0;
1844+
1845+
for (Instruction *Instr : Chain) {
1846+
if (CastInst *CI = dyn_cast<CastInst>(Instr)) {
1847+
assert(CI->isNoopCast(CI->getModule()->getDataLayout()) &&
1848+
"non noop cast is found during rematerialization");
1849+
1850+
Type *SrcTy = CI->getOperand(0)->getType();
1851+
Cost += TTI.getCastInstrCost(CI->getOpcode(), CI->getType(), SrcTy);
1852+
1853+
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Instr)) {
1854+
// Cost of the address calculation
1855+
Type *ValTy = GEP->getPointerOperandType()->getPointerElementType();
1856+
Cost += TTI.getAddressComputationCost(ValTy);
1857+
1858+
// And cost of the GEP itself
1859+
// TODO: Use TTI->getGEPCost here (it exists, but appears to be not
1860+
// allowed for the external usage)
1861+
if (!GEP->hasAllConstantIndices())
1862+
Cost += 2;
1863+
1864+
} else {
1865+
llvm_unreachable("unsupported instruciton type during rematerialization");
1866+
}
1867+
}
1868+
1869+
return Cost;
1870+
}
1871+
1872+
// From the statepoint liveset pick values that are cheaper to recompute then to
1873+
// relocate. Remove this values from the liveset, rematerialize them after
1874+
// statepoint and record them in "Info" structure. Note that similar to
1875+
// relocated values we don't do any user adjustments here.
1876+
static void rematerializeLiveValues(CallSite CS,
1877+
PartiallyConstructedSafepointRecord &Info,
1878+
TargetTransformInfo &TTI) {
1879+
const int ChainLengthThreshold = 10;
1880+
1881+
// Record values we are going to delete from this statepoint live set.
1882+
// We can not di this in following loop due to iterator invalidation.
1883+
SmallVector<Value *, 32> LiveValuesToBeDeleted;
1884+
1885+
for (Value *LiveValue: Info.liveset) {
1886+
// For each live pointer find it's defining chain
1887+
SmallVector<Instruction *, 3> ChainToBase;
1888+
assert(Info.PointerToBase.find(LiveValue) != Info.PointerToBase.end());
1889+
bool FoundChain =
1890+
findRematerializableChainToBasePointer(ChainToBase,
1891+
LiveValue,
1892+
Info.PointerToBase[LiveValue]);
1893+
// Nothing to do, or chain is too long
1894+
if (!FoundChain ||
1895+
ChainToBase.size() == 0 ||
1896+
ChainToBase.size() > ChainLengthThreshold)
1897+
continue;
1898+
1899+
// Compute cost of this chain
1900+
unsigned Cost = chainToBasePointerCost(ChainToBase, TTI);
1901+
// TODO: We can also account for cases when we will be able to remove some
1902+
// of the rematerialized values by later optimization passes. I.e if
1903+
// we rematerialized several intersecting chains. Or if original values
1904+
// don't have any uses besides this statepoint.
1905+
1906+
// For invokes we need to rematerialize each chain twice - for normal and
1907+
// for unwind basic blocks. Model this by multiplying cost by two.
1908+
if (CS.isInvoke()) {
1909+
Cost *= 2;
1910+
}
1911+
// If it's too expensive - skip it
1912+
if (Cost >= RematerializationThreshold)
1913+
continue;
1914+
1915+
// Remove value from the live set
1916+
LiveValuesToBeDeleted.push_back(LiveValue);
1917+
1918+
// Clone instructions and record them inside "Info" structure
1919+
1920+
// Walk backwards to visit top-most instructions first
1921+
std::reverse(ChainToBase.begin(), ChainToBase.end());
1922+
1923+
// Utility function which clones all instructions from "ChainToBase"
1924+
// and inserts them before "InsertBefore". Returns rematerialized value
1925+
// which should be used after statepoint.
1926+
auto rematerializeChain = [&ChainToBase](Instruction *InsertBefore) {
1927+
Instruction *LastClonedValue = nullptr;
1928+
Instruction *LastValue = nullptr;
1929+
for (Instruction *Instr: ChainToBase) {
1930+
// Only GEP's and casts are suported as we need to be careful to not
1931+
// introduce any new uses of pointers not in the liveset.
1932+
// Note that it's fine to introduce new uses of pointers which were
1933+
// otherwise not used after this statepoint.
1934+
assert(isa<GetElementPtrInst>(Instr) || isa<CastInst>(Instr));
1935+
1936+
Instruction *ClonedValue = Instr->clone();
1937+
ClonedValue->insertBefore(InsertBefore);
1938+
ClonedValue->setName(Instr->getName() + ".remat");
1939+
1940+
// If it is not first instruction in the chain then it uses previously
1941+
// cloned value. We should update it to use cloned value.
1942+
if (LastClonedValue) {
1943+
assert(LastValue);
1944+
ClonedValue->replaceUsesOfWith(LastValue, LastClonedValue);
1945+
#ifndef NDEBUG
1946+
// Assert that cloned instruction does not use any instructions
1947+
// other than LastClonedValue
1948+
for (auto OpValue: ClonedValue->operand_values()) {
1949+
if (isa<Instruction>(OpValue))
1950+
assert(OpValue == LastClonedValue &&
1951+
"unexpected use found in rematerialized value");
1952+
}
1953+
#endif
1954+
}
1955+
1956+
LastClonedValue = ClonedValue;
1957+
LastValue = Instr;
1958+
}
1959+
assert(LastClonedValue);
1960+
return LastClonedValue;
1961+
};
1962+
1963+
// Different cases for calls and invokes. For invokes we need to clone
1964+
// instructions both on normal and unwind path.
1965+
if (CS.isCall()) {
1966+
Instruction *InsertBefore = CS.getInstruction()->getNextNode();
1967+
assert(InsertBefore);
1968+
Instruction *RematerializedValue = rematerializeChain(InsertBefore);
1969+
Info.RematerializedValues[RematerializedValue] = LiveValue;
1970+
} else {
1971+
InvokeInst *Invoke = cast<InvokeInst>(CS.getInstruction());
1972+
1973+
Instruction *NormalInsertBefore =
1974+
Invoke->getNormalDest()->getFirstInsertionPt();
1975+
Instruction *UnwindInsertBefore =
1976+
Invoke->getUnwindDest()->getFirstInsertionPt();
1977+
1978+
Instruction *NormalRematerializedValue =
1979+
rematerializeChain(NormalInsertBefore);
1980+
Instruction *UnwindRematerializedValue =
1981+
rematerializeChain(UnwindInsertBefore);
1982+
1983+
Info.RematerializedValues[NormalRematerializedValue] = LiveValue;
1984+
Info.RematerializedValues[UnwindRematerializedValue] = LiveValue;
1985+
}
1986+
}
1987+
1988+
// Remove rematerializaed values from the live set
1989+
for (auto LiveValue: LiveValuesToBeDeleted) {
1990+
Info.liveset.erase(LiveValue);
1991+
}
1992+
}
1993+
17351994
static bool insertParsePoints(Function &F, DominatorTree &DT, Pass *P,
17361995
SmallVectorImpl<CallSite> &toUpdate) {
17371996
#ifndef NDEBUG
@@ -1867,6 +2126,19 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, Pass *P,
18672126
}
18682127
holders.clear();
18692128

2129+
// In order to reduce live set of statepoint we might choose to rematerialize
2130+
// some values instead of relocating them. This is purelly an optimization and
2131+
// does not influence correctness.
2132+
TargetTransformInfo &TTI =
2133+
P->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
2134+
2135+
for (size_t i = 0; i < records.size(); i++) {
2136+
struct PartiallyConstructedSafepointRecord &info = records[i];
2137+
CallSite &CS = toUpdate[i];
2138+
2139+
rematerializeLiveValues(CS, info, TTI);
2140+
}
2141+
18702142
// Now run through and replace the existing statepoints with new ones with
18712143
// the live variables listed. We do not yet update uses of the values being
18722144
// relocated. We have references to live variables that need to

Diff for: ‎llvm/test/Transforms/RewriteStatepointsForGC/basics.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; This is a collection of really basic tests for gc.statepoint rewriting.
2-
; RUN: opt %s -rewrite-statepoints-for-gc -S | FileCheck %s
2+
; RUN: opt %s -rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S | FileCheck %s
33

44
declare void @foo()
55

Diff for: ‎llvm/test/Transforms/RewriteStatepointsForGC/liveness-basics.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
; A collection of liveness test cases to ensure we're reporting the
22
; correct live values at statepoints
3-
; RUN: opt -rewrite-statepoints-for-gc -S < %s | FileCheck %s
3+
; RUN: opt -rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S < %s | FileCheck %s
44

55

66
; Tests to make sure we consider %obj live in both the taken and untaken

Diff for: ‎llvm/test/Transforms/RewriteStatepointsForGC/relocation.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt %s -rewrite-statepoints-for-gc -S 2>&1 | FileCheck %s
1+
; RUN: opt %s -rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S 2>&1 | FileCheck %s
22

33

44
declare void @foo()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
; RUN: opt %s -rewrite-statepoints-for-gc -S 2>&1 | FileCheck %s
2+
3+
declare void @use_obj16(i16 addrspace(1)*)
4+
declare void @use_obj32(i32 addrspace(1)*)
5+
declare void @use_obj64(i64 addrspace(1)*)
6+
declare void @do_safepoint()
7+
8+
define void @"test_gep_const"(i32 addrspace(1)* %base) gc "statepoint-example" {
9+
; CHECK-LABEL: test_gep_const
10+
entry:
11+
%ptr = getelementptr i32, i32 addrspace(1)* %base, i32 15
12+
; CHECK: getelementptr i32, i32 addrspace(1)* %base, i32 15
13+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
14+
; CHECK: %base.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %sp, i32 7, i32 7)
15+
; CHECK: bitcast i8 addrspace(1)* %base.relocated to i32 addrspace(1)*
16+
; CHECK: getelementptr i32, i32 addrspace(1)* %base.relocated.casted, i32 15
17+
call void @use_obj32(i32 addrspace(1)* %base)
18+
call void @use_obj32(i32 addrspace(1)* %ptr)
19+
ret void
20+
}
21+
22+
define void @"test_gep_idx"(i32 addrspace(1)* %base, i32 %idx) gc "statepoint-example" {
23+
; CHECK-LABEL: test_gep_idx
24+
entry:
25+
%ptr = getelementptr i32, i32 addrspace(1)* %base, i32 %idx
26+
; CHECK: getelementptr
27+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
28+
; CHECK: %base.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %sp, i32 7, i32 7)
29+
; CHECK: %base.relocated.casted = bitcast i8 addrspace(1)* %base.relocated to i32 addrspace(1)*
30+
; CHECK: getelementptr i32, i32 addrspace(1)* %base.relocated.casted, i32 %idx
31+
call void @use_obj32(i32 addrspace(1)* %base)
32+
call void @use_obj32(i32 addrspace(1)* %ptr)
33+
ret void
34+
}
35+
36+
define void @"test_bitcast"(i32 addrspace(1)* %base) gc "statepoint-example" {
37+
; CHECK-LABEL: test_bitcast
38+
entry:
39+
%ptr = bitcast i32 addrspace(1)* %base to i64 addrspace(1)*
40+
; CHECK: bitcast i32 addrspace(1)* %base to i64 addrspace(1)*
41+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
42+
; CHECK: %base.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %sp, i32 7, i32 7)
43+
; CHECK: %base.relocated.casted = bitcast i8 addrspace(1)* %base.relocated to i32 addrspace(1)*
44+
; CHECK: bitcast i32 addrspace(1)* %base.relocated.casted to i64 addrspace(1)*
45+
call void @use_obj32(i32 addrspace(1)* %base)
46+
call void @use_obj64(i64 addrspace(1)* %ptr)
47+
ret void
48+
}
49+
50+
define void @"test_bitcast_gep"(i32 addrspace(1)* %base) gc "statepoint-example" {
51+
; CHECK-LABEL: test_bitcast_gep
52+
entry:
53+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
54+
; CHECK: getelementptr
55+
%ptr.cast = bitcast i32 addrspace(1)* %ptr.gep to i64 addrspace(1)*
56+
; CHECK: bitcast
57+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
58+
; CHECK: gc.relocate
59+
; CHECK: bitcast
60+
; CHECK: getelementptr
61+
; CHECK: bitcast
62+
call void @use_obj32(i32 addrspace(1)* %base)
63+
call void @use_obj64(i64 addrspace(1)* %ptr.cast)
64+
ret void
65+
}
66+
67+
define void @"test_intersecting_chains"(i32 addrspace(1)* %base, i32 %idx) gc "statepoint-example" {
68+
; CHECK-LABEL: test_intersecting_chains
69+
entry:
70+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
71+
; CHECK: getelementptr
72+
%ptr.cast = bitcast i32 addrspace(1)* %ptr.gep to i64 addrspace(1)*
73+
; CHECK: bitcast
74+
%ptr.cast2 = bitcast i32 addrspace(1)* %ptr.gep to i16 addrspace(1)*
75+
; CHECK: bitcast
76+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
77+
; CHECK: getelementptr
78+
; CHECK: bitcast
79+
; CHECK: getelementptr
80+
; CHECK: bitcast
81+
call void @use_obj64(i64 addrspace(1)* %ptr.cast)
82+
call void @use_obj16(i16 addrspace(1)* %ptr.cast2)
83+
ret void
84+
}
85+
86+
define void @"test_cost_threshold"(i32 addrspace(1)* %base, i32 %idx1, i32 %idx2, i32 %idx3) gc "statepoint-example" {
87+
; CHECK-LABEL: test_cost_threshold
88+
entry:
89+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
90+
; CHECK: getelementptr
91+
%ptr.gep2 = getelementptr i32, i32 addrspace(1)* %ptr.gep, i32 %idx1
92+
; CHECK: getelementptr
93+
%ptr.gep3 = getelementptr i32, i32 addrspace(1)* %ptr.gep2, i32 %idx2
94+
; CHECK: getelementptr
95+
%ptr.gep4 = getelementptr i32, i32 addrspace(1)* %ptr.gep3, i32 %idx3
96+
; CHECK: getelementptr
97+
%ptr.cast = bitcast i32 addrspace(1)* %ptr.gep4 to i64 addrspace(1)*
98+
; CHECK: bitcast
99+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
100+
; CHECK: gc.relocate
101+
; CHECK: bitcast
102+
; CHECK: gc.relocate
103+
; CHECK: bitcast
104+
call void @use_obj64(i64 addrspace(1)* %ptr.cast)
105+
ret void
106+
}
107+
108+
define void @"test_two_derived"(i32 addrspace(1)* %base) gc "statepoint-example" {
109+
; CHECK-LABEL: test_two_derived
110+
entry:
111+
%ptr = getelementptr i32, i32 addrspace(1)* %base, i32 15
112+
%ptr2 = getelementptr i32, i32 addrspace(1)* %base, i32 12
113+
; CHECK: getelementptr
114+
; CHECK: getelementptr
115+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
116+
; CHECK: gc.relocate
117+
; CHECK: bitcast
118+
; CHECK: getelementptr
119+
; CHECK: getelementptr
120+
call void @use_obj32(i32 addrspace(1)* %ptr)
121+
call void @use_obj32(i32 addrspace(1)* %ptr2)
122+
ret void
123+
}
124+
125+
define void @"test_gep_smallint_array"([3 x i32] addrspace(1)* %base) gc "statepoint-example" {
126+
; CHECK-LABEL: test_gep_smallint_array
127+
entry:
128+
%ptr = getelementptr [3 x i32], [3 x i32] addrspace(1)* %base, i32 0, i32 2
129+
; CHECK: getelementptr
130+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
131+
; CHECK: gc.relocate
132+
; CHECK: bitcast
133+
; CHECK: getelementptr
134+
call void @use_obj32(i32 addrspace(1)* %ptr)
135+
ret void
136+
}
137+
138+
declare i32 @fake_personality_function()
139+
140+
define void @"test_invoke"(i32 addrspace(1)* %base) gc "statepoint-example" {
141+
; CHECK-LABEL: test_invoke
142+
entry:
143+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
144+
; CHECK: getelementptr
145+
%ptr.cast = bitcast i32 addrspace(1)* %ptr.gep to i64 addrspace(1)*
146+
; CHECK: bitcast
147+
%ptr.cast2 = bitcast i32 addrspace(1)* %ptr.gep to i16 addrspace(1)*
148+
; CHECK: bitcast
149+
%sp = invoke i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
150+
to label %normal unwind label %exception
151+
152+
normal:
153+
; CHECK-LABEL: normal:
154+
; CHECK: gc.relocate
155+
; CHECK: bitcast
156+
; CHECK: getelementptr
157+
; CHECK: bitcast
158+
; CHECK: getelementptr
159+
; CHECK: bitcast
160+
call void @use_obj64(i64 addrspace(1)* %ptr.cast)
161+
call void @use_obj16(i16 addrspace(1)* %ptr.cast2)
162+
ret void
163+
164+
exception:
165+
; CHECK-LABEL: exception:
166+
%landing_pad4 = landingpad { i8*, i32 } personality i32 ()* @fake_personality_function
167+
cleanup
168+
; CHECK: gc.relocate
169+
; CHECK: bitcast
170+
; CHECK: getelementptr
171+
; CHECK: bitcast
172+
; CHECK: getelementptr
173+
; CHECK: bitcast
174+
call void @use_obj64(i64 addrspace(1)* %ptr.cast)
175+
call void @use_obj16(i16 addrspace(1)* %ptr.cast2)
176+
ret void
177+
}
178+
179+
define void @"test_loop"(i32 addrspace(1)* %base) gc "statepoint-example" {
180+
; CHECK-LABEL: test_loop
181+
entry:
182+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
183+
; CHECK: getelementptr
184+
br label %loop
185+
186+
loop:
187+
; CHECK: phi i32 addrspace(1)* [ %ptr.gep, %entry ], [ %ptr.gep.remat, %loop ]
188+
; CHECK: phi i32 addrspace(1)* [ %base, %entry ], [ %base.relocated.casted, %loop ]
189+
call void @use_obj32(i32 addrspace(1)* %ptr.gep)
190+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
191+
; CHECK: gc.relocate
192+
; CHECK: bitcast
193+
; CHECK: getelementptr
194+
br label %loop
195+
}
196+
197+
define void @"test_too_long"(i32 addrspace(1)* %base) gc "statepoint-example" {
198+
; CHECK-LABEL: test_too_long
199+
entry:
200+
%ptr.gep = getelementptr i32, i32 addrspace(1)* %base, i32 15
201+
%ptr.gep1 = getelementptr i32, i32 addrspace(1)* %ptr.gep, i32 15
202+
%ptr.gep2 = getelementptr i32, i32 addrspace(1)* %ptr.gep1, i32 15
203+
%ptr.gep3 = getelementptr i32, i32 addrspace(1)* %ptr.gep2, i32 15
204+
%ptr.gep4 = getelementptr i32, i32 addrspace(1)* %ptr.gep3, i32 15
205+
%ptr.gep5 = getelementptr i32, i32 addrspace(1)* %ptr.gep4, i32 15
206+
%ptr.gep6 = getelementptr i32, i32 addrspace(1)* %ptr.gep5, i32 15
207+
%ptr.gep7 = getelementptr i32, i32 addrspace(1)* %ptr.gep6, i32 15
208+
%ptr.gep8 = getelementptr i32, i32 addrspace(1)* %ptr.gep7, i32 15
209+
%ptr.gep9 = getelementptr i32, i32 addrspace(1)* %ptr.gep8, i32 15
210+
%ptr.gep10 = getelementptr i32, i32 addrspace(1)* %ptr.gep9, i32 15
211+
%ptr.gep11 = getelementptr i32, i32 addrspace(1)* %ptr.gep10, i32 15
212+
%sp = call i32 (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @do_safepoint, i32 0, i32 0, i32 0, i32 0)
213+
; CHECK: gc.relocate
214+
; CHECK: bitcast
215+
; CHECK: gc.relocate
216+
; CHECK: bitcast
217+
call void @use_obj32(i32 addrspace(1)* %ptr.gep11)
218+
ret void
219+
}
220+
221+
222+
declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)

0 commit comments

Comments
 (0)
Please sign in to comment.