Skip to content

Commit

Permalink
Implement alias scopes
Browse files Browse the repository at this point in the history
Co-authored-by: Keno Fischer <kfischer@college.harvard.edu>
Co-authored-by: Yingbo Ma <mayingbo5@gmail.com>
Co-authored-by: Valentin Churavy <v.churavy@gmail.com>
  • Loading branch information
3 people committed Feb 22, 2019
1 parent 0d21100 commit 53405a4
Show file tree
Hide file tree
Showing 16 changed files with 114 additions and 22 deletions.
2 changes: 1 addition & 1 deletion base/array.jl
Expand Up @@ -124,7 +124,7 @@ eltype(::Type) = Any
eltype(::Type{Bottom}) = throw(ArgumentError("Union{} does not have elements"))
eltype(x) = eltype(typeof(x))

import Core: arraysize, arrayset, arrayref
import Core: arraysize, arrayset, arrayref, const_arrayref

vect() = Vector{Any}()
vect(X::T...) where {T} = T[ X[i] for i = 1:length(X) ]
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/optimize.jl
Expand Up @@ -89,7 +89,7 @@ const _PURE_BUILTINS = Any[tuple, svec, ===, typeof, nfields]
# known to be effect-free if the are nothrow
const _PURE_OR_ERROR_BUILTINS = [
fieldtype, apply_type, isa, UnionAll,
getfield, arrayref, isdefined, Core.sizeof,
getfield, arrayref, const_arrayref, isdefined, Core.sizeof,
Core.kwfunc, ifelse, Core._typevar, (<:)
]

Expand Down Expand Up @@ -307,7 +307,7 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, sptypes::Vector{Any}
# tuple iteration/destructuring makes that impossible
# return plus_saturate(argcost, isknowntype(extyp) ? 1 : params.inline_nonleaf_penalty)
return 0
elseif f === Main.Core.arrayref && length(ex.args) >= 3
elseif (f === Main.Core.arrayref || f === Main.Core.const_arrayref) && length(ex.args) >= 3
atyp = argextype(ex.args[3], src, sptypes, slottypes)
return isknowntype(atyp) ? 4 : params.inline_nonleaf_penalty
end
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/tfuncs.jl
Expand Up @@ -1186,7 +1186,7 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ
# Check that the element type is compatible with the element we're assigning
(argtypes[3] a.parameters[1]::Type) || return false
return true
elseif f === arrayref
elseif f === arrayref || f === const_arrayref
return array_builtin_common_nothrow(argtypes, 3)
elseif f === Core._expr
length(argtypes) >= 1 || return false
Expand Down Expand Up @@ -1246,7 +1246,7 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
return Bottom
end
return argtypes[2]
elseif f === arrayref
elseif f === arrayref || f === const_arrayref
if length(argtypes) < 3
isva && return Any
return Bottom
Expand Down
3 changes: 3 additions & 0 deletions src/ast.c
Expand Up @@ -61,6 +61,7 @@ jl_sym_t *colon_sym; jl_sym_t *hygienicscope_sym;
jl_sym_t *throw_undef_if_not_sym; jl_sym_t *getfield_undefref_sym;
jl_sym_t *gc_preserve_begin_sym; jl_sym_t *gc_preserve_end_sym;
jl_sym_t *escape_sym;
jl_sym_t *aliasscope_sym; jl_sym_t *popaliasscope_sym;

static uint8_t flisp_system_image[] = {
#include <julia_flisp.boot.inc>
Expand Down Expand Up @@ -364,6 +365,8 @@ void jl_init_frontend(void)
throw_undef_if_not_sym = jl_symbol("throw_undef_if_not");
getfield_undefref_sym = jl_symbol("##getfield##");
do_sym = jl_symbol("do");
aliasscope_sym = jl_symbol("aliasscope");
popaliasscope_sym = jl_symbol("popaliasscope");
}

