mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 09:00:33 +03:00
[svn r92] Fixed support for statically initialized unions. lots of bugfixes as cleanups too.
This commit is contained in:
parent
3b2cb94f6e
commit
34d9e12020
16 changed files with 849 additions and 275 deletions
|
@ -45,6 +45,8 @@ namespace llvm
|
||||||
class ConstantStruct;
|
class ConstantStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DUnion;
|
||||||
|
|
||||||
struct AggregateDeclaration : ScopeDsymbol
|
struct AggregateDeclaration : ScopeDsymbol
|
||||||
{
|
{
|
||||||
Type *type;
|
Type *type;
|
||||||
|
@ -104,6 +106,7 @@ struct AggregateDeclaration : ScopeDsymbol
|
||||||
llvm::ConstantStruct* llvmConstVtbl;
|
llvm::ConstantStruct* llvmConstVtbl;
|
||||||
llvm::Constant* llvmInitZ;
|
llvm::Constant* llvmInitZ;
|
||||||
bool llvmHasUnions;
|
bool llvmHasUnions;
|
||||||
|
DUnion* llvmUnion;
|
||||||
|
|
||||||
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
AggregateDeclaration *isAggregateDeclaration() { return this; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,6 +51,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
|
||||||
llvmInitZ = NULL;
|
llvmInitZ = NULL;
|
||||||
llvmInProgress = false;
|
llvmInProgress = false;
|
||||||
llvmHasUnions = false;
|
llvmHasUnions = false;
|
||||||
|
llvmUnion = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PROT AggregateDeclaration::prot()
|
enum PROT AggregateDeclaration::prot()
|
||||||
|
|
|
@ -251,41 +251,59 @@ void DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr)
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||||
{
|
{
|
||||||
Logger::println("arr init begin");
|
Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars());
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
Type* arrinittype = DtoDType(arrinit->type);
|
Type* arrinittype = DtoDType(arrinit->type);
|
||||||
|
|
||||||
Type* t;
|
Type* t;
|
||||||
integer_t tdim;
|
integer_t tdim;
|
||||||
if (arrinittype->ty == Tsarray) {
|
if (arrinittype->ty == Tsarray) {
|
||||||
|
Logger::println("static array");
|
||||||
TypeSArray* tsa = (TypeSArray*)arrinittype;
|
TypeSArray* tsa = (TypeSArray*)arrinittype;
|
||||||
tdim = tsa->dim->toInteger();
|
tdim = tsa->dim->toInteger();
|
||||||
t = tsa;
|
t = tsa;
|
||||||
}
|
}
|
||||||
else if (arrinittype->ty == Tarray) {
|
else if (arrinittype->ty == Tarray) {
|
||||||
|
Logger::println("dynamic array");
|
||||||
t = arrinittype;
|
t = arrinittype;
|
||||||
tdim = arrinit->dim;
|
tdim = arrinit->dim;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
||||||
std::vector<llvm::Constant*> inits(tdim, 0);
|
Logger::println("dim = %u", tdim);
|
||||||
|
|
||||||
|
std::vector<llvm::Constant*> inits(tdim, NULL);
|
||||||
|
|
||||||
const llvm::Type* elemty = DtoType(arrinittype->next);
|
const llvm::Type* elemty = DtoType(arrinittype->next);
|
||||||
|
|
||||||
assert(arrinit->index.dim == arrinit->value.dim);
|
assert(arrinit->index.dim == arrinit->value.dim);
|
||||||
for (int i=0,j=0; i < tdim; ++i)
|
for (unsigned i=0,j=0; i < tdim; ++i)
|
||||||
{
|
{
|
||||||
Initializer* init = 0;
|
Initializer* init = 0;
|
||||||
Expression* idx = (Expression*)arrinit->index.data[j];
|
Expression* idx = (Expression*)arrinit->index.data[j];
|
||||||
|
|
||||||
if (idx)
|
if (idx)
|
||||||
{
|
{
|
||||||
integer_t k = idx->toInteger();
|
// this is pretty weird :/ idx->type turned out NULL for the initializer:
|
||||||
if (i == k)
|
// const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
|
||||||
{
|
// in std.c.linux.socket
|
||||||
init = (Initializer*)arrinit->value.data[j];
|
if (idx->type) {
|
||||||
assert(init);
|
//integer_t k = idx->toInteger();
|
||||||
++j;
|
Logger::println("getting value for exp: %s | %s", idx->toChars(), idx->type->toChars());
|
||||||
|
llvm::Constant* cc = idx->toConstElem(gIR);
|
||||||
|
Logger::println("value gotten");
|
||||||
|
assert(cc != NULL);
|
||||||
|
llvm::ConstantInt* ci = llvm::dyn_cast<llvm::ConstantInt>(cc);
|
||||||
|
assert(ci != NULL);
|
||||||
|
uint64_t k = ci->getZExtValue();
|
||||||
|
if (i == k)
|
||||||
|
{
|
||||||
|
init = (Initializer*)arrinit->value.data[j];
|
||||||
|
assert(init);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -294,29 +312,7 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit)
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant* v = 0;
|
llvm::Constant* v = DtoConstInitializer(t->next, init);
|
||||||
|
|
||||||
if (!init)
|
|
||||||
{
|
|
||||||
v = t->next->defaultInit()->toConstElem(gIR);
|
|
||||||
}
|
|
||||||
else if (ExpInitializer* ex = init->isExpInitializer())
|
|
||||||
{
|
|
||||||
v = ex->exp->toConstElem(gIR);
|
|
||||||
}
|
|
||||||
else if (StructInitializer* si = init->isStructInitializer())
|
|
||||||
{
|
|
||||||
v = DtoConstStructInitializer(si);
|
|
||||||
}
|
|
||||||
else if (ArrayInitializer* ai = init->isArrayInitializer())
|
|
||||||
{
|
|
||||||
v = DtoConstArrayInitializer(ai);
|
|
||||||
}
|
|
||||||
else if (init->isVoidInitializer())
|
|
||||||
{
|
|
||||||
v = llvm::UndefValue::get(elemty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
assert(v);
|
assert(v);
|
||||||
|
|
||||||
inits[i] = v;
|
inits[i] = v;
|
||||||
|
|
101
gen/dvalue.cpp
Normal file
101
gen/dvalue.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#include "gen/llvm.h"
|
||||||
|
|
||||||
|
#include "declaration.h"
|
||||||
|
|
||||||
|
#include "gen/tollvm.h"
|
||||||
|
#include "gen/irstate.h"
|
||||||
|
#include "gen/logger.h"
|
||||||
|
#include "gen/dvalue.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DVarValue::DVarValue(VarDeclaration* vd, llvm::Value* llvmValue, bool lvalue)
|
||||||
|
{
|
||||||
|
var = vd;
|
||||||
|
val = llvmValue;
|
||||||
|
rval = 0;
|
||||||
|
lval = lvalue;
|
||||||
|
type = var->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
DVarValue::DVarValue(Type* t, llvm::Value* lv, llvm::Value* rv)
|
||||||
|
{
|
||||||
|
var = 0;
|
||||||
|
val = lv;
|
||||||
|
rval = rv;
|
||||||
|
lval = true;
|
||||||
|
type = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
DVarValue::DVarValue(Type* t, llvm::Value* llvmValue, bool lvalue)
|
||||||
|
{
|
||||||
|
var = 0;
|
||||||
|
val = llvmValue;
|
||||||
|
rval = 0;
|
||||||
|
lval = lvalue;
|
||||||
|
type = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* DVarValue::getLVal()
|
||||||
|
{
|
||||||
|
assert(val && lval);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* DVarValue::getRVal()
|
||||||
|
{
|
||||||
|
assert(rval || val);
|
||||||
|
if (DtoIsPassedByRef(type)) {
|
||||||
|
if (rval) return rval;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (rval) return rval;
|
||||||
|
Logger::cout() << "val: " << *val << '\n';
|
||||||
|
if (llvm::isa<llvm::Argument>(val)) {
|
||||||
|
if (var && (var->isRef() || var->isOut()))
|
||||||
|
return DtoLoad(val);
|
||||||
|
}
|
||||||
|
else if (!isField() && DtoCanLoad(val)) {
|
||||||
|
return DtoLoad(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DFuncValue::DFuncValue(FuncDeclaration* fd, llvm::Value* v, llvm::Value* vt)
|
||||||
|
{
|
||||||
|
func = fd;
|
||||||
|
type = func->type;
|
||||||
|
val = v;
|
||||||
|
vthis = vt;
|
||||||
|
cc = (unsigned)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* DFuncValue::getLVal()
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* DFuncValue::getRVal()
|
||||||
|
{
|
||||||
|
assert(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
llvm::Value* DConstValue::getRVal()
|
||||||
|
{
|
||||||
|
assert(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
193
gen/dvalue.h
Normal file
193
gen/dvalue.h
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
#ifndef LLVMDC_GEN_DVALUE_H
|
||||||
|
#define LLVMDC_GEN_DVALUE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
These classes are used for generating the IR. They encapsulate D values and
|
||||||
|
provide a common interface to the most common operations. When more specialized
|
||||||
|
handling is necessary, they hold enough information to do-the-right-thing (TM)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include "root.h"
|
||||||
|
|
||||||
|
struct Type;
|
||||||
|
struct Dsymbol;
|
||||||
|
struct VarDeclaration;
|
||||||
|
struct FuncDeclaration;
|
||||||
|
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
class Type;
|
||||||
|
class Constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DImValue;
|
||||||
|
struct DConstValue;
|
||||||
|
struct DNullValue;
|
||||||
|
struct DVarValue;
|
||||||
|
struct DFieldValue;
|
||||||
|
struct DThisValue;
|
||||||
|
struct DFuncValue;
|
||||||
|
struct DSliceValue;
|
||||||
|
struct DArrayLenValue;
|
||||||
|
struct DLValueCast;
|
||||||
|
|
||||||
|
// base class for d-values
|
||||||
|
struct DValue : Object
|
||||||
|
{
|
||||||
|
virtual Type* getType() = 0;
|
||||||
|
|
||||||
|
virtual llvm::Value* getLVal() { assert(0); return 0; }
|
||||||
|
virtual llvm::Value* getRVal() { assert(0); return 0; }
|
||||||
|
|
||||||
|
virtual DImValue* isIm() { return NULL; }
|
||||||
|
virtual DConstValue* isConst() { return NULL; }
|
||||||
|
virtual DNullValue* isNull() { return NULL; }
|
||||||
|
virtual DVarValue* isVar() { return NULL; }
|
||||||
|
virtual DFieldValue* isField() { return NULL; }
|
||||||
|
virtual DThisValue* isThis() { return NULL; }
|
||||||
|
virtual DSliceValue* isSlice() { return NULL; }
|
||||||
|
virtual DFuncValue* isFunc() { return NULL; }
|
||||||
|
virtual DArrayLenValue* isArrayLen() { return NULL; }
|
||||||
|
virtual DLValueCast* isLValueCast() { return NULL; }
|
||||||
|
|
||||||
|
virtual bool inPlace() { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DValue() {}
|
||||||
|
DValue(const DValue&) { }
|
||||||
|
DValue& operator=(const DValue&) { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// immediate d-value
|
||||||
|
struct DImValue : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
llvm::Value* val;
|
||||||
|
bool inplace;
|
||||||
|
|
||||||
|
DImValue(Type* t, llvm::Value* v, bool i = false) { type = t; val = v; inplace = i; }
|
||||||
|
|
||||||
|
virtual llvm::Value* getRVal() { assert(val); return val; }
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DImValue* isIm() { return this; }
|
||||||
|
|
||||||
|
virtual bool inPlace() { return inplace; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// constant d-value
|
||||||
|
struct DConstValue : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
llvm::Constant* c;
|
||||||
|
|
||||||
|
DConstValue(Type* t, llvm::Constant* con) { type = t; c = con; }
|
||||||
|
|
||||||
|
virtual llvm::Value* getRVal();
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DConstValue* isConst() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// null d-value
|
||||||
|
struct DNullValue : DConstValue
|
||||||
|
{
|
||||||
|
DNullValue(Type* t, llvm::Constant* con) : DConstValue(t,con) {}
|
||||||
|
virtual DNullValue* isNull() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// variable d-value
|
||||||
|
struct DVarValue : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
VarDeclaration* var;
|
||||||
|
llvm::Value* val;
|
||||||
|
llvm::Value* rval;
|
||||||
|
bool lval;
|
||||||
|
|
||||||
|
DVarValue(VarDeclaration* vd, llvm::Value* llvmValue, bool lvalue);
|
||||||
|
DVarValue(Type* vd, llvm::Value* lv, llvm::Value* rv);
|
||||||
|
DVarValue(Type* t, llvm::Value* llvmValue, bool lvalue);
|
||||||
|
|
||||||
|
virtual llvm::Value* getLVal();
|
||||||
|
virtual llvm::Value* getRVal();
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DVarValue* isVar() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// field d-value
|
||||||
|
struct DFieldValue : DVarValue
|
||||||
|
{
|
||||||
|
DFieldValue(Type* t, llvm::Value* llvmValue, bool l) : DVarValue(t, llvmValue, l) {}
|
||||||
|
virtual DFieldValue* isField() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// this d-value
|
||||||
|
struct DThisValue : DVarValue
|
||||||
|
{
|
||||||
|
DThisValue(VarDeclaration* vd, llvm::Value* llvmValue) : DVarValue(vd, llvmValue, true) {}
|
||||||
|
virtual DThisValue* isThis() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// array length d-value
|
||||||
|
struct DArrayLenValue : DVarValue
|
||||||
|
{
|
||||||
|
DArrayLenValue(Type* t, llvm::Value* llvmValue) : DVarValue(t, llvmValue, true) {}
|
||||||
|
virtual DArrayLenValue* isArrayLen() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// slice d-value
|
||||||
|
struct DSliceValue : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
llvm::Value* len;
|
||||||
|
llvm::Value* ptr;
|
||||||
|
|
||||||
|
DSliceValue(Type* t, llvm::Value* l, llvm::Value* p) { type=t; ptr=p; len=l; }
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DSliceValue* isSlice() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// function d-value
|
||||||
|
struct DFuncValue : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
FuncDeclaration* func;
|
||||||
|
llvm::Value* val;
|
||||||
|
llvm::Value* vthis;
|
||||||
|
unsigned cc;
|
||||||
|
|
||||||
|
DFuncValue(FuncDeclaration* fd, llvm::Value* v, llvm::Value* vt = 0);
|
||||||
|
|
||||||
|
virtual llvm::Value* getLVal();
|
||||||
|
virtual llvm::Value* getRVal();
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DFuncValue* isFunc() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// l-value cast d-value
|
||||||
|
struct DLValueCast : DValue
|
||||||
|
{
|
||||||
|
Type* type;
|
||||||
|
llvm::Value* lval;
|
||||||
|
llvm::Value* rval;
|
||||||
|
|
||||||
|
DLValueCast(Type* t, llvm::Value* l, llvm::Value* r) {
|
||||||
|
type = t;
|
||||||
|
lval = l;
|
||||||
|
rval = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual llvm::Value* getLVal() { assert(lval); return lval; }
|
||||||
|
virtual llvm::Value* getRVal() { assert(rval); return rval; }
|
||||||
|
|
||||||
|
virtual Type* getType() { assert(type); return type; }
|
||||||
|
virtual DLValueCast* isLValueCast() { return this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LLVMDC_GEN_DVALUE_H
|
319
gen/structs.cpp
Normal file
319
gen/structs.cpp
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "gen/llvm.h"
|
||||||
|
|
||||||
|
#include "mtype.h"
|
||||||
|
#include "aggregate.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "declaration.h"
|
||||||
|
|
||||||
|
#include "gen/irstate.h"
|
||||||
|
#include "gen/tollvm.h"
|
||||||
|
#include "gen/arrays.h"
|
||||||
|
#include "gen/logger.h"
|
||||||
|
#include "gen/structs.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const llvm::Type* DtoStructType(Type* t)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
std::vector<const llvm::Type*> types;
|
||||||
|
return llvm::StructType::get(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
llvm::Value* DtoStructZeroInit(llvm::Value* v)
|
||||||
|
{
|
||||||
|
assert(gIR);
|
||||||
|
uint64_t n = gTargetData->getTypeSize(v->getType()->getContainedType(0));
|
||||||
|
//llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
|
||||||
|
llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||||
|
|
||||||
|
llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb());
|
||||||
|
|
||||||
|
llvm::Function* fn = LLVM_DeclareMemSet32();
|
||||||
|
std::vector<llvm::Value*> llargs;
|
||||||
|
llargs.resize(4);
|
||||||
|
llargs[0] = sarr;
|
||||||
|
llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
|
||||||
|
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
||||||
|
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||||
|
|
||||||
|
llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src)
|
||||||
|
{
|
||||||
|
Logger::cout() << "dst = " << *dst << " src = " << *src << '\n';
|
||||||
|
assert(dst->getType() == src->getType());
|
||||||
|
assert(gIR);
|
||||||
|
|
||||||
|
uint64_t n = gTargetData->getTypeSize(dst->getType()->getContainedType(0));
|
||||||
|
//llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
|
||||||
|
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
||||||
|
|
||||||
|
llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
|
||||||
|
llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
|
||||||
|
|
||||||
|
llvm::Function* fn = LLVM_DeclareMemCpy32();
|
||||||
|
std::vector<llvm::Value*> llargs;
|
||||||
|
llargs.resize(4);
|
||||||
|
llargs[0] = dstarr;
|
||||||
|
llargs[1] = srcarr;
|
||||||
|
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
||||||
|
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||||
|
|
||||||
|
return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
llvm::Constant* DtoConstStructInitializer(StructInitializer* si)
|
||||||
|
{
|
||||||
|
Logger::println("DtoConstStructInitializer: %s", si->toChars());
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
const llvm::StructType* structtype = llvm::cast<llvm::StructType>(si->ad->llvmType);
|
||||||
|
Logger::cout() << "llvm struct type: " << *structtype << '\n';
|
||||||
|
|
||||||
|
assert(si->value.dim == si->vars.dim);
|
||||||
|
|
||||||
|
std::vector<DUnionIdx> inits;
|
||||||
|
for (int i = 0; i < si->value.dim; ++i)
|
||||||
|
{
|
||||||
|
Initializer* ini = (Initializer*)si->value.data[i];
|
||||||
|
assert(ini);
|
||||||
|
VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
|
||||||
|
assert(vd);
|
||||||
|
llvm::Constant* v = DtoConstInitializer(vd->type, ini);
|
||||||
|
inits.push_back(DUnionIdx(vd->llvmFieldIndex, vd->llvmFieldIndexOffset, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return si->ad->llvmUnion->getConst(inits);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs)
|
||||||
|
{
|
||||||
|
Logger::println("checking for offset %u type %s:", os, t->toChars());
|
||||||
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
if (idxs.empty())
|
||||||
|
idxs.push_back(0);
|
||||||
|
|
||||||
|
const llvm::Type* llt = llvm::PointerType::get(DtoType(t));
|
||||||
|
const llvm::Type* st = llvm::PointerType::get(DtoType(sd->type));
|
||||||
|
if (ptr->getType() != st) {
|
||||||
|
assert(sd->llvmHasUnions);
|
||||||
|
ptr = gIR->ir->CreateBitCast(ptr, st, "tmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i=0; i<sd->fields.dim; ++i) {
|
||||||
|
VarDeclaration* vd = (VarDeclaration*)sd->fields.data[i];
|
||||||
|
Type* vdtype = DtoDType(vd->type);
|
||||||
|
Logger::println("found %u type %s", vd->offset, vdtype->toChars());
|
||||||
|
assert(vd->llvmFieldIndex >= 0);
|
||||||
|
if (os == vd->offset && vdtype == t) {
|
||||||
|
idxs.push_back(vd->llvmFieldIndex);
|
||||||
|
ptr = DtoGEP(ptr, idxs, "tmp");
|
||||||
|
if (ptr->getType() != llt)
|
||||||
|
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
||||||
|
if (vd->llvmFieldIndexOffset)
|
||||||
|
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) {
|
||||||
|
TypeStruct* ts = (TypeStruct*)vdtype;
|
||||||
|
StructDeclaration* ssd = ts->sym;
|
||||||
|
idxs.push_back(vd->llvmFieldIndex);
|
||||||
|
if (vd->llvmFieldIndexOffset) {
|
||||||
|
Logger::println("has union field offset");
|
||||||
|
ptr = DtoGEP(ptr, idxs, "tmp");
|
||||||
|
if (ptr->getType() != llt)
|
||||||
|
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
||||||
|
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
|
||||||
|
std::vector<unsigned> tmp;
|
||||||
|
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type));
|
||||||
|
if (ptr->getType() != sty) {
|
||||||
|
ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
|
||||||
|
std::vector<unsigned> tmp;
|
||||||
|
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0));
|
||||||
|
assert(os % llt_sz == 0);
|
||||||
|
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
||||||
|
return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////// D UNION HELPER CLASS ////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DUnion::DUnion()
|
||||||
|
{
|
||||||
|
DUnionField* f = NULL;
|
||||||
|
IRStruct& topstruct = gIR->topstruct();
|
||||||
|
bool unions = false;
|
||||||
|
for (IRStruct::OffsetMap::iterator i=topstruct.offsets.begin(); i!=topstruct.offsets.end(); ++i)
|
||||||
|
{
|
||||||
|
unsigned o = i->first;
|
||||||
|
IRStruct::Offset* so = &i->second;
|
||||||
|
const llvm::Type* ft = so->init->getType();
|
||||||
|
size_t sz = gTargetData->getTypeSize(ft);
|
||||||
|
if (f == NULL) { // new field
|
||||||
|
fields.push_back(DUnionField());
|
||||||
|
f = &fields.back();
|
||||||
|
f->size = sz;
|
||||||
|
f->offset = o;
|
||||||
|
f->init = so->init;
|
||||||
|
f->initsize = sz;
|
||||||
|
f->types.push_back(ft);
|
||||||
|
}
|
||||||
|
else if (o == f->offset) { // same offset
|
||||||
|
if (sz > f->size)
|
||||||
|
f->size = sz;
|
||||||
|
f->types.push_back(ft);
|
||||||
|
unions = true;
|
||||||
|
}
|
||||||
|
else if (o < f->offset+f->size) {
|
||||||
|
assert((o+sz) <= (f->offset+f->size));
|
||||||
|
unions = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fields.push_back(DUnionField());
|
||||||
|
f = &fields.back();
|
||||||
|
f->size = sz;
|
||||||
|
f->offset = o;
|
||||||
|
f->init = so->init;
|
||||||
|
f->initsize = sz;
|
||||||
|
f->types.push_back(ft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LOG_SCOPE;
|
||||||
|
Logger::println("******** DUnion BEGIN");
|
||||||
|
size_t n = fields.size();
|
||||||
|
for (size_t i=0; i<n; ++i) {
|
||||||
|
Logger::cout()<<"field #"<<i<<" offset: "<<fields[i].offset<<" size: "<<fields[i].size<<'('<<fields[i].initsize<<")\n";
|
||||||
|
LOG_SCOPE;
|
||||||
|
size_t nt = fields[i].types.size();
|
||||||
|
for (size_t j=0; j<nt; ++j) {
|
||||||
|
Logger::cout()<<*fields[i].types[j]<<'\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Logger::println("******** DUnion END");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push_nulls(size_t nbytes, std::vector<llvm::Constant*>& out)
|
||||||
|
{
|
||||||
|
assert(nbytes > 0);
|
||||||
|
std::vector<llvm::Constant*> i(nbytes, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
|
||||||
|
out.push_back(llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, nbytes), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Constant* DUnion::getConst(std::vector<DUnionIdx>& in)
|
||||||
|
{
|
||||||
|
std::sort(in.begin(), in.end());
|
||||||
|
std::vector<llvm::Constant*> out;
|
||||||
|
|
||||||
|
size_t nin = in.size();
|
||||||
|
size_t nfields = fields.size();
|
||||||
|
|
||||||
|
size_t fi = 0;
|
||||||
|
size_t last = 0;
|
||||||
|
size_t ii = 0;
|
||||||
|
size_t os = 0;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if (fi == nfields) break;
|
||||||
|
|
||||||
|
bool nextSame = (ii+1 < nin) && (in[ii+1].idx == fi);
|
||||||
|
|
||||||
|
if (ii < nin && fi == in[ii].idx)
|
||||||
|
{
|
||||||
|
size_t s = gTargetData->getTypeSize(in[ii].c->getType());
|
||||||
|
if (in[ii].idx == last)
|
||||||
|
{
|
||||||
|
size_t nos = in[ii].idxos * s;
|
||||||
|
if (nos && nos-os) {
|
||||||
|
assert(nos >= os);
|
||||||
|
push_nulls(nos-os, out);
|
||||||
|
}
|
||||||
|
os = nos + s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os = s;
|
||||||
|
}
|
||||||
|
out.push_back(in[ii].c);
|
||||||
|
ii++;
|
||||||
|
if (!nextSame)
|
||||||
|
{
|
||||||
|
if (os < fields[fi].size)
|
||||||
|
push_nulls(fields[fi].size - os, out);
|
||||||
|
os = 0;
|
||||||
|
last = fi++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default initialize if necessary
|
||||||
|
if (ii == nin || fi < in[ii].idx)
|
||||||
|
{
|
||||||
|
DUnionField& f = fields[fi];
|
||||||
|
out.push_back(f.init);
|
||||||
|
if (f.initsize < f.size)
|
||||||
|
push_nulls(f.size - f.initsize, out);
|
||||||
|
last = fi++;
|
||||||
|
os = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const llvm::Type*> tys;
|
||||||
|
size_t nout = out.size();
|
||||||
|
for (size_t i=0; i<nout; ++i)
|
||||||
|
tys.push_back(out[i]->getType());
|
||||||
|
|
||||||
|
const llvm::StructType* st = llvm::StructType::get(tys);
|
||||||
|
return llvm::ConstantStruct::get(st, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
49
gen/structs.h
Normal file
49
gen/structs.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef LLVMD_GEN_STRUCTS_H
|
||||||
|
#define LLVMD_GEN_STRUCTS_H
|
||||||
|
|
||||||
|
struct StructInitializer;
|
||||||
|
const llvm::Type* DtoStructType(Type* t);
|
||||||
|
llvm::Value* DtoStructZeroInit(llvm::Value* v);
|
||||||
|
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src);
|
||||||
|
llvm::Constant* DtoConstStructInitializer(StructInitializer* si);
|
||||||
|
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs);
|
||||||
|
|
||||||
|
struct DUnionField
|
||||||
|
{
|
||||||
|
unsigned offset;
|
||||||
|
size_t size;
|
||||||
|
std::vector<const llvm::Type*> types;
|
||||||
|
llvm::Constant* init;
|
||||||
|
size_t initsize;
|
||||||
|
|
||||||
|
DUnionField() {
|
||||||
|
offset = 0;
|
||||||
|
size = 0;
|
||||||
|
init = NULL;
|
||||||
|
initsize = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DUnionIdx
|
||||||
|
{
|
||||||
|
unsigned idx,idxos;
|
||||||
|
llvm::Constant* c;
|
||||||
|
|
||||||
|
DUnionIdx()
|
||||||
|
: idx(0), c(0) {}
|
||||||
|
DUnionIdx(unsigned _idx, unsigned _idxos, llvm::Constant* _c)
|
||||||
|
: idx(_idx), idxos(_idxos), c(_c) {}
|
||||||
|
bool operator<(const DUnionIdx& i) const {
|
||||||
|
return (idx < i.idx) || (idx == i.idx && idxos < i.idxos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DUnion
|
||||||
|
{
|
||||||
|
std::vector<DUnionField> fields;
|
||||||
|
public:
|
||||||
|
DUnion();
|
||||||
|
llvm::Constant* getConst(std::vector<DUnionIdx>& in);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
25
gen/toir.cpp
25
gen/toir.cpp
|
@ -27,6 +27,7 @@
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/arrays.h"
|
#include "gen/arrays.h"
|
||||||
|
#include "gen/structs.h"
|
||||||
|
|
||||||
#include "gen/dvalue.h"
|
#include "gen/dvalue.h"
|
||||||
|
|
||||||
|
@ -178,9 +179,12 @@ DValue* VarExp::toElem(IRState* p)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// take care of forward references of global variables
|
// take care of forward references of global variables
|
||||||
if (!vd->llvmTouched && vd->isDataseg())
|
if (!vd->llvmTouched && (vd->isDataseg() || (vd->storage_class & STCextern))) // !vd->onstack)
|
||||||
vd->toObjFile();
|
vd->toObjFile();
|
||||||
assert(vd->llvmValue);
|
if (!vd->llvmValue) {
|
||||||
|
Logger::println("global variable not resolved :/ %s", vd->toChars());
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
return new DVarValue(vd, vd->llvmValue, true);
|
return new DVarValue(vd, vd->llvmValue, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +229,7 @@ llvm::Constant* VarExp::toConstElem(IRState* p)
|
||||||
assert(ts->sym->llvmInitZ);
|
assert(ts->sym->llvmInitZ);
|
||||||
return ts->sym->llvmInitZ;
|
return ts->sym->llvmInitZ;
|
||||||
}
|
}
|
||||||
assert(0 && "Only support const var exp is SymbolDeclaration");
|
assert(0 && "Only supported const VarExp is of a SymbolDeclaration");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,14 +251,15 @@ llvm::Constant* IntegerExp::toConstElem(IRState* p)
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
const llvm::Type* t = DtoType(type);
|
const llvm::Type* t = DtoType(type);
|
||||||
if (llvm::isa<llvm::PointerType>(t)) {
|
if (llvm::isa<llvm::PointerType>(t)) {
|
||||||
|
Logger::println("pointer");
|
||||||
llvm::Constant* i = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)value,false);
|
llvm::Constant* i = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)value,false);
|
||||||
return llvm::ConstantExpr::getIntToPtr(i, t);
|
return llvm::ConstantExpr::getIntToPtr(i, t);
|
||||||
}
|
}
|
||||||
else if (llvm::isa<llvm::IntegerType>(t)) {
|
assert(llvm::isa<llvm::IntegerType>(t));
|
||||||
return llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned());
|
llvm::Constant* c = llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned());
|
||||||
}
|
assert(c);
|
||||||
assert(0);
|
Logger::cout() << "value = " << *c << '\n';
|
||||||
return NULL;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1447,7 +1452,7 @@ DValue* CastExp::toElem(IRState* p)
|
||||||
if (isslice) {
|
if (isslice) {
|
||||||
return new DSliceValue(type, rval2, rval);
|
return new DSliceValue(type, rval2, rval);
|
||||||
}
|
}
|
||||||
else if (u->isLValueCast() || u->isVar()) {
|
else if (u->isLValueCast() || (u->isVar() && u->isVar()->lval)) {
|
||||||
return new DLValueCast(type, u->getLVal(), rval);
|
return new DLValueCast(type, u->getLVal(), rval);
|
||||||
}
|
}
|
||||||
else if (p->topexp() && p->topexp()->e1 == this) {
|
else if (p->topexp() && p->topexp()->e1 == this) {
|
||||||
|
@ -2875,7 +2880,7 @@ STUB(RemoveExp);
|
||||||
STUB(AssocArrayLiteralExp);
|
STUB(AssocArrayLiteralExp);
|
||||||
//STUB(StructLiteralExp);
|
//STUB(StructLiteralExp);
|
||||||
|
|
||||||
#define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); assert(0); fatal(); return NULL; }
|
#define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); fatal(); return NULL; }
|
||||||
CONSTSTUB(Expression);
|
CONSTSTUB(Expression);
|
||||||
//CONSTSTUB(IntegerExp);
|
//CONSTSTUB(IntegerExp);
|
||||||
//CONSTSTUB(RealExp);
|
//CONSTSTUB(RealExp);
|
||||||
|
|
221
gen/tollvm.cpp
221
gen/tollvm.cpp
|
@ -14,6 +14,7 @@
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/arrays.h"
|
#include "gen/arrays.h"
|
||||||
#include "gen/dvalue.h"
|
#include "gen/dvalue.h"
|
||||||
|
#include "gen/structs.h"
|
||||||
|
|
||||||
bool DtoIsPassedByRef(Type* type)
|
bool DtoIsPassedByRef(Type* type)
|
||||||
{
|
{
|
||||||
|
@ -373,16 +374,6 @@ const llvm::StructType* DtoDelegateType(Type* t)
|
||||||
return llvm::StructType::get(types);
|
return llvm::StructType::get(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const llvm::Type* DtoStructType(Type* t)
|
|
||||||
{
|
|
||||||
assert(0);
|
|
||||||
std::vector<const llvm::Type*> types;
|
|
||||||
return llvm::StructType::get(types);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false)
|
static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false)
|
||||||
|
@ -454,132 +445,6 @@ llvm::Function* LLVM_DeclareMemCpy64()
|
||||||
return _func;
|
return _func;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
llvm::Value* DtoStructZeroInit(llvm::Value* v)
|
|
||||||
{
|
|
||||||
assert(gIR);
|
|
||||||
uint64_t n = gTargetData->getTypeSize(v->getType()->getContainedType(0));
|
|
||||||
//llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
|
|
||||||
llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
||||||
|
|
||||||
llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb());
|
|
||||||
|
|
||||||
llvm::Function* fn = LLVM_DeclareMemSet32();
|
|
||||||
std::vector<llvm::Value*> llargs;
|
|
||||||
llargs.resize(4);
|
|
||||||
llargs[0] = sarr;
|
|
||||||
llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
|
|
||||||
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
|
||||||
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
|
||||||
|
|
||||||
llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src)
|
|
||||||
{
|
|
||||||
Logger::cout() << "dst = " << *dst << " src = " << *src << '\n';
|
|
||||||
assert(dst->getType() == src->getType());
|
|
||||||
assert(gIR);
|
|
||||||
|
|
||||||
uint64_t n = gTargetData->getTypeSize(dst->getType()->getContainedType(0));
|
|
||||||
//llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
|
|
||||||
llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
|
|
||||||
|
|
||||||
llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
|
|
||||||
llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
|
|
||||||
|
|
||||||
llvm::Function* fn = LLVM_DeclareMemCpy32();
|
|
||||||
std::vector<llvm::Value*> llargs;
|
|
||||||
llargs.resize(4);
|
|
||||||
llargs[0] = dstarr;
|
|
||||||
llargs[1] = srcarr;
|
|
||||||
llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
|
|
||||||
llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
|
||||||
|
|
||||||
return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
llvm::Constant* DtoConstStructInitializer(StructInitializer* si)
|
|
||||||
{
|
|
||||||
llvm::StructType* structtype = llvm::cast<llvm::StructType>(si->ad->llvmType);
|
|
||||||
size_t n = structtype->getNumElements();
|
|
||||||
|
|
||||||
assert(si->value.dim == si->vars.dim);
|
|
||||||
|
|
||||||
std::vector<llvm::Constant*> inits;
|
|
||||||
inits.resize(n, NULL);
|
|
||||||
for (int i = 0; i < si->value.dim; ++i)
|
|
||||||
{
|
|
||||||
Initializer* ini = (Initializer*)si->value.data[i];
|
|
||||||
assert(ini);
|
|
||||||
|
|
||||||
VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
|
|
||||||
Type* vdtype = DtoDType(vd->type);
|
|
||||||
assert(vd);
|
|
||||||
Logger::println("vars[%d] = %s", i, vd->toChars());
|
|
||||||
|
|
||||||
llvm::Constant* v = 0;
|
|
||||||
|
|
||||||
assert(vd->llvmFieldIndex >= 0);
|
|
||||||
unsigned idx = vd->llvmFieldIndex;
|
|
||||||
|
|
||||||
if (ExpInitializer* ex = ini->isExpInitializer())
|
|
||||||
{
|
|
||||||
v = ex->exp->toConstElem(gIR);
|
|
||||||
}
|
|
||||||
else if (StructInitializer* si = ini->isStructInitializer())
|
|
||||||
{
|
|
||||||
v = DtoConstStructInitializer(si);
|
|
||||||
}
|
|
||||||
else if (ArrayInitializer* ai = ini->isArrayInitializer())
|
|
||||||
{
|
|
||||||
v = DtoConstArrayInitializer(ai);
|
|
||||||
}
|
|
||||||
else if (ini->isVoidInitializer())
|
|
||||||
{
|
|
||||||
v = llvm::UndefValue::get(structtype->getElementType(idx));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
assert(v);
|
|
||||||
|
|
||||||
inits[idx] = v;
|
|
||||||
Logger::cout() << "init[" << idx << "] = " << *v << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill out nulls
|
|
||||||
assert(si->ad->llvmInitZ);
|
|
||||||
if (si->ad->llvmInitZ->isNullValue())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
if (inits[i] == 0)
|
|
||||||
{
|
|
||||||
inits[i] = llvm::Constant::getNullValue(structtype->getElementType(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
if (inits[i] == 0)
|
|
||||||
{
|
|
||||||
inits[i] = si->ad->llvmInitZ->getOperand(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return llvm::ConstantStruct::get(structtype, inits);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
llvm::Value* DtoNullDelegate(llvm::Value* v)
|
llvm::Value* DtoNullDelegate(llvm::Value* v)
|
||||||
|
@ -1495,65 +1360,6 @@ llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs)
|
|
||||||
{
|
|
||||||
Logger::println("checking for offset %u type %s:", os, t->toChars());
|
|
||||||
LOG_SCOPE;
|
|
||||||
|
|
||||||
if (idxs.empty())
|
|
||||||
idxs.push_back(0);
|
|
||||||
|
|
||||||
const llvm::Type* llt = llvm::PointerType::get(DtoType(t));
|
|
||||||
|
|
||||||
for (unsigned i=0; i<sd->fields.dim; ++i) {
|
|
||||||
VarDeclaration* vd = (VarDeclaration*)sd->fields.data[i];
|
|
||||||
Type* vdtype = DtoDType(vd->type);
|
|
||||||
Logger::println("found %u type %s", vd->offset, vdtype->toChars());
|
|
||||||
assert(vd->llvmFieldIndex >= 0);
|
|
||||||
if (os == vd->offset && vdtype == t) {
|
|
||||||
idxs.push_back(vd->llvmFieldIndex);
|
|
||||||
ptr = DtoGEP(ptr, idxs, "tmp");
|
|
||||||
if (ptr->getType() != llt)
|
|
||||||
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
|
||||||
if (vd->llvmFieldIndexOffset)
|
|
||||||
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) {
|
|
||||||
TypeStruct* ts = (TypeStruct*)vdtype;
|
|
||||||
StructDeclaration* ssd = ts->sym;
|
|
||||||
idxs.push_back(vd->llvmFieldIndex);
|
|
||||||
if (vd->llvmFieldIndexOffset) {
|
|
||||||
Logger::println("has union field offset");
|
|
||||||
ptr = DtoGEP(ptr, idxs, "tmp");
|
|
||||||
if (ptr->getType() != llt)
|
|
||||||
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
|
||||||
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
|
|
||||||
std::vector<unsigned> tmp;
|
|
||||||
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type));
|
|
||||||
if (ptr->getType() != sty) {
|
|
||||||
ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
|
|
||||||
std::vector<unsigned> tmp;
|
|
||||||
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0));
|
|
||||||
assert(os % llt_sz == 0);
|
|
||||||
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
|
|
||||||
return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool DtoIsTemplateInstance(Dsymbol* s)
|
bool DtoIsTemplateInstance(Dsymbol* s)
|
||||||
{
|
{
|
||||||
if (!s) return false;
|
if (!s) return false;
|
||||||
|
@ -1563,3 +1369,28 @@ bool DtoIsTemplateInstance(Dsymbol* s)
|
||||||
return DtoIsTemplateInstance(s->parent);
|
return DtoIsTemplateInstance(s->parent);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type* t)
|
||||||
|
{
|
||||||
|
// create a flag to make sure initialization only happens once
|
||||||
|
llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage;
|
||||||
|
std::string gflagname(gvar->getName());
|
||||||
|
gflagname.append("__initflag");
|
||||||
|
llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,gIR->module);
|
||||||
|
|
||||||
|
// check flag and do init if not already done
|
||||||
|
llvm::BasicBlock* oldend = gIR->scopeend();
|
||||||
|
llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend);
|
||||||
|
llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend);
|
||||||
|
llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false));
|
||||||
|
gIR->ir->CreateCondBr(cond, initbb, endinitbb);
|
||||||
|
gIR->scope() = IRScope(initbb,endinitbb);
|
||||||
|
DValue* ie = DtoInitializer(init);
|
||||||
|
if (!ie->inPlace()) {
|
||||||
|
DValue* dst = new DVarValue(t, gvar, true);
|
||||||
|
DtoAssign(dst, ie);
|
||||||
|
}
|
||||||
|
gIR->ir->CreateStore(DtoConstBool(true), gflag);
|
||||||
|
gIR->ir->CreateBr(endinitbb);
|
||||||
|
gIR->scope() = IRScope(endinitbb,oldend);
|
||||||
|
}
|
||||||
|
|
10
gen/tollvm.h
10
gen/tollvm.h
|
@ -3,18 +3,12 @@
|
||||||
|
|
||||||
// D -> LLVM helpers
|
// D -> LLVM helpers
|
||||||
|
|
||||||
struct StructInitializer;
|
|
||||||
struct DValue;
|
struct DValue;
|
||||||
|
|
||||||
const llvm::Type* DtoType(Type* t);
|
const llvm::Type* DtoType(Type* t);
|
||||||
bool DtoIsPassedByRef(Type* type);
|
bool DtoIsPassedByRef(Type* type);
|
||||||
Type* DtoDType(Type* t);
|
Type* DtoDType(Type* t);
|
||||||
|
|
||||||
const llvm::Type* DtoStructType(Type* t);
|
|
||||||
llvm::Value* DtoStructZeroInit(llvm::Value* v);
|
|
||||||
llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src);
|
|
||||||
llvm::Constant* DtoConstStructInitializer(StructInitializer* si);
|
|
||||||
|
|
||||||
const llvm::FunctionType* DtoFunctionType(Type* t, const llvm::Type* thistype, bool ismain = false);
|
const llvm::FunctionType* DtoFunctionType(Type* t, const llvm::Type* thistype, bool ismain = false);
|
||||||
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
|
const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
|
||||||
llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl);
|
llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl);
|
||||||
|
@ -66,10 +60,10 @@ llvm::Constant* DtoConstString(const char*);
|
||||||
llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0);
|
llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0);
|
||||||
llvm::Constant* DtoConstBool(bool);
|
llvm::Constant* DtoConstBool(bool);
|
||||||
|
|
||||||
llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs);
|
|
||||||
|
|
||||||
bool DtoIsTemplateInstance(Dsymbol* s);
|
bool DtoIsTemplateInstance(Dsymbol* s);
|
||||||
|
|
||||||
|
void DtoLazyStaticInit(bool istempl, llvm::Value* gvar, Initializer* init, Type* t);
|
||||||
|
|
||||||
// llvm wrappers
|
// llvm wrappers
|
||||||
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes);
|
||||||
bool DtoCanLoad(llvm::Value* ptr);
|
bool DtoCanLoad(llvm::Value* ptr);
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/arrays.h"
|
#include "gen/arrays.h"
|
||||||
|
#include "gen/structs.h"
|
||||||
#include "gen/todebug.h"
|
#include "gen/todebug.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
|
|
||||||
|
@ -287,6 +288,8 @@ void StructDeclaration::toObjFile()
|
||||||
gIR->module->addTypeName(mangle(),ts->llvmType);
|
gIR->module->addTypeName(mangle(),ts->llvmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvmUnion = new DUnion; // uses gIR->topstruct()
|
||||||
|
|
||||||
// generate static data
|
// generate static data
|
||||||
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
|
||||||
llvm::Constant* _init = 0;
|
llvm::Constant* _init = 0;
|
||||||
|
@ -572,6 +575,7 @@ void VarDeclaration::toObjFile()
|
||||||
|
|
||||||
if (aliassym)
|
if (aliassym)
|
||||||
{
|
{
|
||||||
|
Logger::println("alias sym");
|
||||||
toAlias()->toObjFile();
|
toAlias()->toObjFile();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -608,35 +612,13 @@ void VarDeclaration::toObjFile()
|
||||||
Logger::println("Creating global variable");
|
Logger::println("Creating global variable");
|
||||||
std::string _name(mangle());
|
std::string _name(mangle());
|
||||||
|
|
||||||
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,0,_name,M);
|
bool emitRTstaticInit = false;
|
||||||
llvmValue = gvar;
|
|
||||||
|
|
||||||
if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl))
|
if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl))
|
||||||
{
|
{
|
||||||
if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) {
|
if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) {
|
||||||
_init = DtoConstInitializer(t, NULL);
|
_init = DtoConstInitializer(t, NULL);
|
||||||
// create a flag to make sure initialization only happens once
|
emitRTstaticInit = true;
|
||||||
llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage;
|
|
||||||
std::string gflagname(_name);
|
|
||||||
gflagname.append("__initflag");
|
|
||||||
llvm::GlobalVariable* gflag = new llvm::GlobalVariable(llvm::Type::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,M);
|
|
||||||
|
|
||||||
// check flag and do init if not already done
|
|
||||||
llvm::BasicBlock* oldend = gIR->scopeend();
|
|
||||||
llvm::BasicBlock* initbb = new llvm::BasicBlock("ifnotinit",gIR->topfunc(),oldend);
|
|
||||||
llvm::BasicBlock* endinitbb = new llvm::BasicBlock("ifnotinitend",gIR->topfunc(),oldend);
|
|
||||||
llvm::Value* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false));
|
|
||||||
gIR->ir->CreateCondBr(cond, initbb, endinitbb);
|
|
||||||
gIR->scope() = IRScope(initbb,endinitbb);
|
|
||||||
elem* ie = DtoInitializer(init);
|
|
||||||
if (!ie->inPlace()) {
|
|
||||||
DValue* dst = new DVarValue(t, gvar, true);
|
|
||||||
DtoAssign(dst, ie);
|
|
||||||
delete dst;
|
|
||||||
}
|
|
||||||
gIR->ir->CreateStore(DtoConstBool(true), gflag);
|
|
||||||
gIR->ir->CreateBr(endinitbb);
|
|
||||||
gIR->scope() = IRScope(endinitbb,oldend);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_init = DtoConstInitializer(t, init);
|
_init = DtoConstInitializer(t, init);
|
||||||
|
@ -668,11 +650,16 @@ void VarDeclaration::toObjFile()
|
||||||
//assert(0);
|
//assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::cout() << "final init = " << *_init << '\n';
|
|
||||||
gvar->setInitializer(_init);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_init && _init->getType() != _type)
|
||||||
|
_type = _init->getType();
|
||||||
|
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M);
|
||||||
|
llvmValue = gvar;
|
||||||
|
|
||||||
|
if (emitRTstaticInit)
|
||||||
|
DtoLazyStaticInit(istempl, gvar, init, t);
|
||||||
|
|
||||||
llvmDModule = gIR->dmodule;
|
llvmDModule = gIR->dmodule;
|
||||||
|
|
||||||
//if (storage_class & STCprivate)
|
//if (storage_class & STCprivate)
|
||||||
|
|
|
@ -3,7 +3,28 @@ module phobos;
|
||||||
import
|
import
|
||||||
std.array,
|
std.array,
|
||||||
std.ctype,
|
std.ctype,
|
||||||
|
std.intrinsic,
|
||||||
|
std.stdint,
|
||||||
std.stdio,
|
std.stdio,
|
||||||
std.stdarg,
|
std.stdarg,
|
||||||
std.uni,
|
std.uni,
|
||||||
std.utf;
|
std.utf,
|
||||||
|
|
||||||
|
std.c.fenv,
|
||||||
|
std.c.locale,
|
||||||
|
std.c.math,
|
||||||
|
std.c.process,
|
||||||
|
std.c.stdarg,
|
||||||
|
std.c.stddef,
|
||||||
|
std.c.stdio,
|
||||||
|
std.c.stdlib,
|
||||||
|
std.c.string,
|
||||||
|
std.c.time;
|
||||||
|
|
||||||
|
version(linux) {
|
||||||
|
import
|
||||||
|
std.c.linux.linux,
|
||||||
|
std.c.linux.linuxextern,
|
||||||
|
std.c.linux.pthread,
|
||||||
|
std.c.linux.socket;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
module std.c.linux.linuxextern;
|
module std.c.linux.linuxextern;
|
||||||
|
|
||||||
extern (C)
|
extern extern (C)
|
||||||
{
|
{
|
||||||
void* __libc_stack_end;
|
void* __libc_stack_end;
|
||||||
int __data_start;
|
int __data_start;
|
||||||
|
|
|
@ -331,7 +331,7 @@ union in6_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
|
const in6_addr IN6ADDR_ANY;
|
||||||
const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
|
const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
|
||||||
//alias IN6ADDR_ANY IN6ADDR_ANY_INIT;
|
//alias IN6ADDR_ANY IN6ADDR_ANY_INIT;
|
||||||
//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT;
|
//alias IN6ADDR_LOOPBACK IN6ADDR_LOOPBACK_INIT;
|
||||||
|
|
26
test/bug51.d
Normal file
26
test/bug51.d
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
module bug51;
|
||||||
|
|
||||||
|
import std.stdint;
|
||||||
|
|
||||||
|
union in6_addr
|
||||||
|
{
|
||||||
|
private union _in6_u_t
|
||||||
|
{
|
||||||
|
uint8_t[16] u6_addr8;
|
||||||
|
uint16_t[8] u6_addr16;
|
||||||
|
uint32_t[4] u6_addr32;
|
||||||
|
}
|
||||||
|
_in6_u_t in6_u;
|
||||||
|
|
||||||
|
uint8_t[16] s6_addr8;
|
||||||
|
uint16_t[8] s6_addr16;
|
||||||
|
uint32_t[4] s6_addr32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const in6_addr IN6ADDR_ANY = { s6_addr8: [0] };
|
||||||
|
const in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
48
test/union7.d
Normal file
48
test/union7.d
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
module union7;
|
||||||
|
|
||||||
|
pragma(LLVM_internal, "notypeinfo")
|
||||||
|
struct Union
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
double g;
|
||||||
|
struct {
|
||||||
|
short s1,s2,s3,s4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
long l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Union a = { f:4f };
|
||||||
|
Union b = { 3.0, f:2 };
|
||||||
|
Union c = { l:42, g:2.0 };
|
||||||
|
Union d = { s2:3 };
|
||||||
|
Union e = { s1:3, s4:4, l:5 };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
assert(a.f == 4f);
|
||||||
|
assert(a.g !<>= 0.0);
|
||||||
|
assert((a.l>>>32) == 0);
|
||||||
|
|
||||||
|
assert(b.g == 3.0);
|
||||||
|
assert(b.f == 2f);
|
||||||
|
|
||||||
|
assert(c.l == 42);
|
||||||
|
assert(c.g == 2.0);
|
||||||
|
|
||||||
|
assert(d.s1 == 0);
|
||||||
|
assert(d.s2 == 3);
|
||||||
|
assert(d.s3 == 0);
|
||||||
|
assert(d.s4 == 0);
|
||||||
|
{assert(d.f !<>= 0f);}
|
||||||
|
{}
|
||||||
|
assert(e.s1 == 3);
|
||||||
|
assert(e.s2 == 0);
|
||||||
|
assert(e.s3 == 0);
|
||||||
|
{assert(e.s4 == 4);}
|
||||||
|
{}
|
||||||
|
assert(e.l == 5);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue