Skip to content

Commit

Permalink
Enable use of vectors for SIMD-friendly tuples.
Browse files Browse the repository at this point in the history
  • Loading branch information
Arch D. Robison committed Aug 4, 2015
1 parent e66175b commit b88313c
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 22 deletions.
11 changes: 10 additions & 1 deletion src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
return boxed(jv,ctx);
}

if (!tojulia && vt != jl_pvalue_llvmt && julia_type_to_llvm(aty)->isAggregateType()) {
if (!tojulia && vt != jl_pvalue_llvmt && julia_type_to_llvm_quick(aty)->isAggregateType()) {
// this value is expected to be a pointer in the julia codegen,
// so it needs to be extracted first if not tojulia
vt = vt->getContainedType(0);
Expand Down Expand Up @@ -381,6 +381,15 @@ static Value *julia_to_native(Type *ty, jl_value_t *jt, Value *jv,
return jv;
}
}
else if (vt->isVectorTy()) {
Value *mem = emit_static_alloca(vt, ctx);
builder.CreateStore(jv, mem);
Value* ptr = builder.CreateBitCast(mem, ty->getPointerTo());
if (byRef)
return ptr;
else
return builder.CreateLoad(ptr);
}

emit_error("ccall: argument type did not match declaration", ctx);
}
Expand Down
60 changes: 50 additions & 10 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

// utility procedures used in code generation

// Get LLVM DataLayout
static const DataLayout* LLVMDataLayout() {
#ifdef LLVM37
return jl_TargetMachine->getDataLayout();
#elif LLVM35
return &jl_data_layout->getDataLayout();
#else
return jl_data_layout;
#endif
}

#if defined(USE_MCJIT) && defined(_OS_WINDOWS_)
template<class T> // for GlobalObject's
static T* addComdat(T *G)
Expand Down Expand Up @@ -528,6 +539,7 @@ static Value *julia_gv(const char *cname, void *addr)
if (it != jl_value_to_llvm.end())
return builder.CreateLoad(it->second.gv);

//printf("\tcname=%s, globalUnique=%d\n", cname, globalUnique);
std::stringstream gvname;
gvname << cname << globalUnique++;
// no existing GlobalVariable, create one and store it
Expand Down Expand Up @@ -748,12 +760,7 @@ static Type *julia_struct_to_llvm(jl_value_t *jt)
}
else {
if (isvector && lasttype != T_int1 && lasttype != T_void) {
// TODO: currently we get LLVM assertion failures for other vector sizes
bool validVectorSize = (ntypes == 2 || ntypes == 4 || ntypes == 6);
if (0 && lasttype->isSingleValueType() && !lasttype->isVectorTy() && validVectorSize) // currently disabled due to load/store alignment issues
jst->struct_decl = VectorType::get(lasttype, ntypes);
else
jst->struct_decl = ArrayType::get(lasttype, ntypes);
jst->struct_decl = ArrayType::get(lasttype, ntypes);
}
else {
jst->struct_decl = StructType::get(jl_LLVMContext,ArrayRef<Type*>(&latypes[0],ntypes));
Expand All @@ -765,6 +772,32 @@ static Type *julia_struct_to_llvm(jl_value_t *jt)
return julia_type_to_llvm(jt);
}

static Type *llvm_quick(Type *ty, jl_value_t *jt) {
if (jl_is_tuple_type(jt) && ty->isArrayTy()) {
uint64_t n = ty->getArrayNumElements();
// FIXME - add n==16 for sake of AVX512
if (n==2 || n==4 || n==8) {
Type* eltype = ty->getArrayElementType();
if (eltype->isIntegerTy() || eltype->isFloatingPointTy() || eltype->isPointerTy()) {
//if ((eltype->isIntegerTy() && n>=4) || eltype->isFloatingPointTy()) {
//if (eltype->isFloatingPointTy()) {
return VectorType::get(eltype, n);
}
}
}
return ty;
}

static Type *julia_type_to_llvm_quick(jl_value_t *jt) {
Type *ty = julia_type_to_llvm(jt);
return llvm_quick(ty,jt);
}

static Type *julia_struct_to_llvm_quick(jl_value_t *jt) {
Type *ty = julia_struct_to_llvm(jt);
return llvm_quick(ty,jt);
}

// NOTE: llvm cannot express all julia types (for example unsigned),
// so this is an approximation. it's only correct if the associated LLVM
// value is not tagged with our value name hack.
Expand Down Expand Up @@ -1262,7 +1295,7 @@ static void typed_store(Value *ptr, Value *idx_0based, Value *rhs,
Value* parent, // for the write barrier, NULL if no barrier needed
size_t alignment = 0)
{
Type *elty = julia_type_to_llvm(jltype);
Type *elty = julia_type_to_llvm_quick(jltype);
assert(elty != NULL);
if (elty == T_void)
return;
Expand Down Expand Up @@ -1905,7 +1938,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt)

Type *llvmt = julia_type_to_llvm(jt);
if (llvmt->isAggregateType() && v->getType()->isPointerTy()) {
v = builder.CreateLoad(v);
v = builder.CreateAlignedLoad(v,1,"debox");
}
return allocate_box_dynamic(literal_pointer_val(jt), ConstantInt::get(T_size, jl_datatype_size(jt)), v);
}
Expand Down Expand Up @@ -2039,7 +2072,7 @@ static Value *emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **args, j
size_t nf = jl_datatype_nfields(sty);
if (nf > 0) {
if (jl_isbits(sty)) {
Type *lt = julia_type_to_llvm(ty);
Type *lt = julia_type_to_llvm_quick(ty);
size_t na = nargs-1 < nf ? nargs-1 : nf;
Value *strct = UndefValue::get(lt == T_void ? NoopType : lt);
unsigned idx = 0;
Expand All @@ -2050,7 +2083,14 @@ static Value *emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **args, j
if (!jl_subtype(expr_type(args[i+1],ctx), jtype, 0))
emit_typecheck(fval, jtype, "new", ctx);
if (!type_is_ghost(fty)) {
fval = emit_unbox(fty, fval, jtype);
if(fval->getType()->isVectorTy() && fty->isArrayTy()) {
// FIXME use llvm_type_rewrite?
Value *mem = emit_static_alloca(fty, ctx);
builder.CreateStore(fval, builder.CreatePointerCast(mem, fval->getType()->getPointerTo()));
fval = builder.CreateLoad(mem);
} else {
fval = emit_unbox(fty, fval, jtype);
}
if (fty == T_int1)
fval = builder.CreateZExt(fval, T_int8);
if (lt->isVectorTy())
Expand Down
22 changes: 12 additions & 10 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ static Value *alloc_local(jl_sym_t *s, jl_codectx_t *ctx)
jl_value_t *jt = vi.declType;
Value *lv = NULL;
assert(store_unboxed_p(s,ctx));
Type *vtype = julia_struct_to_llvm(jt);
Type *vtype = julia_struct_to_llvm_quick(jt);
assert(vtype != jl_pvalue_llvmt);
if (!type_is_ghost(vtype)) {
// CreateAlloca is OK here because alloc_local is only called during prologue setup
Expand Down Expand Up @@ -2511,7 +2511,7 @@ static Value *emit_call_function_object(jl_function_t *f, Value *theF, Value *th
for(size_t i=0; i < nargs; i++) {
Type *at = cft->getParamType(idx);
jl_value_t *jt = jl_nth_slot_type(f->linfo->specTypes,i);
Type *et = julia_type_to_llvm(jt);
Type *et = julia_type_to_llvm_quick(jt);
if (et == T_void || et->isEmptyTy()) {
// Still emit the expression in case it has side effects
emit_expr(args[i+1], ctx);
Expand All @@ -2537,7 +2537,8 @@ static Value *emit_call_function_object(jl_function_t *f, Value *theF, Value *th
argvals[idx] = emit_reg2mem(emit_unbox(et, arg, jt), ctx);
}
else {
assert(at == et);
//OUCH - et was <2 x i64> and at was [2 x i64]*
assert(at == et || (et->isVectorTy() && at->isPointerTy()));
argvals[idx] = emit_unbox(et, emit_unboxed(args[i+1], ctx), jt);
assert(dyn_cast<UndefValue>(argvals[idx]) == 0);
}
Expand Down Expand Up @@ -2967,7 +2968,7 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx)
jl_value_t *declType = (jl_is_array(gensym_types) ? jl_cellref(gensym_types, idx) : (jl_value_t*)jl_any_type);
Value *bp = NULL;
if (store_unboxed_p(declType)) {
Type *vtype = julia_struct_to_llvm(declType);
Type *vtype = julia_struct_to_llvm_quick(declType);
assert(vtype != jl_pvalue_llvmt);
if (!type_is_ghost(vtype)) {
// add a stack slot for this (non-ghost) GenSym node
Expand Down Expand Up @@ -3555,6 +3556,7 @@ static Function *gen_cfun_wrapper(jl_function_t *ff, jl_value_t *jlrettype, jl_t
if (fargt.size() != fargt_sig.size())
jl_error("va_arg syntax not allowed for cfunction argument list");

//printf("\tjlcapi_ %s globalUnique = %d\n",lam->name->name, int(globalUnique));
std::stringstream funcName;
funcName << "jlcapi_" << lam->name->name << "_" << globalUnique++;

Expand Down Expand Up @@ -3769,7 +3771,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct
unsigned idx = 0;
for(size_t i=0; i < nargs; i++) {
jl_value_t *ty = jl_nth_slot_type(lam->specTypes, i);
Type *lty = julia_type_to_llvm(ty);
Type *lty = julia_type_to_llvm_quick(ty);
if (lty != NULL && type_is_ghost(lty))
continue;
Value *argPtr = builder.CreateGEP(argArray,
Expand Down Expand Up @@ -3939,12 +3941,12 @@ static Function *emit_function(jl_lambda_info_t *lam)
#else
m = jl_Module;
#endif
//printf("\tname = %s globalUnique = %d\n",lam->name->name, int(globalUnique));
funcName << "_" << globalUnique++;

if (specsig) { // assumes !va
std::vector<Type*> fsig(0);
for(size_t i=0; i < jl_nparams(lam->specTypes); i++) {
Type *ty = julia_type_to_llvm(jl_tparam(lam->specTypes,i));
Type *ty = julia_type_to_llvm_quick(jl_tparam(lam->specTypes,i));
if (type_is_ghost(ty)) {
// mark as a ghost for now, we'll revise this later if needed as a local
ctx.vars[jl_decl_var(jl_cellref(largs,i))].isGhost = true;
Expand All @@ -3954,7 +3956,7 @@ static Function *emit_function(jl_lambda_info_t *lam)
ty = PointerType::get(ty,0);
fsig.push_back(ty);
}
Type *rt = (jlrettype == (jl_value_t*)jl_void_type ? T_void : julia_type_to_llvm(jlrettype));
Type *rt = (jlrettype == (jl_value_t*)jl_void_type ? T_void : julia_type_to_llvm_quick(jlrettype));
f = Function::Create(FunctionType::get(rt, fsig, false),
imaging_mode ? GlobalVariable::InternalLinkage : GlobalVariable::ExternalLinkage,
funcName.str(), m);
Expand Down Expand Up @@ -4676,14 +4678,14 @@ extern "C" void jl_fptr_to_llvm(void *fptr, jl_lambda_info_t *lam, int specsig)
jl_value_t *jlrettype = jl_ast_rettype(lam, (jl_value_t*)lam->ast);
std::vector<Type*> fsig(0);
for (size_t i=0; i < jl_nparams(lam->specTypes); i++) {
Type *ty = julia_type_to_llvm(jl_tparam(lam->specTypes,i));
Type *ty = julia_type_to_llvm_quick(jl_tparam(lam->specTypes,i));
if (type_is_ghost(ty))
continue;
if (ty->isAggregateType())
ty = PointerType::get(ty,0);
fsig.push_back(ty);
}
Type *rt = (jlrettype == (jl_value_t*)jl_void_type ? T_void : julia_type_to_llvm(jlrettype));
Type *rt = (jlrettype == (jl_value_t*)jl_void_type ? T_void : julia_type_to_llvm_quick(jlrettype));
Function *f = Function::Create(FunctionType::get(rt, fsig, false), Function::ExternalLinkage, funcName,
shadow_module);

Expand Down
12 changes: 11 additions & 1 deletion src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,17 @@ static Value *emit_unbox(Type *to, Value *x, jl_value_t *jt)
}
if (ty != jl_pvalue_llvmt) {
if (ty->isPointerTy() && to->isAggregateType()) {
x = builder.CreateLoad(x); // something stack allocated
x = builder.CreateLoad(x,"unbox");
ty = x->getType();
}
else if (ty->isPointerTy() && to->isVectorTy()) {
Type* elty = ty->getContainedType(0);
if (elty->isArrayTy())
x = builder.CreateBitCast(x,PointerType::get(to,0));
else
assert(elty->isVectorTy());
unsigned align = LLVMDataLayout()->getABITypeAlignment(elty);
x = builder.CreateAlignedLoad(x,align,"unbox");
ty = x->getType();
}
else {
Expand Down

0 comments on commit b88313c

Please sign in to comment.