Skip to content

Commit

Permalink
AllocOpt: Fix stack lowering where object contains both julia and non…
Browse files Browse the repository at this point in the history
…-julia objects
  • Loading branch information
wsmoses committed Jul 29, 2024
1 parent 20b3af3 commit 81e683a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/llvm-alloc-helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ bool AllocUseInfo::addMemOp(Instruction *inst, unsigned opno, uint32_t offset,
memop.isaggr = isa<StructType>(elty) || isa<ArrayType>(elty) || isa<VectorType>(elty);
memop.isobjref = hasObjref(elty);
auto &field = getField(offset, size, elty);

Check warning on line 91 in src/llvm-alloc-helpers.cpp

View workflow job for this annotation

GitHub Actions / Check whitespace

Whitespace check

trailing whitespace
field.second.hasbits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));

if (field.second.hasobjref != memop.isobjref)
field.second.multiloc = true; // can't split this field, since it contains a mix of references and bits
if (!isstore)
Expand Down Expand Up @@ -198,6 +201,7 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
auto elty = inst->getType();
required.use_info.has_unknown_objref |= hasObjref(elty);
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
required.use_info.hasunknownmem = true;
} else if (!required.use_info.addMemOp(inst, 0, cur.offset,
inst->getType(),
Expand Down Expand Up @@ -289,6 +293,7 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
auto elty = storev->getType();
required.use_info.has_unknown_objref |= hasObjref(elty);
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
required.use_info.hasunknownmem = true;
} else if (!required.use_info.addMemOp(inst, use->getOperandNo(),
cur.offset, storev->getType(),
Expand All @@ -310,10 +315,14 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r
}
required.use_info.hasload = true;
auto storev = isa<AtomicCmpXchgInst>(inst) ? cast<AtomicCmpXchgInst>(inst)->getNewValOperand() : cast<AtomicRMWInst>(inst)->getValOperand();
Type *elty = storev->getType();
if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, use->getOperandNo(),
cur.offset, storev->getType(),
cur.offset, elty,
true, required.DL)) {
LLVM_DEBUG(dbgs() << "Atomic inst has unknown offset\n");
required.use_info.has_unknown_objref |= hasObjref(elty);
required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa<PointerType>(elty);
required.use_info.has_unknown_bits |= !hasObjref(elty) || (hasObjref(elty) && !isa<PointerType>(elty));
required.use_info.hasunknownmem = true;
}
required.use_info.refload = true;
Expand Down
7 changes: 7 additions & 0 deletions src/llvm-alloc-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ namespace jl_alloc {
bool hasaggr:1;
bool multiloc:1;
bool hasload:1;
// The alloc has a non-julia object at this offset.
bool hasbits:1;
llvm::Type *elty;
llvm::SmallVector<MemOp,4> accesses;
Field(uint32_t size, llvm::Type *elty)
Expand All @@ -54,6 +56,7 @@ namespace jl_alloc {
hasaggr(false),
multiloc(false),
hasload(false),
hasbits(false),
elty(elty)
{
}
Expand Down Expand Up @@ -95,6 +98,9 @@ namespace jl_alloc {
// The alloc has an aggregate Julia object reference not in an explicit field.
bool has_unknown_objrefaggr:1;

// The alloc has a non-julia object at an unknown offset.
bool has_unknown_bits:1;

void reset()
{
escaped = false;
Expand All @@ -110,6 +116,7 @@ namespace jl_alloc {
allockind = llvm::AllocFnKind::Unknown;
has_unknown_objref = false;
has_unknown_objrefaggr = false;
has_unknown_bits = false;
uses.clear();
preserves.clear();
memops.clear();
Expand Down
11 changes: 11 additions & 0 deletions src/llvm-alloc-opt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,12 @@ void Optimizer::optimizeAll()
removeAlloc(orig);
continue;
}
bool has_bits = use_info.has_unknown_bits;
bool has_ref = use_info.has_unknown_objref;
bool has_refaggr = use_info.has_unknown_objrefaggr;
for (auto memop: use_info.memops) {
auto &field = memop.second;
has_bits |= field.hasbits;
if (field.hasobjref) {
has_ref = true;
// This can be relaxed a little based on hasload
Expand Down Expand Up @@ -284,6 +286,15 @@ void Optimizer::optimizeAll()
splitOnStack(orig);
continue;
}
if (has_bits && has_ref) {
REMARK([&]() {
return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
<< "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);
});
if (use_info.hastypeof)
optimizeTag(orig);
continue;
}
REMARK([&](){
return OptimizationRemark(DEBUG_TYPE, "Stack Move Allocation", orig)
<< "GC allocation moved to stack " << ore::NV("GC Allocation", orig);
Expand Down
36 changes: 36 additions & 0 deletions test/llvmpasses/alloc-opt-bits.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; This file is a part of Julia. License is MIT: https://julialang.org/license

; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(AllocOpt)' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE


@tag = external addrspace(10) global {}

@glob = external addrspace(10) global {}

; Test that the gc_preserve intrinsics are deleted directly.

; CHECK-LABEL: @ptr_and_bits
; CHECK: call noalias ptr addrspace(10) @julia.gc_alloc_obj

define void @ptr_and_bits(ptr %fptr, i1 %b, i1 %b2, i32 %idx) {
%pgcstack = call ptr @julia.get_pgcstack()
%ptls = call ptr @julia.ptls_states()
%ptls_i8 = bitcast ptr %ptls to ptr
%v = call noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 16, ptr addrspace(10) @tag)

%g0 = getelementptr { i64, ptr addrspace(10) }, ptr addrspace(10) %v, i32 %idx, i32 1
store ptr addrspace(10) @glob, ptr addrspace(10) %g0

%g1 = getelementptr { i64, ptr addrspace(10) }, ptr addrspace(10) %v, i32 %idx, i32 0
store i64 7, ptr addrspace(10) %g1

%res = load ptr addrspace(10), ptr addrspace(10) %g0
%res2 = load i64, ptr addrspace(10) %g1
ret void
}

declare noalias ptr addrspace(10) @julia.gc_alloc_obj(ptr, i64, ptr addrspace(10))

declare ptr @julia.ptls_states()

declare ptr @julia.get_pgcstack()

0 comments on commit 81e683a

Please sign in to comment.