mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 16:11:08 +03:00
Rewritten DtoArrayInit().
It does not create calls to runtime functions and generates a faster code, especially if optimizations are on.
This commit is contained in:
parent
40fa7653e2
commit
22d0f00027
2 changed files with 35 additions and 165 deletions
167
gen/arrays.cpp
167
gen/arrays.cpp
|
@ -106,64 +106,20 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op)
|
|||
LOG_SCOPE;
|
||||
|
||||
#if DMDV2
|
||||
|
||||
if (op != -1 && op != TOKblit && arrayNeedsPostblit(array->type))
|
||||
{
|
||||
DtoArraySetAssign(loc, array, value, op);
|
||||
return;
|
||||
}
|
||||
|
||||
LLValue* ptr = DtoArrayPtr(array);
|
||||
LLValue* dim;
|
||||
if (array->type->ty == Tsarray) {
|
||||
// Calculate length of the static array
|
||||
LLValue* rv = array->getRVal();
|
||||
const LLArrayType* t = isaArray(rv->getType()->getContainedType(0));
|
||||
uint64_t c = t->getNumElements();
|
||||
while (t = isaArray(t->getContainedType(0)))
|
||||
c *= t->getNumElements();
|
||||
assert(c > 0);
|
||||
dim = DtoConstSize_t(c);
|
||||
ptr = DtoBitCast(ptr, DtoType(DtoArrayElementType(array->type)->pointerTo()));
|
||||
} else {
|
||||
dim = DtoArrayLen(array);
|
||||
}
|
||||
|
||||
#else // DMDV1
|
||||
#endif
|
||||
|
||||
LLValue* dim = DtoArrayLen(array);
|
||||
LLValue* ptr = DtoArrayPtr(array);
|
||||
|
||||
#endif
|
||||
|
||||
LLValue* val;
|
||||
|
||||
// give slices and complex values storage (and thus an address to pass)
|
||||
if (value->isSlice() || value->type->ty == Tdelegate)
|
||||
{
|
||||
val = DtoAlloca(value->getType(), ".tmpparam");
|
||||
DVarValue lval(value->getType(), val);
|
||||
DtoAssign(loc, &lval, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = value->getRVal();
|
||||
}
|
||||
assert(val);
|
||||
|
||||
// prepare runtime call
|
||||
LLSmallVector<LLValue*, 4> args;
|
||||
args.push_back(ptr);
|
||||
args.push_back(dim);
|
||||
args.push_back(val);
|
||||
|
||||
// determine the right runtime function to call
|
||||
const char* funcname = NULL;
|
||||
Type* arrayelemty = array->getType()->nextOf()->toBasetype();
|
||||
Type* valuety = value->getType()->toBasetype();
|
||||
|
||||
// lets first optimize all zero initializations down to a memset.
|
||||
// this simplifies codegen later on as llvm null's have no address!
|
||||
LLValue *val = value->getRVal();
|
||||
if (isaConstant(val) && isaConstant(val)->isNullValue())
|
||||
{
|
||||
size_t X = getTypePaddedSize(val->getType());
|
||||
|
@ -172,103 +128,48 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op)
|
|||
return;
|
||||
}
|
||||
|
||||
// if not a zero initializer, call the appropriate runtime function!
|
||||
switch (valuety->ty)
|
||||
{
|
||||
case Tbool:
|
||||
val = gIR->ir->CreateZExt(val, LLType::getInt8Ty(gIR->context()), ".bool");
|
||||
// fall through
|
||||
// create blocks
|
||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||
llvm::BasicBlock* condbb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.cond",
|
||||
gIR->topfunc(), oldend);
|
||||
llvm::BasicBlock* bodybb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.body",
|
||||
gIR->topfunc(), oldend);
|
||||
llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.end",
|
||||
gIR->topfunc(), oldend);
|
||||
|
||||
case Tvoid:
|
||||
case Tchar:
|
||||
case Tint8:
|
||||
case Tuns8:
|
||||
Logger::println("Using memset for array init");
|
||||
DtoMemSet(ptr, val, dim);
|
||||
return;
|
||||
// initialize iterator
|
||||
LLValue *itr = DtoAlloca(Type::tsize_t, "arrayinit.itr");
|
||||
DtoStore(DtoConstSize_t(0), itr);
|
||||
|
||||
case Twchar:
|
||||
case Tint16:
|
||||
case Tuns16:
|
||||
funcname = "_d_array_init_i16";
|
||||
break;
|
||||
// move into the for condition block, ie. start the loop
|
||||
assert(!gIR->scopereturned());
|
||||
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||
|
||||
case Tdchar:
|
||||
case Tint32:
|
||||
case Tuns32:
|
||||
funcname = "_d_array_init_i32";
|
||||
break;
|
||||
// replace current scope
|
||||
gIR->scope() = IRScope(condbb,bodybb);
|
||||
|
||||
case Tint64:
|
||||
case Tuns64:
|
||||
funcname = "_d_array_init_i64";
|
||||
break;
|
||||
// create the condition
|
||||
LLValue* cond_val = gIR->ir->CreateICmpNE(DtoLoad(itr), dim, "arrayinit.condition");
|
||||
|
||||
case Tfloat32:
|
||||
case Timaginary32:
|
||||
funcname = "_d_array_init_float";
|
||||
break;
|
||||
// conditional branch
|
||||
assert(!gIR->scopereturned());
|
||||
llvm::BranchInst::Create(bodybb, endbb, cond_val, gIR->scopebb());
|
||||
|
||||
case Tfloat64:
|
||||
case Timaginary64:
|
||||
funcname = "_d_array_init_double";
|
||||
break;
|
||||
// rewrite scope
|
||||
gIR->scope() = IRScope(bodybb, endbb);
|
||||
|
||||
case Tfloat80:
|
||||
case Timaginary80:
|
||||
funcname = "_d_array_init_real";
|
||||
break;
|
||||
// assign array element value
|
||||
DValue *arrayelem = new DVarValue(arrayelemty, DtoGEP1(ptr, DtoLoad(itr), "arrayinit.arrayelem"));
|
||||
DtoAssign(loc, arrayelem, value, op);
|
||||
|
||||
case Tcomplex32:
|
||||
funcname = "_d_array_init_cfloat";
|
||||
break;
|
||||
// increment iterator
|
||||
DtoStore(gIR->ir->CreateAdd(DtoLoad(itr), DtoConstSize_t(1), "arrayinit.new_itr"), itr);
|
||||
|
||||
case Tcomplex64:
|
||||
funcname = "_d_array_init_cdouble";
|
||||
break;
|
||||
// loop
|
||||
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||
|
||||
case Tcomplex80:
|
||||
funcname = "_d_array_init_creal";
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
case Tclass:
|
||||
funcname = "_d_array_init_pointer";
|
||||
args[0] = DtoBitCast(args[0], getPtrToType(getVoidPtrType()));
|
||||
args[2] = DtoBitCast(args[2], getVoidPtrType());
|
||||
break;
|
||||
|
||||
// this currently acts as a kind of fallback for all the bastards...
|
||||
// FIXME: this is probably too slow.
|
||||
case Tstruct:
|
||||
case Tdelegate:
|
||||
case Tarray:
|
||||
case Tsarray:
|
||||
funcname = "_d_array_init_mem";
|
||||
assert(arrayelemty == valuety && "ArrayInit doesn't work on elem-initialized static arrays");
|
||||
args[0] = DtoBitCast(args[0], getVoidPtrType());
|
||||
args[2] = DtoBitCast(args[2], getVoidPtrType());
|
||||
args.push_back(DtoConstSize_t(getTypePaddedSize(DtoTypeNotVoid(arrayelemty))));
|
||||
break;
|
||||
|
||||
default:
|
||||
error("unhandled array init: %s = %s", array->getType()->toChars(), value->getType()->toChars());
|
||||
assert(0 && "unhandled array init");
|
||||
}
|
||||
|
||||
if (Logger::enabled())
|
||||
{
|
||||
Logger::cout() << "ptr = " << *args[0] << std::endl;
|
||||
Logger::cout() << "dim = " << *args[1] << std::endl;
|
||||
Logger::cout() << "val = " << *args[2] << std::endl;
|
||||
}
|
||||
|
||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, funcname);
|
||||
assert(fn);
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "calling array init function: " << *fn <<'\n';
|
||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end());
|
||||
call.setCallingConv(llvm::CallingConv::C);
|
||||
// rewrite the scope
|
||||
gIR->scope() = IRScope(endbb, oldend);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -534,39 +534,10 @@ static void LLVM_D_BuildRuntimeModule()
|
|||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ARRAY_INIT(TY,suffix) \
|
||||
{ \
|
||||
std::string fname = (llvm::StringRef("_d_array_init_") + llvm::StringRef(suffix)).str(); \
|
||||
std::vector<const LLType*> types; \
|
||||
types.push_back(rt_ptr(TY)); \
|
||||
types.push_back(sizeTy); \
|
||||
types.push_back(TY); \
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); \
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M) \
|
||||
->setAttributes(Attr_1_NoCapture); \
|
||||
}
|
||||
|
||||
ARRAY_INIT(shortTy,"i16")
|
||||
ARRAY_INIT(intTy,"i32")
|
||||
ARRAY_INIT(longTy,"i64")
|
||||
ARRAY_INIT(floatTy,"float")
|
||||
ARRAY_INIT(doubleTy,"double")
|
||||
ARRAY_INIT(realTy,"real")
|
||||
ARRAY_INIT(cfloatTy,"cfloat")
|
||||
ARRAY_INIT(cdoubleTy,"cdouble")
|
||||
ARRAY_INIT(crealTy,"creal")
|
||||
ARRAY_INIT(voidPtrTy,"pointer")
|
||||
|
||||
#undef ARRAY_INIT
|
||||
|
||||
// array init mem
|
||||
// void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
|
||||
// +
|
||||
// array slice copy when assertions are on!
|
||||
// void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen)
|
||||
{
|
||||
llvm::StringRef fname("_d_array_init_mem");
|
||||
llvm::StringRef fname2("_d_array_slice_copy");
|
||||
llvm::StringRef fname("_d_array_slice_copy");
|
||||
std::vector<const LLType*> types;
|
||||
types.push_back(voidPtrTy);
|
||||
types.push_back(sizeTy);
|
||||
|
@ -575,8 +546,6 @@ static void LLVM_D_BuildRuntimeModule()
|
|||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)
|
||||
->setAttributes(Attr_1_3_NoCapture);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M)
|
||||
->setAttributes(Attr_1_3_NoCapture);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue