diff --git a/base/array.jl b/base/array.jl index c82a053c66538..84af3cb766919 100644 --- a/base/array.jl +++ b/base/array.jl @@ -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 @@ -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 @@ -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 @@ -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 @@ -1006,7 +1006,7 @@ 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 @@ -1014,7 +1014,7 @@ 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 @@ -1022,7 +1022,7 @@ 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 diff --git a/base/base.jl b/base/base.jl index 693a3f570aef2..a542d1b05700b 100644 --- a/base/base.jl +++ b/base/base.jl @@ -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}) = diff --git a/base/exports.jl b/base/exports.jl index 7ea3062faee20..740bd38c4ef24 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1254,4 +1254,6 @@ export @show, @printf, @sprintf, - @deprecate + @deprecate, + @boundscheck, + @inbounds diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 8e121d84b0b00..4bf1d5f80a0bc 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -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) @@ -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 diff --git a/src/alloc.c b/src/alloc.c index 34c31442a6c0d..a0f19571c2f92 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -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; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index de71fe1334181..1736bfadf7be2 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -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; } @@ -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)); @@ -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; diff --git a/src/codegen.cpp b/src/codegen.cpp index e577faf1b87bb..3cbc189f27c60 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -383,6 +383,7 @@ typedef struct { bool vaStack; // varargs stack-allocated int nReqArgs; int lineno; + std::vector boundsCheck; } jl_codectx_t; static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool boxed=true, @@ -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)) @@ -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); diff --git a/src/dump.c b/src/dump.c index 88c160b7afef4..4d1dc0ddac042 100644 --- a/src/dump.c +++ b/src/dump.c @@ -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"), diff --git a/src/interpreter.c b/src/interpreter.c index 5b9e6c179f4aa..e4ecfe9dbb75f 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -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; } diff --git a/src/jltypes.c b/src/jltypes.c index 22ab1570416e3..e7d545143f348 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -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"); } diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index a58725b95abf1..384483a53700f 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -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))))) @@ -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) @@ -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))))) diff --git a/src/julia.h b/src/julia.h index 1591a32d6aec3..7412ba4bb3c08 100644 --- a/src/julia.h +++ b/src/julia.h @@ -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