mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-28 18:43:13 +01:00
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:
19
gen/aa.cpp
19
gen/aa.cpp
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user