JL_DLLEXPORT void jl_lisp_prompt(void)
Expand Down
1 change: 1 addition & 0 deletions src/builtin_proto.h
Expand Up @@ -28,6 +28,7 @@ DECLARE_BUILTIN(isdefined); DECLARE_BUILTIN(nfields);
DECLARE_BUILTIN(tuple); DECLARE_BUILTIN(svec);
DECLARE_BUILTIN(getfield); DECLARE_BUILTIN(setfield);
DECLARE_BUILTIN(fieldtype); DECLARE_BUILTIN(arrayref);
DECLARE_BUILTIN(const_arrayref);
DECLARE_BUILTIN(arrayset); DECLARE_BUILTIN(arraysize);
DECLARE_BUILTIN(apply_type); DECLARE_BUILTIN(applicable);
DECLARE_BUILTIN(invoke); DECLARE_BUILTIN(_expr);
Expand Down
6 changes: 6 additions & 0 deletions src/builtins.c
Expand Up @@ -1059,6 +1059,11 @@ JL_CALLABLE(jl_f_arrayref)
return jl_arrayref(a, i);
}

JL_CALLABLE(jl_f_const_arrayref)
{
return jl_f_arrayref(F, args, nargs);
}

JL_CALLABLE(jl_f_arrayset)
{
JL_NARGSV(arrayset, 4);
Expand Down Expand Up @@ -1210,6 +1215,7 @@ void jl_init_primitives(void) JL_GC_DISABLED

// array primitives
add_builtin_func("arrayref", jl_f_arrayref);
add_builtin_func("const_arrayref", jl_f_arrayref);
add_builtin_func("arrayset", jl_f_arrayset);
add_builtin_func("arraysize", jl_f_arraysize);

Expand Down
19 changes: 13 additions & 6 deletions src/cgutils.cpp
Expand Up @@ -1240,7 +1240,8 @@ static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_v
static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_value_t *jt, Value* dest = NULL, MDNode *tbaa_dest = nullptr, bool isVolatile = false);

static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, jl_value_t *jltype,
MDNode *tbaa, bool maybe_null_if_boxed = true, unsigned alignment = 0)
MDNode *tbaa, MDNode *aliasscope,
bool maybe_null_if_boxed = true, unsigned alignment = 0)
{
bool isboxed;
Type *elty = julia_type_to_llvm(jltype, &isboxed);
Expand All @@ -1265,8 +1266,12 @@ static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, j
Instruction *load = ctx.builder.CreateAlignedLoad(data,
isboxed || alignment ? alignment : julia_alignment(jltype),
false);
if (isboxed)
if (aliasscope) {
load->setMetadata("alias.scope", aliasscope);
}
if (isboxed) {
load = maybe_mark_load_dereferenceable(load, true, jltype);
}
if (tbaa) {
elt = tbaa_decorate(tbaa, load);
}
Expand All @@ -1282,7 +1287,7 @@ static jl_cgval_t typed_load(jl_codectx_t &ctx, Value *ptr, Value *idx_0based, j

static void typed_store(jl_codectx_t &ctx,
Value *ptr, Value *idx_0based, const jl_cgval_t &rhs,
jl_value_t *jltype, MDNode *tbaa,
jl_value_t *jltype, MDNode *tbaa, MDNode *aliasscope,
Value *parent, // for the write barrier, NULL if no barrier needed
unsigned alignment = 0)
{
Expand Down Expand Up @@ -1313,6 +1318,8 @@ static void typed_store(jl_codectx_t &ctx,
if (idx_0based)
data = ctx.builder.CreateInBoundsGEP(r->getType(), data, idx_0based);
Instruction *store = ctx.builder.CreateAlignedStore(r, data, isboxed || alignment ? alignment : julia_alignment(jltype));
if (aliasscope)
store->setMetadata("noalias", aliasscope);
if (tbaa)
tbaa_decorate(tbaa, store);
}
Expand Down Expand Up @@ -1465,7 +1472,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
*ret = mark_julia_slot(addr, jt, NULL, strct.tbaa);
return true;
}
*ret = typed_load(ctx, ptr, idx, jt, strct.tbaa, false);
*ret = typed_load(ctx, ptr, idx, jt, strct.tbaa, nullptr, false);
return true;
}
else if (strct.isboxed) {
Expand Down Expand Up @@ -1590,7 +1597,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
// just compute the pointer and let user load it when necessary
return mark_julia_slot(addr, jfty, NULL, strct.tbaa);
}
return typed_load(ctx, addr, NULL, jfty, strct.tbaa, true, align);
return typed_load(ctx, addr, NULL, jfty, strct.tbaa, nullptr, true, align);
}
else if (isa<UndefValue>(strct.V)) {
return jl_cgval_t();
Expand Down Expand Up @@ -2424,7 +2431,7 @@ static void emit_setfield(jl_codectx_t &ctx,
else {
unsigned align = jl_field_align(sty, idx0);
typed_store(ctx, addr, NULL, rhs, jfty,
strct.tbaa, maybe_bitcast(ctx,
strct.tbaa, nullptr, maybe_bitcast(ctx,
data_pointer(ctx, strct), T_pjlvalue), align);
}
}
Expand Down
50 changes: 45 additions & 5 deletions src/codegen.cpp
Expand Up @@ -523,6 +523,7 @@ class jl_codectx_t {
Value *spvals_ptr = NULL;
Value *argArray = NULL;
Value *argCount = NULL;
MDNode *aliasscope = NULL;
std::string funcName;
int vaSlot = -1; // name of vararg argument
bool has_sret = false;
Expand Down Expand Up @@ -2521,7 +2522,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
}
}

else if (f == jl_builtin_arrayref && nargs >= 3) {
else if ((f == jl_builtin_arrayref || f == jl_builtin_const_arrayref) && nargs >= 3) {
const jl_cgval_t &ary = argv[2];
bool indices_ok = true;
for (size_t i = 3; i <= nargs; i++) {
Expand Down Expand Up @@ -2573,10 +2574,11 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
*ret = mark_julia_slot(lv, ety, ctx.builder.CreateNUWAdd(ConstantInt::get(T_int8, 1), tindex), tbaa_arraybuf);
}
else {
MDNode *aliasscope = (f == jl_builtin_const_arrayref) ? ctx.aliasscope : nullptr;
*ret = typed_load(ctx,
emit_arrayptr(ctx, ary, ary_ex),
idx, ety,
!isboxed ? tbaa_arraybuf : tbaa_ptrarraybuf);
!isboxed ? tbaa_arraybuf : tbaa_ptrarraybuf, aliasscope);
}
return true;
}
Expand Down Expand Up @@ -2677,7 +2679,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
emit_arrayptr(ctx, ary, ary_ex, isboxed),
idx, val, ety,
!isboxed ? tbaa_arraybuf : tbaa_ptrarraybuf,
data_owner, 0);
ctx.aliasscope, data_owner, 0);
}
}
*ret = ary;
Expand Down Expand Up @@ -2760,7 +2762,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
jl_true);
}
Value *ptr = maybe_decay_tracked(data_pointer(ctx, obj));
*ret = typed_load(ctx, ptr, vidx, jt, obj.tbaa, false);
*ret = typed_load(ctx, ptr, vidx, jt, obj.tbaa, nullptr, false);
return true;
}
}
Expand Down Expand Up @@ -3833,7 +3835,7 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result)
jl_expr_t *ex = (jl_expr_t*)expr;
jl_value_t **args = (jl_value_t**)jl_array_data(ex->args);
jl_sym_t *head = ex->head;
if (head == meta_sym || head == inbounds_sym) {
if (head == meta_sym || head == inbounds_sym || head == aliasscope_sym || head == popaliasscope_sym) {
// some expression types are metadata and can be ignored
// in statement position
return;
Expand Down Expand Up @@ -4123,6 +4125,12 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
else if (head == inbounds_sym) {
jl_error("Expr(:inbounds) in value position");
}
else if (head == aliasscope_sym) {
jl_error("Expr(:aliasscope) in value position");
}
else if (head == popaliasscope_sym) {
jl_error("Expr(:popaliasscope) in value position");
}
else if (head == boundscheck_sym) {
return mark_julia_const(bounds_check_enabled(ctx, jl_true) ? jl_true : jl_false);
}
Expand Down Expand Up @@ -5986,6 +5994,36 @@ static std::unique_ptr<Module> emit_function(
}
}
}

std::vector<MDNode*> aliasscopes;
MDNode* current_aliasscope = nullptr;
std::vector<Metadata*> scope_stack;
std::vector<MDNode*> scope_list_stack;
{
size_t nstmts = jl_array_len(src->code);
aliasscopes.resize(nstmts + 1, nullptr);
static MDBuilder *mbuilder = new MDBuilder(jl_LLVMContext);
MDNode *alias_domain = mbuilder->createAliasScopeDomain(ctx.name);
for (i = 0; i < nstmts; i++) {
jl_value_t *stmt = jl_array_ptr_ref(stmts, i);
jl_expr_t *expr = jl_is_expr(stmt) ? (jl_expr_t*)stmt : nullptr;
if (expr) {
if (expr->head == aliasscope_sym) {
MDNode *scope = mbuilder->createAliasScope("aliasscope", alias_domain);
scope_stack.push_back(scope);
MDNode *scope_list = MDNode::get(jl_LLVMContext, ArrayRef<Metadata*>(scope_stack));
scope_list_stack.push_back(scope_list);
current_aliasscope = scope_list;
} else if (expr->head == popaliasscope_sym) {
scope_stack.pop_back();
scope_list_stack.pop_back();
current_aliasscope = scope_list_stack.back();
}
}
aliasscopes[i+1] = current_aliasscope;
}
}

