Skip to content

Commit cccb057

Browse files
committed
Optimize ABIRewrite system for lvalues
Allow ABIRewrites to return the D parameter's LL value directly. Most rewrites store to memory anyway, so let the D parameter point directly to that memory instead of a dedicated alloca bitcopy.
1 parent a6a6786 commit cccb057

File tree

9 files changed

+83
-140
lines changed

9 files changed

+83
-140
lines changed

gen/abi-generic.h

Lines changed: 38 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,17 @@ struct LLTypeMemoryLayout {
8484

8585
/// Removes padding fields for (non-union-containing!) structs
8686
struct RemoveStructPadding : ABIRewrite {
87-
/// get a rewritten value back to its original form
88-
LLValue *get(Type *dty, LLValue *v) override {
89-
LLValue *lval = DtoAlloca(dty, ".rewritetmp");
90-
getL(dty, v, lval);
91-
return lval;
87+
LLValue *put(DValue *v) override {
88+
return DtoUnpaddedStruct(v->getType()->toBasetype(), v->getRVal());
9289
}
9390

94-
/// get a rewritten value back to its original form and store result in
95-
/// provided lvalue
96-
void getL(Type *dty, LLValue *v, LLValue *lval) override {
91+
LLValue *getLVal(Type *dty, LLValue *v) override {
92+
LLValue *lval = DtoAlloca(dty, ".RemoveStructPadding_dump");
9793
// Make sure the padding is zero, so struct comparisons work.
9894
// TODO: Only do this if there's padding, and/or only initialize padding.
9995
DtoMemSetZero(lval, DtoConstSize_t(getTypeAllocSize(DtoType(dty))));
10096
DtoPaddedStruct(dty->toBasetype(), v, lval);
101-
}
102-
103-
/// put out rewritten value
104-
LLValue *put(DValue *v) override {
105-
return DtoUnpaddedStruct(v->getType()->toBasetype(), v->getRVal());
97+
return lval;
10698
}
10799

108100
/// return the transformed type for this rewrite
@@ -164,20 +156,14 @@ struct IntegerRewrite : ABIRewrite {
164156
return LLTypeMemoryLayout::typesAreEquivalent(llType, integerType);
165157
}
166158

167-
LLValue *get(Type *dty, LLValue *v) override {
168-
LLValue *integerDump = DtoAllocaDump(v, dty, ".IntegerRewrite_dump");
169-
LLType *type = DtoType(dty);
170-
return loadFromMemory(integerDump, type, ".IntegerRewrite_getResult");
171-
}
172-
173-
void getL(Type *dty, LLValue *v, LLValue *lval) override {
174-
storeToMemory(v, lval);
175-
}
176-
177159
LLValue *put(DValue *dv) override {
178160
LLValue *address = getAddressOf(dv);
179161
LLType *integerType = getIntegerType(dv->getType()->size());
180-
return loadFromMemory(address, integerType, ".IntegerRewrite_putResult");
162+
return loadFromMemory(address, integerType);
163+
}
164+
165+
LLValue *getLVal(Type *dty, LLValue *v) override {
166+
return DtoAllocaDump(v, dty, ".IntegerRewrite_dump");
181167
}
182168

183169
LLType *type(Type *t, LLType *) override { return getIntegerType(t->size()); }
@@ -204,29 +190,25 @@ struct ExplicitByvalRewrite : ABIRewrite {
204190
explicit ExplicitByvalRewrite(unsigned minAlignment = 16)
205191
: minAlignment(minAlignment) {}
206192

207-
LLValue *get(Type *dty, LLValue *v) override {
208-
return DtoLoad(v, ".ExplicitByvalRewrite_getResult");
209-
}
210-
211-
void getL(Type *dty, LLValue *v, LLValue *lval) override {
212-
DtoMemCpy(lval, v);
213-
}
214-
215193
LLValue *put(DValue *v) override {
216194
Type *dty = v->getType();
217195
const unsigned align = alignment(dty);
218196

219-
if (DtoIsInMemoryOnly(dty)) {
220-
LLValue *originalPointer = v->getRVal();
221-
LLType *type = originalPointer->getType()->getPointerElementType();
222-
LLValue *copyForCallee =
223-
DtoRawAlloca(type, align, ".ExplicitByvalRewrite_putResult");
224-
DtoMemCpy(copyForCallee, originalPointer);
225-
return copyForCallee;
197+
if (!DtoIsInMemoryOnly(dty)) {
198+
return DtoAllocaDump(v->getRVal(), align,
199+
".ExplicitByvalRewrite_dump");
226200
}
227201

228-
return DtoAllocaDump(v->getRVal(), align,
229-
".ExplicitByvalRewrite_putResult");
202+
LLValue *originalPointer = v->getRVal();
203+
LLType *type = originalPointer->getType()->getPointerElementType();
204+
LLValue *copyForCallee =
205+
DtoRawAlloca(type, align, ".ExplicitByvalRewrite_dump");
206+
DtoMemCpy(copyForCallee, originalPointer);
207+
return copyForCallee;
208+
}
209+
210+
LLValue *getLVal(Type *dty, LLValue *v) override {
211+
return DtoBitCast(v, DtoPtrToType(dty));
230212
}
231213

232214
LLType *type(Type *dty, LLType *t) override { return DtoPtrToType(dty); }
@@ -245,22 +227,18 @@ struct HFAToArray : ABIRewrite {
245227

246228
HFAToArray(const int max = 4) : maxFloats(max) {}
247229

248-
LLValue *get(Type *dty, LLValue *v) override {
249-
Logger::println("rewriting array -> as HFA %s", dty->toChars());
250-
LLValue *lval = DtoRawAlloca(v->getType(), 0);
251-
DtoStore(v, lval);
252-
253-
LLType *pTy = getPtrToType(DtoType(dty));
254-
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
255-
}
256-
257230
LLValue *put(DValue *dv) override {
258231
Type *dty = dv->getType();
259232
Logger::println("rewriting HFA %s -> as array", dty->toChars());
260233
LLType *t = type(dty, nullptr);
261234
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
262235
}
263236

237+
LLValue *getLVal(Type *dty, LLValue *v) override {
238+
Logger::println("rewriting array -> as HFA %s", dty->toChars());
239+
return DtoAllocaDump(v, dty, ".HFAToArray_dump");
240+
}
241+
264242
LLType *type(Type *dty, LLType *) override {
265243
assert(dty->ty == Tstruct);
266244
LLType *floatArrayType = nullptr;
@@ -274,22 +252,18 @@ struct HFAToArray : ABIRewrite {
274252
* Rewrite a composite as array of i64.
275253
*/
276254
struct CompositeToArray64 : ABIRewrite {
277-
LLValue *get(Type *dty, LLValue *v) override {
278-
Logger::println("rewriting i64 array -> as %s", dty->toChars());
279-
LLValue *lval = DtoRawAlloca(v->getType(), 0);
280-
DtoStore(v, lval);
281-
282-
LLType *pTy = getPtrToType(DtoType(dty));
283-
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
284-
}
285-
286255
LLValue *put(DValue *dv) override {
287256
Type *dty = dv->getType();
288257
Logger::println("rewriting %s -> as i64 array", dty->toChars());
289258
LLType *t = type(dty, nullptr);
290259
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
291260
}
292261

262+
LLValue *getLVal(Type *dty, LLValue *v) override {
263+
Logger::println("rewriting i64 array -> as %s", dty->toChars());
264+
return DtoAllocaDump(v, dty, ".CompositeToArray64_dump");
265+
}
266+
293267
LLType *type(Type *t, LLType *) override {
294268
// An i64 array that will hold Type 't'
295269
size_t sz = (t->size() + 7) / 8;
@@ -301,22 +275,18 @@ struct CompositeToArray64 : ABIRewrite {
301275
* Rewrite a composite as array of i32.
302276
*/
303277
struct CompositeToArray32 : ABIRewrite {
304-
LLValue *get(Type *dty, LLValue *v) override {
305-
Logger::println("rewriting i32 array -> as %s", dty->toChars());
306-
LLValue *lval = DtoRawAlloca(v->getType(), 0);
307-
DtoStore(v, lval);
308-
309-
LLType *pTy = getPtrToType(DtoType(dty));
310-
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
311-
}
312-
313278
LLValue *put(DValue *dv) override {
314279
Type *dty = dv->getType();
315280
Logger::println("rewriting %s -> as i32 array", dty->toChars());
316281
LLType *t = type(dty, nullptr);
317282
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
318283
}
319284

285+
LLValue *getLVal(Type *dty, LLValue *v) override {
286+
Logger::println("rewriting i32 array -> as %s", dty->toChars());
287+
return DtoAllocaDump(v, dty, ".CompositeToArray32_dump");
288+
}
289+
320290
LLType *type(Type *t, LLType *) override {
321291
// An i32 array that will hold Type 't'
322292
size_t sz = (t->size() + 3) / 4;

gen/abi-x86-64.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,6 @@ struct RegCount {
169169
* memory so that it's then readable as the other type (i.e., bit-casting).
170170
*/
171171
struct X86_64_C_struct_rewrite : ABIRewrite {
172-
LLValue *get(Type *dty, LLValue *v) override {
173-
LLValue *address = DtoAllocaDump(v, dty, ".X86_64_C_struct_rewrite_dump");
174-
LLType *type = DtoType(dty);
175-
return loadFromMemory(address, type, ".X86_64_C_struct_rewrite_getResult");
176-
}
177-
178-
void getL(Type *dty, LLValue *v, LLValue *lval) override {
179-
storeToMemory(v, lval);
180-
}
181-
182172
LLValue *put(DValue *v) override {
183173
LLValue *address = getAddressOf(v);
184174

@@ -188,6 +178,10 @@ struct X86_64_C_struct_rewrite : ABIRewrite {
188178
return loadFromMemory(address, abiTy, ".X86_64_C_struct_rewrite_putResult");
189179
}
190180

181+
LLValue *getLVal(Type *dty, LLValue *v) override {
182+
return DtoBitCast(v, DtoPtrToType(dty));
183+
}
184+
191185
LLType *type(Type *dty, LLType *t) override { return getAbiType(dty); }
192186
};
193187

@@ -200,16 +194,10 @@ struct X86_64_C_struct_rewrite : ABIRewrite {
200194
* the ByVal LLVM attribute.
201195
*/
202196
struct ImplicitByvalRewrite : ABIRewrite {
203-
LLValue *get(Type *dty, LLValue *v) override {
204-
return DtoLoad(v, ".ImplicitByvalRewrite_getResult");
205-
}
206-
207-
void getL(Type *dty, LLValue *v, LLValue *lval) override {
208-
DtoMemCpy(lval, v);
209-
}
210-
211197
LLValue *put(DValue *v) override { return getAddressOf(v); }
212198

199+
LLValue *getLVal(Type *dty, LLValue *v) override { return v; }
200+
213201
LLType *type(Type *dty, LLType *t) override { return DtoPtrToType(dty); }
214202
};
215203

gen/abi.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@
3131

3232
//////////////////////////////////////////////////////////////////////////////
3333

34-
void ABIRewrite::getL(Type *dty, LLValue *v, LLValue *lval) {
35-
LLValue *rval = get(dty, v);
36-
assert(rval->getType() == lval->getType()->getContainedType(0));
37-
DtoStore(rval, lval);
34+
llvm::Value *ABIRewrite::getRVal(Type *dty, LLValue *v) {
35+
return DtoLoad(DtoBitCast(getLVal(dty, v), DtoType(dty)->getPointerTo()));
3836
}
3937

4038
//////////////////////////////////////////////////////////////////////////////

gen/abi.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ class FunctionType;
3939
struct ABIRewrite {
4040
virtual ~ABIRewrite() = default;
4141

42-
/// get a rewritten value back to its original form
43-
virtual llvm::Value *get(Type *dty, llvm::Value *v) = 0;
42+
/// Transforms the D argument to a suitable LL argument.
43+
virtual llvm::Value *put(DValue *v) = 0;
4444

45-
/// get a rewritten value back to its original form and store result in
46-
/// provided lvalue
47-
/// this one is optional and defaults to calling the one above
48-
virtual void getL(Type *dty, llvm::Value *v, llvm::Value *lval);
45+
/// Transforms the LL parameter back and returns the address for the D
46+
/// parameter.
47+
virtual llvm::Value *getLVal(Type *dty, llvm::Value *v) = 0;
4948

50-
/// put out rewritten value
51-
virtual llvm::Value *put(DValue *v) = 0;
49+
/// Transforms the LL parameter back and returns the value for the D
50+
/// parameter.
51+
virtual llvm::Value *getRVal(Type *dty, llvm::Value *v);
5252

5353
/// should return the transformed type for this rewrite
5454
virtual llvm::Type *type(Type *dty, llvm::Type *t) = 0;

gen/functions.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -917,11 +917,9 @@ void DtoDefineFunction(FuncDeclaration *fd) {
917917
irparam->value = DtoAlloca(vd, vd->ident->toChars());
918918
} else {
919919
if (!irparam->arg->byref) {
920-
// alloca a stack slot for this first class value arg
921-
LLValue *mem = DtoAlloca(irparam->arg->type, vd->ident->toChars());
922-
923920
// let the abi transform the argument back first
924-
irFty.getParam(vd->type, llArgIdx, irparam->value, mem);
921+
LLValue *mem = irFty.getParamLVal(irparam->arg->type, llArgIdx, irparam->value);
922+
mem->setName(vd->ident->toChars());
925923

926924
// set the arg var value to the alloca
927925
irparam->value = mem;

gen/llvmhelpers.cpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -227,14 +227,14 @@ LLValue *DtoAllocaDump(LLValue *val, Type *asType, const char *name) {
227227

228228
LLValue *DtoAllocaDump(LLValue *val, LLType *asType, int alignment,
229229
const char *name) {
230-
LLType *valType = i1ToI8(voidToI8(val->getType()));
231-
asType = i1ToI8(voidToI8(asType));
230+
LLType *memType = i1ToI8(voidToI8(val->getType()));
231+
LLType *asMemType = i1ToI8(voidToI8(asType));
232232
LLType *allocaType =
233-
(getTypeStoreSize(valType) <= getTypeAllocSize(asType) ? asType
234-
: valType);
233+
(getTypeStoreSize(memType) <= getTypeAllocSize(asMemType) ? asMemType
234+
: memType);
235235
LLValue *mem = DtoRawAlloca(allocaType, alignment, name);
236-
DtoStoreZextI8(val, DtoBitCast(mem, valType->getPointerTo()));
237-
return DtoBitCast(mem, asType->getPointerTo());
236+
DtoStoreZextI8(val, DtoBitCast(mem, memType->getPointerTo()));
237+
return DtoBitCast(mem, asMemType->getPointerTo());
238238
}
239239

240240
/******************************************************************************
@@ -1602,18 +1602,10 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
16021602
assert(type->ty == Tdelegate);
16031603
return new DVarValue(type, getIrValue(vd));
16041604
}
1605-
if (vd->isRef() || vd->isOut() || DtoIsInMemoryOnly(vd->type) ||
1606-
llvm::isa<llvm::AllocaInst>(getIrValue(vd))) {
1607-
assert(!isSpecialRefVar(vd) && "Code not expected to handle special "
1608-
"ref vars, although it can easily be "
1609-
"made to.");
1610-
return new DVarValue(type, getIrValue(vd));
1611-
}
1612-
if (llvm::isa<llvm::Argument>(getIrValue(vd))) {
1613-
return new DImValue(type, getIrValue(vd));
1614-
}
1615-
llvm_unreachable("Unexpected parameter value.");
1616-
1605+
assert(!isSpecialRefVar(vd) && "Code not expected to handle special "
1606+
"ref vars, although it can easily be "
1607+
"made to.");
1608+
return new DVarValue(type, getIrValue(vd));
16171609
} else {
16181610
Logger::println("a normal variable");
16191611

gen/tocall.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,11 @@ DValue *DtoCallFunction(Loc &loc, Type *resulttype, DValue *fnval,
900900
// do ABI specific return value fixups
901901
if (storeReturnValueOnStack) {
902902
Logger::println("Storing return value to stack slot");
903-
LLValue *mem = DtoAlloca(returntype);
904-
irFty.getRet(returntype, retllval, mem);
905-
retllval = mem;
903+
retllval = irFty.getRetLVal(returntype, retllval);
906904
retValIsAlloca = true;
907905
storeReturnValueOnStack = false;
908906
} else {
909-
retllval = irFty.getRet(returntype, retllval);
907+
retllval = irFty.getRetRVal(returntype, retllval);
910908
storeReturnValueOnStack =
911909
(returnTy == Tstruct && !isaPointer(retllval)) ||
912910
(returnTy == Tsarray && isaArray(retllval));

0 commit comments

Comments
 (0)