Skip to content

Commit 66ab577

Browse files
committed
macros for turning off bounds checks. fixes #1392
`@inbounds expr` allows bounds checks to be omitted for code syntactically inside the argument expression. adds @inbounds to matmul, comprehensions, and vectorized binary operators.
1 parent 5af0445 commit 66ab577

File tree

11 files changed

+91
-35
lines changed

11 files changed

+91
-35
lines changed

base/array.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,7 @@ for f in (:+, :-, :div, :mod, :&, :|, :$)
934934
function ($f){S,T}(A::StridedArray{S}, B::StridedArray{T})
935935
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
936936
for i=1:length(A)
937-
F[i] = ($f)(A[i], B[i])
937+
@inbounds F[i] = ($f)(A[i], B[i])
938938
end
939939
return F
940940
end
@@ -945,14 +945,14 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
945945
function ($f){T}(A::Number, B::StridedArray{T})
946946
F = similar(B, promote_array_type(typeof(A),T))
947947
for i=1:length(B)
948-
F[i] = ($f)(A, B[i])
948+
@inbounds F[i] = ($f)(A, B[i])
949949
end
950950
return F
951951
end
952952
function ($f){T}(A::StridedArray{T}, B::Number)
953953
F = similar(A, promote_array_type(typeof(B),T))
954954
for i=1:length(A)
955-
F[i] = ($f)(A[i], B)
955+
@inbounds F[i] = ($f)(A[i], B)
956956
end
957957
return F
958958
end
@@ -961,7 +961,7 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
961961
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
962962
i = 1
963963
for b in B
964-
F[i] = ($f)(A[i], b)
964+
@inbounds F[i] = ($f)(A[i], b)
965965
i += 1
966966
end
967967
return F
@@ -970,7 +970,7 @@ for f in (:+, :-, :.*, :./, :div, :mod, :&, :|, :$)
970970
F = Array(promote_type(S,T), promote_shape(size(A),size(B)))
971971
i = 1
972972
for a in A
973-
F[i] = ($f)(a, B[i])
973+
@inbounds F[i] = ($f)(a, B[i])
974974
i += 1
975975
end
976976
return F
@@ -1000,23 +1000,23 @@ function complex{S<:Real,T<:Real}(A::Array{S}, B::Array{T})
10001000
if size(A) != size(B); error("argument dimensions must match"); end
10011001
F = similar(A, typeof(complex(zero(S),zero(T))))
10021002
for i=1:length(A)
1003-
F[i] = complex(A[i], B[i])
1003+
@inbounds F[i] = complex(A[i], B[i])
10041004
end
10051005
return F
10061006
end
10071007

10081008
function complex{T<:Real}(A::Real, B::Array{T})
10091009
F = similar(B, typeof(complex(A,zero(T))))
10101010
for i=1:length(B)
1011-
F[i] = complex(A, B[i])
1011+
@inbounds F[i] = complex(A, B[i])
10121012
end
10131013
return F
10141014
end
10151015

10161016
function complex{T<:Real}(A::Array{T}, B::Real)
10171017
F = similar(A, typeof(complex(zero(T),B)))
10181018
for i=1:length(A)
1019-
F[i] = complex(A[i], B)
1019+
@inbounds F[i] = complex(A[i], B)
10201020
end
10211021
return F
10221022
end

base/base.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ function precompile(f, args::Tuple)
127127
end
128128
end
129129

130+
macro boundscheck(yesno,blk)
131+
quote
132+
$(Expr(:boundscheck,yesno))
133+
$(esc(blk))
134+
$(Expr(:boundscheck,0))
135+
end
136+
end
137+
138+
macro inbounds(blk)
139+
:(@boundscheck false $(esc(blk)))
140+
end
141+
130142
# NOTE: Base shares Array with Core so we can add definitions to it
131143

132144
Array{T,N}(::Type{T}, d::NTuple{N,Int}) =

base/exports.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,4 +1215,6 @@ export
12151215
@show,
12161216
@printf,
12171217
@sprintf,
1218-
@deprecate
1218+
@deprecate,
1219+
@boundscheck,
1220+
@inbounds

base/linalg/matmul.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ function generic_matmatmul{T,S,R}(C::StridedVecOrMat{R}, tA, tB, A::StridedVecOr
407407
if mA == nA == nB == 2; return matmul2x2(C, tA, tB, A, B); end
408408
if mA == nA == nB == 3; return matmul3x3(C, tA, tB, A, B); end
409409

410+
@inbounds begin
410411
if isbits(R)
411412
tile_size = int(ifloor(sqrt(tilebufsize/sizeof(R))))
412413
sz = (tile_size, tile_size)
@@ -559,6 +560,7 @@ function generic_matmatmul{T,S,R}(C::StridedVecOrMat{R}, tA, tB, A::StridedVecOr
559560
end
560561
end
561562
end
563+
end
562564
return C
563565
end
564566

src/alloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jl_sym_t *anonymous_sym; jl_sym_t *underscore_sym;
8484
jl_sym_t *abstracttype_sym; jl_sym_t *bitstype_sym;
8585
jl_sym_t *compositetype_sym; jl_sym_t *type_goto_sym;
8686
jl_sym_t *global_sym; jl_sym_t *tuple_sym;
87-
jl_sym_t *dot_sym;
87+
jl_sym_t *dot_sym; jl_sym_t *boundscheck_sym;
8888

8989
typedef struct {
9090
int64_t a;

src/cgutils.cpp

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,10 @@ static Value *emit_bounds_check(Value *i, Value *len, jl_codectx_t *ctx)
371371
{
372372
Value *im1 = builder.CreateSub(i, ConstantInt::get(T_size, 1));
373373
#if CHECK_BOUNDS==1
374-
Value *ok = builder.CreateICmpULT(im1, len);
375-
raise_exception_unless(ok, jlboundserr_var, ctx);
374+
if (ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) {
375+
Value *ok = builder.CreateICmpULT(im1, len);
376+
raise_exception_unless(ok, jlboundserr_var, ctx);
377+
}
376378
#endif
377379
return im1;
378380
}
@@ -681,9 +683,13 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_
681683
{
682684
Value *i = ConstantInt::get(T_size, 0);
683685
Value *stride = ConstantInt::get(T_size, 1);
686+
bool bc = ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true;
684687
#if CHECK_BOUNDS==1
685-
BasicBlock *failBB = BasicBlock::Create(getGlobalContext(), "oob");
686-
BasicBlock *endBB = BasicBlock::Create(getGlobalContext(), "idxend");
688+
BasicBlock *failBB=NULL, *endBB=NULL;
689+
if (bc) {
690+
failBB = BasicBlock::Create(getGlobalContext(), "oob");
691+
endBB = BasicBlock::Create(getGlobalContext(), "idxend");
692+
}
687693
#endif
688694
for(size_t k=0; k < nidxs; k++) {
689695
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_
693699
Value *d =
694700
k >= nd ? ConstantInt::get(T_size, 1) : emit_arraysize(a, ex, k+1, ctx);
695701
#if CHECK_BOUNDS==1
696-
BasicBlock *okBB = BasicBlock::Create(getGlobalContext(), "ib");
697-
// if !(i < d) goto error
698-
builder.CreateCondBr(builder.CreateICmpULT(ii, d), okBB, failBB);
699-
ctx->f->getBasicBlockList().push_back(okBB);
700-
builder.SetInsertPoint(okBB);
702+
if (bc) {
703+
BasicBlock *okBB = BasicBlock::Create(getGlobalContext(), "ib");
704+
// if !(i < d) goto error
705+
builder.CreateCondBr(builder.CreateICmpULT(ii, d), okBB, failBB);
706+
ctx->f->getBasicBlockList().push_back(okBB);
707+
builder.SetInsertPoint(okBB);
708+
}
701709
#endif
702710
stride = builder.CreateMul(stride, d);
703711
}
704712
}
705713
#if CHECK_BOUNDS==1
706-
Value *alen = emit_arraylen(a, ex, ctx);
707-
// if !(i < alen) goto error
708-
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
709-
710-
ctx->f->getBasicBlockList().push_back(failBB);
711-
builder.SetInsertPoint(failBB);
712-
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
713-
ConstantInt::get(T_int32, ctx->lineno));
714-
builder.CreateUnreachable();
715-
716-
ctx->f->getBasicBlockList().push_back(endBB);
717-
builder.SetInsertPoint(endBB);
714+
if (bc) {
715+
Value *alen = emit_arraylen(a, ex, ctx);
716+
// if !(i < alen) goto error
717+
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
718+
719+
ctx->f->getBasicBlockList().push_back(failBB);
720+
builder.SetInsertPoint(failBB);
721+
builder.CreateCall2(jlthrow_line_func, builder.CreateLoad(jlboundserr_var),
722+
ConstantInt::get(T_int32, ctx->lineno));
723+
builder.CreateUnreachable();
724+
725+
ctx->f->getBasicBlockList().push_back(endBB);
726+
builder.SetInsertPoint(endBB);
727+
}
718728
#endif
719729

720730
return i;

src/codegen.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ typedef struct {
402402
bool vaStack; // varargs stack-allocated
403403
int nReqArgs;
404404
int lineno;
405+
std::vector<bool> boundsCheck;
405406
} jl_codectx_t;
406407

407408
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,
20572058
#endif
20582059
builder.SetInsertPoint(tryblk);
20592060
}
2061+
else if (head == boundscheck_sym) {
2062+
if (jl_array_len(ex->args) > 0) {
2063+
jl_value_t *arg = args[0];
2064+
if (arg == jl_true) {
2065+
ctx->boundsCheck.push_back(true);
2066+
}
2067+
else if (arg == jl_false) {
2068+
ctx->boundsCheck.push_back(false);
2069+
}
2070+
else {
2071+
if (!ctx->boundsCheck.empty())
2072+
ctx->boundsCheck.pop_back();
2073+
}
2074+
}
2075+
if (valuepos)
2076+
return literal_pointer_val((jl_value_t*)jl_nothing);
2077+
}
20602078
else {
20612079
if (!strcmp(head->name, "$"))
20622080
jl_error("syntax: prefix $ in non-quoted expression");
@@ -2211,6 +2229,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
22112229
ctx.funcName = lam->name->name;
22122230
ctx.vaName = NULL;
22132231
ctx.vaStack = false;
2232+
ctx.boundsCheck.push_back(true);
22142233

22152234
// step 2. process var-info lists to see what vars are captured, need boxing
22162235
jl_array_t *largs = jl_lam_args(ast);

src/interpreter.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl)
349349
jl_errorf("syntax: %s", jl_string_data(args[0]));
350350
jl_throw(args[0]);
351351
}
352+
else if (ex->head == boundscheck_sym) {
353+
return (jl_value_t*)jl_nothing;
354+
}
352355
jl_errorf("unsupported or misplaced expression %s", ex->head->name);
353356
return (jl_value_t*)jl_nothing;
354357
}

