mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 10:57:35 +03:00
Merge branch 'master' into merge-2.070
This commit is contained in:
commit
15aebef5be
23 changed files with 525 additions and 230 deletions
|
@ -17,32 +17,6 @@
|
|||
#include "gen/abi-generic.h"
|
||||
#include "gen/abi-aarch64.h"
|
||||
|
||||
namespace {
|
||||
struct CompositeToArray64 : ABIRewrite {
|
||||
LLValue *get(Type *dty, LLValue *v) override {
|
||||
Logger::println("rewriting i64 array -> as %s", dty->toChars());
|
||||
LLValue *lval = DtoRawAlloca(v->getType(), 0);
|
||||
DtoStore(v, lval);
|
||||
|
||||
LLType *pTy = getPtrToType(DtoType(dty));
|
||||
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
|
||||
}
|
||||
|
||||
LLValue *put(DValue *dv) override {
|
||||
Type *dty = dv->getType();
|
||||
Logger::println("rewriting %s -> as i64 array", dty->toChars());
|
||||
LLType *t = type(dty, nullptr);
|
||||
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
|
||||
}
|
||||
|
||||
LLType *type(Type *t, LLType *) override {
|
||||
// An i64 array that will hold Type 't'
|
||||
size_t sz = (t->size() + 7) / 8;
|
||||
return LLArrayType::get(LLIntegerType::get(gIR->context(), 64), sz);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct AArch64TargetABI : TargetABI {
|
||||
HFAToArray hfaToArray;
|
||||
CompositeToArray64 compositeToArray64;
|
||||
|
|
|
@ -241,6 +241,10 @@ struct ExplicitByvalRewrite : ABIRewrite {
|
|||
* float type.
|
||||
*/
|
||||
struct HFAToArray : ABIRewrite {
|
||||
const int maxFloats = 4;
|
||||
|
||||
HFAToArray(const int max = 4) : maxFloats(max) {}
|
||||
|
||||
LLValue *get(Type *dty, LLValue *v) override {
|
||||
Logger::println("rewriting array -> as HFA %s", dty->toChars());
|
||||
LLValue *lval = DtoRawAlloca(v->getType(), 0);
|
||||
|
@ -260,10 +264,37 @@ struct HFAToArray : ABIRewrite {
|
|||
LLType *type(Type *dty, LLType *) override {
|
||||
assert(dty->ty == Tstruct);
|
||||
LLType *floatArrayType = nullptr;
|
||||
if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType))
|
||||
if (TargetABI::isHFA((TypeStruct *)dty, &floatArrayType, maxFloats))
|
||||
return floatArrayType;
|
||||
llvm_unreachable("Type dty should be an HFA");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rewrite a composite as array of i64.
|
||||
*/
|
||||
struct CompositeToArray64 : ABIRewrite {
|
||||
LLValue *get(Type *dty, LLValue *v) override {
|
||||
Logger::println("rewriting i64 array -> as %s", dty->toChars());
|
||||
LLValue *lval = DtoRawAlloca(v->getType(), 0);
|
||||
DtoStore(v, lval);
|
||||
|
||||
LLType *pTy = getPtrToType(DtoType(dty));
|
||||
return DtoLoad(DtoBitCast(lval, pTy), "get-result");
|
||||
}
|
||||
|
||||
LLValue *put(DValue *dv) override {
|
||||
Type *dty = dv->getType();
|
||||
Logger::println("rewriting %s -> as i64 array", dty->toChars());
|
||||
LLType *t = type(dty, nullptr);
|
||||
return DtoLoad(DtoBitCast(dv->getRVal(), getPtrToType(t)));
|
||||
}
|
||||
|
||||
LLType *type(Type *t, LLType *) override {
|
||||
// An i64 array that will hold Type 't'
|
||||
size_t sz = (t->size() + 7) / 8;
|
||||
return LLArrayType::get(LLIntegerType::get(gIR->context(), 64), sz);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,25 +7,32 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The ABI implementation used for 32/64 bit big-endian PowerPC targets.
|
||||
//
|
||||
// The System V Application Binary Interface PowerPC Processor Supplement can be
|
||||
// found here:
|
||||
// http://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf
|
||||
//
|
||||
// The PowerOpen 64bit ABI can be found here:
|
||||
// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
|
||||
// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gen/abi.h"
|
||||
#include "gen/abi-generic.h"
|
||||
#include "gen/abi-ppc64.h"
|
||||
#include "gen/abi-ppc.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/tollvm.h"
|
||||
|
||||
struct PPC64TargetABI : TargetABI {
|
||||
struct PPCTargetABI : TargetABI {
|
||||
ExplicitByvalRewrite byvalRewrite;
|
||||
IntegerRewrite integerRewrite;
|
||||
const bool Is64Bit;
|
||||
|
||||
explicit PPC64TargetABI(const bool Is64Bit) : Is64Bit(Is64Bit) {}
|
||||
explicit PPCTargetABI(const bool Is64Bit) : Is64Bit(Is64Bit) {}
|
||||
|
||||
bool returnInArg(TypeFunction *tf) override {
|
||||
if (tf->isref) {
|
||||
|
@ -81,6 +88,6 @@ struct PPC64TargetABI : TargetABI {
|
|||
};
|
||||
|
||||
// The public getter for abi.cpp
|
||||
TargetABI *getPPC64TargetABI(bool Is64Bit) {
|
||||
return new PPC64TargetABI(Is64Bit);
|
||||
TargetABI *getPPCTargetABI(bool Is64Bit) {
|
||||
return new PPCTargetABI(Is64Bit);
|
||||
}
|
|
@ -7,15 +7,15 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The ABI implementation used for 64 bit PowerPC targets.
|
||||
// The ABI implementation used for 32/64 bit big-endian PowerPC targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LDC_GEN_ABI_PPC64_H
|
||||
#define LDC_GEN_ABI_PPC64_H
|
||||
#ifndef LDC_GEN_ABI_PPC_H
|
||||
#define LDC_GEN_ABI_PPC_H
|
||||
|
||||
struct TargetABI;
|
||||
|
||||
TargetABI *getPPC64TargetABI(bool Is64Bit);
|
||||
TargetABI *getPPCTargetABI(bool Is64Bit);
|
||||
|
||||
#endif
|
107
gen/abi-ppc64le.cpp
Normal file
107
gen/abi-ppc64le.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
//===-- abi-ppc64.cpp -----------------------------------------------------===//
|
||||
//
|
||||
// LDC - the LLVM D compiler
|
||||
//
|
||||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||
// file for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The ABI implementation used for 64 bit little-endian PowerPC targets.
|
||||
//
|
||||
// The PowerOpen 64bit ELF v2 ABI can be found here:
|
||||
// https://members.openpowerfoundation.org/document/dl/576
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gen/abi.h"
|
||||
#include "gen/abi-generic.h"
|
||||
#include "gen/abi-ppc64le.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/tollvm.h"
|
||||
|
||||
struct PPC64LETargetABI : TargetABI {
|
||||
HFAToArray hfaToArray;
|
||||
CompositeToArray64 compositeToArray64;
|
||||
IntegerRewrite integerRewrite;
|
||||
|
||||
explicit PPC64LETargetABI() : hfaToArray(8) {}
|
||||
|
||||
bool returnInArg(TypeFunction *tf) override {
|
||||
if (tf->isref) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *rt = tf->next->toBasetype();
|
||||
|
||||
// FIXME: The return value of this function translates
|
||||
// to RETstack or RETregs in function retStyle(), which
|
||||
// directly influences if NRVO is possible or not
|
||||
// (false -> RETregs -> nrvo_can = false). Depending on
|
||||
// NRVO, the postblit constructor is called or not.
|
||||
// Thus using the rules of the C ABI here (as mandated by
|
||||
// the D specification) leads to crashes.
|
||||
if (tf->linkage == LINKd)
|
||||
return rt->ty == Tsarray || rt->ty == Tstruct;
|
||||
|
||||
return rt->ty == Tsarray || (rt->ty == Tstruct && rt->size() > 16 &&
|
||||
!isHFA((TypeStruct *)rt, nullptr, 8));
|
||||
}
|
||||
|
||||
bool passByVal(Type *t) override {
|
||||
t = t->toBasetype();
|
||||
return t->ty == Tsarray || (t->ty == Tstruct && t->size() > 16 &&
|
||||
!isHFA((TypeStruct *)t, nullptr, 8));
|
||||
}
|
||||
|
||||
void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override {
|
||||
// RETURN VALUE
|
||||
Type *retTy = fty.ret->type->toBasetype();
|
||||
if (!fty.ret->byref) {
|
||||
if (retTy->ty == Tstruct || retTy->ty == Tsarray) {
|
||||
if (retTy->ty == Tstruct &&
|
||||
isHFA((TypeStruct *)retTy, &fty.ret->ltype, 8)) {
|
||||
fty.ret->rewrite = &hfaToArray;
|
||||
fty.ret->ltype = hfaToArray.type(fty.ret->type, fty.ret->ltype);
|
||||
} else if (canRewriteAsInt(retTy, true)) {
|
||||
fty.ret->rewrite = &integerRewrite;
|
||||
fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype);
|
||||
} else {
|
||||
fty.ret->rewrite = &compositeToArray64;
|
||||
fty.ret->ltype =
|
||||
compositeToArray64.type(fty.ret->type, fty.ret->ltype);
|
||||
}
|
||||
} else if (retTy->isintegral())
|
||||
fty.ret->attrs.add(retTy->isunsigned() ? LLAttribute::ZExt
|
||||
: LLAttribute::SExt);
|
||||
}
|
||||
|
||||
// EXPLICIT PARAMETERS
|
||||
for (auto arg : fty.args) {
|
||||
if (!arg->byref) {
|
||||
rewriteArgument(fty, *arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override {
|
||||
Type *ty = arg.type->toBasetype();
|
||||
if (ty->ty == Tstruct || ty->ty == Tsarray) {
|
||||
if (ty->ty == Tstruct && isHFA((TypeStruct *)ty, &arg.ltype, 8)) {
|
||||
arg.rewrite = &hfaToArray;
|
||||
arg.ltype = hfaToArray.type(arg.type, arg.ltype);
|
||||
} else if (canRewriteAsInt(ty, true)) {
|
||||
arg.rewrite = &integerRewrite;
|
||||
arg.ltype = integerRewrite.type(arg.type, arg.ltype);
|
||||
} else {
|
||||
arg.rewrite = &compositeToArray64;
|
||||
arg.ltype = compositeToArray64.type(arg.type, arg.ltype);
|
||||
}
|
||||
} else if (ty->isintegral())
|
||||
arg.attrs.add(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt);
|
||||
}
|
||||
};
|
||||
|
||||
// The public getter for abi.cpp
|
||||
TargetABI *getPPC64LETargetABI() { return new PPC64LETargetABI(); }
|
21
gen/abi-ppc64le.h
Normal file
21
gen/abi-ppc64le.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//===-- gen/abi-ppc-64.h - PPC64 ABI description ----------------*- C++ -*-===//
|
||||
//
|
||||
// LDC – the LLVM D compiler
|
||||
//
|
||||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||||
// file for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The ABI implementation used for 64 bit little-endian PowerPC targets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LDC_GEN_ABI_PPC64LE_H
|
||||
#define LDC_GEN_ABI_PPC64LE_H
|
||||
|
||||
struct TargetABI;
|
||||
|
||||
TargetABI *getPPC64LETargetABI();
|
||||
|
||||
#endif
|
15
gen/abi.cpp
15
gen/abi.cpp
|
@ -14,7 +14,8 @@
|
|||
#include "gen/abi-aarch64.h"
|
||||
#include "gen/abi-arm.h"
|
||||
#include "gen/abi-mips64.h"
|
||||
#include "gen/abi-ppc64.h"
|
||||
#include "gen/abi-ppc.h"
|
||||
#include "gen/abi-ppc64le.h"
|
||||
#include "gen/abi-win64.h"
|
||||
#include "gen/abi-x86-64.h"
|
||||
#include "gen/abi-x86.h"
|
||||
|
@ -166,8 +167,8 @@ bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num,
|
|||
else if (sz != floatSize) // different float size, reject
|
||||
return false;
|
||||
|
||||
if (n > 4)
|
||||
return false; // too many floats for HFA, reject
|
||||
//if (n > 4)
|
||||
// return false; // too many floats for HFA, reject
|
||||
} else {
|
||||
return false; // reject all other types
|
||||
}
|
||||
|
@ -181,11 +182,12 @@ bool isNestedHFA(const TypeStruct *t, d_uns64 &floatSize, int &num,
|
|||
}
|
||||
}
|
||||
|
||||
bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType) {
|
||||
bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType, const int maxFloats) {
|
||||
d_uns64 floatSize = 0;
|
||||
int num = 0;
|
||||
|
||||
if (isNestedHFA(t, floatSize, num, 1)) {
|
||||
if (num <= maxFloats) {
|
||||
if (rewriteType) {
|
||||
llvm::Type *floatType = nullptr;
|
||||
switch (floatSize) {
|
||||
|
@ -205,6 +207,7 @@ bool TargetABI::isHFA(TypeStruct *t, llvm::Type **rewriteType) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -336,9 +339,11 @@ TargetABI *TargetABI::getTarget() {
|
|||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
return getMIPS64TargetABI(global.params.is64bit);
|
||||
case llvm::Triple::ppc:
|
||||
case llvm::Triple::ppc64:
|
||||
return getPPCTargetABI(global.params.targetTriple->isArch64Bit());
|
||||
case llvm::Triple::ppc64le:
|
||||
return getPPC64TargetABI(global.params.targetTriple->isArch64Bit());
|
||||
return getPPC64LETargetABI();
|
||||
#if LDC_LLVM_VER == 305
|
||||
case llvm::Triple::arm64:
|
||||
case llvm::Triple::arm64_be:
|
||||
|
|
|
@ -154,7 +154,7 @@ struct TargetABI {
|
|||
/// Check if struct 't' is a Homogeneous Floating-point Aggregate (HFA)
|
||||
/// consisting of up to 4 of same floating point type. If so, optionally
|
||||
/// produce the rewriteType: an array of that floating point type
|
||||
static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr);
|
||||
static bool isHFA(TypeStruct *t, llvm::Type **rewriteType = nullptr, const int maxFloats = 4);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -15,7 +15,29 @@
|
|||
#include "gen/logger.h"
|
||||
#include "gen/tollvm.h"
|
||||
|
||||
namespace {
|
||||
bool isDefinedInFuncEntryBB(llvm::Value *v) {
|
||||
auto instr = llvm::dyn_cast<llvm::Instruction>(v);
|
||||
if (!instr) {
|
||||
// Global, constant, ...
|
||||
return true;
|
||||
}
|
||||
|
||||
auto bb = instr->getParent();
|
||||
if (bb != &(bb->getParent()->getEntryBlock())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// An invoke instruction in the entry BB does not necessarily dominate the
|
||||
// rest of the function because of the failure path.
|
||||
return !llvm::isa<llvm::InvokeInst>(instr);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool DImValue::definedInFuncEntryBB() { return isDefinedInFuncEntryBB(val); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool checkVarValueType(LLType *t, bool extraDeref) {
|
||||
|
@ -41,29 +63,19 @@ static bool checkVarValueType(LLType *t, bool extraDeref) {
|
|||
return true;
|
||||
}
|
||||
|
||||
DVarValue::DVarValue(Type *t, VarDeclaration *vd, LLValue *llvmValue)
|
||||
: DValue(t), var(vd), val(llvmValue) {
|
||||
assert(checkVarValueType(llvmValue->getType(), isSpecialRefVar(vd)));
|
||||
DVarValue::DVarValue(Type *t, LLValue *llvmValue, bool isSpecialRefVar)
|
||||
: DValue(t), val(llvmValue), isSpecialRefVar(isSpecialRefVar) {
|
||||
assert(llvmValue && "Unexpected null llvm::Value.");
|
||||
assert(checkVarValueType(llvmValue->getType(), isSpecialRefVar));
|
||||
}
|
||||
|
||||
DVarValue::DVarValue(Type *t, LLValue *llvmValue)
|
||||
: DValue(t), var(nullptr), val(llvmValue) {
|
||||
assert(checkVarValueType(llvmValue->getType(), false));
|
||||
}
|
||||
|
||||
LLValue *DVarValue::getLVal() {
|
||||
assert(val);
|
||||
if (var && isSpecialRefVar(var)) {
|
||||
return DtoLoad(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
LLValue *DVarValue::getLVal() { return isSpecialRefVar ? DtoLoad(val) : val; }
|
||||
|
||||
LLValue *DVarValue::getRVal() {
|
||||
assert(val);
|
||||
|
||||
llvm::Value *storage = val;
|
||||
if (var && isSpecialRefVar(var)) {
|
||||
if (isSpecialRefVar) {
|
||||
storage = DtoLoad(storage);
|
||||
}
|
||||
|
||||
|
@ -83,12 +95,12 @@ LLValue *DVarValue::getRVal() {
|
|||
}
|
||||
|
||||
LLValue *DVarValue::getRefStorage() {
|
||||
assert(val);
|
||||
assert(isSpecialRefVar(var));
|
||||
assert(isSpecialRefVar);
|
||||
return val;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool DVarValue::definedInFuncEntryBB() { return isDefinedInFuncEntryBB(val); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue *DSliceValue::getRVal() {
|
||||
|
@ -97,7 +109,10 @@ LLValue *DSliceValue::getRVal() {
|
|||
return DtoAggrPair(len, ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool DSliceValue::definedInFuncEntryBB() {
|
||||
return isDefinedInFuncEntryBB(len) && isDefinedInFuncEntryBB(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, llvm::Value *v,
|
||||
|
@ -112,7 +127,18 @@ LLValue *DFuncValue::getRVal() {
|
|||
return val;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool DFuncValue::definedInFuncEntryBB() {
|
||||
if (!isDefinedInFuncEntryBB(val)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vthis && !isDefinedInFuncEntryBB(vthis)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue *DConstValue::getRVal() {
|
||||
|
|
45
gen/dvalue.h
45
gen/dvalue.h
|
@ -35,7 +35,6 @@ class DImValue;
|
|||
class DConstValue;
|
||||
class DNullValue;
|
||||
class DVarValue;
|
||||
class DFieldValue;
|
||||
class DFuncValue;
|
||||
class DSliceValue;
|
||||
|
||||
|
@ -62,11 +61,20 @@ public:
|
|||
|
||||
virtual bool isLVal() { return false; }
|
||||
|
||||
/// Returns true iff the value can be accessed at the end of the entry basic
|
||||
/// block of the current function, in the sense that it is either not derived
|
||||
/// from an llvm::Instruction (but from a global, constant, etc.) or that
|
||||
/// instruction is part of the entry basic block.
|
||||
///
|
||||
/// In other words, whatever value the result of getLVal()/getRVal() might be
|
||||
/// derived from then certainly dominates uses in all other basic blocks of
|
||||
/// the function.
|
||||
virtual bool definedInFuncEntryBB() = 0;
|
||||
|
||||
virtual DImValue *isIm() { return nullptr; }
|
||||
virtual DConstValue *isConst() { return nullptr; }
|
||||
virtual DNullValue *isNull() { return nullptr; }
|
||||
virtual DVarValue *isVar() { return nullptr; }
|
||||
virtual DFieldValue *isField() { return nullptr; }
|
||||
virtual DSliceValue *isSlice() { return nullptr; }
|
||||
virtual DFuncValue *isFunc() { return nullptr; }
|
||||
|
||||
|
@ -89,6 +97,8 @@ public:
|
|||
return val;
|
||||
}
|
||||
|
||||
bool definedInFuncEntryBB() override;
|
||||
|
||||
DImValue *isIm() override { return this; }
|
||||
|
||||
protected:
|
||||
|
@ -102,6 +112,8 @@ public:
|
|||
|
||||
llvm::Value *getRVal() override;
|
||||
|
||||
bool definedInFuncEntryBB() override { return true; }
|
||||
|
||||
DConstValue *isConst() override { return this; }
|
||||
|
||||
llvm::Constant *c;
|
||||
|
@ -114,11 +126,14 @@ public:
|
|||
DNullValue *isNull() override { return this; }
|
||||
};
|
||||
|
||||
// variable d-value
|
||||
/// This is really a misnomer, DVarValue represents generic lvalues, which
|
||||
/// might or might not come from variable declarations.
|
||||
// TODO: Rename this, probably remove getLVal() from parent since this is the
|
||||
// only lvalue. The isSpecialRefVar case should probably also be its own
|
||||
// subclass.
|
||||
class DVarValue : public DValue {
|
||||
public:
|
||||
DVarValue(Type *t, VarDeclaration *vd, llvm::Value *llvmValue);
|
||||
DVarValue(Type *t, llvm::Value *llvmValue);
|
||||
DVarValue(Type *t, llvm::Value *llvmValue, bool isSpecialRefVar = false);
|
||||
|
||||
bool isLVal() override { return true; }
|
||||
llvm::Value *getLVal() override;
|
||||
|
@ -126,21 +141,15 @@ public:
|
|||
|
||||
/// Returns the underlying storage for special internal ref variables.
|
||||
/// Illegal to call on any other value.
|
||||
virtual llvm::Value *getRefStorage();
|
||||
llvm::Value *getRefStorage();
|
||||
|
||||
bool definedInFuncEntryBB() override;
|
||||
|
||||
DVarValue *isVar() override { return this; }
|
||||
|
||||
VarDeclaration *var;
|
||||
|
||||
protected:
|
||||
llvm::Value *val;
|
||||
};
|
||||
|
||||
// field d-value
|
||||
class DFieldValue : public DVarValue {
|
||||
public:
|
||||
DFieldValue(Type *t, llvm::Value *llvmValue) : DVarValue(t, llvmValue) {}
|
||||
DFieldValue *isField() override { return this; }
|
||||
llvm::Value *const val;
|
||||
bool const isSpecialRefVar;
|
||||
};
|
||||
|
||||
// slice d-value
|
||||
|
@ -151,6 +160,8 @@ public:
|
|||
|
||||
llvm::Value *getRVal() override;
|
||||
|
||||
bool definedInFuncEntryBB() override;
|
||||
|
||||
DSliceValue *isSlice() override { return this; }
|
||||
|
||||
llvm::Value *len;
|
||||
|
@ -166,6 +177,8 @@ public:
|
|||
|
||||
llvm::Value *getRVal() override;
|
||||
|
||||
bool definedInFuncEntryBB() override;
|
||||
|
||||
DFuncValue *isFunc() override { return this; }
|
||||
|
||||
FuncDeclaration *func;
|
||||
|
|
|
@ -10,11 +10,7 @@
|
|||
#include "gen/llvmhelpers.h"
|
||||
#include "declaration.h"
|
||||
#include "expression.h"
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "mars.h"
|
||||
#include "module.h"
|
||||
#include "template.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/arrays.h"
|
||||
#include "gen/classes.h"
|
||||
#include "gen/complex.h"
|
||||
|
@ -30,10 +26,14 @@
|
|||
#include "gen/tollvm.h"
|
||||
#include "gen/typeinf.h"
|
||||
#include "gen/uda.h"
|
||||
#include "gen/abi.h"
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "ir/irfunction.h"
|
||||
#include "ir/irmodule.h"
|
||||
#include "ir/irtypeaggr.h"
|
||||
#include "mars.h"
|
||||
#include "module.h"
|
||||
#include "template.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
|
@ -884,23 +884,21 @@ void DtoVarDeclaration(VarDeclaration *vd) {
|
|||
|
||||
if (isIrLocalCreated(vd)) {
|
||||
// Nothing to do if it has already been allocated.
|
||||
}
|
||||
/* Named Return Value Optimization (NRVO):
|
||||
T f(){
|
||||
T ret; // &ret == hidden pointer
|
||||
ret = ...
|
||||
return ret; // NRVO.
|
||||
}
|
||||
*/
|
||||
else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can &&
|
||||
} else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can &&
|
||||
gIR->func()->decl->nrvo_var == vd) {
|
||||
// Named Return Value Optimization (NRVO):
|
||||
// T f() {
|
||||
// T ret; // &ret == hidden pointer
|
||||
// ret = ...
|
||||
// return ret; // NRVO.
|
||||
// }
|
||||
assert(!isSpecialRefVar(vd) && "Can this happen?");
|
||||
IrLocal *irLocal = getIrLocal(vd, true);
|
||||
irLocal->value = gIR->func()->retArg;
|
||||
getIrLocal(vd, true)->value = gIR->func()->retArg;
|
||||
}
|
||||
// normal stack variable, allocate storage on the stack if it has not already
|
||||
// been done
|
||||
|
||||
else {
|
||||
// normal stack variable, allocate storage on the stack if it has not
|
||||
// already been done
|
||||
IrLocal *irLocal = getIrLocal(vd, true);
|
||||
|
||||
Type *type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type;
|
||||
|
@ -978,7 +976,6 @@ DValue *DtoDeclarationExp(Dsymbol *declaration) {
|
|||
IF_LOG Logger::print("DtoDeclarationExp: %s\n", declaration->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// variable declaration
|
||||
if (VarDeclaration *vd = declaration->isVarDeclaration()) {
|
||||
Logger::println("VarDeclaration");
|
||||
|
||||
|
@ -1000,25 +997,19 @@ DValue *DtoDeclarationExp(Dsymbol *declaration) {
|
|||
} else {
|
||||
DtoVarDeclaration(vd);
|
||||
}
|
||||
return new DVarValue(vd->type, vd, getIrValue(vd));
|
||||
return makeVarDValue(vd->type, vd);
|
||||
}
|
||||
// struct declaration
|
||||
|
||||
if (StructDeclaration *s = declaration->isStructDeclaration()) {
|
||||
Logger::println("StructDeclaration");
|
||||
Declaration_codegen(s);
|
||||
}
|
||||
// function declaration
|
||||
else if (FuncDeclaration *f = declaration->isFuncDeclaration()) {
|
||||
} else if (FuncDeclaration *f = declaration->isFuncDeclaration()) {
|
||||
Logger::println("FuncDeclaration");
|
||||
Declaration_codegen(f);
|
||||
}
|
||||
// class
|
||||
else if (ClassDeclaration *e = declaration->isClassDeclaration()) {
|
||||
} else if (ClassDeclaration *e = declaration->isClassDeclaration()) {
|
||||
Logger::println("ClassDeclaration");
|
||||
Declaration_codegen(e);
|
||||
}
|
||||
// attribute declaration
|
||||
else if (AttribDeclaration *a = declaration->isAttribDeclaration()) {
|
||||
} else if (AttribDeclaration *a = declaration->isAttribDeclaration()) {
|
||||
Logger::println("AttribDeclaration");
|
||||
// choose the right set in case this is a conditional declaration
|
||||
Dsymbols *d = a->include(nullptr, nullptr);
|
||||
|
@ -1027,17 +1018,13 @@ DValue *DtoDeclarationExp(Dsymbol *declaration) {
|
|||
DtoDeclarationExp((*d)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// mixin declaration
|
||||
else if (TemplateMixin *m = declaration->isTemplateMixin()) {
|
||||
} else if (TemplateMixin *m = declaration->isTemplateMixin()) {
|
||||
Logger::println("TemplateMixin");
|
||||
for (unsigned i = 0; i < m->members->dim; ++i) {
|
||||
Dsymbol *mdsym = static_cast<Dsymbol *>(m->members->data[i]);
|
||||
DtoDeclarationExp(mdsym);
|
||||
}
|
||||
}
|
||||
// tuple declaration
|
||||
else if (TupleDeclaration *tupled = declaration->isTupleDeclaration()) {
|
||||
} else if (TupleDeclaration *tupled = declaration->isTupleDeclaration()) {
|
||||
Logger::println("TupleDeclaration");
|
||||
assert(tupled->isexp && "Non-expression tuple decls not handled yet.");
|
||||
assert(tupled->objects);
|
||||
|
@ -1522,25 +1509,29 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
|
|||
if (vd->ident == Id::_arguments && gIR->func()->_arguments) {
|
||||
Logger::println("Id::_arguments");
|
||||
LLValue *v = gIR->func()->_arguments;
|
||||
return new DVarValue(type, vd, v);
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||
"vars, although it can easily be made "
|
||||
"to.");
|
||||
return new DVarValue(type, v);
|
||||
}
|
||||
// _argptr
|
||||
if (vd->ident == Id::_argptr && gIR->func()->_argptr) {
|
||||
Logger::println("Id::_argptr");
|
||||
LLValue *v = gIR->func()->_argptr;
|
||||
return new DVarValue(type, vd, v);
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||
"vars, although it can easily be made "
|
||||
"to.");
|
||||
return new DVarValue(type, v);
|
||||
}
|
||||
// _dollar
|
||||
if (vd->ident == Id::dollar) {
|
||||
Logger::println("Id::dollar");
|
||||
LLValue *val = nullptr;
|
||||
if (isIrVarCreated(vd) && (val = getIrValue(vd))) {
|
||||
// It must be length of a range
|
||||
return new DVarValue(type, vd, val);
|
||||
if (isIrVarCreated(vd)) {
|
||||
// This is the length of a range.
|
||||
return makeVarDValue(type, vd);
|
||||
}
|
||||
assert(!gIR->arrays.empty());
|
||||
val = DtoArrayLen(gIR->arrays.back());
|
||||
return new DImValue(type, val);
|
||||
return new DImValue(type, DtoArrayLen(gIR->arrays.back()));
|
||||
}
|
||||
// typeinfo
|
||||
if (TypeInfoDeclaration *tid = vd->isTypeInfoDeclaration()) {
|
||||
|
@ -1577,7 +1568,10 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
|
|||
}
|
||||
if (vd->isRef() || vd->isOut() || DtoIsInMemoryOnly(vd->type) ||
|
||||
llvm::isa<llvm::AllocaInst>(getIrValue(vd))) {
|
||||
return new DVarValue(type, vd, getIrValue(vd));
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special "
|
||||
"ref vars, although it can easily be "
|
||||
"made to.");
|
||||
return new DVarValue(type, getIrValue(vd));
|
||||
}
|
||||
if (llvm::isa<llvm::Argument>(getIrValue(vd))) {
|
||||
return new DImValue(type, getIrValue(vd));
|
||||
|
@ -1588,32 +1582,11 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
|
|||
Logger::println("a normal variable");
|
||||
|
||||
// take care of forward references of global variables
|
||||
const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern);
|
||||
if (isGlobal) {
|
||||
if (vd->isDataseg() || (vd->storage_class & STCextern)) {
|
||||
DtoResolveVariable(vd);
|
||||
}
|
||||
|
||||
assert(isIrVarCreated(vd) && "Variable not resolved.");
|
||||
|
||||
llvm::Value *val = getIrValue(vd);
|
||||
assert(val && "Variable value not set yet.");
|
||||
|
||||
if (isGlobal) {
|
||||
llvm::Type *expectedType =
|
||||
llvm::PointerType::getUnqual(DtoMemType(type));
|
||||
// The type of globals is determined by their initializer, so
|
||||
// we might need to cast. Make sure that the type sizes fit -
|
||||
// '==' instead of '<=' should probably work as well.
|
||||
if (val->getType() != expectedType) {
|
||||
llvm::Type *t =
|
||||
llvm::cast<llvm::PointerType>(val->getType())->getElementType();
|
||||
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(t) &&
|
||||
"Global type mismatch, encountered type too small.");
|
||||
val = DtoBitCast(val, expectedType);
|
||||
}
|
||||
}
|
||||
|
||||
return new DVarValue(type, vd, val);
|
||||
return makeVarDValue(type, vd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1845,3 +1818,28 @@ unsigned getFieldGEPIndex(AggregateDeclaration *ad, VarDeclaration *vd) {
|
|||
assert(byteOffset == 0 && "Cannot address field by a simple GEP.");
|
||||
return fieldIndex;
|
||||
}
|
||||
|
||||
DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
|
||||
auto val = storage;
|
||||
if (!val) {
|
||||
assert(isIrVarCreated(vd) && "Variable not resolved.");
|
||||
val = getIrValue(vd);
|
||||
}
|
||||
|
||||
if (vd->isDataseg() || (vd->storage_class & STCextern)) {
|
||||
// The type of globals is determined by their initializer, so
|
||||
// we might need to cast. Make sure that the type sizes fit -
|
||||
// '==' instead of '<=' should probably work as well.
|
||||
llvm::Type *expectedType = llvm::PointerType::getUnqual(DtoMemType(type));
|
||||
|
||||
if (val->getType() != expectedType) {
|
||||
llvm::Type *t =
|
||||
llvm::cast<llvm::PointerType>(val->getType())->getElementType();
|
||||
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(t) &&
|
||||
"Global type mismatch, encountered type too small.");
|
||||
val = DtoBitCast(val, expectedType);
|
||||
}
|
||||
}
|
||||
|
||||
return new DVarValue(type, val, isSpecialRefVar(vd));
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
#ifndef LDC_GEN_LLVMHELPERS_H
|
||||
#define LDC_GEN_LLVMHELPERS_H
|
||||
|
||||
#include "mtype.h"
|
||||
#include "statement.h"
|
||||
#include "gen/dvalue.h"
|
||||
#include "gen/llvm.h"
|
||||
#include "ir/irfuncty.h"
|
||||
#include "mtype.h"
|
||||
#include "statement.h"
|
||||
|
||||
struct IRState;
|
||||
|
||||
|
@ -262,4 +262,11 @@ DValue *toElem(Expression *e, bool tryGetLvalue);
|
|||
DValue *toElemDtor(Expression *e);
|
||||
LLConstant *toConstElem(Expression *e, IRState *p);
|
||||
|
||||
/// Creates a DVarValue for the given VarDeclaration.
|
||||
///
|
||||
/// If the storage is not given explicitly, the declaration is expected to be
|
||||
/// already resolved, and the value from the associated IrVar will be used.
|
||||
DValue *makeVarDValue(Type *type, VarDeclaration *vd,
|
||||
llvm::Value *storage = nullptr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -62,8 +62,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
if (fd->isStatic()) {
|
||||
error(loc, "function %s cannot access frame of function %s",
|
||||
irfunc->decl->toPrettyChars(), vdparent->toPrettyChars());
|
||||
return new DVarValue(astype, vd,
|
||||
llvm::UndefValue::get(DtoPtrToType(astype)));
|
||||
return new DVarValue(astype, llvm::UndefValue::get(DtoPtrToType(astype)));
|
||||
}
|
||||
fd = getParentFunc(fd, false);
|
||||
assert(fd);
|
||||
|
@ -71,8 +70,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
|
||||
// is the nested variable in this scope?
|
||||
if (vdparent == irfunc->decl) {
|
||||
LLValue *val = getIrValue(vd);
|
||||
return new DVarValue(astype, vd, val);
|
||||
return makeVarDValue(astype, vd);
|
||||
}
|
||||
|
||||
LLValue *dwarfValue = nullptr;
|
||||
|
@ -120,8 +118,9 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
Logger::cout() << "of type: " << *irfunc->frameType << '\n';
|
||||
}
|
||||
|
||||
unsigned vardepth = getIrLocal(vd)->nestedDepth;
|
||||
unsigned funcdepth = irfunc->depth;
|
||||
IrLocal *const irLocal = getIrLocal(vd);
|
||||
const auto vardepth = irLocal->nestedDepth;
|
||||
const auto funcdepth = irfunc->depth;
|
||||
|
||||
IF_LOG {
|
||||
Logger::cout() << "Variable: " << vd->toChars() << '\n';
|
||||
|
@ -148,7 +147,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
IF_LOG Logger::cout() << "Frame: " << *val << '\n';
|
||||
}
|
||||
|
||||
int idx = getIrLocal(vd)->nestedIndex;
|
||||
const auto idx = irLocal->nestedIndex;
|
||||
assert(idx != -1 && "Nested context not yet resolved for variable.");
|
||||
|
||||
if (dwarfValue && global.params.symdebug) {
|
||||
|
@ -165,8 +164,8 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
val = DtoAlignedLoad(val);
|
||||
// dwarfOpDeref(dwarfAddr);
|
||||
IF_LOG {
|
||||
Logger::cout() << "Was byref, now: " << *val << '\n';
|
||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||
Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
|
||||
Logger::cout() << "of type: " << *irLocal->value->getType() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +173,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, dwarfAddr);
|
||||
}
|
||||
|
||||
return new DVarValue(astype, vd, val);
|
||||
return makeVarDValue(astype, vd, val);
|
||||
}
|
||||
|
||||
void DtoResolveNestedContext(Loc &loc, AggregateDeclaration *decl,
|
||||
|
|
87
gen/toir.cpp
87
gen/toir.cpp
|
@ -9,15 +9,6 @@
|
|||
|
||||
#include "attrib.h"
|
||||
#include "enum.h"
|
||||
#include "hdrgen.h"
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "mtype.h"
|
||||
#include "ldcbindings.h"
|
||||
#include "module.h"
|
||||
#include "port.h"
|
||||
#include "rmem.h"
|
||||
#include "template.h"
|
||||
#include "gen/aa.h"
|
||||
#include "gen/abi.h"
|
||||
#include "gen/arrays.h"
|
||||
|
@ -38,9 +29,18 @@
|
|||
#include "gen/tollvm.h"
|
||||
#include "gen/typeinf.h"
|
||||
#include "gen/warnings.h"
|
||||
#include "hdrgen.h"
|
||||
#include "id.h"
|
||||
#include "init.h"
|
||||
#include "ir/irfunction.h"
|
||||
#include "ir/irtypeclass.h"
|
||||
#include "ir/irtypestruct.h"
|
||||
#include "ldcbindings.h"
|
||||
#include "module.h"
|
||||
#include "mtype.h"
|
||||
#include "port.h"
|
||||
#include "rmem.h"
|
||||
#include "template.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include <fstream>
|
||||
|
@ -157,7 +157,9 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
|
|||
}
|
||||
|
||||
// get a pointer to this field
|
||||
DVarValue field(vd->type, vd, DtoIndexAggregate(mem, sd, vd));
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||
"vars, although it can easily be made to.");
|
||||
DVarValue field(vd->type, DtoIndexAggregate(mem, sd, vd));
|
||||
|
||||
// store the initializer there
|
||||
DtoAssign(loc, &field, val, TOKconstruct, true);
|
||||
|
@ -287,11 +289,17 @@ public:
|
|||
DValue *getResult() {
|
||||
if (destructTemporaries &&
|
||||
p->func()->scopes->currentCleanupScope() != initialCleanupScope) {
|
||||
// If the results is an (LLVM) r-value, temporarily store it in an
|
||||
// alloca slot to avoid running into instruction dominance issues
|
||||
// if we share the cleanups with another exit path (e.g. unwinding).
|
||||
// We might share the CFG edges through the below cleanup blocks with
|
||||
// other paths (e.g. exception unwinding) where the result value has not
|
||||
// been constructed. At runtime, the branches will be chosen such that the
|
||||
// end bb (which will likely go on to access the value) is never executed
|
||||
// in those other cases, but we need to make sure that the SSA is also
|
||||
// well-formed statically (i.e. all instructions dominate their uses).
|
||||
// Thus, dump the result to a temporary stack slot (created in the entry
|
||||
// bb) if it is not guaranteed to dominate the end bb after possibly
|
||||
// adding more control flow.
|
||||
if (result && result->getType()->ty != Tvoid &&
|
||||
(result->isIm() || result->isSlice())) {
|
||||
!result->definedInFuncEntryBB()) {
|
||||
LLValue *alloca = DtoAllocaDump(result);
|
||||
result = new DVarValue(result->getType(), alloca);
|
||||
}
|
||||
|
@ -322,15 +330,12 @@ public:
|
|||
|
||||
result = DtoDeclarationExp(e->declaration);
|
||||
|
||||
if (result) {
|
||||
if (DVarValue *varValue = result->isVar()) {
|
||||
VarDeclaration *vd = varValue->var;
|
||||
if (auto vd = e->declaration->isVarDeclaration()) {
|
||||
if (!vd->isDataseg() && vd->edtor && !vd->noscope) {
|
||||
pushVarDtorCleanup(p, vd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1045,11 +1050,6 @@ public:
|
|||
}
|
||||
|
||||
DValue *v = toElem(e->e1, true);
|
||||
if (v->isField()) {
|
||||
Logger::println("is field");
|
||||
result = v;
|
||||
return;
|
||||
}
|
||||
if (DFuncValue *fv = v->isFunc()) {
|
||||
Logger::println("is func");
|
||||
// Logger::println("FuncDeclaration");
|
||||
|
@ -1139,9 +1139,10 @@ public:
|
|||
if (e->cachedLvalue) {
|
||||
Logger::println("using cached lvalue");
|
||||
LLValue *V = e->cachedLvalue;
|
||||
VarDeclaration *vd = e->var->isVarDeclaration();
|
||||
assert(vd);
|
||||
result = new DVarValue(e->type, vd, V);
|
||||
assert(!isSpecialRefVar(e->var->isVarDeclaration()) &&
|
||||
"Code not expected to handle special ref vars, although it can "
|
||||
"easily be made to.");
|
||||
result = new DVarValue(e->type, V);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1175,7 @@ public:
|
|||
}
|
||||
|
||||
// Logger::cout() << "mem: " << *arrptr << '\n';
|
||||
result = new DVarValue(e->type, vd, arrptr);
|
||||
result = new DVarValue(e->type, arrptr);
|
||||
} else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) {
|
||||
DtoResolveFunction(fdecl);
|
||||
|
||||
|
@ -1236,7 +1237,10 @@ public:
|
|||
Logger::println("normal this exp");
|
||||
v = p->func()->thisArg;
|
||||
}
|
||||
result = new DVarValue(e->type, vd, v);
|
||||
assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
|
||||
"vars, although it can easily be made "
|
||||
"to.");
|
||||
result = new DVarValue(e->type, v);
|
||||
} else {
|
||||
llvm_unreachable("No VarDeclaration in ThisExp.");
|
||||
}
|
||||
|
@ -1294,25 +1298,20 @@ public:
|
|||
e->type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
// this is the new slicing code, it's different in that a full slice will no
|
||||
// longer retain the original pointer.
|
||||
// but this was broken if there *was* no original pointer, ie. a slice of a
|
||||
// slice...
|
||||
// now all slices have *both* the 'len' and 'ptr' fields set to != null.
|
||||
|
||||
// value being sliced
|
||||
LLValue *elen = nullptr;
|
||||
LLValue *eptr;
|
||||
DValue *v = toElem(e->e1);
|
||||
|
||||
// handle pointer slicing
|
||||
Type *etype = e->e1->type->toBasetype();
|
||||
if (etype->ty == Tpointer) {
|
||||
// pointer slicing
|
||||
assert(e->lwr);
|
||||
eptr = v->getRVal();
|
||||
}
|
||||
// array slice
|
||||
|
||||
else {
|
||||
// array slice
|
||||
eptr = DtoArrayPtr(v);
|
||||
}
|
||||
|
||||
|
@ -1373,8 +1372,7 @@ public:
|
|||
// no bounds or full slice -> just convert to slice
|
||||
else {
|
||||
assert(e->e1->type->toBasetype()->ty != Tpointer);
|
||||
// if the sliceee is a static array, we use the length of that as DMD
|
||||
// seems
|
||||
// if the slicee is a static array, we use the length of that as DMD seems
|
||||
// to give contrary inconsistent sizesin some multidimensional static
|
||||
// array cases.
|
||||
// (namely default initialization, int[16][16] arr; -> int[256] arr = 0;)
|
||||
|
@ -1785,12 +1783,14 @@ public:
|
|||
if (tc->sym->isInterfaceDeclaration()) {
|
||||
DtoDeleteInterface(e->loc, dval);
|
||||
onstack = true;
|
||||
} else if (DVarValue *vv = dval->isVar()) {
|
||||
if (vv->var && vv->var->onstack) {
|
||||
} else if (e->e1->op == TOKvar) {
|
||||
if (auto vd = static_cast<VarExp *>(e->e1)->var->isVarDeclaration()) {
|
||||
if (vd->onstack) {
|
||||
DtoFinalizeClass(e->loc, dval->getRVal());
|
||||
onstack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!onstack) {
|
||||
DtoDeleteClass(e->loc, dval); // sets dval to null
|
||||
|
@ -1896,8 +1896,9 @@ public:
|
|||
// struct invariants
|
||||
else if (global.params.useInvariants && condty->ty == Tpointer &&
|
||||
condty->nextOf()->ty == Tstruct &&
|
||||
(invdecl = static_cast<TypeStruct *>(condty->nextOf())
|
||||
->sym->inv) != nullptr) {
|
||||
(invdecl =
|
||||
static_cast<TypeStruct *>(condty->nextOf())->sym->inv) !=
|
||||
nullptr) {
|
||||
Logger::print("calling struct invariant");
|
||||
DtoResolveFunction(invdecl);
|
||||
DFuncValue invfunc(invdecl, getIrFunc(invdecl)->func, cond->getRVal());
|
||||
|
@ -2266,7 +2267,7 @@ public:
|
|||
|
||||
p->scope() = IRScope(condend);
|
||||
if (retPtr) {
|
||||
result = new DVarValue(e->type, DtoLoad(retPtr));
|
||||
result = new DVarValue(e->type, retPtr, true);
|
||||
} else {
|
||||
result = new DConstValue(e->type, getNullValue(DtoMemType(dtype)));
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "gen/runtime.h"
|
||||
#include "gen/structs.h"
|
||||
#include "gen/typeinf.h"
|
||||
#include "gen/uda.h"
|
||||
#include "ir/irtype.h"
|
||||
#include "ir/irtypeclass.h"
|
||||
#include "ir/irtypefunction.h"
|
||||
|
@ -247,6 +248,12 @@ LLValue *DtoDelegateEquals(TOK op, LLValue *lhs, LLValue *rhs) {
|
|||
LinkageWithCOMDAT DtoLinkage(Dsymbol *sym) {
|
||||
auto linkage = (DtoIsTemplateInstance(sym) ? templateLinkage
|
||||
: LLGlobalValue::ExternalLinkage);
|
||||
|
||||
// If @(ldc.attributes.weak) is applied, override the linkage to WeakAny
|
||||
if (hasWeakUDA(sym)) {
|
||||
linkage = LLGlobalValue::WeakAnyLinkage;
|
||||
}
|
||||
|
||||
return {linkage, supportsCOMDAT()};
|
||||
}
|
||||
|
||||
|
|
45
gen/uda.cpp
45
gen/uda.cpp
|
@ -15,10 +15,11 @@ namespace {
|
|||
namespace attr {
|
||||
const std::string section = "section";
|
||||
const std::string target = "target";
|
||||
const std::string weak = "_weak";
|
||||
}
|
||||
|
||||
bool isFromLdcAttibutes(StructLiteralExp *e) {
|
||||
auto moduleDecl = e->sd->getModule()->md;
|
||||
/// Checks whether `moduleDecl` is the ldc.attributes module.
|
||||
bool isLdcAttibutes(const ModuleDeclaration *moduleDecl) {
|
||||
if (!moduleDecl)
|
||||
return false;
|
||||
|
||||
|
@ -33,6 +34,12 @@ bool isFromLdcAttibutes(StructLiteralExp *e) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Checks whether the type of `e` is a struct from the ldc.attributes module.
|
||||
bool isFromLdcAttibutes(const StructLiteralExp *e) {
|
||||
auto moduleDecl = e->sd->getModule()->md;
|
||||
return isLdcAttibutes(moduleDecl);
|
||||
}
|
||||
|
||||
StructLiteralExp *getLdcAttributesStruct(Expression *attr) {
|
||||
// See whether we can evaluate the attribute at compile-time. All the LDC
|
||||
// attributes are struct literals that may be constructed using a CTFE
|
||||
|
@ -171,6 +178,8 @@ void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar) {
|
|||
} else if (name == attr::target) {
|
||||
sle->error("Special attribute 'ldc.attributes.target' is only valid for "
|
||||
"functions");
|
||||
} else if (name == attr::weak) {
|
||||
// @weak is applied elsewhere
|
||||
} else {
|
||||
sle->warning(
|
||||
"Ignoring unrecognized special attribute 'ldc.attributes.%s'",
|
||||
|
@ -195,6 +204,8 @@ void applyFuncDeclUDAs(FuncDeclaration *decl, llvm::Function *func) {
|
|||
applyAttrSection(sle, func);
|
||||
} else if (name == attr::target) {
|
||||
applyAttrTarget(sle, func);
|
||||
} else if (name == attr::weak) {
|
||||
// @weak is applied elsewhere
|
||||
} else {
|
||||
sle->warning(
|
||||
"ignoring unrecognized special attribute 'ldc.attributes.%s'",
|
||||
|
@ -202,3 +213,33 @@ void applyFuncDeclUDAs(FuncDeclaration *decl, llvm::Function *func) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether 'sym' has the @ldc.attributes._weak() UDA applied.
|
||||
bool hasWeakUDA(Dsymbol *sym) {
|
||||
if (!sym->userAttribDecl)
|
||||
return false;
|
||||
|
||||
// Loop over all UDAs and early return true if @weak was found.
|
||||
Expressions *attrs = sym->userAttribDecl->getAttributes();
|
||||
expandTuples(attrs);
|
||||
for (auto &attr : *attrs) {
|
||||
auto sle = getLdcAttributesStruct(attr);
|
||||
if (!sle)
|
||||
continue;
|
||||
|
||||
auto name = sle->sd->ident->string;
|
||||
if (name == attr::weak) {
|
||||
// Check whether @weak can be applied to this symbol.
|
||||
// Because hasWeakUDA is currently only called for global symbols, this check never errors.
|
||||
auto vd = sym->isVarDeclaration();
|
||||
if (!(vd && vd->isDataseg()) && !sym->isFuncDeclaration()) {
|
||||
sym->error("@ldc.attributes.weak can only be applied to functions or global variables");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef GEN_UDA_H
|
||||
#define GEN_UDA_H
|
||||
|
||||
class Dsymbol;
|
||||
class FuncDeclaration;
|
||||
class VarDeclaration;
|
||||
namespace llvm {
|
||||
|
@ -25,4 +26,6 @@ class GlobalVariable;
|
|||
void applyFuncDeclUDAs(FuncDeclaration *decl, llvm::Function *func);
|
||||
void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar);
|
||||
|
||||
bool hasWeakUDA(Dsymbol *sym);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8438312451713a6e80f53efde0adb17ff3d0a535
|
||||
Subproject commit 822be5157906f13d0eb6763d10f80e54ec41a350
|
|
@ -14,6 +14,17 @@ import ldc.attributes;
|
|||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
//---- @(weak) --------------------------------------------------------
|
||||
|
||||
// CHECK-DAG: @{{.*}}myWeakGlobali = weak
|
||||
@(ldc.attributes.weak) int myWeakGlobal;
|
||||
|
||||
// CHECK-DAG: define{{.*}} weak {{.*}}void @{{.*}}weakFunc
|
||||
@weak void weakFunc() {}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
|
||||
// CHECK-LABEL: define i32 @_Dmain
|
||||
void main() {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d006abf3c861c6f07069e1004ea545d7a464961a
|
||||
Subproject commit 7fbd3606b5a5735738f6cc449b5e05c090180ad0
|
21
tests/ir/attr_weak.d
Normal file
21
tests/ir/attr_weak.d
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Test linking+running a program with @weak functions
|
||||
|
||||
// RUN: %ldc -O3 %S/inputs/attr_weak_input.d -c -of=%t%obj
|
||||
// RUN: %ldc -O3 %t%obj -run %s
|
||||
|
||||
|
||||
import ldc.attributes;
|
||||
|
||||
extern(C) int return_two() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Should be overridden by attr_weak_input.d
|
||||
extern(C) @weak int return_seven() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void main() {
|
||||
assert( return_two() == 2 );
|
||||
assert( return_seven() == 7 );
|
||||
}
|
9
tests/ir/inputs/attr_weak_input.d
Normal file
9
tests/ir/inputs/attr_weak_input.d
Normal file
|
@ -0,0 +1,9 @@
|
|||
import ldc.attributes;
|
||||
|
||||
extern(C) @weak int return_two() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern(C) int return_seven() {
|
||||
return 7;
|
||||
}
|
|
@ -20,10 +20,15 @@ config.test_format = lit.formats.ShTest(execute_external=False)
|
|||
config.suffixes = ['.d',
|
||||
]
|
||||
|
||||
# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
|
||||
# excludes: A list of directories to exclude from the testsuite. The 'inputs'
|
||||
# subdirectories contain auxiliary inputs for various tests in their parent
|
||||
# directories.
|
||||
config.excludes = ['d2', 'CMakeLists.txt', 'runlit.py']
|
||||
config.excludes = [
|
||||
'inputs',
|
||||
'd2',
|
||||
'CMakeLists.txt',
|
||||
'runlit.py',
|
||||
]
|
||||
|
||||
# Define available features so that we can disable tests depending on LLVM version
|
||||
config.available_features.add("llvm%d" % config.llvm_version)
|
||||
|
@ -52,3 +57,12 @@ config.environment['PATH'] = path
|
|||
|
||||
# Add substitutions
|
||||
config.substitutions.append( ('%ldc', config.ldc2_bin) )
|
||||
|
||||
# Add platform-dependent file extension substitutions
|
||||
if (platform.system() == 'Windows'):
|
||||
config.substitutions.append( ('%obj', '.obj') )
|
||||
config.substitutions.append( ('%exe', '.exe') )
|
||||
else:
|
||||
config.substitutions.append( ('%obj', '.o') )
|
||||
config.substitutions.append( ('%exe', '') )
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue