ldc/gen/toconstelem.cpp
Kai Nacke d1e764cec1 Backport of "Avoid using llvm::Linker" to master.
See pull request #974 for the original code.
2015-06-27 22:08:44 +02:00

793 lines
28 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- toconstelem.cpp ---------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/arrays.h"
#include "gen/classes.h"
#include "gen/complex.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "ir/irtypeclass.h"
#include "ir/irtypestruct.h"
// Needs other includes.
#include "ctfe.h"
extern dinteger_t undoStrideMul(Loc& loc, Type* t, dinteger_t offset);
/// 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).
class ToConstElemVisitor : public Visitor
{
IRState *p;
LLConstant *result;
public:
ToConstElemVisitor(IRState *p_) : p(p_) { }
// Import all functions from class Visitor
using Visitor::visit;
//////////////////////////////////////////////////////////////////////////////////////////
LLConstant *toConstElem(Expression *e)
{
result = 0;
e->accept(this);
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(VarExp *e)
{
IF_LOG Logger::print("VarExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
if (SymbolDeclaration* sdecl = e->var->isSymbolDeclaration())
{
// this seems to be the static initialiser for structs
Type* sdecltype = sdecl->type->toBasetype();
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
DtoResolveStruct(ts->sym);
result = getIrAggr(ts->sym)->getDefaultInit();
return;
}
if (TypeInfoDeclaration* ti = e->var->isTypeInfoDeclaration())
{
LLType* vartype = DtoType(e->type);
result = DtoTypeInfoOf(ti->tinfo, false);
if (result->getType() != getPtrToType(vartype))
result = llvm::ConstantExpr::getBitCast(result, vartype);
return;
}
VarDeclaration* vd = e->var->isVarDeclaration();
if (vd && vd->isConst() && vd->init)
{
if (vd->inuse)
{
e->error("recursive reference %s", e->toChars());
result = llvm::UndefValue::get(DtoType(e->type));
}
else
{
vd->inuse++;
// return the initializer
result = DtoConstInitializer(e->loc, e->type, vd->init);
vd->inuse--;
}
}
// fail
else
{
e->error("non-constant expression %s", e->toChars());
result = llvm::UndefValue::get(DtoType(e->type));
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(IntegerExp *e)
{
IF_LOG Logger::print("IntegerExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
LLType* t = DtoType(e->type);
if (isaPointer(t))
{
Logger::println("pointer");
LLConstant* i = LLConstantInt::get(DtoSize_t(), (uint64_t)e->getInteger(), false);
result = llvm::ConstantExpr::getIntToPtr(i, t);
}
else
{
assert(llvm::isa<LLIntegerType>(t));
result = LLConstantInt::get(t, (uint64_t)e->getInteger(), !e->type->isunsigned());
assert(result);
IF_LOG Logger::cout() << "value = " << *result << '\n';
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(RealExp *e)
{
IF_LOG Logger::print("RealExp::toConstElem: %s @ %s | %La\n", e->toChars(), e->type->toChars(), e->value);
LOG_SCOPE;
Type* t = e->type->toBasetype();
result = DtoConstFP(t, e->value);
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(NullExp *e)
{
IF_LOG Logger::print("NullExp::toConstElem(type=%s): %s\n", e->type->toChars(), e->toChars());
LOG_SCOPE;
LLType* t = DtoType(e->type);
if (e->type->ty == Tarray)
{
assert(isaStruct(t));
result = llvm::ConstantAggregateZero::get(t);
}
else
{
result = LLConstant::getNullValue(t);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(ComplexExp *e)
{
IF_LOG Logger::print("ComplexExp::toConstElem(): %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
result = DtoConstComplex(e->type, e->value.re, e->value.im);
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(StringExp *e)
{
IF_LOG Logger::print("StringExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
Type* t = e->type->toBasetype();
Type* cty = t->nextOf()->toBasetype();
bool nullterm = (t->ty != Tsarray);
size_t endlen = nullterm ? e->len+1 : e->len;
LLType* ct = voidToI8(DtoType(cty));
LLArrayType* at = LLArrayType::get(ct,endlen);
#if LDC_LLVM_VER >= 305
llvm::StringMap<llvm::GlobalVariable*>* stringLiteralCache = 0;
#else
std::map<llvm::StringRef, llvm::GlobalVariable*>* stringLiteralCache = 0;
#endif
LLConstant* _init;
switch (cty->size())
{
default:
llvm_unreachable("Unknown char type");
case 1:
_init = toConstantArray(ct, at, static_cast<uint8_t *>(e->string), e->len, nullterm);
stringLiteralCache = &(gIR->stringLiteral1ByteCache);
break;
case 2:
_init = toConstantArray(ct, at, static_cast<uint16_t *>(e->string), e->len, nullterm);
stringLiteralCache = &(gIR->stringLiteral2ByteCache);
break;
case 4:
_init = toConstantArray(ct, at, static_cast<uint32_t *>(e->string), e->len, nullterm);
stringLiteralCache = &(gIR->stringLiteral4ByteCache);
break;
}
if (t->ty == Tsarray)
{
result = _init;
return;
}
llvm::StringRef key(e->toChars());
llvm::GlobalVariable* gvar = (stringLiteralCache->find(key) ==
stringLiteralCache->end())
? 0 : (*stringLiteralCache)[key];
if (gvar == 0)
{
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::PrivateLinkage;
gvar = new llvm::GlobalVariable(gIR->module, _init->getType(), true, _linkage, _init, ".str");
gvar->setUnnamedAddr(true);
(*stringLiteralCache)[key] = gvar;
}
llvm::ConstantInt* zero = LLConstantInt::get(LLType::getInt32Ty(gIR->context()), 0, false);
LLConstant* idxs[2] = { zero, zero };
#if LDC_LLVM_VER >= 307
LLConstant* arrptr = llvm::ConstantExpr::getGetElementPtr(isaPointer(gvar)->getElementType(), gvar, idxs, true);
#else
LLConstant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar, idxs, true);
#endif
if (t->ty == Tpointer)
{
result = arrptr;
}
else if (t->ty == Tarray)
{
LLConstant* clen = LLConstantInt::get(DtoSize_t(), e->len, false);
result = DtoConstSlice(clen, arrptr, e->type);
}
else
{
llvm_unreachable("Unknown type for StringExp.");
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(AddExp *e)
{
IF_LOG Logger::print("AddExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
// add to pointer
Type* t1b = e->e1->type->toBasetype();
if (t1b->ty == Tpointer && e->e2->type->isintegral())
{
llvm::Constant* ptr = toConstElem(e->e1);
dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger());
#if LDC_LLVM_VER >= 307
result = llvm::ConstantExpr::getGetElementPtr(isaPointer(ptr)->getElementType(), ptr, DtoConstSize_t(idx));
#else
result = llvm::ConstantExpr::getGetElementPtr(ptr, DtoConstSize_t(idx));
#endif
}
else
{
e->error("expression '%s' is not a constant", e->toChars());
if (!global.gag) fatal();
result = llvm::UndefValue::get(DtoType(e->type));
}
}
void visit(MinExp *e)
{
IF_LOG Logger::print("MinExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
Type* t1b = e->e1->type->toBasetype();
if (t1b->ty == Tpointer && e->e2->type->isintegral())
{
llvm::Constant* ptr = toConstElem(e->e1);
dinteger_t idx = undoStrideMul(e->loc, t1b, e->e2->toInteger());
llvm::Constant* negIdx = llvm::ConstantExpr::getNeg(DtoConstSize_t(idx));
#if LDC_LLVM_VER >= 307
result = llvm::ConstantExpr::getGetElementPtr(isaPointer(ptr)->getElementType(), ptr, negIdx);
#else
result = llvm::ConstantExpr::getGetElementPtr(ptr, negIdx);
#endif
}
else
{
e->error("expression '%s' is not a constant", e->toChars());
if (!global.gag) fatal();
result = llvm::UndefValue::get(DtoType(e->type));
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(CastExp *e)
{
IF_LOG Logger::print("CastExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
LLType* lltype = DtoType(e->type);
Type* tb = e->to->toBasetype();
// string literal to dyn array:
// reinterpret the string data as an array, calculate the length
if (e->e1->op == TOKstring && tb->ty == Tarray)
{
#if 0
StringExp *strexp = static_cast<StringExp*>(e1);
size_t datalen = strexp->sz * strexp->len;
Type* eltype = tb->nextOf()->toBasetype();
if (datalen % eltype->size() != 0) {
error("the sizes don't line up");
return e1->toConstElem(p);
}
size_t arrlen = datalen / eltype->size();
#endif
e->error("ct cast of string to dynamic array not fully implemented");
result = toConstElem(e->e1);
}
// pointer to pointer
else if (tb->ty == Tpointer && e->e1->type->toBasetype()->ty == Tpointer)
{
result = llvm::ConstantExpr::getBitCast(toConstElem(e->e1), lltype);
}
// global variable to pointer
else if (tb->ty == Tpointer && e->e1->op == TOKvar)
{
VarDeclaration *vd = static_cast<VarExp*>(e->e1)->var->isVarDeclaration();
assert(vd);
DtoResolveVariable(vd);
LLConstant *value = isIrGlobalCreated(vd) ? isaConstant(getIrGlobal(vd)->value) : 0;
if (!value)
goto Lerr;
Type *type = vd->type->toBasetype();
if (type->ty == Tarray || type->ty == Tdelegate) {
LLConstant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(1) };
#if LDC_LLVM_VER >= 307
value = llvm::ConstantExpr::getGetElementPtr(isaPointer(value)->getElementType(), value, idxs, true);
#else
value = llvm::ConstantExpr::getGetElementPtr(value, idxs, true);
#endif
}
result = DtoBitCast(value, DtoType(tb));
}
else if (tb->ty == Tclass && e->e1->type->ty == Tclass)
{
assert(e->e1->op == TOKclassreference);
ClassDeclaration* cd = static_cast<ClassReferenceExp*>(e->e1)->originalClass();
llvm::Constant* instance = toConstElem(e->e1);
if (InterfaceDeclaration* it = static_cast<TypeClass*>(tb)->sym->isInterfaceDeclaration()) {
assert(it->isBaseOf(cd, NULL));
IrTypeClass* typeclass = cd->type->ctype->isClass();
// find interface impl
size_t i_index = typeclass->getInterfaceIndex(it);
assert(i_index != ~0UL);
// offset pointer
instance = DtoGEPi(instance, 0, i_index);
}
result = DtoBitCast(instance, DtoType(tb));
}
else
{
goto Lerr;
}
return;
Lerr:
e->error("cannot cast %s to %s at compile time", e->e1->type->toChars(), e->type->toChars());
if (!global.gag)
fatal();
result = llvm::UndefValue::get(DtoType(e->type));
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(SymOffExp *e)
{
IF_LOG Logger::println("SymOffExp::toConstElem: %s @ %s", e->toChars(), e->type->toChars());
LOG_SCOPE;
llvm::Constant* base = DtoConstSymbolAddress(e->loc, e->var);
if (base == 0)
{
result = llvm::UndefValue::get(DtoType(e->type));
return;
}
if (e->offset == 0)
{
result = base;
}
else
{
const unsigned elemSize = gDataLayout->getTypeStoreSize(
base->getType()->getContainedType(0));
IF_LOG Logger::println("adding offset: %llu (elem size: %u)", static_cast<unsigned long long>(e->offset), elemSize);
if (e->offset % elemSize == 0)
{
// We can turn this into a "nice" GEP.
result = llvm::ConstantExpr::getGetElementPtr(
#if LDC_LLVM_VER >= 307
LLType::getInt8Ty(gIR->context()),
#endif
base,
DtoConstSize_t(e->offset / elemSize));
}
else
{
// Offset isn't a multiple of base type size, just cast to i8* and
// apply the byte offset.
result = llvm::ConstantExpr::getGetElementPtr(
#if LDC_LLVM_VER >= 307
getVoidPtrType(),
#endif
DtoBitCast(base, getVoidPtrType()),
DtoConstSize_t(e->offset));
}
}
result = DtoBitCast(result, DtoType(e->type));
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(AddrExp *e)
{
IF_LOG Logger::println("AddrExp::toConstElem: %s @ %s", e->toChars(), e->type->toChars());
LOG_SCOPE;
// FIXME: this should probably be generalized more so we don't
// need to have a case for each thing we can take the address of
// address of global variable
if (e->e1->op == TOKvar)
{
VarExp* vexp = static_cast<VarExp*>(e->e1);
LLConstant *c = DtoConstSymbolAddress(e->loc, vexp->var);
result = c ? DtoBitCast(c, DtoType(e->type)) : 0;
}
// address of indexExp
else if (e->e1->op == TOKindex)
{
IndexExp* iexp = static_cast<IndexExp*>(e->e1);
// indexee must be global static array var
assert(iexp->e1->op == TOKvar);
VarExp* vexp = static_cast<VarExp*>(iexp->e1);
VarDeclaration* vd = vexp->var->isVarDeclaration();
assert(vd);
assert(vd->type->toBasetype()->ty == Tsarray);
DtoResolveVariable(vd);
assert(isIrGlobalCreated(vd));
// get index
LLConstant* index = toConstElem(iexp->e2);
assert(index->getType() == DtoSize_t());
// gep
LLConstant* idxs[2] = { DtoConstSize_t(0), index };
LLConstant *val = isaConstant(getIrGlobal(vd)->value);
val = DtoBitCast(val, DtoType(vd->type->pointerTo()));
#if LDC_LLVM_VER >= 307
LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(isaPointer(val)->getElementType(), val, idxs, true);
#else
LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(val, idxs, true);
#endif
// bitcast to requested type
assert(e->type->toBasetype()->ty == Tpointer);
result = DtoBitCast(gep, DtoType(e->type));
}
else if (e->e1->op == TOKstructliteral)
{
StructLiteralExp* se = static_cast<StructLiteralExp*>(e->e1);
if (se->globalVar)
{
IF_LOG Logger::cout() << "Returning existing global: " << *se->globalVar << '\n';
result = se->globalVar;
return;
}
se->globalVar = new llvm::GlobalVariable(p->module,
DtoType(e->e1->type), false, llvm::GlobalValue::InternalLinkage, 0,
".structliteral");
llvm::Constant* constValue = toConstElem(se);
if (constValue->getType() != se->globalVar->getType()->getContainedType(0))
{
llvm::GlobalVariable* finalGlobalVar = new llvm::GlobalVariable(
p->module, constValue->getType(), false,
llvm::GlobalValue::InternalLinkage, 0, ".structliteral");
se->globalVar->replaceAllUsesWith(
DtoBitCast(finalGlobalVar, se->globalVar->getType()));
se->globalVar->eraseFromParent();
se->globalVar = finalGlobalVar;
}
se->globalVar->setInitializer(constValue);
se->globalVar->setAlignment(e->e1->type->alignsize());
result = se->globalVar;
}
else if (e->e1->op == TOKslice)
{
e->error("non-constant expression '%s'", e->toChars());
if (!global.gag) fatal();
result = llvm::UndefValue::get(DtoType(e->type));
}
// not yet supported
else
{
e->error("constant expression '%s' not yet implemented", e->toChars());
fatal();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(FuncExp *e)
{
IF_LOG Logger::print("FuncExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
FuncLiteralDeclaration *fd = e->fd;
assert(fd);
if (fd->tok == TOKreserved && e->type->ty == Tpointer)
{
// This is a lambda that was inferred to be a function literal instead
// of a delegate, so set tok here in order to get correct types/mangling.
// Horrible hack, but DMD does the same thing in FuncExp::toElem and
// other random places.
fd->tok = TOKfunction;
fd->vthis = NULL;
}
if (fd->tok != TOKfunction)
{
assert(fd->tok == TOKdelegate || fd->tok == TOKreserved);
e->error("non-constant nested delegate literal expression %s", e->toChars());
if (!global.gag) fatal();
result = llvm::UndefValue::get(DtoType(e->type));
}
else
{
// We need to actually codegen the function here, as literals are not added
// to the module member list.
Declaration_codegen(fd, p);
assert(getIrFunc(fd)->func);
result = getIrFunc(fd)->func;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(ArrayLiteralExp *e)
{
IF_LOG Logger::print("ArrayLiteralExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
// extract D types
Type* bt = e->type->toBasetype();
Type* elemt = bt->nextOf();
// build llvm array type
LLArrayType* arrtype = LLArrayType::get(i1ToI8(voidToI8(DtoType(elemt))), e->elements->dim);
// dynamic arrays can occur here as well ...
bool dyn = (bt->ty != Tsarray);
llvm::Constant* initval = arrayLiteralToConst(p, e);
// if static array, we're done
if (!dyn)
{
result = initval;
return;
}
bool canBeConst = e->type->isConst() || e->type->isImmutable();
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(gIR->module,
initval->getType(), canBeConst, llvm::GlobalValue::InternalLinkage, initval,
".dynarrayStorage");
gvar->setUnnamedAddr(canBeConst);
llvm::Constant* store = DtoBitCast(gvar, getPtrToType(arrtype));
if (bt->ty == Tpointer)
{
// we need to return pointer to the static array.
result = store;
return;
}
// build a constant dynamic array reference with the .ptr field pointing into store
LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
#if LDC_LLVM_VER >= 307
LLConstant* globalstorePtr = llvm::ConstantExpr::getGetElementPtr(isaPointer(store)->getElementType(), store, idxs, true);
#else
LLConstant* globalstorePtr = llvm::ConstantExpr::getGetElementPtr(store, idxs, true);
#endif
result = DtoConstSlice(DtoConstSize_t(e->elements->dim), globalstorePtr);
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(StructLiteralExp *e)
{
// type can legitimately be null for ClassReferenceExp::value.
IF_LOG Logger::print("StructLiteralExp::toConstElem: %s @ %s\n",
e->toChars(), e->type ? e->type->toChars() : "(null)");
LOG_SCOPE;
if (e->sinit)
{
// Copied from VarExp::toConstElem, need to clean this mess up.
Type* sdecltype = e->sinit->type->toBasetype();
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
DtoResolveStruct(ts->sym);
result = getIrAggr(ts->sym)->getDefaultInit();
}
else
{
// make sure the struct is resolved
DtoResolveStruct(e->sd);
std::map<VarDeclaration*, llvm::Constant*> varInits;
const size_t nexprs = e->elements->dim;
for (size_t i = 0; i < nexprs; i++)
{
if ((*e->elements)[i])
{
varInits[e->sd->fields[i]] = toConstElem((*e->elements)[i]);
}
}
result = getIrAggr(e->sd)->createInitializerConstant(varInits);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(ClassReferenceExp *e)
{
IF_LOG Logger::print("ClassReferenceExp::toConstElem: %s @ %s\n",
e->toChars(), e->type->toChars());
LOG_SCOPE;
ClassDeclaration* origClass = e->originalClass();
DtoResolveClass(origClass);
StructLiteralExp *value = e->value;
if (value->globalVar)
{
IF_LOG Logger::cout() << "Using existing global: " << *value->globalVar << '\n';
}
else
{
value->globalVar = new llvm::GlobalVariable(p->module,
origClass->type->ctype->isClass()->getMemoryLLType(),
false, llvm::GlobalValue::InternalLinkage, 0, ".classref");
std::map<VarDeclaration*, llvm::Constant*> varInits;
// Unfortunately, ClassReferenceExp::getFieldAt is badly broken it
// places the base class fields _after_ those of the subclass.
{
const size_t nexprs = value->elements->dim;
std::stack<ClassDeclaration*> classHierachy;
ClassDeclaration* cur = origClass;
while (cur)
{
classHierachy.push(cur);
cur = cur->baseClass;
}
size_t i = 0;
while (!classHierachy.empty())
{
cur = classHierachy.top();
classHierachy.pop();
for (size_t j = 0; j < cur->fields.dim; ++j)
{
if ((*value->elements)[i])
{
VarDeclaration* field = cur->fields[j];
IF_LOG Logger::println("Getting initializer for: %s", field->toChars());
LOG_SCOPE;
varInits[field] = toConstElem((*value->elements)[i]);
}
++i;
}
}
assert(i == nexprs);
}
llvm::Constant* constValue = getIrAggr(origClass)->createInitializerConstant(varInits);
if (constValue->getType() != value->globalVar->getType()->getContainedType(0))
{
llvm::GlobalVariable* finalGlobalVar = new llvm::GlobalVariable(
p->module, constValue->getType(), false,
llvm::GlobalValue::InternalLinkage, 0, ".classref");
value->globalVar->replaceAllUsesWith(
DtoBitCast(finalGlobalVar, value->globalVar->getType()));
value->globalVar->eraseFromParent();
value->globalVar = finalGlobalVar;
}
value->globalVar->setInitializer(constValue);
}
result = value->globalVar;
if (e->type->ty == Tclass) {
ClassDeclaration* targetClass = static_cast<TypeClass*>(e->type)->sym;
if (InterfaceDeclaration* it = targetClass->isInterfaceDeclaration()) {
assert(it->isBaseOf(origClass, NULL));
IrTypeClass* typeclass = origClass->type->ctype->isClass();
// find interface impl
size_t i_index = typeclass->getInterfaceIndex(it);
assert(i_index != ~0UL);
// offset pointer
result = DtoGEPi(result, 0, i_index);
}
}
assert(e->type->ty == Tclass || e->type->ty == Tenum);
result = DtoBitCast(result, DtoType(e->type));
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(VectorExp *e)
{
IF_LOG Logger::print("VectorExp::toConstElem: %s @ %s\n", e->toChars(), e->type->toChars());
LOG_SCOPE;
TypeVector *tv = static_cast<TypeVector*>(e->to->toBasetype());
assert(tv->ty == Tvector);
// The AST for
// static immutable ubyte16 vec1 = 123;
// differs from
// static immutable ubyte[16] vec1 = 123;
// In the vector case the AST contains an IntegerExp (of type int) and a
// CastExp to type ubyte. In the static array case the AST only contains an
// IntegerExp of type ubyte. Simply call optimize to get rid of the cast.
// FIXME: Check DMD source to understand why two different ASTs are
// constructed.
llvm::Constant *val = toConstElem(e->e1->optimize(WANTvalue));
dinteger_t elemCount =
static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
result = llvm::ConstantVector::getSplat(elemCount, val);
}
//////////////////////////////////////////////////////////////////////////////////////////
void visit(Expression *e)
{
e->error("expression '%s' is not a constant", e->toChars());
if (!global.gag)
fatal();
// 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.
result = llvm::UndefValue::get(DtoType(e->type));
}
};
LLConstant *toConstElem(Expression *e, IRState *p)
{
return ToConstElemVisitor(p).toConstElem(e);
}