Skip to content

Commit

Permalink
Merge pull request #3268 from JuliaLang/jb/inbounds
Browse files Browse the repository at this point in the history
RFC: macros for disabling bounds checks
  • Loading branch information
JeffBezanson committed Jul 5, 2013
2 parents d852e9c + e0cdf63 commit c575c41
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 35 deletions.
16 changes: 8 additions & 8 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,7 @@ for f in (:+, :-, :div, :mod, :&, :|, :$)
function ($f){S,T}(A::StridedArray{S}, B::StridedArray{T})
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
for i=1:length(A)
F[i] = ($f)(A[i], B[i])
@inbounds F[i] = ($f)(A[i], B[i])
end
return F
end
Expand All @@ -951,14 +951,14 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
function ($f){T}(A::Number, B::StridedArray{T})
F = similar(B, promote_array_type(typeof(A),T))
for i=1:length(B)
F[i] = ($f)(A, B[i])
@inbounds F[i] = ($f)(A, B[i])
end
return F
end
function ($f){T}(A::StridedArray{T}, B::Number)
F = similar(A, promote_array_type(typeof(B),T))
for i=1:length(A)
F[i] = ($f)(A[i], B)
@inbounds F[i] = ($f)(A[i], B)
end
return F
end
Expand All @@ -967,7 +967,7 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
i = 1
for b in B
F[i] = ($f)(A[i], b)
@inbounds F[i] = ($f)(A[i], b)
i += 1
end
return F
Expand All @@ -976,7 +976,7 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
i = 1
for a in A
F[i] = ($f)(a, B[i])
@inbounds F[i] = ($f)(a, B[i])
i += 1
end
return F
Expand Down Expand Up @@ -1006,23 +1006,23 @@ function complex{S<:Real,T<:Real}(A::Array{S}, B::Array{T})
if size(A) != size(B); error("argument dimensions must match"); end
F = similar(A, typeof(complex(zero(S),zero(T))))
for i=1:length(A)
F[i] = complex(A[i], B[i])
@inbounds F[i] = complex(A[i], B[i])
end
return F
end

function complex{T<:Real}(A::Real, B::Array{T})
F = similar(B, typeof(complex(A,zero(T))))
for i=1:length(B)
F[i] = complex(A, B[i])
@inbounds F[i] = complex(A, B[i])
end
return F
end

function complex{T<:Real}(A::Array{T}, B::Real)
F = similar(A, typeof(complex(zero(T),B)))
for i=1:length(A)
F[i] = complex(A[i], B)
@inbounds F[i] = complex(A[i], B)
end
return F
end
Expand Down
12 changes: 12 additions & 0 deletions base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ function precompile(f, args::Tuple)
end
end

macro boundscheck(yesno,blk)
quote
$(Expr(:boundscheck,yesno))
$(esc(blk))
$(Expr(:boundscheck,:pop))
end
end

macro inbounds(blk)
:(@boundscheck false $(esc(blk)))
end

# NOTE: Base shares Array with Core so we can add definitions to it

Array{T,N}(::Type{T}, d::NTuple{N,Int}) =
Expand Down
4 changes: 3 additions & 1 deletion base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1254,4 +1254,6 @@ export
@show,
@printf,
@sprintf,
@deprecate
@deprecate,
@boundscheck,
@inbounds
2 changes: 2 additions & 0 deletions base/linalg/matmul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ function generic_matmatmul{T,S,R}(C::StridedVecOrMat{R}, tA, tB, A::StridedVecOr
if mA == nA == nB == 2; return matmul2x2(C, tA, tB, A, B); end
if mA == nA == nB == 3; return matmul3x3(C, tA, tB, A, B); end

@inbounds begin
if isbits(R)
tile_size = int(ifloor(sqrt(tilebufsize/sizeof(R))))
sz = (tile_size, tile_size)
Expand Down Expand Up @@ -562,6 +563,7 @@ function generic_matmatmul{T,S,R}(C::StridedVecOrMat{R}, tA, tB, A::StridedVecOr
end
end
end
end # @inbounds
return C
end

Expand Down
1 change: 1 addition & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ jl_sym_t *abstracttype_sym; jl_sym_t *bitstype_sym;
jl_sym_t *compositetype_sym; jl_sym_t *type_goto_sym;
jl_sym_t *global_sym; jl_sym_t *tuple_sym;
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
jl_sym_t *boundscheck_sym;

typedef struct {
int64_t a;
Expand Down
52 changes: 31 additions & 21 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,10 @@ static Value *emit_bounds_check(Value *i, Value *len, jl_codectx_t *ctx)
{
Value *im1 = builder.CreateSub(i, ConstantInt::get(T_size, 1));
#if CHECK_BOUNDS==1
Value *ok = builder.CreateICmpULT(im1, len);
raise_exception_unless(ok, jlboundserr_var, ctx);
if (ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) {
Value *ok = builder.CreateICmpULT(im1, len);
raise_exception_unless(ok, jlboundserr_var, ctx);
}
#endif
return im1;
}
Expand Down Expand Up @@ -683,9 +685,13 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_
{
Value *i = ConstantInt::get(T_size, 0);
Value *stride = ConstantInt::get(T_size, 1);
bool bc = ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true;
#if CHECK_BOUNDS==1
BasicBlock *failBB = BasicBlock::Create(getGlobalContext(), "oob");
BasicBlock *endBB = BasicBlock::Create(getGlobalContext(), "idxend");
BasicBlock *failBB=NULL, *endBB=NULL;
if (bc) {
failBB = BasicBlock::Create(getGlobalContext(), "oob");
endBB = BasicBlock::Create(getGlobalContext(), "idxend");
}
#endif
for(size_t k=0; k < nidxs; k++) {
Value *ii = emit_unbox(T_size, T_psize, emit_unboxed(args[k], ctx));
Expand All @@ -695,28 +701,32 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_
Value *d =
k >= nd ? ConstantInt::get(T_size, 1) : emit_arraysize(a, ex, k+1, ctx);
#if CHECK_BOUNDS==1
BasicBlock *okBB = BasicBlock::Create(getGlobalContext(), "ib");
// if !(i < d) goto error
builder.CreateCondBr(builder.CreateICmpULT(ii, d), okBB, failBB);
ctx->f->getBasicBlockList().push_back(okBB);
builder.SetInsertPoint(okBB);
if (bc) {
BasicBlock *okBB = BasicBlock::Create(getGlobalContext(), "ib");
// if !(i < d) goto error
builder.CreateCondBr(builder.CreateICmpULT(ii, d), okBB, failBB);
ctx->f->getBasicBlockList().push_back(okBB);
builder.SetInsertPoint(okBB);
}
#endif
stride = builder.CreateMul(stride, d);
}
}
#if CHECK_BOUNDS==1
Value *alen = emit_arraylen(a, ex, ctx);
// if !(i < alen) goto error
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);

ctx->f->getBasicBlockList().push_back(failBB);
builder.SetInsertPoint(failBB);
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
ConstantInt::get(T_int32, ctx->lineno));
builder.CreateUnreachable();

ctx->f->getBasicBlockList().push_back(endBB);
builder.SetInsertPoint(endBB);
if (bc) {
Value *alen = emit_arraylen(a, ex, ctx);
// if !(i < alen) goto error
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);

ctx->f->getBasicBlockList().push_back(failBB);
builder.SetInsertPoint(failBB);
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
ConstantInt::get(T_int32, ctx->lineno));
builder.CreateUnreachable();

ctx->f->getBasicBlockList().push_back(endBB);
builder.SetInsertPoint(endBB);
}
#endif

return i;
Expand Down
19 changes: 19 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ typedef struct {
bool vaStack; // varargs stack-allocated
int nReqArgs;
int lineno;
std::vector<bool> boundsCheck;
} jl_codectx_t;

