mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 08:30:47 +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;
|
LOG_SCOPE;
|
||||||
|
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
|
|
||||||
if (op != -1 && op != TOKblit && arrayNeedsPostblit(array->type))
|
if (op != -1 && op != TOKblit && arrayNeedsPostblit(array->type))
|
||||||
{
|
{
|
||||||
DtoArraySetAssign(loc, array, value, op);
|
DtoArraySetAssign(loc, array, value, op);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
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
|
|
||||||
|
|
||||||
LLValue* dim = DtoArrayLen(array);
|
LLValue* dim = DtoArrayLen(array);
|
||||||
LLValue* ptr = DtoArrayPtr(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* arrayelemty = array->getType()->nextOf()->toBasetype();
|
||||||
Type* valuety = value->getType()->toBasetype();
|
|
||||||
|
|
||||||
// lets first optimize all zero initializations down to a memset.
|
// lets first optimize all zero initializations down to a memset.
|
||||||
// this simplifies codegen later on as llvm null's have no address!
|
// this simplifies codegen later on as llvm null's have no address!
|
||||||
|
LLValue *val = value->getRVal();
|
||||||
if (isaConstant(val) && isaConstant(val)->isNullValue())
|
if (isaConstant(val) && isaConstant(val)->isNullValue())
|
||||||
{
|
{
|
||||||
size_t X = getTypePaddedSize(val->getType());
|
size_t X = getTypePaddedSize(val->getType());
|
||||||
|
@ -172,103 +128,48 @@ void DtoArrayInit(Loc& loc, DValue* array, DValue* value, int op)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not a zero initializer, call the appropriate runtime function!
|
// create blocks
|
||||||
switch (valuety->ty)
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
{
|
llvm::BasicBlock* condbb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.cond",
|
||||||
case Tbool:
|
gIR->topfunc(), oldend);
|
||||||
val = gIR->ir->CreateZExt(val, LLType::getInt8Ty(gIR->context()), ".bool");
|
llvm::BasicBlock* bodybb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.body",
|
||||||
// fall through
|
gIR->topfunc(), oldend);
|
||||||
|
llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "arrayinit.end",
|
||||||
|
gIR->topfunc(), oldend);
|
||||||
|
|
||||||
case Tvoid:
|
// initialize iterator
|
||||||
case Tchar:
|
LLValue *itr = DtoAlloca(Type::tsize_t, "arrayinit.itr");
|
||||||
case Tint8:
|
DtoStore(DtoConstSize_t(0), itr);
|
||||||
case Tuns8:
|
|
||||||
Logger::println("Using memset for array init");
|
|
||||||
DtoMemSet(ptr, val, dim);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Twchar:
|
// move into the for condition block, ie. start the loop
|
||||||
case Tint16:
|
assert(!gIR->scopereturned());
|
||||||
case Tuns16:
|
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||||
funcname = "_d_array_init_i16";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Tdchar:
|
// replace current scope
|
||||||
case Tint32:
|
gIR->scope() = IRScope(condbb,bodybb);
|
||||||
case Tuns32:
|
|
||||||
funcname = "_d_array_init_i32";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Tint64:
|
// create the condition
|
||||||
case Tuns64:
|
LLValue* cond_val = gIR->ir->CreateICmpNE(DtoLoad(itr), dim, "arrayinit.condition");
|
||||||
funcname = "_d_array_init_i64";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Tfloat32:
|
// conditional branch
|
||||||
case Timaginary32:
|
assert(!gIR->scopereturned());
|
||||||
funcname = "_d_array_init_float";
|
llvm::BranchInst::Create(bodybb, endbb, cond_val, gIR->scopebb());
|
||||||
break;
|
|
||||||
|
|
||||||
case Tfloat64:
|
// rewrite scope
|
||||||
case Timaginary64:
|
gIR->scope() = IRScope(bodybb, endbb);
|
||||||
funcname = "_d_array_init_double";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Tfloat80:
|
// assign array element value
|
||||||
case Timaginary80:
|
DValue *arrayelem = new DVarValue(arrayelemty, DtoGEP1(ptr, DtoLoad(itr), "arrayinit.arrayelem"));
|
||||||
funcname = "_d_array_init_real";
|
DtoAssign(loc, arrayelem, value, op);
|
||||||
break;
|
|
||||||
|
|
||||||
case Tcomplex32:
|
// increment iterator
|
||||||
funcname = "_d_array_init_cfloat";
|
DtoStore(gIR->ir->CreateAdd(DtoLoad(itr), DtoConstSize_t(1), "arrayinit.new_itr"), itr);
|
||||||
break;
|
|
||||||
|
|
||||||
case Tcomplex64:
|
// loop
|
||||||
funcname = "_d_array_init_cdouble";
|
llvm::BranchInst::Create(condbb, gIR->scopebb());
|
||||||
break;
|
|
||||||
|
|
||||||
case Tcomplex80:
|
// rewrite the scope
|
||||||
funcname = "_d_array_init_creal";
|
gIR->scope() = IRScope(endbb, oldend);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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!
|
// array slice copy when assertions are on!
|
||||||
// void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen)
|
// void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen)
|
||||||
{
|
{
|
||||||
llvm::StringRef fname("_d_array_init_mem");
|
llvm::StringRef fname("_d_array_slice_copy");
|
||||||
llvm::StringRef fname2("_d_array_slice_copy");
|
|
||||||
std::vector<const LLType*> types;
|
std::vector<const LLType*> types;
|
||||||
types.push_back(voidPtrTy);
|
types.push_back(voidPtrTy);
|
||||||
types.push_back(sizeTy);
|
types.push_back(sizeTy);
|
||||||
|
@ -575,8 +546,6 @@ static void LLVM_D_BuildRuntimeModule()
|
||||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)
|
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)
|
||||||
->setAttributes(Attr_1_3_NoCapture);
|
->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