Skip to content

Commit

Permalink
Mark array/string/svec size range (JuliaLang#37051)
Browse files Browse the repository at this point in the history
We require the length and size to both be signed integer so mark them as such for LLVM.
This helps removing some unnecessary sign checks when calling C functions that expect a `size_t`
  • Loading branch information
yuyichao committed Aug 19, 2020
1 parent c15560e commit 72ffbf1
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1683,7 +1683,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
LoadInst *load = ctx.builder.CreateAlignedLoad(T_prjlvalue, slot_addr, sizeof(void*));
load->setAtomic(AtomicOrdering::Unordered);
tbaa_decorate(tbaa_ptrarraybuf, load);
Value *res = ctx.builder.CreateZExt(ctx.builder.CreateICmpNE(load, Constant::getNullValue(T_prjlvalue)), T_int32);
Value *res = ctx.builder.CreateZExt(ctx.builder.CreateICmpNE(load, V_rnull), T_int32);
JL_GC_POP();
return mark_or_box_ccall_result(ctx, res, retboxed, rt, unionall, static_rt);
}
Expand Down
60 changes: 48 additions & 12 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,18 +819,18 @@ static Value *emit_nthptr_addr(jl_codectx_t &ctx, Value *v, Value *idx)
idx);
}

static Value *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, Value *idx, MDNode *tbaa, Type *ptype)
static LoadInst *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, Value *idx, MDNode *tbaa, Type *ptype)
{
// p = (jl_value_t**)v; *(ptype)&p[n]
Value *vptr = emit_nthptr_addr(ctx, v, idx);
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype)));
return cast<LoadInst>(tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype))));
}

static Value *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, ssize_t n, MDNode *tbaa, Type *ptype)
static LoadInst *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, ssize_t n, MDNode *tbaa, Type *ptype)
{
// p = (jl_value_t**)v; *(ptype)&p[n]
Value *vptr = emit_nthptr_addr(ctx, v, n);
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype)));
return cast<LoadInst>(tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype))));
}

static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &v);
Expand Down Expand Up @@ -864,8 +864,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
[&](unsigned idx, jl_datatype_t *jt) { },
p.typ,
counter);
Value *datatype_or_p = (imaging_mode ? Constant::getNullValue(T_ppjlvalue) :
Constant::getNullValue(T_prjlvalue));
Value *datatype_or_p = imaging_mode ? Constant::getNullValue(T_ppjlvalue) : V_rnull;
counter = 0;
for_each_uniontype_small(
[&](unsigned idx, jl_datatype_t *jt) {
Expand Down Expand Up @@ -1017,7 +1016,7 @@ static Value *emit_datatype_abstract(jl_codectx_t &ctx, Value *dt)
static Value *emit_datatype_isprimitivetype(jl_codectx_t &ctx, Value *dt)
{
Value *immut = ctx.builder.CreateNot(emit_datatype_mutabl(ctx, dt));
Value *nofields = ctx.builder.CreateICmpEQ(emit_datatype_nfields(ctx, dt), ConstantInt::get(T_size, 0));
Value *nofields = ctx.builder.CreateICmpEQ(emit_datatype_nfields(ctx, dt), V_size0);
Value *sized = ctx.builder.CreateICmpSGT(emit_datatype_size(ctx, dt), ConstantInt::get(T_int32, 0));
return ctx.builder.CreateAnd(immut, ctx.builder.CreateAnd(nofields, sized));
}
Expand Down Expand Up @@ -1830,15 +1829,51 @@ static bool arraytype_constshape(jl_value_t *ty)
jl_is_long(jl_tparam1(ty)) && jl_unbox_long(jl_tparam1(ty)) != 1);
}

static bool arraytype_constelsize(jl_datatype_t *ty, size_t *elsz)
{
assert(jl_is_array_type(ty));
jl_value_t *ety = jl_tparam0(ty);
if (jl_has_free_typevars(ety))
return false;
// `jl_islayout_inline` requires `*elsz` and `al` to be initialized.
size_t al = 0;
*elsz = 0;
int union_max = jl_islayout_inline(ety, elsz, &al);
bool isboxed = (union_max == 0);
if (isboxed) {
*elsz = sizeof(void*);
}
else if (jl_is_primitivetype(ety)) {
// Primitive types should use the array element size, but
// this can be different from the type's size
*elsz = LLT_ALIGN(*elsz, al);
}
return true;
}