Instruction &prologue_end = ctx.builder.GetInsertBlock()->back();


Expand Down Expand Up @@ -6129,6 +6167,7 @@ static std::unique_ptr<Module> emit_function(
ctx.builder.SetCurrentDebugLocation(linetable.at(debuginfoloc).loc);
coverageVisitStmt(debuginfoloc);
}
ctx.aliasscope = aliasscopes[cursor];
jl_value_t *stmt = jl_array_ptr_ref(stmts, cursor);
jl_expr_t *expr = jl_is_expr(stmt) ? (jl_expr_t*)stmt : nullptr;
if (expr && expr->head == unreachable_sym) {
Expand Down Expand Up @@ -7107,6 +7146,7 @@ static void init_julia_llvm_env(Module *m)
builtin_func_map[jl_f__expr] = jlcall_func_to_llvm("jl_f__expr", &jl_f__expr, m);
builtin_func_map[jl_f__typevar] = jlcall_func_to_llvm("jl_f__typevar", &jl_f__typevar, m);
builtin_func_map[jl_f_arrayref] = jlcall_func_to_llvm("jl_f_arrayref", &jl_f_arrayref, m);
builtin_func_map[jl_f_const_arrayref] = jlcall_func_to_llvm("jl_f_const_arrayref", &jl_f_arrayref, m);
builtin_func_map[jl_f_arrayset] = jlcall_func_to_llvm("jl_f_arrayset", &jl_f_arrayset, m);
builtin_func_map[jl_f_arraysize] = jlcall_func_to_llvm("jl_f_arraysize", &jl_f_arraysize, m);
builtin_func_map[jl_f_apply_type] = jlcall_func_to_llvm("jl_f_apply_type", &jl_f_apply_type, m);
Expand Down
1 change: 1 addition & 0 deletions src/init.c
Expand Up @@ -913,6 +913,7 @@ void jl_get_builtins(void)
jl_builtin_tuple = core("tuple"); jl_builtin_svec = core("svec");
jl_builtin_getfield = core("getfield"); jl_builtin_setfield = core("setfield!");
jl_builtin_fieldtype = core("fieldtype"); jl_builtin_arrayref = core("arrayref");
jl_builtin_const_arrayref = core("const_arrayref");
jl_builtin_arrayset = core("arrayset"); jl_builtin_arraysize = core("arraysize");
jl_builtin_apply_type = core("apply_type"); jl_builtin_applicable = core("applicable");
jl_builtin_invoke = core("invoke"); jl_builtin__expr = core("_expr");
Expand Down
4 changes: 2 additions & 2 deletions src/intrinsics.cpp
Expand Up @@ -601,7 +601,7 @@ static jl_cgval_t emit_pointerref(jl_codectx_t &ctx, jl_cgval_t *argv)
Type *ptrty = julia_type_to_llvm(ety, &isboxed);
assert(!isboxed);
Value *thePtr = emit_unbox(ctx, ptrty->getPointerTo(), e, e.typ);
return typed_load(ctx, thePtr, im1, ety, tbaa_data, true, align_nb);
return typed_load(ctx, thePtr, im1, ety, tbaa_data, nullptr, true, align_nb);
}
}

