Skip to content

Commit 3544692

Browse files
committed
AllocOpt: Fix stack lowering where object contains both julia and non-julia objects
1 parent 20b3af3 commit 3544692

File tree

4 files changed

+65
-1
lines changed

4 files changed

+65
-1
lines changed

src/llvm-alloc-helpers.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ bool AllocUseInfo::addMemOp(Instruction *inst, unsigned opno, uint32_t offset,
8888
memop.isaggr = isa<StructType>(elty) || isa<ArrayType>(elty) || isa<VectorType>(elty);
8989
memop.isobjref = hasObjref(elty);
9090
auto &field = getField(offset, size, elty);
91+
92+
field.second.hasbits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
93+
9194
if (field.second.hasobjref != memop.isobjref)
9295
field.second.multiloc = true; // can't split this field, since it contains a mix of references and bits
9396
if (!isstore)
@@ -198,6 +201,7 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
198201
auto elty = inst->getType();
199202
required.use_info.has_unknown_objref |= hasObjref(elty);
200203
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
204+
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
201205
required.use_info.hasunknownmem = true;
202206
} else if (!required.use_info.addMemOp(inst, 0, cur.offset,
203207
inst->getType(),
@@ -289,6 +293,7 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
289293
auto elty = storev->getType();
290294
required.use_info.has_unknown_objref |= hasObjref(elty);
291295
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
296+
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
292297
required.use_info.hasunknownmem = true;
293298
} else if (!required.use_info.addMemOp(inst, use->getOperandNo(),
294299
cur.offset, storev->getType(),
@@ -310,10 +315,14 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
310315
}
311316
required.use_info.hasload = true;
312317
auto storev = isa<AtomicCmpXchgInst>(inst) ? cast<AtomicCmpXchgInst>(inst)->getNewValOperand() : cast<AtomicRMWInst>(inst)->getValOperand();
318+
Type *elty = storev->getType();
313319
if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, use->getOperandNo(),
314-
cur.offset, storev->getType(),
320+
cur.offset, elty,
315321
true, required.DL)) {
316322
LLVM_DEBUG(dbgs() << "Atomic inst has unknown offset\n");
323+
required.use_info.has_unknown_objref |= hasObjref(elty);
324+
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
325+
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
317326
required.use_info.hasunknownmem = true;
318327
}
319328
required.use_info.refload = true;

src/llvm-alloc-helpers.h

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ namespace jl_alloc {
4646
bool hasaggr:1;
4747
bool multiloc:1;
4848
bool hasload:1;
49+
// The alloc has a non-julia object at this offset.
50+
bool hasbits:1;
4951
llvm::Type *elty;
5052
llvm::SmallVector<MemOp,4> accesses;
5153
Field(uint32_t size, llvm::Type *elty)
@@ -54,6 +56,7 @@ namespace jl_alloc {
5456
hasaggr(false),
5557
multiloc(false),
5658
hasload(false),
59+
hasbits(false),
5760
elty(elty)
5861
{
5962
}
@@ -95,6 +98,9 @@ namespace jl_alloc {
9598
// The alloc has an aggregate Julia object reference not in an explicit field.
9699
bool has_unknown_objrefaggr:1;
97100

101+
// The alloc has a non-julia object at an unknown offset.
102+
bool has_unknown_bits:1;
103+
98104
void reset()
99105
{
100106
escaped = false;
@@ -110,6 +116,7 @@ namespace jl_alloc {
110116
allockind = llvm::AllocFnKind::Unknown;
111117
has_unknown_objref = false;
112118
has_unknown_objrefaggr = false;
119+
has_unknown_bits = false;
113120
uses.clear();
114121
preserves.clear();
115122
memops.clear();

src/llvm-alloc-opt.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,12 @@ void Optimizer::optimizeAll()
252252
removeAlloc(orig);
253253
continue;
254254
}
255+
bool has_bits = use_info.has_unknown_bits;
255256
bool has_ref = use_info.has_unknown_objref;
256257
bool has_refaggr = use_info.has_unknown_objrefaggr;
257258
for (auto memop: use_info.memops) {
258259
auto &field = memop.second;
260+
has_bits |= field.hasbits;
259261
if (field.hasobjref) {
260262
has_ref = true;
261263
// This can be relaxed a little based on hasload
@@ -284,6 +286,15 @@ void Optimizer::optimizeAll()
284286
splitOnStack(orig);
285287
continue;
286288
}
289+
if (has_bits && has_ref) {
290+
REMARK([&]() {
291+
return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
292+
<< "GC allocation could not be split and contained both julia object and non-julia-object data, unable to move to stack " << ore::NV("GC Allocation", orig);
293+
});
294+
if (use_info.hastypeof)
295+
optimizeTag(orig);
296+
continue;
297+
}
287298
REMARK([&](){
288299
return OptimizationRemark(DEBUG_TYPE, "Stack Move Allocation", orig)
289300
<< "GC allocation moved to stack " << ore::NV("GC Allocation", orig);

test/llvmpasses/alloc-opt-bits.ll

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(AllocOpt)' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE
4+
5+
6+
@tag = external addrspace(10) global {}
7+
8+
@glob = external addrspace(10) global {}
9+
10+
; Test that the gc_preserve intrinsics are deleted directly.
11+
12+
; CHECK-LABEL: @ptr_and_bits
13+
; CHECK-NOT: alloca
14+
; CHECK: call noalias ptr addrspace(10) @julia.gc_alloc_obj
15+
16+
define void @ptr_and_bits(ptr %fptr, i1 %b, i1 %b2, i32 %idx) {
17+
%pgcstack = call ptr @julia.get_pgcstack()
18+
%ptls = call ptr @julia.ptls_states()
19+
%ptls_i8 = bitcast ptr %ptls to ptr
20+
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 16, ptr addrspace(10) @tag)
21+
22+
%g0 = getelementptr { i64, ptr addrspace(10) }, ptr addrspace(10) %v, i32 %idx, i32 1
23+
store ptr addrspace(10) @glob, ptr addrspace(10) %g0
24+
25+
%g1 = getelementptr { i64, ptr addrspace(10) }, ptr addrspace(10) %v, i32 %idx, i32 0
26+
store i64 7, ptr addrspace(10) %g1
27+
28+
%res = load ptr addrspace(10), ptr addrspace(10) %g0
29+
%res2 = load i64, ptr addrspace(10) %g1
30+
ret void
31+
}
32+
33+
declare noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr, i64, ptr addrspace(10))
34+
35+
declare ptr @julia.ptls_states()
36+
37+
declare ptr @julia.get_pgcstack()

0 commit comments

Comments
 (0)