Skip to content

Commit

Permalink
if a bitstype contains padding (or is really large), emit inline code to
Browse files Browse the repository at this point in the history
test the fields rather than using memcmp over the whole thing

this is the compile time system side of JuliaLang#11813

(closes JuliaLang#11813)
  • Loading branch information
vtjnash committed Jun 23, 2015
1 parent 6ec7c21 commit 9cd6ad4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 16 deletions.
56 changes: 40 additions & 16 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1960,20 +1960,45 @@ static Value *emit_f_is(jl_value_t *rt1, jl_value_t *rt2,
if (at1->isPointerTy()) {
Type *elty = julia_type_to_llvm(rt1);
if (elty->isAggregateType()) {
assert(jl_is_datatype(rt1));
size_t sz = jl_datatype_size(rt1);
if (sz > 512 && !((jl_datatype_t*)rt1)->haspadding) {
#ifdef LLVM37
answer = builder.CreateCall(prepare_call(memcmp_func),
{
builder.CreatePointerCast(varg1, T_pint8),
builder.CreatePointerCast(varg2, T_pint8),
builder.CreateTrunc(ConstantExpr::getSizeOf(elty), T_size)
});
answer = builder.CreateCall(prepare_call(memcmp_func),
{
builder.CreatePointerCast(varg1, T_pint8),
builder.CreatePointerCast(varg2, T_pint8),
ConstantInt::get(T_size, sz)
});
#else
answer = builder.CreateCall3(memcmp_func,
builder.CreatePointerCast(varg1, T_pint8),
builder.CreatePointerCast(varg2, T_pint8),
builder.CreateTrunc(ConstantExpr::getSizeOf(elty), T_size));
answer = builder.CreateCall3(prepare_call(memcmp_func),
builder.CreatePointerCast(varg1, T_pint8),
builder.CreatePointerCast(varg2, T_pint8),
ConstantInt::get(T_size, sz));
#endif
answer = builder.CreateICmpEQ(answer, ConstantInt::get(T_int32, 0));
answer = builder.CreateICmpEQ(answer, ConstantInt::get(T_int32, 0));
}
else {
varg1 = builder.CreatePointerCast(varg1, elty->getPointerTo());
varg2 = builder.CreatePointerCast(varg2, elty->getPointerTo());
jl_svec_t *types = ((jl_datatype_t*)rt1)->types;
answer = ConstantInt::get(T_int1, 1);
size_t l = jl_svec_len(types);
for(unsigned i=0; i < l; i++) {
jl_value_t *fldty = jl_svecref(types, i);
Value *subAns;
Value *fld1 = builder.CreateConstGEP2_32(varg1, 0, i);
Value *fld2 = builder.CreateConstGEP2_32(varg2, 0, i);
if (type_is_ghost(fld1->getType()))
continue;
if (!fld1->getType()->getContainedType(0)->isAggregateType()) {
fld1 = builder.CreateLoad(fld1);
fld2 = builder.CreateLoad(fld2);
}
subAns = emit_f_is(fldty, fldty, NULL, NULL, fld1, fld2, ctx);
answer = builder.CreateAnd(answer, subAns);
}
}
goto done;
}
}
Expand All @@ -1990,11 +2015,10 @@ static Value *emit_f_is(jl_value_t *rt1, jl_value_t *rt2,
for(unsigned i=0; i < l; i++) {
jl_value_t *fldty = jl_svecref(types,i);
Value *subAns;
subAns =
emit_f_is(fldty, fldty, NULL, NULL,
builder.CreateExtractElement(varg1, ConstantInt::get(T_int32,i)),
builder.CreateExtractElement(varg2, ConstantInt::get(T_int32,i)),
ctx);
subAns = emit_f_is(fldty, fldty, NULL, NULL,
builder.CreateExtractElement(varg1, ConstantInt::get(T_int32,i)),
builder.CreateExtractElement(varg2, ConstantInt::get(T_int32,i)),
ctx);
answer = builder.CreateAnd(answer, subAns);
}
goto done;
Expand Down
9 changes: 9 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3004,4 +3004,13 @@ let a = UInt8[1, 107, 66, 88, 2, 99, 254, 13, 0, 0, 0, 0]
a[9:end] = reinterpret(UInt8, u32)
p = pointer(a)
@test (Int8(1),(Int8(2),Int32(3))) === unsafe_load(convert(Ptr{Tuple{Int8,Tuple{Int8,Int32}}},p))
f11813(p) = (Int8(1),(Int8(2),Int32(3))) === unsafe_load(convert(Ptr{Tuple{Int8,Tuple{Int8,Int32}}},p))
@test f11813(p) === true # redundant comparison test seems to make this test more reliable, don't remove
end
let a = (1:1000...),
b = (1:1000...)
@test a == b
@test a === b
@test (a == b) === true
@test (a === b) === true
end

0 comments on commit 9cd6ad4

Please sign in to comment.