Expand Down Expand Up @@ -664,7 +664,7 @@ static jl_cgval_t emit_pointerset(jl_codectx_t &ctx, jl_cgval_t *argv)
Type *ptrty = julia_type_to_llvm(ety, &isboxed);
assert(!isboxed);
thePtr = emit_unbox(ctx, ptrty->getPointerTo(), e, e.typ);
typed_store(ctx, thePtr, im1, x, ety, tbaa_data, NULL, align_nb);
typed_store(ctx, thePtr, im1, x, ety, tbaa_data, nullptr, nullptr, align_nb);
}
return mark_julia_type(ctx, thePtr, false, aty);
}
Expand Down
2 changes: 2 additions & 0 deletions src/jitlayers.cpp
Expand Up @@ -10,6 +10,7 @@
#include <llvm/Analysis/Passes.h>
#include <llvm/Analysis/BasicAliasAnalysis.h>
#include <llvm/Analysis/TypeBasedAliasAnalysis.h>
#include <llvm/Analysis/ScopedNoAliasAA.h>
#include <llvm/Analysis/TargetTransformInfo.h>
#include <llvm/Analysis/TargetLibraryInfo.h>
#include <llvm/IR/Verifier.h>
Expand Down Expand Up @@ -124,6 +125,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool dump
return;
}
PM->add(createPropagateJuliaAddrspaces());
PM->add(createScopedNoAliasAAWrapperPass());
PM->add(createTypeBasedAAWrapperPass());
if (opt_level >= 3) {
PM->add(createBasicAAWrapperPass());
Expand Down
4 changes: 2 additions & 2 deletions src/julia-syntax.scm
Expand Up @@ -2951,7 +2951,7 @@ f(x) = yt(x)

(define lambda-opt-ignored-exprs
(Set '(quote top core line inert local local-def unnecessary copyast
meta inbounds boundscheck simdloop decl
meta inbounds boundscheck simdloop decl aliasscope popaliasscope
struct_type abstract_type primitive_type thunk with-static-parameters
implicit-global global globalref outerref const-if-global
const null ssavalue isdefined toplevel module lambda error
Expand Down Expand Up @@ -3971,7 +3971,7 @@ f(x) = yt(x)
s))

;; metadata expressions
((line meta inbounds simdloop gc_preserve_end)
((line meta inbounds simdloop gc_preserve_end aliasscope popaliasscope)
(let ((have-ret? (and (pair? code) (pair? (car code)) (eq? (caar code) 'return))))
(cond ((eq? (car e) 'line)
(set! current-loc e)
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Expand Up @@ -999,6 +999,7 @@ extern jl_sym_t *structtype_sym; extern jl_sym_t *foreigncall_sym;
extern jl_sym_t *global_sym; extern jl_sym_t *list_sym;
extern jl_sym_t *dot_sym; extern jl_sym_t *newvar_sym;
extern jl_sym_t *boundscheck_sym; extern jl_sym_t *inbounds_sym;
extern jl_sym_t *aliasscope_sym; extern jl_sym_t *popaliasscope_sym;
extern jl_sym_t *copyast_sym; extern jl_sym_t *cfunction_sym;
extern jl_sym_t *pure_sym; extern jl_sym_t *simdloop_sym;
extern jl_sym_t *meta_sym; extern jl_sym_t *inert_sym;
Expand Down
3 changes: 2 additions & 1 deletion src/method.c
Expand Up @@ -37,7 +37,8 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve
if (jl_is_toplevel_only_expr(expr) || e->head == const_sym || e->head == copyast_sym ||
e->head == quote_sym || e->head == inert_sym ||
e->head == meta_sym || e->head == inbounds_sym ||
e->head == boundscheck_sym || e->head == simdloop_sym) {
e->head == boundscheck_sym || e->head == simdloop_sym || e->head == aliasscope_sym ||
e->head == popaliasscope_sym) {
// ignore these
}
else {
Expand Down
2 changes: 1 addition & 1 deletion src/staticdata.c
Expand Up @@ -62,7 +62,7 @@ static const jl_fptr_args_t id_to_fptrs[] = {
jl_f_typeassert, jl_f__apply, jl_f__apply_pure, jl_f__apply_latest, jl_f_isdefined,
jl_f_tuple, jl_f_svec, jl_f_intrinsic_call, jl_f_invoke_kwsorter,
jl_f_getfield, jl_f_setfield, jl_f_fieldtype, jl_f_nfields,
jl_f_arrayref, jl_f_arrayset, jl_f_arraysize, jl_f_apply_type,
jl_f_arrayref, jl_f_const_arrayref, jl_f_arrayset, jl_f_arraysize, jl_f_apply_type,
jl_f_applicable, jl_f_invoke, jl_f_sizeof, jl_f__expr, jl_f__typevar,
jl_f_ifelse,
NULL };
Expand Down

0 comments on commit 53405a4

Please sign in to comment.