diff --git a/base/array.jl b/base/array.jl index a1d5b63d91619..8adcd4c9aaf28 100644 --- a/base/array.jl +++ b/base/array.jl @@ -934,7 +934,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 @@ -945,14 +945,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 @@ -961,7 +961,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 @@ -970,7 +970,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 @@ -1000,7 +1000,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 @@ -1008,7 +1008,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 @@ -1016,7 +1016,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 920f37d550a7f..ffdf0f76dbf00 100644 --- a/base/base.jl +++ b/base/base.jl @@ -127,6 +127,18 @@ function precompile(f, args::Tuple) end end +macro boundscheck(yesno,blk) + quote + $(Expr(:boundscheck,yesno)) + $(esc(blk)) + $(Expr(:boundscheck,0)) + 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 666386d886233..db011be0e1a5a 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1215,4 +1215,6 @@ export @show, @printf, @sprintf, - @deprecate + @deprecate, + @boundscheck, + @inbounds diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 0307961155f35..d54a1e0bd9cc1 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -407,6 +407,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) @@ -559,6 +560,7 @@ function generic_matmatmul{T,S,R}(C::StridedVecOrMat{R}, tA, tB, A::StridedVecOr end end end + end return C end diff --git a/src/alloc.c b/src/alloc.c index dded6c40a1176..36d427cc88674 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -84,7 +84,7 @@ jl_sym_t *anonymous_sym; jl_sym_t *underscore_sym; 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 *dot_sym; jl_sym_t *boundscheck_sym; typedef struct { int64_t a; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index c41576a228b49..4f8a9cdd3f604 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -371,8 +371,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; } @@ -681,9 +683,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)); @@ -693,28 +699,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 e4c9629104e0b..39dea76131bca 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -402,6 +402,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, @@ -2057,6 +2058,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 (!strcmp(head->name, "$")) jl_error("syntax: prefix $ in non-quoted expression"); @@ -2211,6 +2229,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/interpreter.c b/src/interpreter.c index 2e1cdf537cc6f..56ae60d3e8fa5 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -349,6 +349,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 866ceb09cff4a..f73c61ad487b3 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2791,4 +2791,5 @@ void jl_init_types(void) tuple_sym = jl_symbol("tuple"); kw_sym = jl_symbol("kw"); dot_sym = jl_symbol("."); + boundscheck_sym = jl_symbol("boundscheck"); } diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 6586556581674..95d406f5de906 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1565,7 +1565,9 @@ (if (null? ranges) `(block (= ,oneresult ,expr) (type_goto ,initlabl) + (boundscheck false) (call (top setindex!) ,result ,oneresult ,ri) + (boundscheck 0) (= ,ri (call (top +) ,ri 1))) `(for ,(car ranges) ,(construct-loops (cdr ranges))))) @@ -1593,9 +1595,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) @@ -1605,7 +1608,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 0) (= ,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 fc9e9b12d70e4..2365d2d0f335b 100644 --- a/src/julia.h +++ b/src/julia.h @@ -461,6 +461,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