Skip to content

Commit

Permalink
Handle VecElement in julia_const_to_llvm
Browse files Browse the repository at this point in the history
Also clean up `julia_const_to_llvm` to avoid boxing due to `getfield`.

Fix #18236
  • Loading branch information
yuyichao committed Aug 26, 2016
1 parent e6a9d7f commit c4093ba
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 67 deletions.
125 changes: 58 additions & 67 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,55 +155,52 @@ static Value *uint_cnvt(Type *to, Value *x)
}

#define LLVM_FP(a,b) APFloat(a,b)
static Constant *julia_const_to_llvm(jl_value_t *e, bool nested=false)
static Constant *julia_const_to_llvm(void *ptr, jl_value_t *bt)
{
jl_value_t *jt = jl_typeof(e);
jl_datatype_t *bt = (jl_datatype_t*)jt;
// assume `jl_isbits(bt)`.
// `ptr` can point to a inline field, do not read the tag from it.
if (bt == (jl_value_t*)jl_bool_type)
return ConstantInt::get(T_int8, (*(uint8_t*)ptr) ? 1 : 0);

if (!jl_is_datatype(bt) || bt == jl_ssavalue_type)
if (bt == (jl_value_t*)jl_ssavalue_type)
return NULL;

if (e == jl_true)
return ConstantInt::get(T_int8, 1);
if (e == jl_false)
return ConstantInt::get(T_int8, 0);
if (jl_is_vecelement_type(bt))
bt = jl_tparam0(bt);

if (jl_is_cpointer_type(jt))
return ConstantExpr::getIntToPtr(ConstantInt::get(T_size, jl_unbox_long(e)), julia_type_to_llvm((jl_value_t*)bt));
if (jl_is_bitstype(jt)) {
if (jl_is_cpointer_type(bt))
return ConstantExpr::getIntToPtr(ConstantInt::get(T_size, *(uintptr_t*)ptr), julia_type_to_llvm(bt));
if (jl_is_bitstype(bt)) {
int nb = jl_datatype_size(bt);
//TODO: non-power-of-2 size datatypes may not be interpreted correctly on big-endian systems
// TODO: non-power-of-2 size datatypes may not be interpreted correctly on big-endian systems
switch (nb) {
case 1: {
uint8_t data8 = *(uint8_t*)jl_data_ptr(e);
uint8_t data8 = *(uint8_t*)ptr;
return ConstantInt::get(T_int8, data8);
}
case 2: {
uint16_t data16 = *(uint16_t*)jl_data_ptr(e);
uint16_t data16 = *(uint16_t*)ptr;
#ifndef DISABLE_FLOAT16
if (jl_is_float(e)) {
return ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEhalf,APInt(16,data16)));
}
if (jl_is_floattype(bt))
return ConstantFP::get(jl_LLVMContext, LLVM_FP(APFloat::IEEEhalf,APInt(16,data16)));
#endif
return ConstantInt::get(T_int16, data16);
}
case 4: {
uint32_t data32 = *(uint32_t*)jl_data_ptr(e);
if (jl_is_float(e)) {
return ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEsingle,APInt(32,data32)));
}
uint32_t data32 = *(uint32_t*)ptr;
if (jl_is_floattype(bt))
return ConstantFP::get(jl_LLVMContext, LLVM_FP(APFloat::IEEEsingle,APInt(32,data32)));
return ConstantInt::get(T_int32, data32);
}
case 8: {
uint64_t data64 = *(uint64_t*)jl_data_ptr(e);
if (jl_is_float(e)) {
return ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEdouble,APInt(64,data64)));
}
uint64_t data64 = *(uint64_t*)ptr;
if (jl_is_floattype(bt))
return ConstantFP::get(jl_LLVMContext, LLVM_FP(APFloat::IEEEdouble,APInt(64,data64)));
return ConstantInt::get(T_int64, data64);
}
default:
size_t nw = (nb+sizeof(uint64_t)-1)/sizeof(uint64_t);
uint64_t *data = (uint64_t*)jl_data_ptr(e);
uint64_t *data = (uint64_t*)ptr;
APInt val;
#if !defined(_P64)
// malloc may not be 16-byte aligned on P32,
Expand All @@ -218,54 +215,48 @@ static Constant *julia_const_to_llvm(jl_value_t *e, bool nested=false)
else
#endif
val = APInt(8*nb, ArrayRef<uint64_t>(data, nw));
if (nb == 16 && jl_is_float(e)) {
if (nb == 16 && jl_is_floattype(bt)) {
return ConstantFP::get(jl_LLVMContext,LLVM_FP(APFloat::IEEEquad,val));
// If we have a floating point type that's not hardware supported, just treat it like an integer for LLVM purposes
}
return ConstantInt::get(IntegerType::get(jl_LLVMContext,8*nb),val);
}
}
if (jl_isbits(jt)) {
size_t nf = jl_datatype_nfields(bt), i;
size_t llvm_nf = 0;
Constant **fields = (Constant**)alloca(nf * sizeof(Constant*));
jl_value_t *f=NULL;
JL_GC_PUSH1(&f);
for(i=0; i < nf; i++) {
f = jl_get_nth_field(e, i);
Constant *val;
if (f == jl_true)
val = ConstantInt::get(T_int8,1);
else if (f == jl_false)
val = ConstantInt::get(T_int8,0);
else
val = julia_const_to_llvm(f, true);
if (val == NULL) {
JL_GC_POP();
return NULL;
}
fields[llvm_nf++] = val;
}
JL_GC_POP();

Type *t = julia_struct_to_llvm(jt, NULL);
if (type_is_ghost(t))
return UndefValue::get(NoopType);
if (t->isVectorTy())
return ConstantVector::get(ArrayRef<Constant*>(fields,llvm_nf));
if (t->isStructTy()) {
StructType *st = dyn_cast<StructType>(t);
assert(st);
return ConstantStruct::get(st, ArrayRef<Constant*>(fields,llvm_nf));
}
else {
assert(t->isArrayTy());
ArrayType *at = dyn_cast<ArrayType>(t);
assert(at);
return ConstantArray::get(at, ArrayRef<Constant*>(fields,llvm_nf));
}
size_t nf = jl_datatype_nfields(bt);
Constant **fields = (Constant**)alloca(nf * sizeof(Constant*));
for (size_t i = 0; i < nf; i++) {
size_t offs = jl_field_offset((jl_datatype_t*)bt, i);
jl_value_t *ft = jl_field_type(bt, i);
Constant *val = julia_const_to_llvm((char*)ptr + offs, ft);
if (val == NULL)
return NULL;
fields[i] = val;
}
return NULL;

Type *t = julia_struct_to_llvm(bt, NULL);
if (type_is_ghost(t))
return UndefValue::get(NoopType);
if (t->isVectorTy())
return ConstantVector::get(ArrayRef<Constant*>(fields, nf));
if (StructType *st = dyn_cast<StructType>(t)) {
return ConstantStruct::get(st, ArrayRef<Constant*>(fields, nf));
}
else {
ArrayType *at = cast<ArrayType>(t);
return ConstantArray::get(at, ArrayRef<Constant*>(fields, nf));
}
}

static Constant *julia_const_to_llvm(jl_value_t *e)
{
if (e == jl_true)
return ConstantInt::get(T_int8, 1);
if (e == jl_false)
return ConstantInt::get(T_int8, 0);
jl_value_t *bt = jl_typeof(e);
if (!jl_isbits(bt))
return NULL;
return julia_const_to_llvm(e, bt);
}

static jl_cgval_t ghostValue(jl_value_t *ty);
Expand Down
22 changes: 22 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4497,6 +4497,28 @@ for (f,g) in ((:asin,:sin), (:acos,:cos))
end
@test f18085(Val{:asin},3) === (0.0,)

# issue #18236 constant VecElement in ast triggers codegen assertion/undef
# VecElement of scalar
v18236 = VecElement(1.0)
ptr18236 = cfunction(identity, VecElement{Float64}, Tuple{VecElement{Float64}})
@eval @noinline f18236(ptr) = ccall(ptr, VecElement{Float64},
(VecElement{Float64},), $v18236)
@test f18236(ptr18236) === v18236
@test !contains(sprint(code_llvm, f18236, Tuple{Ptr{Void}}), "double undef")
# VecElement of struct type, not necessarily useful but does have special
# ABI so should be handled correctly
# This struct should be small enough to be passed by value in C ABI
# in order to trigger the problematic code path.
# We should be at least testing this on some platforms.
# Not sure if there's a better way to trigger unboxing in codegen.
v18236_2 = VecElement((Int8(1), Int8(2)))
ptr18236_2 = cfunction(identity, VecElement{NTuple{2,Int8}},
Tuple{VecElement{NTuple{2,Int8}}})
@eval @noinline f18236_2(ptr) = ccall(ptr, VecElement{NTuple{2,Int8}},
(VecElement{NTuple{2,Int8}},),
$v18236_2)
@test f18236_2(ptr18236_2) === v18236_2

# issue #18173
function f18173()
identity(()->successflag)
Expand Down

0 comments on commit c4093ba

Please sign in to comment.