From bb1260f96b930edc847d0726f63f4a9f12b21236 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 10 Jul 2015 23:00:32 -0400 Subject: [PATCH 1/3] WIP: Implement #11902 This is WIP towards #11902. Only bits tuples are supported, and this has only so far been tested on Mac/LLVM37 --- base/boot.jl | 2 +- base/inference.jl | 1 + base/refpointer.jl | 5 ++ src/builtin_proto.h | 1 + src/builtins.c | 52 ++++++++++++++++ src/cgutils.cpp | 89 ++++++++++++++++----------- src/codegen.cpp | 143 +++++++++++++++++++++++++++++++++++++++++--- src/dump.c | 4 +- test/core.jl | 19 ++++++ 9 files changed, 272 insertions(+), 44 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index b95d541127e42..b03f229b48003 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -146,7 +146,7 @@ export Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode, GlobalRef, NewvarNode, GenSym, # object model functions - fieldtype, getfield, setfield!, nfields, throw, tuple, is, ===, isdefined, + fieldtype, getfield, setfield!, modifyelement, nfields, throw, tuple, is, ===, isdefined, # arraylen, arrayref, arrayset, arraysize, # _apply, kwcall, # sizeof # not exported, to avoid conflicting with Base.sizeof diff --git a/base/inference.jl b/base/inference.jl index c4e23c8f41c96..21e2e82911a40 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -321,6 +321,7 @@ const getfield_tfunc = function (A, s0, name) end add_tfunc(getfield, 2, 2, (A,s,name)->getfield_tfunc(A,s,name)[1]) add_tfunc(setfield!, 3, 3, (o, f, v)->v) +add_tfunc(modifyelement, 3, 3, (args...)->Void) const fieldtype_tfunc = function (A, s, name) if isType(s) s = s.parameters[1] diff --git a/base/refpointer.jl b/base/refpointer.jl index 67a3b5e052061..c1f4f87cfbeb4 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -37,6 +37,11 @@ function unsafe_convert(P::Type{Ptr{Any}}, b::RefValue{Any}) end unsafe_convert{T}(::Type{Ptr{Void}}, b::RefValue{T}) = convert(Ptr{Void}, unsafe_convert(Ptr{T}, b)) +function setindex!{T<:Tuple}(x::RefValue{T}, val, idxs...) + Core.modifyelement(x, idxs, val) + val +end + ### Methods for a Ref object that is backed by an array at index i immutable RefArray{T, A<:AbstractArray, R} <: Ref{T} x::A diff --git a/src/builtin_proto.h b/src/builtin_proto.h index e4bb2187ff9c9..2efb6275c6a3a 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -24,6 +24,7 @@ JL_CALLABLE(jl_f_tuple); JL_CALLABLE(jl_f_svec); JL_CALLABLE(jl_f_get_field); JL_CALLABLE(jl_f_set_field); +JL_CALLABLE(jl_f_modifyelement); JL_CALLABLE(jl_f_field_type); JL_CALLABLE(jl_f_arraylen); JL_CALLABLE(jl_f_arrayref); diff --git a/src/builtins.c b/src/builtins.c index 364356335febc..6025fb9a6da8a 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -717,6 +717,57 @@ JL_CALLABLE(jl_f_set_field) return args[2]; } +static uint8_t *_getelmentptr(uint8_t *ptr, size_t idx, jl_datatype_t *st) +{ + if (idx >= jl_datatype_nfields(st)) + jl_bounds_error_int((jl_value_t*)st, idx+1); + return (uint8_t*)(ptr + jl_field_offset(st,idx)); +} + +JL_CALLABLE(jl_f_modifyelement) +{ + JL_NARGS(modifyelement, 3, 3) + jl_value_t *v = args[0]; + jl_value_t *vt = jl_typeof(v); + if (!jl_is_ref_type(vt)) + jl_type_error("modifyelement", (jl_value_t*)jl_ref_type, v); + jl_value_t *tt = jl_tparam0(vt); + if (!jl_is_datatype(tt)) + jl_type_error("modifyelement", (jl_value_t*)jl_datatype_type, v); + if (!jl_is_tuple_type(tt)) + jl_type_error("modifyelement", (jl_value_t*)jl_tuple_type, v); + if (!jl_isbits(tt)) + jl_error("modifyelement currently only applies to isbits tuples"); + jl_datatype_t *st = (jl_datatype_t*)tt; + uint8_t *ptr = (uint8_t*)v; + jl_value_t *tpl_type = (jl_value_t*)st; + if (jl_is_long(args[1])) { + size_t idx = jl_unbox_long(args[1])-1; + ptr = _getelmentptr(ptr, idx, st); + tpl_type = jl_field_type(tpl_type, idx); + } else { + jl_value_t *idxval = NULL; + JL_TYPECHK(modifyelement, tuple, args[1]); + JL_GC_PUSH2(&idxval, &tpl_type); + for (int idx = 0; idx < jl_nfields(args[1]); ++idx) { + idxval = jl_get_nth_field(args[1], idx); + if (!jl_is_long(idxval)) + jl_error("modifyelement can only take Ints or tuples thereof"); + size_t tplidx = jl_unbox_long(idxval)-1; + if (!jl_is_datatype(tpl_type)) + jl_type_error("modifyelement", (jl_value_t*)jl_datatype_type, tpl_type); + ptr = _getelmentptr(ptr, tplidx, (jl_datatype_t*)tpl_type); + tpl_type = jl_field_type(tpl_type, tplidx); + } + JL_GC_POP(); + } + if (jl_typeof(args[2]) != tpl_type) + jl_type_error("modifyelement", (jl_value_t*)tpl_type, args[2]); + jl_assign_bits(ptr,args[2]); + jl_gc_wb(args[0],args[2]); + return jl_nothing; +} + JL_CALLABLE(jl_f_field_type) { JL_NARGS(fieldtype, 2, 2); @@ -1186,6 +1237,7 @@ void jl_init_primitives(void) // functions for internal use add_builtin_func("getfield", jl_f_get_field); add_builtin_func("setfield!", jl_f_set_field); + add_builtin_func("modifyelement", jl_f_modifyelement); add_builtin_func("fieldtype", jl_f_field_type); add_builtin_func("nfields", jl_f_nfields); add_builtin_func("_expr", jl_f_new_expr); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 92d1edd7de990..e4abd4208ee5b 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1091,9 +1091,9 @@ static Value *emit_bounds_check(Value *a, jl_value_t *ty, Value *i, Value *len, } else { #ifdef LLVM37 - builder.CreateCall(prepare_call(jlboundserror_func), { a, i }); + builder.CreateCall(prepare_call(jlboundserrorint_func), { a, i }); #else - builder.CreateCall2(prepare_call(jlboundserror_func), a, i); + builder.CreateCall2(prepare_call(jlboundserrorint_func), a, i); #endif } builder.CreateUnreachable(); @@ -1363,6 +1363,35 @@ static Value *emit_getfield_unknownidx(Value *strct, Value *idx, jl_datatype_t * return NULL; } +static Value *emit_gep_knownidx(Value *strct, ArrayRef idxs, jl_datatype_t *jt) +{ + Type *strctty = julia_struct_to_llvm((jl_value_t*)jt); + if (strct->getType() == jl_pvalue_llvmt) + strct = builder.CreateBitCast(strct, PointerType::get(strctty,0)); + return builder.CreateInBoundsGEP(strctty, strct, idxs); +} + +static Value *emit_gep_knownidx(Value *strct, unsigned idx, jl_datatype_t *jt) +{ + Value *addr; + if (strct->getType() == jl_pvalue_llvmt) { + addr = builder.CreateGEP(builder.CreateBitCast(strct, T_pint8), + ConstantInt::get(T_size, jl_field_offset(jt,idx))); + } + else if (strct->getType()->isPointerTy()) { // something stack allocated +# ifdef LLVM37 + addr = builder.CreateConstInBoundsGEP2_32( + cast(strct->getType()->getScalarType())->getElementType(), + strct, 0, idx); +# else + addr = builder.CreateConstInBoundsGEP2_32(strct, 0, idx); +# endif + } else { + assert(false && "Cannot call GEP on this"); + } + return addr; +} + static Value *emit_getfield_knownidx(Value *strct, unsigned idx, jl_datatype_t *jt, jl_codectx_t *ctx) { jl_value_t *jfty = jl_field_type(jt,idx); @@ -1375,39 +1404,31 @@ static Value *emit_getfield_knownidx(Value *strct, unsigned idx, jl_datatype_t * if (elty == T_void) return ghostValue(jfty); Value *fldv = NULL; - if (strct->getType() == jl_pvalue_llvmt) { - Value *addr = - builder.CreateGEP(builder.CreateBitCast(strct, T_pint8), - ConstantInt::get(T_size, jl_field_offset(jt,idx))); - MDNode *tbaa = jt->mutabl ? tbaa_user : tbaa_immut; - if (jl_field_isptr(jt,idx)) { - Value *fldv = tbaa_decorate(tbaa, builder.CreateLoad(builder.CreateBitCast(addr,jl_ppvalue_llvmt))); - if (idx >= (unsigned)jt->ninitialized) - null_pointer_check(fldv, ctx); - return fldv; - } - else { - int align = jl_field_offset(jt,idx); - if (align & 1) align = 1; - else if (align & 2) align = 2; - else if (align & 4) align = 4; - else if (align & 8) align = 8; - else align = 16; - return typed_load(addr, ConstantInt::get(T_size, 0), jfty, ctx, tbaa, align); + + if (strct->getType() == jl_pvalue_llvmt || strct->getType()->isPointerTy()) { + Value *addr = emit_gep_knownidx(strct, idx, jt); + if (strct->getType() == jl_pvalue_llvmt) { + MDNode *tbaa = jt->mutabl ? tbaa_user : tbaa_immut; + if (jl_field_isptr(jt,idx)) { + Value *fldv = tbaa_decorate(tbaa, builder.CreateLoad(builder.CreateBitCast(addr,jl_ppvalue_llvmt))); + if (idx >= (unsigned)jt->ninitialized) + null_pointer_check(fldv, ctx); + return fldv; + } + else { + int align = jl_field_offset(jt,idx); + if (align & 1) align = 1; + else if (align & 2) align = 2; + else if (align & 4) align = 4; + else if (align & 8) align = 8; + else align = 16; + return typed_load(addr, ConstantInt::get(T_size, 0), jfty, ctx, tbaa, align); + } + } else { + assert(!jt->mutabl); + return typed_load(addr, NULL, jfty, ctx, NULL); } - } - else if (strct->getType()->isPointerTy()) { // something stack allocated -# ifdef LLVM37 - Value *addr = builder.CreateConstInBoundsGEP2_32( - cast(strct->getType()->getScalarType())->getElementType(), - strct, 0, idx); -# else - Value *addr = builder.CreateConstInBoundsGEP2_32(strct, 0, idx); -# endif - assert(!jt->mutabl); - return typed_load(addr, NULL, jfty, ctx, NULL); - } - else { + } else { assert(strct->getType()->isVectorTy()); fldv = builder.CreateExtractElement(strct, ConstantInt::get(T_int32, idx)); if (jfty == (jl_value_t*)jl_bool_type) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2fd62c8fb4611..6b4d4a2a823c5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -288,6 +288,7 @@ static Function *jlthrow_line_func; static Function *jlerror_func; static Function *jltypeerror_func; static Function *jlundefvarerror_func; +static Function *jlboundserrorint_func; static Function *jlboundserror_func; static Function *jluboundserror_func; static Function *jlvboundserror_func; @@ -2488,6 +2489,123 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } // TODO: faster code for integer index } + else if (f->fptr == &jl_f_modifyelement && nargs == 3) { + jl_datatype_t *sty = (jl_datatype_t*)expr_type(args[1], ctx); + // First check if this is a constant index + bool isconstidx = jl_is_long(args[2]); + if (!isconstidx && jl_is_tuple(args[2])) { + isconstidx = true; + jl_datatype_t *tt = (jl_datatype_t*)jl_typeof(args[2]); + for (size_t i = 0; i < jl_nfields(args[2]); ++i) { + if ((jl_datatype_t*)jl_field_type(tt, i) != jl_long_type) { + isconstidx = false; + break; + } + } + } + + rt1 = (jl_value_t*)sty; + if (jl_is_ref_type((jl_value_t*)sty)) { + jl_datatype_t *tt = (jl_datatype_t*)jl_tparam0(sty); + if (jl_is_tuple_type(tt)){ + Value *addr = NULL; + Value *strct = NULL; + jl_datatype_t *fieldty; + if (isconstidx) { + if (jl_is_long(args[2])) { + size_t idx = jl_unbox_long(args[2]) - 1; + if (idx < jl_datatype_nfields(sty)) { + Value *strct = emit_expr(args[1], ctx); + addr = emit_gep_knownidx(strct, idx, sty); + fieldty = (jl_datatype_t*)jl_field_type(tt, idx); + } + } + else { + // First check bounds, then emit code + bool boundsok = true; + fieldty = tt; + for (size_t i = 0; i < jl_nfields(args[2]); ++i) { + unsigned idx = jl_unbox_long(jl_get_nth_field(args[2],i))-1; + if (idx >= jl_datatype_nfields(fieldty)) { + boundsok = false; + break; + } + fieldty = (jl_datatype_t*)jl_field_type(fieldty, idx); + } + if (boundsok) { + Value *strct = emit_expr(args[1], ctx); + std::vector idxs; + idxs.push_back(ConstantInt::get(T_int32, 0)); + idxs.push_back(ConstantInt::get(T_int32, 0)); + for (size_t i = 0; i < jl_nfields(args[2]); ++i) + idxs.push_back(ConstantInt::get(T_int32, jl_unbox_long(jl_get_nth_field(args[2],i))-1)); + addr = emit_gep_knownidx(strct, idxs, sty); + } + } + } else { + // Not const index, first check if the tuple is homogeneous to the required depth + jl_datatype_t *idxty = (jl_datatype_t*)expr_type(args[2], ctx); + int depth = idxty == jl_long_type ? 1 : jl_is_tuple_type(idxty) ? + jl_svec_len(idxty->types) : 0; + if (depth != 0) { + fieldty = tt; + bool ishomogeneous = true; + for (size_t i = 0; i < depth; ++i) { + if (!is_tupletype_homogeneous(fieldty->types)) { + ishomogeneous = false; + break; + } + fieldty = (jl_datatype_t*)jl_field_type(fieldty,0); + } + if (ishomogeneous) { + // Now we know we can emit this efficiently + strct = emit_expr(args[1], ctx); + Value *idxval = emit_expr(args[2], ctx); + // Emit boundscheck + std::vector idxs; + idxs.push_back(ConstantInt::get(T_int32, 0)); + idxs.push_back(ConstantInt::get(T_int32, 0)); + fieldty = tt; + Value *bndacc = ConstantInt::get(T_int1, 1); + for (size_t i = 0; i < depth; ++i) { + Value *idx = builder.CreateSub( + emit_getfield_knownidx(idxval, i, idxty, ctx), + ConstantInt::get(T_size, 1)); + // For bounds check + Value *ok = builder.CreateICmpULT(idx, + ConstantInt::get(T_size, jl_datatype_nfields(fieldty))); + bndacc = builder.CreateAnd(ok,bndacc); + idxs.push_back(idx); + fieldty = (jl_datatype_t*)jl_field_type(fieldty,0); + } + if (((ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) && + jl_options.check_bounds != JL_OPTIONS_CHECK_BOUNDS_OFF) || + jl_options.check_bounds == JL_OPTIONS_CHECK_BOUNDS_ON) { + BasicBlock *failBB = BasicBlock::Create(getGlobalContext(),"fail",ctx->f); + BasicBlock *passBB = BasicBlock::Create(getGlobalContext(),"pass",ctx->f); + builder.CreateCondBr(bndacc, passBB, failBB); + builder.SetInsertPoint(failBB); + builder.CreateCall(prepare_call(jlboundserror_func), { + boxed(strct, ctx), boxed(idxval, ctx, (jl_value_t*)idxty) + }); + builder.CreateUnreachable(); + builder.SetInsertPoint(passBB); + } + addr = emit_gep_knownidx(strct, idxs, sty); + } + } + } + + if (addr != NULL) { + int align = jl_datatype_size(fieldty); + typed_store(addr, ConstantInt::get(T_int32, 0), emit_expr(args[3], ctx), + (jl_value_t*)fieldty, ctx, tbaa_user, strct, align); + JL_GC_POP(); + return ghostValue(jl_typeof(jl_nothing)); + } + } + } + } else if (f->fptr == &jl_f_nfields && nargs==1) { if (ctx->vaStack && symbol_eq(args[1], ctx->vaName) && !ctx->vars[ctx->vaName].isAssigned) { JL_GC_POP(); @@ -5059,6 +5177,16 @@ static void init_julia_llvm_env(Module *m) jlundefvarerror_func->setDoesNotReturn(); add_named_global(jlundefvarerror_func, (void*)&jl_undefined_var_error); + std::vector args2_boundserror(0); + args2_boundserror.push_back(jl_pvalue_llvmt); + args2_boundserror.push_back(jl_pvalue_llvmt); + jlboundserror_func = + Function::Create(FunctionType::get(T_void, args2_boundserror, false), + Function::ExternalLinkage, + "jl_bounds_error", m); + jlboundserror_func->setDoesNotReturn(); + add_named_global(jlboundserror_func, (void*)&jl_bounds_error); + std::vector args2_boundserrorv(0); args2_boundserrorv.push_back(jl_pvalue_llvmt); args2_boundserrorv.push_back(T_psize); @@ -5070,15 +5198,15 @@ static void init_julia_llvm_env(Module *m) jlboundserrorv_func->setDoesNotReturn(); add_named_global(jlboundserrorv_func, (void*)&jl_bounds_error_ints); - std::vector args2_boundserror(0); - args2_boundserror.push_back(jl_pvalue_llvmt); - args2_boundserror.push_back(T_size); - jlboundserror_func = - Function::Create(FunctionType::get(T_void, args2_boundserror, false), + std::vector args2_boundserrorint(0); + args2_boundserrorint.push_back(jl_pvalue_llvmt); + args2_boundserrorint.push_back(T_size); + jlboundserrorint_func = + Function::Create(FunctionType::get(T_void, args2_boundserrorint, false), Function::ExternalLinkage, "jl_bounds_error_int", m); - jlboundserror_func->setDoesNotReturn(); - add_named_global(jlboundserror_func, (void*)&jl_bounds_error_int); + jlboundserrorint_func->setDoesNotReturn(); + add_named_global(jlboundserrorint_func, (void*)&jl_bounds_error_int); std::vector args3_vboundserror(0); args3_vboundserror.push_back(jl_ppvalue_llvmt); @@ -5190,6 +5318,7 @@ static void init_julia_llvm_env(Module *m) builtin_func_map[jl_f_isdefined] = jlcall_func_to_llvm("jl_f_isdefined", (void*)&jl_f_isdefined, m); builtin_func_map[jl_f_get_field] = jlcall_func_to_llvm("jl_f_get_field", (void*)&jl_f_get_field, m); builtin_func_map[jl_f_set_field] = jlcall_func_to_llvm("jl_f_set_field", (void*)&jl_f_set_field, m); + builtin_func_map[jl_f_modifyelement] = jlcall_func_to_llvm("jl_f_modifyelement", (void*)&jl_f_modifyelement, m); builtin_func_map[jl_f_field_type] = jlcall_func_to_llvm("jl_f_field_type", (void*)&jl_f_field_type, m); builtin_func_map[jl_f_nfields] = jlcall_func_to_llvm("jl_f_nfields", (void*)&jl_f_nfields, m); builtin_func_map[jl_f_new_expr] = jlcall_func_to_llvm("jl_f_new_expr", (void*)&jl_f_new_expr, m); diff --git a/src/dump.c b/src/dump.c index 0cba4fc56690f..b18f880c4dcd4 100644 --- a/src/dump.c +++ b/src/dump.c @@ -65,8 +65,8 @@ static jl_fptr_t id_to_fptrs[] = { jl_f_throw, jl_f_is, jl_f_no_function, jl_f_typeof, jl_f_subtype, jl_f_isa, jl_f_typeassert, jl_f_apply, jl_f_top_eval, jl_f_isdefined, jl_f_tuple, jl_f_svec, - jl_f_get_field, jl_f_set_field, jl_f_field_type, jl_f_nfields, - jl_f_arraylen, jl_f_arrayref, jl_f_arrayset, jl_f_arraysize, + jl_f_get_field, jl_f_set_field, jl_f_modifyelement, jl_f_field_type, + jl_f_nfields, jl_f_arraylen, jl_f_arrayref, jl_f_arrayset, jl_f_arraysize, jl_f_instantiate_type, jl_f_kwcall, jl_trampoline, jl_f_methodexists, jl_f_applicable, jl_f_invoke, jl_apply_generic, jl_unprotect_stack, jl_f_sizeof, jl_f_new_expr, diff --git a/test/core.jl b/test/core.jl index ad1f88d875fe6..217b9ab2426b8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3106,3 +3106,22 @@ end const DATE12003 = DateTime(1917,1,1) failure12003(dt=DATE12003) = Dates.year(dt) @test isa(failure12003(), Integer) + +# Julep #11902 +x11902 = Ref{Tuple{Int64,Int64}}() +x11902[1] = 1 +@test x11902.x[1] == 1 +x11902[2] = 2 +@test x11902.x == (1,2) +@test_throws BoundsError x11902[0] = 1 +@test_throws BoundsError x11902[3] = 1 +try + x11902[3] = 1 +catch e + @test e.i == (3,) +end + +x11902 = Ref{Tuple{Ref{Int64},Int64}}() +@test_throws ErrorException x11902[1] = Ref{Int64}() +x11902 = Ref{Ref{Int64}}() +@test_throws MethodError x11902[1] = Ref{Int64}() From 556e3b00977ecf377f6b652a5c1a5238f5b28a55 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 11 Jul 2015 17:03:16 -0400 Subject: [PATCH 2/3] Fix assertion failure when overindexing --- src/codegen.cpp | 5 ++++- test/core.jl | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 6b4d4a2a823c5..51707167ab172 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2551,7 +2551,10 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, fieldty = tt; bool ishomogeneous = true; for (size_t i = 0; i < depth; ++i) { - if (!is_tupletype_homogeneous(fieldty->types)) { + // If we have more arguments than nesting, + // or the tuple is not homgenous, fall back on generic code + if (!jl_is_tuple_type(fieldty) || + !is_tupletype_homogeneous(fieldty->types)) { ishomogeneous = false; break; } diff --git a/test/core.jl b/test/core.jl index 217b9ab2426b8..c1e95eb108229 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3115,6 +3115,7 @@ x11902[2] = 2 @test x11902.x == (1,2) @test_throws BoundsError x11902[0] = 1 @test_throws BoundsError x11902[3] = 1 +@test_throws BoundsError x11902[1,1] = 1 try x11902[3] = 1 catch e From 531d5b8c22fc90770c4357f22ecab9c83d88e8f0 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 11 Jul 2015 17:34:52 -0400 Subject: [PATCH 3/3] LLVM 3.3 Support --- src/cgutils.cpp | 4 ++++ src/codegen.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index e4abd4208ee5b..aee2c10ae4656 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1368,7 +1368,11 @@ static Value *emit_gep_knownidx(Value *strct, ArrayRef idxs, jl_datatyp Type *strctty = julia_struct_to_llvm((jl_value_t*)jt); if (strct->getType() == jl_pvalue_llvmt) strct = builder.CreateBitCast(strct, PointerType::get(strctty,0)); +#ifdef LLVM37 return builder.CreateInBoundsGEP(strctty, strct, idxs); +#else + return builder.CreateInBoundsGEP(strct, idxs); +#endif } static Value *emit_gep_knownidx(Value *strct, unsigned idx, jl_datatype_t *jt) diff --git a/src/codegen.cpp b/src/codegen.cpp index 51707167ab172..0f1383a6f703d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2588,9 +2588,15 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, BasicBlock *passBB = BasicBlock::Create(getGlobalContext(),"pass",ctx->f); builder.CreateCondBr(bndacc, passBB, failBB); builder.SetInsertPoint(failBB); +#ifdef LLVM37 builder.CreateCall(prepare_call(jlboundserror_func), { boxed(strct, ctx), boxed(idxval, ctx, (jl_value_t*)idxty) }); +#else + builder.CreateCall2(prepare_call(jlboundserror_func), + boxed(strct, ctx), boxed(idxval, ctx, (jl_value_t*)idxty) + ); +#endif builder.CreateUnreachable(); builder.SetInsertPoint(passBB); }