src/jltypes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,4 +2791,5 @@ void jl_init_types(void)
27912791
tuple_sym = jl_symbol("tuple");
27922792
kw_sym = jl_symbol("kw");
27932793
dot_sym = jl_symbol(".");
2794+
boundscheck_sym = jl_symbol("boundscheck");
27942795
}

src/julia-syntax.scm

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,7 +1565,9 @@
15651565
(if (null? ranges)
15661566
`(block (= ,oneresult ,expr)
15671567
(type_goto ,initlabl)
1568+
(boundscheck false)
15681569
(call (top setindex!) ,result ,oneresult ,ri)
1570+
(boundscheck 0)
15691571
(= ,ri (call (top +) ,ri 1)))
15701572
`(for ,(car ranges)
15711573
,(construct-loops (cdr ranges)))))
@@ -1593,9 +1595,10 @@
15931595
(typed_comprehension atype expr . ranges)
15941596
(if (any (lambda (x) (eq? x ':)) ranges)
15951597
(lower-nd-comprehension atype expr ranges)
1596-
(let ( (result (gensy))
1597-
(ri (gensy))
1598-
(rs (map (lambda (x) (gensy)) ranges)) )
1598+
(let ((result (gensy))
1599+
(oneresult (gensy))
1600+
(ri (gensy))
1601+
(rs (map (lambda (x) (gensy)) ranges)) )
15991602

16001603
;; compute the dimensions of the result
16011604
(define (compute-dims ranges)
@@ -1605,7 +1608,10 @@
16051608
;; construct loops to cycle over all dimensions of an n-d comprehension
16061609
(define (construct-loops ranges rs)
16071610
(if (null? ranges)
1608-
`(block (call (top setindex!) ,result ,expr ,ri)
1611+
`(block (= ,oneresult ,expr)
1612+
(boundscheck false)
1613+
(call (top setindex!) ,result ,oneresult ,ri)
1614+
(boundscheck 0)
16091615
(= ,ri (call (top +) ,ri 1)))
16101616
`(for (= ,(cadr (car ranges)) ,(car rs))
16111617
,(construct-loops (cdr ranges) (cdr rs)))))

0 commit comments

Comments
 (0)