static intptr_t arraytype_maxsize(jl_value_t *ty)
{
if (!jl_is_array_type(ty))
return INTPTR_MAX;
size_t elsz;
if (arraytype_constelsize((jl_datatype_t*)ty, &elsz) || elsz == 0)
return INTPTR_MAX;
return INTPTR_MAX / elsz;
}

static Value *emit_arraysize(jl_codectx_t &ctx, const jl_cgval_t &tinfo, Value *dim)
{
Value *t = boxed(ctx, tinfo);
int o = offsetof(jl_array_t, nrows) / sizeof(void*) - 1;
MDNode *tbaa = arraytype_constshape(tinfo.typ) ? tbaa_const : tbaa_arraysize;
return emit_nthptr_recast(ctx,
auto load = emit_nthptr_recast(ctx,
t,
ctx.builder.CreateAdd(dim, ConstantInt::get(dim->getType(), o)),
tbaa, T_psize);
MDBuilder MDB(jl_LLVMContext);
auto rng = MDB.createRange(V_size0, ConstantInt::get(T_size, arraytype_maxsize(tinfo.typ)));
load->setMetadata(LLVMContext::MD_range, rng);
return load;
}

static Value *emit_arraysize(jl_codectx_t &ctx, const jl_cgval_t &tinfo, int dim)
Expand All @@ -1862,6 +1897,9 @@ static Value *emit_arraylen_prim(jl_codectx_t &ctx, const jl_cgval_t &tinfo)
MDNode *tbaa = arraytype_constshape(ty) ? tbaa_const : tbaa_arraylen;
LoadInst *len = ctx.builder.CreateAlignedLoad(addr, sizeof(size_t));
len->setOrdering(AtomicOrdering::NotAtomic);
MDBuilder MDB(jl_LLVMContext);
auto rng = MDB.createRange(V_size0, ConstantInt::get(T_size, arraytype_maxsize(tinfo.typ)));
len->setMetadata(LLVMContext::MD_range, rng);
return tbaa_decorate(tbaa, len);
#else
jl_value_t *p1 = jl_tparam1(ty); // FIXME: check that ty is an array type
Expand Down Expand Up @@ -2007,7 +2045,7 @@ static Value *emit_array_nd_index(
const jl_cgval_t *argv, size_t nidxs, jl_value_t *inbounds)
{
Value *a = boxed(ctx, ainfo);
Value *i = ConstantInt::get(T_size, 0);
Value *i = V_size0;
Value *stride = ConstantInt::get(T_size, 1);
#if CHECK_BOUNDS==1
bool bc = bounds_check_enabled(ctx, inbounds);
Expand Down Expand Up @@ -2493,9 +2531,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, con
// TODO: this Select is very bad for performance, but is necessary to work around LLVM bugs with the undef option that we want to use:
// select copy dest -> dest to simulate an undef value / conditional copy
// src_ptr = ctx.builder.CreateSelect(skip, dest, src_ptr);
nbytes = ctx.builder.CreateSelect(skip,
ConstantInt::get(T_size, 0),
nbytes);
nbytes = ctx.builder.CreateSelect(skip, V_size0, nbytes);
}
emit_memcpy(ctx, dest, tbaa_dst, src_ptr, src.tbaa, nbytes, alignment, isVolatile);
}
Expand Down
36 changes: 16 additions & 20 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ static DISubroutineType *jl_di_func_null_sig;
// constants
static Constant *V_null;
static Constant *V_rnull;
static Constant *V_size0;
static bool type_is_ghost(Type *ty)
{
return (ty == T_void || ty->isEmptyTy());
Expand Down Expand Up @@ -2690,7 +2691,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
}
else {
Value *idx_dyn = emit_unbox(ctx, T_size, idx, (jl_value_t*)jl_long_type);
error_unless(ctx, ctx.builder.CreateICmpSGT(idx_dyn, ConstantInt::get(T_size, 0)),
error_unless(ctx, ctx.builder.CreateICmpSGT(idx_dyn, V_size0),
"arraysize: dimension out of range");
BasicBlock *outBB = BasicBlock::Create(jl_LLVMContext, "outofrange", ctx.f);
BasicBlock *inBB = BasicBlock::Create(jl_LLVMContext, "inrange");
Expand Down Expand Up @@ -3058,32 +3059,27 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
// String and SimpleVector's length fields have the same layout
auto ptr = emit_bitcast(ctx, boxed(ctx, obj), T_psize);
Value *len = tbaa_decorate(tbaa_mutab, ctx.builder.CreateAlignedLoad(T_size, ptr, sizeof(size_t)));
MDBuilder MDB(jl_LLVMContext);
if (sty == jl_simplevector_type) {
auto rng = MDB.createRange(
V_size0, ConstantInt::get(T_size, INTPTR_MAX / sizeof(void*) - 1));
cast<LoadInst>(len)->setMetadata(LLVMContext::MD_range, rng);
len = ctx.builder.CreateMul(len, ConstantInt::get(T_size, sizeof(void*)));
len = ctx.builder.CreateAdd(len, ConstantInt::get(T_size, sizeof(void*)));
}
else {
auto rng = MDB.createRange(V_size0, ConstantInt::get(T_size, INTPTR_MAX));
cast<LoadInst>(len)->setMetadata(LLVMContext::MD_range, rng);
}
*ret = mark_julia_type(ctx, len, false, jl_long_type);
return true;
}
else if (jl_is_array_type(sty)) {
auto len = emit_arraylen(ctx, obj);
jl_value_t *ety = jl_tparam0(sty);
Value *elsize;
size_t elsz = 0, al = 0;
int union_max = jl_islayout_inline(ety, &elsz, &al);
bool isboxed = (union_max == 0);
if (!jl_has_free_typevars(ety)) {
if (isboxed) {
elsize = ConstantInt::get(T_size, sizeof(void*));
}
else if (jl_is_primitivetype(ety)) {
// Primitive types should use the array element size, but
// this can be different from the type's size
elsize = ConstantInt::get(T_size, LLT_ALIGN(elsz, al));
}
else {
elsize = ConstantInt::get(T_size, elsz);
}
size_t elsz;
if (arraytype_constelsize(sty, &elsz)) {
elsize = ConstantInt::get(T_size, elsz);
}
else {
elsize = ctx.builder.CreateZExt(emit_arrayelsize(ctx, obj), T_size);
Expand Down Expand Up @@ -5267,10 +5263,9 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con
tbaa_decorate(tbaa, ctx.builder.CreateStore(
ctx.builder.CreatePtrToInt(literal_pointer_val(ctx, fexpr_rt.constant), T_size),
ctx.builder.CreateConstInBoundsGEP1_32(T_size, derived_strct, 1)));
Value *zero = ConstantInt::get(T_size, 0);
tbaa_decorate(tbaa, ctx.builder.CreateStore(zero,
tbaa_decorate(tbaa, ctx.builder.CreateStore(V_size0,
ctx.builder.CreateConstInBoundsGEP1_32(T_size, derived_strct, 2)));
tbaa_decorate(tbaa, ctx.builder.CreateStore(zero,
tbaa_decorate(tbaa, ctx.builder.CreateStore(V_size0,
ctx.builder.CreateConstInBoundsGEP1_32(T_size, derived_strct, 3)));
F = strct;
}
Expand Down Expand Up @@ -7374,6 +7369,7 @@ static void init_julia_llvm_env(Module *m)
T_pprjlvalue = PointerType::get(T_prjlvalue, 0);
V_null = Constant::getNullValue(T_pjlvalue);
V_rnull = Constant::getNullValue(T_prjlvalue);
V_size0 = Constant::getNullValue(T_size);

std::vector<Type*> ftargs(0);
ftargs.push_back(T_prjlvalue); // function
Expand Down

0 comments on commit 72ffbf1

Please sign in to comment.