static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool boxed=true,
Expand Down Expand Up @@ -2145,6 +2146,23 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed,
#endif
builder.SetInsertPoint(tryblk);
}
else if (head == boundscheck_sym) {
if (jl_array_len(ex->args) > 0) {
jl_value_t *arg = args[0];
if (arg == jl_true) {
ctx->boundsCheck.push_back(true);
}
else if (arg == jl_false) {
ctx->boundsCheck.push_back(false);
}
else {
if (!ctx->boundsCheck.empty())
ctx->boundsCheck.pop_back();
}
}
if (valuepos)
return literal_pointer_val((jl_value_t*)jl_nothing);
}
else if (head == newvar_sym) {
jl_sym_t *var = (jl_sym_t*)args[0];
if (jl_is_symbolnode(var))
Expand Down Expand Up @@ -2318,6 +2336,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
ctx.funcName = lam->name->name;
ctx.vaName = NULL;
ctx.vaStack = false;
ctx.boundsCheck.push_back(true);

// step 2. process var-info lists to see what vars are captured, need boxing
jl_array_t *largs = jl_lam_args(ast);
Expand Down
2 changes: 1 addition & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ void jl_init_serializer(void)
jl_symbol("eq_int"), jl_symbol("slt_int"),
jl_symbol("sle_int"), jl_symbol("ne_int"),
jl_symbol("arrayset"), jl_symbol("arrayref"),
jl_symbol("arraylen"),
jl_symbol("arraylen"), jl_symbol("boundscheck"),
jl_symbol("convert"), jl_symbol("typeassert"),
jl_symbol("getfield"), jl_symbol("setfield"),
jl_symbol("tupleref"), jl_symbol("tuplelen"),
Expand Down
3 changes: 3 additions & 0 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl)
jl_errorf("syntax: %s", jl_string_data(args[0]));
jl_throw(args[0]);
}
else if (ex->head == boundscheck_sym) {
return (jl_value_t*)jl_nothing;
}
jl_errorf("unsupported or misplaced expression %s", ex->head->name);
return (jl_value_t*)jl_nothing;
}
Expand Down
1 change: 1 addition & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2794,5 +2794,6 @@ void jl_init_types(void)
tuple_sym = jl_symbol("tuple");
kw_sym = jl_symbol("kw");
dot_sym = jl_symbol(".");
boundscheck_sym = jl_symbol("boundscheck");
newvar_sym = jl_symbol("newvar");
}
14 changes: 10 additions & 4 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,9 @@
(if (null? ranges)
`(block (= ,oneresult ,expr)
(type_goto ,initlabl)
(boundscheck false)
(call (top setindex!) ,result ,oneresult ,ri)
(boundscheck pop)
(= ,ri (call (top +) ,ri 1)))
`(for ,(car ranges)
,(construct-loops (cdr ranges)))))
Expand Down Expand Up @@ -1613,9 +1615,10 @@
(typed_comprehension atype expr . ranges)
(if (any (lambda (x) (eq? x ':)) ranges)
(lower-nd-comprehension atype expr ranges)
(let ( (result (gensy))
(ri (gensy))
(rs (map (lambda (x) (gensy)) ranges)) )
(let ((result (gensy))
(oneresult (gensy))
(ri (gensy))
(rs (map (lambda (x) (gensy)) ranges)) )

;; compute the dimensions of the result
(define (compute-dims ranges)
Expand All @@ -1625,7 +1628,10 @@
;; construct loops to cycle over all dimensions of an n-d comprehension
(define (construct-loops ranges rs)
(if (null? ranges)
`(block (call (top setindex!) ,result ,expr ,ri)
`(block (= ,oneresult ,expr)
(boundscheck false)
(call (top setindex!) ,result ,oneresult ,ri)
(boundscheck pop)
(= ,ri (call (top +) ,ri 1)))
`(for (= ,(cadr (car ranges)) ,(car rs))
,(construct-loops (cdr ranges) (cdr rs)))))
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ extern jl_sym_t *anonymous_sym; extern jl_sym_t *underscore_sym;
extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym;
extern jl_sym_t *compositetype_sym; extern jl_sym_t *type_goto_sym;
extern jl_sym_t *global_sym; extern jl_sym_t *tuple_sym;
extern jl_sym_t *boundscheck_sym;


#ifdef _P64
Expand Down

0 comments on commit c575c41

Please sign in to comment.