Merge branch 'merge-2.064' into merge-2.065

This commit is contained in:
Kai Nacke
2013-12-29 20:49:43 +01:00
10 changed files with 135 additions and 67 deletions

View File

@@ -236,9 +236,15 @@ public:
virtual elem *toElem(IRState *irs);
elem *toElemDtor(IRState *irs);
#if IN_LLVM
/// Emits an LLVM constant corresponding to the expression.
///
/// Due to the current implementation of AssocArrayLiteralExp::toElem,the
/// implementations have to be able to handle being called on expressions
/// that are not actually constant. In such a case, an LLVM undef of the
/// expected type should be returned (_not_ null).
virtual llvm::Constant *toConstElem(IRState *irs);
virtual void cacheLvalue(IRState* irs);
virtual void cacheLvalue(IRState* irs);
llvm::Value* cachedLvalue;
virtual AssignExp* isAssignExp() { return NULL; }

View File

@@ -121,9 +121,6 @@ LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
//////////////////////////////////////////////////////////////////////////////////////////
// helper function that adds zero bytes to a vector of constants
extern size_t add_zeros(std::vector<LLConstant*>& values, size_t diff);
/// Return the type returned by DtoUnpaddedStruct called on a value of the
/// specified type.
/// Union types will get expanded into a struct, with a type for each member.

View File

@@ -652,8 +652,8 @@ LLConstant* AddExp::toConstElem(IRState* p)
}
error("expression '%s' is not a constant", toChars());
fatal();
return NULL;
if (!global.gag) fatal();
return llvm::UndefValue::get(DtoType(type));
}
/// Tries to remove a MulExp by a constant value of baseSize from e. Returns
@@ -766,8 +766,8 @@ LLConstant* MinExp::toConstElem(IRState* p)
}
error("expression '%s' is not a constant", toChars());
fatal();
return NULL;
if (!global.gag) fatal();
return llvm::UndefValue::get(DtoType(type));
}
DValue* MinExp::toElem(IRState* p)
@@ -1231,7 +1231,7 @@ Lerr:
error("cannot cast %s to %s at compile time", e1->type->toChars(), type->toChars());
if (!global.gag)
fatal();
return NULL;
return llvm::UndefValue::get(DtoType(type));
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1290,11 +1290,7 @@ llvm::Constant* SymOffExp::toConstElem(IRState* p)
IF_LOG Logger::println("SymOffExp::toConstElem: %s @ %s", toChars(), type->toChars());
LOG_SCOPE;
// We might get null here due to the hackish implementation of
// AssocArrayLiteralExp::toElem.
llvm::Constant* base = DtoConstSymbolAddress(loc, var);
if (!base) return 0;
llvm::Constant* result;
if (offset == 0)
{
@@ -1462,7 +1458,8 @@ LLConstant* AddrExp::toConstElem(IRState* p)
else if (e1->op == TOKslice)
{
error("non-constant expression '%s'", toChars());
fatal();
if (!global.gag) fatal();
return llvm::UndefValue::get(DtoType(type));
}
// not yet supported
else
@@ -2872,7 +2869,8 @@ LLConstant* FuncExp::toConstElem(IRState* p)
{
assert(fd->tok == TOKdelegate || fd->tok == TOKreserved);
error("delegate literals as constant expressions are not yet allowed");
return 0;
if (!global.gag) fatal();
return llvm::UndefValue::get(DtoType(type));
}
// We need to actually codegen the function here, as literals are not added
@@ -3302,6 +3300,36 @@ DValue* RemoveExp::toElem(IRState* p)
//////////////////////////////////////////////////////////////////////////////////////////
/// Constructs an array initializer constant with the given constants as its
/// elements. If the element types differ (unions, …), an anonymous struct
/// literal is emitted (as for array constant initializers).
static llvm::Constant* arrayConst(std::vector<llvm::Constant*>& vals,
Type* nominalElemType)
{
if (vals.size() == 0)
{
llvm::ArrayType* type = llvm::ArrayType::get(DtoType(nominalElemType), 0);
return llvm::ConstantArray::get(type, vals);
}
llvm::Type* elementType = NULL;
bool differentTypes = false;
for (std::vector<llvm::Constant*>::iterator i = vals.begin(), end = vals.end();
i != end; ++i)
{
if (!elementType)
elementType = (*i)->getType();
else
differentTypes |= (elementType != (*i)->getType());
}
if (differentTypes)
return llvm::ConstantStruct::getAnon(vals, true);
llvm::ArrayType *t = llvm::ArrayType::get(elementType, vals.size());
return llvm::ConstantArray::get(t, vals);
}
DValue* AssocArrayLiteralExp::toElem(IRState* p)
{
Logger::print("AssocArrayLiteralExp::toElem: %s @ %s\n", toChars(), type->toChars());
@@ -3356,16 +3384,16 @@ DValue* AssocArrayLiteralExp::toElem(IRState* p)
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
LLArrayType* arrtype = LLArrayType::get(DtoType(indexType), keys->dim);
LLConstant* initval = LLConstantArray::get(arrtype, keysInits);
LLConstant* globalstore = new LLGlobalVariable(*gIR->module, arrtype, false, LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
LLConstant* initval = arrayConst(keysInits, indexType);
LLConstant* globalstore = new LLGlobalVariable(*gIR->module, initval->getType(),
false, LLGlobalValue::InternalLinkage, initval, ".aaKeysStorage");
LLConstant* slice = llvm::ConstantExpr::getGetElementPtr(globalstore, idxs, true);
slice = DtoConstSlice(DtoConstSize_t(keys->dim), slice);
LLValue* keysArray = DtoAggrPaint(slice, funcTy->getParamType(1));
arrtype = LLArrayType::get(DtoType(vtype), values->dim);
initval = LLConstantArray::get(arrtype, valuesInits);
globalstore = new LLGlobalVariable(*gIR->module, arrtype, false, LLGlobalValue::InternalLinkage, initval, ".aaValuesStorage");
initval = arrayConst(valuesInits, vtype);
globalstore = new LLGlobalVariable(*gIR->module, initval->getType(),
false, LLGlobalValue::InternalLinkage, initval, ".aaValuesStorage");
slice = llvm::ConstantExpr::getGetElementPtr(globalstore, idxs, true);
slice = DtoConstSlice(DtoConstSize_t(keys->dim), slice);
LLValue* valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
@@ -3527,5 +3555,10 @@ llvm::Constant* Expression::toConstElem(IRState * p)
error("expression '%s' is not a constant", toChars());
if (!global.gag)
fatal();
return NULL;
// Do not return null here, as AssocArrayLiteralExp::toElem determines
// whether it can allocate the needed arrays statically by just invoking
// toConstElem on its key/value expressions, and handling the null value
// consequently would require error-prone adaptions in all other code.
return llvm::UndefValue::get(DtoType(type));
}

View File

@@ -382,6 +382,10 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
llvm_unreachable("not global/function");
}
// The logic here should be sound in theory, but as long as the frontend
// keeps inserting templates into wrong modules, this yields to linking
// errors (see e.g. GitHub issue #558).
#if 0
// Check if sym is a nested function and we can declare it as internal.
//
// Nested naked functions and the implicitly generated __require/__ensure
@@ -427,7 +431,7 @@ LLGlobalValue::LinkageTypes DtoLinkage(Dsymbol* sym)
}
}
}
#endif
// default to external linkage
return llvm::GlobalValue::ExternalLinkage;
}

