Skip to content

Commit

Permalink
Emit simpler array bounds checks when using Polly
Browse files Browse the repository at this point in the history
This helps to enable Polly's bounds check elimination logic for
multi-dimensional array accesses which would hoist those checks
out of loops (or remove them entirely) if possible.

For example, the bounds checks that are currently emitted for an access
`A[i,j,k]` to an array `A::Array{Float32,m,n,o}` would correspond to
the following pseudo-code:

```
if (i >= m)
  out_of_bounds_error();
elseif (j >= n)
  out_of_bounds_error();
elseif (((k * n + j) * m + i) < m * n * o)
  out_of_bounds_error();
```

The expression `((k * n + j) * m + i)` is non-affine, therefore Polly
would not be able to analyze it. Instead, we now emit simpler bounds
checks for those code parts that Polly will be applied to:

```
if (i >= m)
  out_of_bounds_error();
elseif (j >= n)
  out_of_bounds_error();
elseif (k >= o)
  out_of_bounds_error();
```
  • Loading branch information
MatthiasJReisinger committed Aug 16, 2016
1 parent f5d6124 commit 32d9e28
Showing 1 changed file with 32 additions and 6 deletions.
38 changes: 32 additions & 6 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,14 @@ static void assign_arrayvar(jl_arrayvar_t &av, const jl_cgval_t &ainfo, jl_codec
builder.CreateStore(emit_arraysize(ainfo, i+1, ctx), av.sizes[i]);
}

// Returns the size of the array represented by `tinfo` for the given dimension `dim` if
// `dim` is a valid dimension, otherwise returns constant one.
static Value *emit_arraysize_for_unsafe_dim(const jl_cgval_t &tinfo, jl_value_t *ex, size_t dim,
size_t nd, jl_codectx_t *ctx)
{
return dim > nd ? ConstantInt::get(T_size, 1) : emit_arraysize(tinfo, ex, dim, ctx);
}

static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, size_t nd, jl_value_t **args,
size_t nidxs, jl_codectx_t *ctx)
{
Expand All @@ -1267,12 +1275,12 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, size_
for(size_t k=0; k < nidxs; k++) {
idxs[k] = emit_unbox(T_size, emit_expr(args[k], ctx), NULL);
}
Value *ii;
for(size_t k=0; k < nidxs; k++) {
Value *ii = builder.CreateSub(idxs[k], ConstantInt::get(T_size, 1));
ii = builder.CreateSub(idxs[k], ConstantInt::get(T_size, 1));
i = builder.CreateAdd(i, builder.CreateMul(ii, stride));
if (k < nidxs-1) {
Value *d =
k >= nd ? ConstantInt::get(T_size, 1) : emit_arraysize(ainfo, ex, k+1, ctx);
Value *d = emit_arraysize_for_unsafe_dim(ainfo, ex, k+1, nd, ctx);
#if CHECK_BOUNDS==1
if (bc) {
BasicBlock *okBB = BasicBlock::Create(jl_LLVMContext, "ib");
Expand All @@ -1287,9 +1295,27 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, size_
}
#if CHECK_BOUNDS==1
if (bc) {
Value *alen = emit_arraylen(ainfo, ex, ctx);
// if !(i < alen) goto error
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
bool check_linearized_index = true;
#ifdef USE_POLLY
// For a multi-dimensional array access the linearized index expression
// represented by `i` becomes non-affine. Bounds checks involving such
// expressions will not be able to be analyzed by Polly, thus we cannot
// use such checks in code parts to which Polly will be applied.
check_linearized_index = !ctx->polly;
#endif
if (check_linearized_index) {
// Compare the linearized index `i` against the linearized size of
// the accessed array, i.e. `if !(i < alen) goto error`.
Value *alen = emit_arraylen(ainfo, ex, ctx);
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
} else {
// We have already emitted a bounds check for each index except for
// the last one which we therefore emit here, i.e.
// `if !(last_index < last_dimension) goto error`.
Value *last_index = ii;
Value *last_dimension = emit_arraysize_for_unsafe_dim(ainfo, ex, nidxs, nd, ctx);
builder.CreateCondBr(builder.CreateICmpULT(last_index, last_dimension), endBB, failBB);
}

ctx->f->getBasicBlockList().push_back(failBB);
builder.SetInsertPoint(failBB);
Expand Down

0 comments on commit 32d9e28

Please sign in to comment.