Make "aa[key]" use the same runtime call as "key in aa". The runtime calls

these were using were different, but with equivalent definitions.

With `ldc -O3`, the following functions now all compile to the exact same code:
{{{
int[int] y;
void foo(int x) {
    if (x in y) {
        auto z = x in y;
        sink(*z);
    }
}

void bar(int x) {
    if (x in y) {
        sink(y[x]);
    }
}

void baz(int x) {
    if (auto p = x in y) {
        sink(*p);
    }
}
}}}
This commit is contained in:
Frits van Bommel
2009-05-25 12:50:40 +02:00
parent c8665ddc88
commit e7b3f5415f
3 changed files with 13 additions and 57 deletions

View File

@@ -64,10 +64,10 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
// call:
// extern(C) void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey)
// or
// extern(C) void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void* pkey)
// extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey)
// first get the runtime function
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGet":"_aaGetRvalue");
llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, lvalue?"_aaGet":"_aaIn");
const llvm::FunctionType* funcTy = func->getFunctionType();
// aa param
@@ -78,15 +78,20 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
LLValue* keyti = to_keyti(key);
keyti = DtoBitCast(keyti, funcTy->getParamType(1));
// valuesize param
LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
// pkey param
LLValue* pkey = to_pkey(loc, key);
pkey = DtoBitCast(pkey, funcTy->getParamType(3));
pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2));
// call runtime
LLValue* ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction();
LLValue* ret;
if (lvalue) {
// valuesize param
LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction();
} else {
ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction();
}
// cast return value
const LLType* targettype = getPtrToType(DtoType(type));

View File

@@ -659,19 +659,6 @@ static void LLVM_D_BuildRuntimeModule()
->setAttributes(Attr_1_4_NoCapture);
}
// void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void* pkey)
{
std::string fname("_aaGetRvalue");
std::vector<const LLType*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
types.push_back(sizeTy);
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)
->setAttributes(Attr_ReadOnly_1_4_NoCapture);
}
// void* _aaIn(AA aa, TypeInfo keyti, void* pkey)
{
std::string fname("_aaIn");

View File

@@ -292,43 +292,7 @@ Lret:
/*************************************************
* Get pointer to value in associative array indexed by key.
* Returns null if it is not already there.
*/
void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void *pkey)
{
//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
if (!aa)
return null;
//auto pkey = cast(void *)(&valuesize + 1);
auto keysize = aligntsize(keyti.tsize());
auto len = aa.b.length;
if (len)
{
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
size_t i = key_hash % len;
auto e = aa.b[i];
while (e !is null)
{
if (key_hash == e.hash)
{
auto c = keyti.compare(pkey, e + 1);
if (c == 0)
return cast(void *)(e + 1) + keysize;
e = (c < 0) ? e.left : e.right;
}
else
e = (key_hash < e.hash) ? e.left : e.right;
}
}
return null; // not found, caller will throw exception
}
/*************************************************
* Determine if key is in aa.
* Used for both "aa[key]" and "key in aa"
* Returns:
* null not in aa
* !=null in aa, return pointer to value