View File

@@ -87,34 +87,50 @@ llvm::Constant * IrAggr::getDefaultInit()
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static bool isAligned(llvm::Type* type, size_t offset) {
return gDataLayout->getABITypeAlignment(type) % offset == 0;
}
// helper function that adds zero bytes to a vector of constants
size_t add_zeros(llvm::SmallVectorImpl<llvm::Constant*>& constants, size_t diff)
size_t add_zeros(llvm::SmallVectorImpl<llvm::Constant*>& constants,
size_t startOffset, size_t endOffset)
{
size_t n = constants.size();
while (diff)
size_t const oldLength = constants.size();
llvm::Type* const eightByte = llvm::Type::getInt64Ty(gIR->context());
llvm::Type* const fourByte = llvm::Type::getInt32Ty(gIR->context());
llvm::Type* const twoByte = llvm::Type::getInt16Ty(gIR->context());
assert(startOffset <= endOffset);
size_t paddingLeft = endOffset - startOffset;
while (paddingLeft)
{
if (global.params.is64bit && diff % 8 == 0)
if (global.params.is64bit && paddingLeft >= 8 && isAligned(eightByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt64Ty(gIR->context())));
diff -= 8;
constants.push_back(llvm::Constant::getNullValue(eightByte));
startOffset += 8;
}
else if (diff % 4 == 0)
else if (paddingLeft >= 4 && isAligned(fourByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt32Ty(gIR->context())));
diff -= 4;
constants.push_back(llvm::Constant::getNullValue(fourByte));
startOffset += 4;
}
else if (diff % 2 == 0)
else if (paddingLeft >= 2 && isAligned(twoByte, startOffset))
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt16Ty(gIR->context())));
diff -= 2;
constants.push_back(llvm::Constant::getNullValue(twoByte));
startOffset += 2;
}
else
{
constants.push_back(LLConstant::getNullValue(llvm::Type::getInt8Ty(gIR->context())));
diff -= 1;
constants.push_back(llvm::Constant::getNullValue(
llvm::Type::getInt8Ty(gIR->context())));
startOffset += 1;
}
paddingLeft = endOffset - startOffset;
}
return constants.size() - n;
return constants.size() - oldLength;
}
//////////////////////////////////////////////////////////////////////////////
@@ -201,9 +217,7 @@ llvm::Constant* IrAggr::createInitializerConstant(
const size_t structsize = type->size();
if (offset < structsize)
{
size_t diff = structsize - offset;
IF_LOG Logger::println("adding %zu bytes zero padding", diff);
add_zeros(constants, diff);
add_zeros(constants, offset, structsize);
}
// get initializer type
@@ -324,9 +338,7 @@ void IrAggr::addFieldInitializers(
// insert explicit padding?
if (alignedoffset < vd->offset)
{
size_t diff = vd->offset - alignedoffset;
IF_LOG Logger::println("adding %zu bytes zero padding", diff);
add_zeros(constants, diff);
add_zeros(constants, alignedoffset, vd->offset);
}
IF_LOG Logger::println("adding field %s", vd->toChars());

View File

@@ -37,7 +37,6 @@
//////////////////////////////////////////////////////////////////////////////
extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init);
extern size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff);
extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);

View File

@@ -131,7 +131,7 @@ struct IrFuncTy
// Copy constructor and operator= seems to be required for MSC
IrFuncTy(const IrFuncTy& rhs)
: funcType(ths.funcType),
: funcType(rhs.funcType),
ret(rhs.ret),
args(IrFuncTy::ArgList(rhs.args)),
arg_sret(rhs.arg_sret),

View File

@@ -30,7 +30,8 @@
//////////////////////////////////////////////////////////////////////////////
extern size_t add_zeros(std::vector<llvm::Type*>& defaultTypes, size_t diff);
extern size_t add_zeros(std::vector<llvm::Type*>& defaultTypes,
size_t startOffset, size_t endOffset);
extern bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2);
//////////////////////////////////////////////////////////////////////////////
@@ -167,7 +168,7 @@ void IrTypeClass::addBaseClassData(
// insert explicit padding?
if (alignedoffset < vd->offset)
{
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
field_index += add_zeros(defaultTypes, alignedoffset, vd->offset);
}
// add default type
@@ -220,7 +221,7 @@ void IrTypeClass::addBaseClassData(
// tail padding?
if (offset < base->structsize)
{
field_index += add_zeros(defaultTypes, base->structsize - offset);
field_index += add_zeros(defaultTypes, offset, base->structsize);
offset = base->structsize;
}
#endif
@@ -268,7 +269,7 @@ IrTypeClass* IrTypeClass::get(ClassDeclaration* cd)
// tail padding?
if (offset < cd->structsize)
{
field_index += add_zeros(defaultTypes, cd->structsize - offset);
field_index += add_zeros(defaultTypes, offset, cd->structsize);
offset = cd->structsize;
}
#endif

View File

@@ -38,35 +38,51 @@ IrTypeStruct::IrTypeStruct(StructDeclaration * sd)
//////////////////////////////////////////////////////////////////////////////
size_t add_zeros(std::vector<llvm::Type*>& defaultTypes, size_t diff)
static bool isAligned(llvm::Type* type, size_t offset) {
return gDataLayout->getABITypeAlignment(type) % offset == 0;
}
size_t add_zeros(std::vector<llvm::Type*>& defaultTypes,
size_t startOffset, size_t endOffset)
{
size_t n = defaultTypes.size();
while (diff)
size_t const oldLength = defaultTypes.size();
llvm::Type* const eightByte = llvm::Type::getInt64Ty(gIR->context());
llvm::Type* const fourByte = llvm::Type::getInt32Ty(gIR->context());
llvm::Type* const twoByte = llvm::Type::getInt16Ty(gIR->context());
assert(startOffset <= endOffset);
size_t paddingLeft = endOffset - startOffset;
while (paddingLeft)
{
if (global.params.is64bit && diff % 8 == 0)
if (global.params.is64bit && paddingLeft >= 8 && isAligned(eightByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt64Ty(gIR->context()));
diff -= 8;
defaultTypes.push_back(eightByte);
startOffset += 8;
}
else if (diff % 4 == 0)
else if (paddingLeft >= 4 && isAligned(fourByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt32Ty(gIR->context()));
diff -= 4;
defaultTypes.push_back(fourByte);
startOffset += 4;
}
else if (diff % 2 == 0)
else if (paddingLeft >= 2 && isAligned(twoByte, startOffset))
{
defaultTypes.push_back(llvm::Type::getInt16Ty(gIR->context()));
diff -= 2;
defaultTypes.push_back(twoByte);
startOffset += 2;
}
else
{
defaultTypes.push_back(llvm::Type::getInt8Ty(gIR->context()));
diff -= 1;
startOffset += 1;
}
paddingLeft = endOffset - startOffset;
}
return defaultTypes.size() - n;
return defaultTypes.size() - oldLength;
}
bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2)
{
if (v1 && v2)
@@ -209,7 +225,7 @@ IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
// insert explicit padding?
if (alignedoffset < vd->offset)
{
field_index += add_zeros(defaultTypes, vd->offset - alignedoffset);
field_index += add_zeros(defaultTypes, alignedoffset, vd->offset);
}
// add default type
@@ -225,7 +241,7 @@ IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd)
// tail padding?
if (offset < sd->structsize)
{
add_zeros(defaultTypes, sd->structsize - offset);
add_zeros(defaultTypes, offset, sd->structsize);
}
// set struct body