diff --git a/dmd/declaration.h b/dmd/declaration.h index 8bc76e57..2a9647e4 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -527,6 +527,7 @@ struct FuncDeclaration : Declaration llvm::Value* llvmArguments; llvm::Value* llvmArgPtr; llvm::Constant* llvmDwarfSubProgram; + bool llvmRunTimeHack; }; struct FuncAliasDeclaration : FuncDeclaration diff --git a/dmd/expression.h b/dmd/expression.h index 98d9a5c3..664ce2b3 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -56,11 +56,16 @@ enum TOK; struct IRState; struct dt_t; +#if IN_LLVM +struct DValue; +typedef DValue elem; +#else #ifdef IN_GCC union tree_node; typedef union tree_node elem; #else struct elem; #endif +#endif void initPrecedence(); diff --git a/dmd/func.c b/dmd/func.c index 3bea465b..72a2b2b1 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -79,6 +79,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC s llvmArguments = NULL; llvmArgPtr = NULL; llvmDwarfSubProgram = NULL; + llvmRunTimeHack = false; } Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) diff --git a/dmd/module.h b/dmd/module.h index df86002d..ceacfeec 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -26,11 +26,16 @@ struct Escape; struct VarDeclaration; // Back end -#if IN_GCC +#if IN_LLVM +struct DValue; +typedef DValue elem; +#else +#ifdef IN_GCC union tree_node; typedef union tree_node elem; #else struct elem; #endif +#endif struct Package : ScopeDsymbol { diff --git a/dmd/statement.c b/dmd/statement.c index b3dc416a..c0a0a672 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -1438,6 +1438,7 @@ Statement *ForeachStatement::semantic(Scope *sc) fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply2"); else fdapply = FuncDeclaration::genCfunc(Type::tindex, "_aaApply"); + fdapply->llvmRunTimeHack = true; ec = new VarExp(0, fdapply); Expressions *exps = new Expressions(); exps->push(aggr); @@ -1479,6 +1480,7 @@ Statement *ForeachStatement::semantic(Scope *sc) int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim); assert(j < sizeof(fdname)); fdapply = FuncDeclaration::genCfunc(Type::tindex, fdname); + fdapply->llvmRunTimeHack = true; ec = new VarExp(0, fdapply); Expressions *exps = new Expressions(); @@ -3464,7 +3466,7 @@ LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) this->statement = statement; this->tf = NULL; this->lblock = NULL; - this->isReturnLabel = 0; + this->isReturnLabel = 0; this->llvmBB = NULL; } diff --git a/dmd/statement.h b/dmd/statement.h index 2b6ed9ca..6fa73d12 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -51,19 +51,24 @@ enum TOK; namespace llvm { - class Value; + class Value; class BasicBlock; } // Back end struct IRState; struct Blockx; +#if IN_LLVM +struct DValue; +typedef DValue elem; +#endif + #if IN_GCC union tree_node; typedef union tree_node block; -union tree_node; typedef union tree_node elem; +//union tree_node; typedef union tree_node elem; #else struct block; -struct elem; +//struct elem; #endif struct code; @@ -715,8 +720,8 @@ struct LabelStatement : Statement Statement *inlineScan(InlineScanState *iss); - void toIR(IRState *irs); - + void toIR(IRState *irs); + llvm::BasicBlock* llvmBB; }; diff --git a/gen/arrays.c b/gen/arrays.cpp similarity index 83% rename from gen/arrays.c rename to gen/arrays.cpp index 16a319bc..5cbdbe81 100644 --- a/gen/arrays.c +++ b/gen/arrays.cpp @@ -11,7 +11,7 @@ #include "gen/arrays.h" #include "gen/runtime.h" #include "gen/logger.h" -#include "gen/elem.h" +#include "gen/dvalue.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -125,17 +125,18 @@ void DtoArrayInit(llvm::Value* l, llvm::Value* r) { const llvm::PointerType* ptrty = llvm::cast(l->getType()); const llvm::Type* t = ptrty->getContainedType(0); - const llvm::ArrayType* arrty = llvm::cast_or_null(t); + const llvm::ArrayType* arrty = llvm::dyn_cast(t); if (arrty) { llvm::Value* ptr = DtoGEPi(l,0,0,"tmp",gIR->scopebb()); llvm::Value* dim = llvm::ConstantInt::get(DtoSize_t(), arrty->getNumElements(), false); - llvm::Value* val = r; - DtoArrayInit(ptr, dim, val); + DtoArrayInit(ptr, dim, r); } else if (llvm::isa(t)) { - assert(0 && "Only static arrays support initialisers atm"); + llvm::Value* dim = DtoLoad(DtoGEPi(l, 0,0, "tmp")); + llvm::Value* ptr = DtoLoad(DtoGEPi(l, 0,1, "tmp")); + DtoArrayInit(ptr, dim, r); } else assert(0); @@ -159,6 +160,8 @@ static size_t checkRectArrayInit(const llvm::Type* pt, constLLVMTypeP& finalty) void DtoArrayInit(llvm::Value* ptr, llvm::Value* dim, llvm::Value* val) { + Logger::println("HELLO"); + Logger::cout() << "array: " << *ptr << " dim: " << *dim << " val: " << *val << '\n'; const llvm::Type* pt = ptr->getType()->getContainedType(0); const llvm::Type* t = val->getType(); const llvm::Type* finalTy; @@ -250,9 +253,20 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit) { Logger::println("arr init begin"); Type* arrinittype = DtoDType(arrinit->type); - assert(arrinittype->ty == Tsarray); - TypeSArray* t = (TypeSArray*)arrinittype; - integer_t tdim = t->dim->toInteger(); + + Type* t; + integer_t tdim; + if (arrinittype->ty == Tsarray) { + TypeSArray* tsa = (TypeSArray*)arrinittype; + tdim = tsa->dim->toInteger(); + t = tsa; + } + else if (arrinittype->ty == Tarray) { + t = arrinittype; + tdim = arrinit->dim; + } + else + assert(0); std::vector inits(tdim, 0); @@ -308,32 +322,41 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* arrinit) inits[i] = v; } - const llvm::ArrayType* arrty = DtoStaticArrayType(t); - return llvm::ConstantArray::get(arrty, inits); + const llvm::ArrayType* arrty = llvm::ArrayType::get(elemty,tdim); + llvm::Constant* constarr = llvm::ConstantArray::get(arrty, inits); + + if (arrinittype->ty == Tsarray) + return constarr; + else + assert(arrinittype->ty == Tarray); + + llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrty,true,llvm::GlobalValue::InternalLinkage,constarr,"constarray",gIR->module); + llvm::Constant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; + llvm::Constant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); + return DtoConstSlice(DtoConstSize_t(tdim),gep); } ////////////////////////////////////////////////////////////////////////////////////////// -static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz) +static llvm::Value* get_slice_ptr(DSliceValue* e, llvm::Value*& sz) { - assert(e->mem); - const llvm::Type* t = e->mem->getType()->getContainedType(0); + const llvm::Type* t = e->ptr->getType()->getContainedType(0); llvm::Value* ret = 0; - if (e->arg != 0) { + if (e->len != 0) { // this means it's a real slice - ret = e->mem; + ret = e->ptr; size_t elembsz = gTargetData->getTypeSize(ret->getType()); llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false); - if (llvm::isa(e->arg)) { - sz = llvm::ConstantExpr::getMul(elemsz, llvm::cast(e->arg)); + if (llvm::isa(e->len)) { + sz = llvm::ConstantExpr::getMul(elemsz, llvm::cast(e->len)); } else { - sz = llvm::BinaryOperator::createMul(elemsz,e->arg,"tmp",gIR->scopebb()); + sz = llvm::BinaryOperator::createMul(elemsz,e->len,"tmp",gIR->scopebb()); } } else if (llvm::isa(t)) { - ret = DtoGEPi(e->mem, 0, 0, "tmp", gIR->scopebb()); + ret = DtoGEPi(e->ptr, 0, 0, "tmp", gIR->scopebb()); size_t elembsz = gTargetData->getTypeSize(ret->getType()->getContainedType(0)); llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false); @@ -344,13 +367,13 @@ static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz) sz = llvm::ConstantExpr::getMul(elemsz, nelems); } else if (llvm::isa(t)) { - ret = DtoGEPi(e->mem, 0, 1, "tmp", gIR->scopebb()); + ret = DtoGEPi(e->ptr, 0, 1, "tmp", gIR->scopebb()); ret = new llvm::LoadInst(ret, "tmp", gIR->scopebb()); size_t elembsz = gTargetData->getTypeSize(ret->getType()->getContainedType(0)); llvm::ConstantInt* elemsz = llvm::ConstantInt::get(DtoSize_t(), elembsz, false); - llvm::Value* len = DtoGEPi(e->mem, 0, 0, "tmp", gIR->scopebb()); + llvm::Value* len = DtoGEPi(e->ptr, 0, 0, "tmp", gIR->scopebb()); len = new llvm::LoadInst(len, "tmp", gIR->scopebb()); sz = llvm::BinaryOperator::createMul(len,elemsz,"tmp",gIR->scopebb()); } @@ -360,13 +383,8 @@ static llvm::Value* get_slice_ptr(elem* e, llvm::Value*& sz) return ret; } -void DtoArrayCopy(elem* dst, elem* src) +void DtoArrayCopy(DSliceValue* dst, DSliceValue* src) { - Logger::cout() << "Array copy ((((" << *src->mem << ")))) into ((((" << *dst->mem << "))))\n"; - - assert(dst->type == elem::SLICE); - assert(src->type == elem::SLICE); - llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); llvm::Value* sz1; @@ -435,9 +453,8 @@ llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool llvm::Value* newptr = DtoRealloc(nullptr, bytesize); if (doinit) { - elem* e = dty->defaultInit()->toElem(gIR); - DtoArrayInit(newptr,dim,e->getValue()); - delete e; + DValue* e = dty->defaultInit()->toElem(gIR); + DtoArrayInit(newptr,dim,e->getRVal()); } llvm::Value* lenptr = DtoGEPi(dst,0,0,"tmp",gIR->scopebb()); @@ -449,7 +466,7 @@ llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool } ////////////////////////////////////////////////////////////////////////////////////////// -void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz) +llvm::Value* DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz) { llvm::Value* ptr = DtoGEPi(arr, 0, 1, "tmp", gIR->scopebb()); llvm::Value* ptrld = new llvm::LoadInst(ptr,"tmp",gIR->scopebb()); @@ -463,25 +480,52 @@ void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz) llvm::Value* len = DtoGEPi(arr, 0, 0, "tmp", gIR->scopebb()); new llvm::StoreInst(sz,len,gIR->scopebb()); + + return newptr; } ////////////////////////////////////////////////////////////////////////////////////////// void DtoCatAssignElement(llvm::Value* arr, Expression* exp) { - llvm::Value* ptr = DtoGEPi(arr, 0, 0, "tmp", gIR->scopebb()); - llvm::Value* idx = new llvm::LoadInst(ptr, "tmp", gIR->scopebb()); + llvm::Value* ptr = DtoGEPi(arr, 0, 0, "tmp"); + llvm::Value* idx = DtoLoad(ptr); llvm::Value* one = llvm::ConstantInt::get(idx->getType(),1,false); llvm::Value* len = llvm::BinaryOperator::createAdd(idx, one, "tmp", gIR->scopebb()); DtoResizeDynArray(arr,len); - ptr = DtoGEPi(arr, 0, 1, "tmp", gIR->scopebb()); - ptr = new llvm::LoadInst(ptr, "tmp", gIR->scopebb()); + ptr = DtoLoad(DtoGEPi(arr, 0, 1, "tmp")); ptr = new llvm::GetElementPtrInst(ptr, idx, "tmp", gIR->scopebb()); - elem* e = exp->toElem(gIR); - Type* et = DtoDType(exp->type); - DtoAssign(et, ptr, e->getValue()); - delete e; + DValue* dptr = new DVarValue(exp->type, ptr, true); + + gIR->exps.push_back(IRExp(0,exp,dptr)); + DValue* e = exp->toElem(gIR); + gIR->exps.pop_back(); + + if (!e->inPlace()) + DtoAssign(dptr, e); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void DtoCatAssignArray(llvm::Value* arr, Expression* exp) +{ + DValue* e = exp->toElem(gIR); + + llvm::Value *len1, *len2, *src1, *src2, *res; + + DValue* darr = new DVarValue(exp->type, arr, true); + + len1 = DtoArrayLen(darr); + len2 = DtoArrayLen(e); + res = gIR->ir->CreateAdd(len1,len2,"tmp"); + + llvm::Value* mem = DtoResizeDynArray(arr,res); + + src1 = DtoArrayPtr(darr); + src2 = DtoArrayPtr(e); + + mem = gIR->ir->CreateGEP(mem,len1,"tmp"); + DtoMemCpy(mem,src2,len2); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -493,13 +537,11 @@ void DtoCatArrays(llvm::Value* arr, Expression* exp1, Expression* exp2) assert(t1->ty == Tarray); assert(t1->ty == t2->ty); - elem* e1 = exp1->toElem(gIR); - llvm::Value* a = e1->getValue(); - delete e1; + DValue* e1 = exp1->toElem(gIR); + llvm::Value* a = e1->getRVal(); - elem* e2 = exp2->toElem(gIR); - llvm::Value* b = e2->getValue(); - delete e2; + DValue* e2 = exp2->toElem(gIR); + llvm::Value* b = e2->getRVal(); llvm::Value *len1, *len2, *src1, *src2, *res; len1 = gIR->ir->CreateLoad(DtoGEPi(a,0,0,"tmp"),"tmp"); @@ -670,3 +712,43 @@ llvm::Constant* DtoConstStaticArray(const llvm::Type* t, llvm::Constant* c) initvals.resize(at->getNumElements(), c); return llvm::ConstantArray::get(at, initvals); } + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Value* DtoArrayLen(DValue* v) +{ + Type* t = DtoDType(v->getType()); + if (t->ty == Tarray) { + if (DSliceValue* s = v->isSlice()) { + if (s->len) return s->len; + DValue* next = new DVarValue(t,s->ptr,true); + return DtoArrayLen(next); + } + return DtoLoad(DtoGEPi(v->getRVal(), 0,0, "tmp")); + } + else if (t->ty == Tsarray) { + const llvm::ArrayType* t = llvm::cast(v->getLVal()->getType()); + return DtoConstSize_t(t->getNumElements()); + } + assert(0); + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////////// +llvm::Value* DtoArrayPtr(DValue* v) +{ + Type* t = DtoDType(v->getType()); + if (t->ty == Tarray) { + if (DSliceValue* s = v->isSlice()) { + if (s->len) return s->ptr; + DValue* next = new DVarValue(t,s->ptr,true); + return DtoArrayPtr(next); + } + return DtoLoad(DtoGEPi(v->getRVal(), 0,1, "tmp")); + } + else if (t->ty == Tsarray) { + return DtoGEPi(v->getRVal(), 0,0, "tmp"); + } + assert(0); + return 0; +} + diff --git a/gen/arrays.h b/gen/arrays.h index d4461ccd..2a72a4ec 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -1,6 +1,8 @@ #ifndef LLVMC_GEN_ARRAYS_H #define LLVMC_GEN_ARRAYS_H +struct DSliceValue; + const llvm::StructType* DtoArrayType(Type* t); const llvm::ArrayType* DtoStaticArrayType(Type* t); @@ -8,7 +10,8 @@ llvm::Constant* DtoConstArrayInitializer(ArrayInitializer* si); llvm::Constant* DtoConstSlice(llvm::Constant* dim, llvm::Constant* ptr); llvm::Constant* DtoConstStaticArray(const llvm::Type* t, llvm::Constant* c); -void DtoArrayCopy(elem* dst, elem* src); +void DtoArrayCopy(DSliceValue* dst, DSliceValue* src); + void DtoArrayInit(llvm::Value* l, llvm::Value* r); void DtoArrayInit(llvm::Value* ptr, llvm::Value* dim, llvm::Value* val); void DtoArrayAssign(llvm::Value* l, llvm::Value* r); @@ -16,9 +19,10 @@ void DtoSetArray(llvm::Value* arr, llvm::Value* dim, llvm::Value* ptr); void DtoNullArray(llvm::Value* v); llvm::Value* DtoNewDynArray(llvm::Value* dst, llvm::Value* dim, Type* dty, bool doinit=true); -void DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz); +llvm::Value* DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz); void DtoCatAssignElement(llvm::Value* arr, Expression* exp); +void DtoCatAssignArray(llvm::Value* arr, Expression* exp); void DtoCatArrays(llvm::Value* arr, Expression* e1, Expression* e2); void DtoStaticArrayCopy(llvm::Value* dst, llvm::Value* src); @@ -30,4 +34,7 @@ llvm::Value* DtoDynArrayIs(TOK op, llvm::Value* l, llvm::Value* r); llvm::Value* DtoArrayCastLength(llvm::Value* len, const llvm::Type* elemty, const llvm::Type* newelemty); +llvm::Value* DtoArrayLen(DValue* v); +llvm::Value* DtoArrayPtr(DValue* v); + #endif // LLVMC_GEN_ARRAYS_H diff --git a/gen/binops.cpp b/gen/binops.cpp new file mode 100644 index 00000000..81bc218c --- /dev/null +++ b/gen/binops.cpp @@ -0,0 +1,56 @@ +#include "gen/llvm.h" + +#include "declaration.h" + +#include "gen/irstate.h" +#include "gen/dvalue.h" + +DValue* DtoBinAdd(DValue* lhs, DValue* rhs) +{ + llvm::Value* v = gIR->ir->CreateAdd(lhs->getRVal(), rhs->getRVal(), "tmp"); + return new DImValue( lhs->getType(), v ); +} + +DValue* DtoBinSub(DValue* lhs, DValue* rhs) +{ + llvm::Value* v = gIR->ir->CreateSub(lhs->getRVal(), rhs->getRVal(), "tmp"); + return new DImValue( lhs->getType(), v ); +} + +DValue* DtoBinMul(DValue* lhs, DValue* rhs) +{ + llvm::Value* v = gIR->ir->CreateMul(lhs->getRVal(), rhs->getRVal(), "tmp"); + return new DImValue( lhs->getType(), v ); +} + +DValue* DtoBinDiv(DValue* lhs, DValue* rhs) +{ + Type* t = lhs->getType(); + llvm::Value *l, *r; + l = lhs->getRVal(); + r = rhs->getRVal(); + llvm::Value* res; + if (t->isfloating()) + res = gIR->ir->CreateFDiv(l, r, "tmp"); + else if (!t->isunsigned()) + res = gIR->ir->CreateSDiv(l, r, "tmp"); + else + res = gIR->ir->CreateUDiv(l, r, "tmp"); + return new DImValue( lhs->getType(), res ); +} + +DValue* DtoBinRem(DValue* lhs, DValue* rhs) +{ + Type* t = lhs->getType(); + llvm::Value *l, *r; + l = lhs->getRVal(); + r = rhs->getRVal(); + llvm::Value* res; + if (t->isfloating()) + res = gIR->ir->CreateFRem(l, r, "tmp"); + else if (!t->isunsigned()) + res = gIR->ir->CreateSRem(l, r, "tmp"); + else + res = gIR->ir->CreateURem(l, r, "tmp"); + return new DImValue( lhs->getType(), res ); +} diff --git a/gen/dwarftypes.c b/gen/dwarftypes.cpp similarity index 100% rename from gen/dwarftypes.c rename to gen/dwarftypes.cpp diff --git a/gen/elem.c b/gen/elem.cpp similarity index 80% rename from gen/elem.c rename to gen/elem.cpp index 6285d693..3ea14b9a 100644 --- a/gen/elem.c +++ b/gen/elem.cpp @@ -1,3 +1,4 @@ +/* #include #include "gen/llvm.h" @@ -5,11 +6,14 @@ #include "gen/elem.h" #include "gen/irstate.h" #include "gen/logger.h" +#include "gen/dvalue.h" ////////////////////////////////////////////////////////////////////////////////////////// -elem::elem() +elem::elem(Expression* e) { + exp = e; + mem = 0; val = 0; arg = 0; @@ -24,10 +28,22 @@ elem::elem() vardecl = 0; funcdecl = 0; + + dvalue = 0; +} + +elem::~elem() +{ + delete dvalue; } llvm::Value* elem::getValue() { + if (dvalue && !dvalue->isSlice()) { + Logger::println("HAS DVALUE"); + return dvalue->getRVal(); + } + assert(val || mem); switch(type) { @@ -66,3 +82,4 @@ llvm::Value* elem::getValue() assert(0 && "type == invalid value"); return 0; } +*/ diff --git a/gen/elem.h b/gen/elem.h index 9882766a..57fdae64 100644 --- a/gen/elem.h +++ b/gen/elem.h @@ -1,10 +1,17 @@ #ifndef LLVMDC_GEN_ELEM_H #define LLVMDC_GEN_ELEM_H +#include "dvalue.h" +typedef DValue elem; + +/* + #include "root.h" #include "declaration.h" #include "aggregate.h" +struct DValue; + // represents a value. be it a constant literal, a variable etc. // maintains all the information for doing load/store appropriately struct elem : Object @@ -22,7 +29,10 @@ struct elem : Object }; public: - elem(); + elem(Expression* e); + virtual ~elem(); + + Expression* exp; llvm::Value* mem; llvm::Value* val; @@ -41,7 +51,11 @@ public: llvm::Value* getValue(); //llvm::Value* getMemory(); + DValue* dvalue; + bool isNull() {return !(mem || val);} }; +*/ + #endif // LLVMDC_GEN_ELEM_H diff --git a/gen/irstate.c b/gen/irstate.cpp similarity index 93% rename from gen/irstate.c rename to gen/irstate.cpp index 6f303d33..cdf123d0 100644 --- a/gen/irstate.c +++ b/gen/irstate.cpp @@ -164,7 +164,7 @@ IRExp::IRExp() v = NULL; } -IRExp::IRExp(Expression* l, Expression* r, llvm::Value* val) +IRExp::IRExp(Expression* l, Expression* r, DValue* val) { e1 = l; e2 = r; diff --git a/gen/irstate.h b/gen/irstate.h index 3a2c695d..2f93f94e 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -101,9 +101,9 @@ struct IRExp { Expression* e1; Expression* e2; - llvm::Value* v; + DValue* v; IRExp(); - IRExp(Expression* l, Expression* r, llvm::Value* val); + IRExp(Expression* l, Expression* r, DValue* val); }; // represents the module @@ -158,7 +158,7 @@ struct IRState // might be a better way but it works. problem is I only get a // VarDeclaration for __dollar, but I can't see how to get the // array pointer from this :( - std::vector arrays; + std::vector arrays; // builder helper IRBuilderHelper ir; diff --git a/gen/logger.c b/gen/logger.cpp similarity index 100% rename from gen/logger.c rename to gen/logger.cpp diff --git a/gen/runtime.c b/gen/runtime.cpp similarity index 100% rename from gen/runtime.c rename to gen/runtime.cpp diff --git a/gen/statements.c b/gen/statements.cpp similarity index 90% rename from gen/statements.c rename to gen/statements.cpp index 82dda1a1..398290d5 100644 --- a/gen/statements.c +++ b/gen/statements.cpp @@ -23,6 +23,7 @@ #include "gen/runtime.h" #include "gen/arrays.h" #include "gen/todebug.h" +#include "gen/dvalue.h" ////////////////////////////////////////////////////////////////////////////// @@ -66,34 +67,14 @@ void ReturnStatement::toIR(IRState* p) if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); - p->exps.push_back(IRExp(NULL,exp,f->llvmRetArg)); - elem* e = exp->toElem(p); + DValue* rvar = new DVarValue(f->next, f->llvmRetArg, true); + + p->exps.push_back(IRExp(NULL,exp,rvar)); + DValue* e = exp->toElem(p); p->exps.pop_back(); - if (expty == Tstruct) { - if (!e->inplace) - DtoStructCopy(f->llvmRetArg,e->getValue()); - } - else if (expty == Tdelegate) { - if (!e->inplace) - DtoDelegateCopy(f->llvmRetArg,e->getValue()); - } - else if (expty == Tarray) { - if (e->type == elem::SLICE) { - assert(e->mem); - DtoSetArray(f->llvmRetArg,e->arg,e->mem); - } - else if (!e->inplace) { - if (e->type == elem::NUL) { - DtoNullArray(f->llvmRetArg); - } - else { - DtoArrayAssign(f->llvmRetArg, e->getValue()); - } - } - } - else - assert(0); + if (!e->inPlace()) + DtoAssign(rvar, e); IRFunction::FinallyVec& fin = p->func().finallys; if (fin.empty()) { @@ -103,12 +84,11 @@ void ReturnStatement::toIR(IRState* p) else { new llvm::BranchInst(fin.back().retbb, p->scopebb()); } - delete e; } else { if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); - elem* e = exp->toElem(p); - llvm::Value* v = e->getValue(); + DValue* e = exp->toElem(p); + llvm::Value* v = e->getRVal(); delete e; Logger::cout() << "return value is '" <<*v << "'\n"; @@ -174,8 +154,8 @@ void IfStatement::toIR(IRState* p) Logger::println("IfStatement::toIR(%d): %s", wsi++, toChars()); LOG_SCOPE; - elem* cond_e = condition->toElem(p); - llvm::Value* cond_val = cond_e->getValue(); + DValue* cond_e = condition->toElem(p); + llvm::Value* cond_val = cond_e->getRVal(); delete cond_e; llvm::BasicBlock* oldend = gIR->scopeend(); @@ -265,8 +245,8 @@ void WhileStatement::toIR(IRState* p) gIR->scope() = IRScope(whilebb,endbb); // create the condition - elem* cond_e = condition->toElem(p); - llvm::Value* cond_val = DtoBoolean(cond_e->getValue()); + DValue* cond_e = condition->toElem(p); + llvm::Value* cond_val = DtoBoolean(cond_e->getRVal()); delete cond_e; // conditional branch @@ -308,8 +288,8 @@ void DoStatement::toIR(IRState* p) body->toIR(p); // create the condition - elem* cond_e = condition->toElem(p); - llvm::Value* cond_val = DtoBoolean(cond_e->getValue()); + DValue* cond_e = condition->toElem(p); + llvm::Value* cond_val = DtoBoolean(cond_e->getRVal()); delete cond_e; // conditional branch @@ -347,8 +327,8 @@ void ForStatement::toIR(IRState* p) gIR->scope() = IRScope(forbb,forbodybb); // create the condition - elem* cond_e = condition->toElem(p); - llvm::Value* cond_val = DtoBoolean(cond_e->getValue()); + DValue* cond_e = condition->toElem(p); + llvm::Value* cond_val = DtoBoolean(cond_e->getRVal()); delete cond_e; // conditional branch @@ -366,7 +346,7 @@ void ForStatement::toIR(IRState* p) // increment if (increment) { - elem* inc = increment->toElem(p); + DValue* inc = increment->toElem(p); delete inc; } @@ -543,7 +523,7 @@ void ThrowStatement::toIR(IRState* p) /* assert(exp); - elem* e = exp->toElem(p); + DValue* e = exp->toElem(p); delete e; */ } @@ -565,9 +545,10 @@ void SwitchStatement::toIR(IRState* p) CaseStatement* cs = (CaseStatement*)cases->data[i]; // get the case value - elem* e = cs->exp->toElem(p); - assert(e->val && llvm::isa(e->val)); - llvm::ConstantInt* ec = llvm::cast(e->val); + DValue* e = cs->exp->toElem(p); + DConstValue* ce = e->isConst(); + assert(ce && llvm::isa(ce->c)); + llvm::ConstantInt* ec = llvm::cast(ce->c); delete e; // create the case bb with a nice label @@ -587,8 +568,8 @@ void SwitchStatement::toIR(IRState* p) llvm::BasicBlock* endbb = new llvm::BasicBlock("switchend", p->topfunc(), oldend); // condition var - elem* cond = condition->toElem(p); - llvm::SwitchInst* si = new llvm::SwitchInst(cond->getValue(), defbb ? defbb : endbb, cases->dim, p->scopebb()); + DValue* cond = condition->toElem(p); + llvm::SwitchInst* si = new llvm::SwitchInst(cond->getRVal(), defbb ? defbb : endbb, cases->dim, p->scopebb()); delete cond; // add the cases @@ -678,9 +659,12 @@ void ForeachStatement::toIR(IRState* p) Logger::println("aggr = %s", aggr->toChars()); Logger::println("func = %s", func->toChars()); - elem* arr = aggr->toElem(p); - llvm::Value* val = arr->getValue(); - Logger::cout() << "aggr2llvm = " << *val << '\n'; + DValue* arr = aggr->toElem(p); + llvm::Value* val = 0; + if (!arr->isSlice()) { + val = arr->getRVal(); + Logger::cout() << "aggr2llvm = " << *val << '\n'; + } llvm::Value* numiters = 0; @@ -689,7 +673,7 @@ void ForeachStatement::toIR(IRState* p) if (key) key->llvmValue = keyvar; const llvm::Type* valtype = DtoType(value->type); - llvm::Value* valvar = !value->isRef() ? new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint()) : NULL; + llvm::Value* valvar = !(value->isRef() || value->isOut()) ? new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint()) : NULL; Type* aggrtype = DtoDType(aggr->type); if (aggrtype->ty == Tsarray) @@ -702,9 +686,9 @@ void ForeachStatement::toIR(IRState* p) } else if (aggrtype->ty == Tarray) { - if (arr->type == elem::SLICE) { - numiters = arr->arg; - val = arr->mem; + if (DSliceValue* slice = arr->isSlice()) { + numiters = slice->len; + val = slice->ptr; } else { numiters = p->ir->CreateLoad(DtoGEPi(val,0,0,"tmp",p->scopebb())); @@ -760,12 +744,12 @@ void ForeachStatement::toIR(IRState* p) else if (aggrtype->ty == Tarray) value->llvmValue = new llvm::GetElementPtrInst(val,loadedKey,"tmp",p->scopebb()); - if (!value->isRef()) { - elem* e = new elem; - e->mem = value->llvmValue; - e->type = elem::VAR; - DtoAssign(DtoDType(value->type), valvar, e->getValue()); - delete e; + if (!value->isRef() && !value->isOut()) { + DValue* dst = new DVarValue(value->type, valvar, true); + DValue* src = new DVarValue(value->type, value->llvmValue, true); + DtoAssign(dst, src); + delete dst; + delete src; value->llvmValue = valvar; } @@ -798,9 +782,12 @@ void LabelStatement::toIR(IRState* p) else llvmBB = new llvm::BasicBlock("label", p->topfunc(), oldend); - new llvm::BranchInst(llvmBB, p->scopebb()); + if (!p->scopereturned()) + new llvm::BranchInst(llvmBB, p->scopebb()); + p->scope() = IRScope(llvmBB,oldend); - statement->toIR(p); + if (statement) + statement->toIR(p); } ////////////////////////////////////////////////////////////////////////////// @@ -817,6 +804,7 @@ void GotoStatement::toIR(IRState* p) if (label->statement->llvmBB == NULL) label->statement->llvmBB = new llvm::BasicBlock("label", p->topfunc()); + assert(!p->scopereturned()); new llvm::BranchInst(label->statement->llvmBB, p->scopebb()); p->scope() = IRScope(bb,oldend); } @@ -831,8 +819,8 @@ void WithStatement::toIR(IRState* p) assert(exp); assert(body); - elem* e = exp->toElem(p); - wthis->llvmValue = e->getValue(); + DValue* e = exp->toElem(p); + wthis->llvmValue = e->getRVal(); delete e; body->toIR(p); diff --git a/gen/tocsym.c b/gen/tocsym.cpp similarity index 100% rename from gen/tocsym.c rename to gen/tocsym.cpp diff --git a/gen/todebug.c b/gen/todebug.cpp similarity index 100% rename from gen/todebug.c rename to gen/todebug.cpp diff --git a/gen/todt.c b/gen/todt.cpp similarity index 100% rename from gen/todt.c rename to gen/todt.cpp diff --git a/gen/toir.c b/gen/toir.cpp similarity index 73% rename from gen/toir.c rename to gen/toir.cpp index 94169a21..5ebd8137 100644 --- a/gen/toir.c +++ b/gen/toir.cpp @@ -28,13 +28,14 @@ #include "gen/runtime.h" #include "gen/arrays.h" +#include "gen/dvalue.h" + ////////////////////////////////////////////////////////////////////////////////////////// -elem* DeclarationExp::toElem(IRState* p) +DValue* DeclarationExp::toElem(IRState* p) { Logger::print("DeclarationExp::toElem: %s | T=%s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; // variable declaration if (VarDeclaration* vd = declaration->isVarDeclaration()) @@ -64,9 +65,11 @@ elem* DeclarationExp::toElem(IRState* p) //allocainst->setAlignment(vd->type->alignsize()); // TODO vd->llvmValue = allocainst; } - elem* ie = DtoInitializer(vd->init); + DValue* ie = DtoInitializer(vd->init); delete ie; } + + return new DVarValue(vd, vd->llvmValue, true); } // struct declaration else if (StructDeclaration* s = declaration->isStructDeclaration()) @@ -97,18 +100,16 @@ elem* DeclarationExp::toElem(IRState* p) error("Only Var/Struct-Declaration is supported for DeclarationExp"); assert(0); } - return e; + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* VarExp::toElem(IRState* p) +DValue* VarExp::toElem(IRState* p) { Logger::print("VarExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - assert(var); if (VarDeclaration* vd = var->isVarDeclaration()) { @@ -118,28 +119,27 @@ elem* VarExp::toElem(IRState* p) if (vd->ident == Id::_arguments) { Logger::println("Id::_arguments"); - vd->llvmValue = p->func().decl->llvmArguments; + if (!vd->llvmValue) + vd->llvmValue = p->func().decl->llvmArguments; assert(vd->llvmValue); - e->mem = vd->llvmValue; - e->type = elem::VAR; + return new DVarValue(vd, vd->llvmValue, true); } // _argptr else if (vd->ident == Id::_argptr) { Logger::println("Id::_argptr"); - vd->llvmValue = p->func().decl->llvmArgPtr; + if (!vd->llvmValue) + vd->llvmValue = p->func().decl->llvmArgPtr; assert(vd->llvmValue); - e->mem = vd->llvmValue; - e->type = elem::VAR; + return new DVarValue(vd, vd->llvmValue, true); } // _dollar else if (vd->ident == Id::dollar) { Logger::println("Id::dollar"); assert(!p->arrays.empty()); - llvm::Value* tmp = DtoGEPi(p->arrays.back(),0,0,"tmp",p->scopebb()); - e->val = new llvm::LoadInst(tmp,"tmp",p->scopebb()); - e->type = elem::VAL; + llvm::Value* tmp = DtoArrayLen(p->arrays.back()); + return new DVarValue(vd, tmp, false); } // typeinfo else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration()) @@ -148,18 +148,17 @@ elem* VarExp::toElem(IRState* p) tid->toObjFile(); assert(tid->llvmValue); const llvm::Type* vartype = DtoType(type); + llvm::Value* m; if (tid->llvmValue->getType() != llvm::PointerType::get(vartype)) - e->mem = p->ir->CreateBitCast(tid->llvmValue, vartype, "tmp"); + m = p->ir->CreateBitCast(tid->llvmValue, vartype, "tmp"); else - e->mem = tid->llvmValue; - e->type = elem::VAR; + m = tid->llvmValue; + return new DVarValue(vd, m, true); } // nested variable else if (vd->nestedref) { Logger::println("nested variable"); - e->mem = DtoNestedVariable(vd); - e->type = elem::VAR; - e->vardecl = vd; + return new DVarValue(vd, DtoNestedVariable(vd), true); } // function parameter else if (vd->isParameter()) { @@ -170,14 +169,10 @@ elem* VarExp::toElem(IRState* p) vd->llvmValue = &p->func().func->getArgumentList().back(); } if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa(vd->llvmValue)) { - e->mem = vd->llvmValue; - e->type = elem::VAR; - e->vardecl = vd; + return new DVarValue(vd, vd->llvmValue, true); } else if (llvm::isa(vd->llvmValue)) { - e->val = vd->llvmValue; - e->type = elem::VAL; - e->vardecl = vd; + return new DImValue(type, vd->llvmValue); } else assert(0); } @@ -186,21 +181,15 @@ elem* VarExp::toElem(IRState* p) if (!vd->llvmTouched && vd->isDataseg()) vd->toObjFile(); assert(vd->llvmValue); - e->mem = vd->llvmValue; - e->vardecl = vd; - e->type = elem::VAR; + return new DVarValue(vd, vd->llvmValue, true); } - - assert(e->mem || e->val); } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) { Logger::println("FuncDeclaration"); - if (fdecl->llvmInternal != LLVMva_arg && fdecl->llvmValue == 0) + if (fdecl->llvmInternal != LLVMva_arg)// && fdecl->llvmValue == 0) fdecl->toObjFile(); - e->val = fdecl->llvmValue; - e->type = elem::FUNC; - e->funcdecl = fdecl; + return new DFuncValue(fdecl, fdecl->llvmValue); } else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration()) { @@ -209,16 +198,15 @@ elem* VarExp::toElem(IRState* p) Logger::print("Sym: type=%s\n", sdecltype->toChars()); assert(sdecltype->ty == Tstruct); TypeStruct* ts = (TypeStruct*)sdecltype; - e->mem = ts->llvmInit; - assert(e->mem); - e->type = elem::VAR; + assert(ts->llvmInit); + return new DVarValue(type, ts->llvmInit, true); } else { assert(0 && "Unimplemented VarExp type"); } - return e; + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -243,14 +231,12 @@ llvm::Constant* VarExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* IntegerExp::toElem(IRState* p) +DValue* IntegerExp::toElem(IRState* p) { Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - e->val = toConstElem(p); - e->type = elem::CONST; - return e; + llvm::Constant* c = toConstElem(p); + return new DConstValue(type, c); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -273,14 +259,12 @@ llvm::Constant* IntegerExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* RealExp::toElem(IRState* p) +DValue* RealExp::toElem(IRState* p) { Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - e->val = toConstElem(p); - e->type = elem::CONST; - return e; + llvm::Constant* c = toConstElem(p); + return new DConstValue(type, c); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -301,15 +285,12 @@ llvm::Constant* RealExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* NullExp::toElem(IRState* p) +DValue* NullExp::toElem(IRState* p) { Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars()); LOG_SCOPE; - elem* e = new elem; - e->val = toConstElem(p); - e->type = elem::NUL; - //Logger::cout() << "null value is now " << *e->val << '\n'; - return e; + llvm::Constant* c = toConstElem(p); + return new DNullValue(type, c); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -332,24 +313,44 @@ llvm::Constant* NullExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* StringExp::toElem(IRState* p) +DValue* StringExp::toElem(IRState* p) { Logger::print("StringExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; Type* dtype = DtoDType(type); - - assert(dtype->next->ty == Tchar && "Only char is supported"); - assert(sz == 1); + Type* cty = DtoDType(dtype->next); const llvm::Type* ct = DtoType(dtype->next); //printf("ct = %s\n", type->next->toChars()); const llvm::ArrayType* at = llvm::ArrayType::get(ct,len+1); - uint8_t* str = (uint8_t*)string; - std::string cont((char*)str, len); - - llvm::Constant* _init = llvm::ConstantArray::get(cont,true); + llvm::Constant* _init; + if (cty->ty == Tchar) { + uint8_t* str = (uint8_t*)string; + std::string cont((char*)str, len); + _init = llvm::ConstantArray::get(cont,true); + } + else if (cty->ty == Twchar) { + uint16_t* str = (uint16_t*)string; + std::vector vals; + for(size_t i=0; ity == Tdchar) { + uint32_t* str = (uint32_t*)string; + std::vector vals; + for(size_t i=0; imodule); @@ -358,39 +359,32 @@ elem* StringExp::toElem(IRState* p) llvm::Constant* idxs[2] = { zero, zero }; llvm::Constant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); - elem* e = new elem; - if (dtype->ty == Tarray) { llvm::Constant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false); if (!p->topexp() || p->topexp()->e2 != this) { llvm::Value* tmpmem = new llvm::AllocaInst(DtoType(dtype),"tempstring",p->topallocapoint()); DtoSetArray(tmpmem, clen, arrptr); - e->mem = tmpmem; - e->temp = true; + return new DVarValue(type, tmpmem, true); } else if (p->topexp()->e2 == this) { - llvm::Value* arr = p->topexp()->v; + DValue* arr = p->topexp()->v; assert(arr); - DtoSetArray(arr, clen, arrptr); - e->inplace = true; + DtoSetArray(arr->getLVal(), clen, arrptr); + return new DImValue(type, arr->getLVal(), true); } - else assert(0); } else if (dtype->ty == Tsarray) { const llvm::Type* dstType = llvm::PointerType::get(llvm::ArrayType::get(ct, len)); - e->mem = new llvm::BitCastInst(gvar, dstType, "tmp", gIR->scopebb()); + llvm::Value* emem = (gvar->getType() == dstType) ? gvar : DtoBitCast(gvar, dstType); + return new DVarValue(type, emem, true); } else if (dtype->ty == Tpointer) { - e->mem = arrptr; - } - else { - assert(0); + return new DImValue(type, arrptr); } - e->type = elem::VAL; - - return e; + assert(0); + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -432,20 +426,27 @@ llvm::Constant* StringExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* AssignExp::toElem(IRState* p) +DValue* AssignExp::toElem(IRState* p) { Logger::print("AssignExp::toElem: %s | %s = %s\n", toChars(), e1->type->toChars(), e2->type ? e2->type->toChars() : 0); LOG_SCOPE; p->exps.push_back(IRExp(e1,e2,NULL)); - elem* l = e1->toElem(p); - p->topexp()->v = l->mem; - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + p->topexp()->v = l; + DValue* r = e2->toElem(p); p->exps.pop_back(); - if (l->type == elem::ARRAYLEN) + if (l->isArrayLen()) + DtoResizeDynArray(l->getLVal(), r->getRVal()); + else + DtoAssign(l, r); + return l; + + /* + if (l->type == DValue::ARRAYLEN) { DtoResizeDynArray(l->mem, r->getValue()); delete r; @@ -458,8 +459,8 @@ elem* AssignExp::toElem(IRState* p) TY e1ty = e1type->ty; TY e2ty = e2type->ty; - elem* e = new elem; - e->type = elem::VAR; + DValue* e = new DValue(this); + e->type = DValue::VAR; // struct if (e1ty == Tstruct) { @@ -489,20 +490,25 @@ elem* AssignExp::toElem(IRState* p) } else if (e1ty == Tarray) { if (e2type->isscalar() || e2type->ty == Tclass){ - DtoArrayInit(l->mem, r->getValue()); + if (l->type == DValue::SLICE) { + DtoArrayInit(l->mem, l->arg, r->getValue()); + } + else { + DtoArrayInit(l->mem, r->getValue()); + } } else if (e2ty == Tarray) { //new llvm::StoreInst(r->val,l->val,p->scopebb()); - if (r->type == elem::NUL) { + if (r->type == DValue::NUL) { llvm::Constant* c = llvm::cast(r->val); assert(c->isNullValue()); DtoNullArray(l->mem); e->mem = l->mem; } - else if (r->type == elem::SLICE) { - if (l->type == elem::SLICE) { + else if (r->type == DValue::SLICE) { + if (l->type == DValue::SLICE) { DtoArrayCopy(l,r); - e->type = elem::SLICE; + e->type = DValue::SLICE; e->mem = l->mem; e->arg = l->arg; } @@ -562,7 +568,7 @@ elem* AssignExp::toElem(IRState* p) else if (e1ty == Tdelegate) { Logger::println("Assigning to delegate"); if (e2ty == Tdelegate) { - if (r->type == elem::NUL) { + if (r->type == DValue::NUL) { llvm::Constant* c = llvm::cast(r->val); if (c->isNullValue()) { DtoNullDelegate(l->mem); @@ -595,17 +601,18 @@ elem* AssignExp::toElem(IRState* p) delete l; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* AddExp::toElem(IRState* p) +DValue* AddExp::toElem(IRState* p) { Logger::print("AddExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); Type* t = DtoDType(type); Type* e1type = DtoDType(e1->type); @@ -613,46 +620,54 @@ elem* AddExp::toElem(IRState* p) if (e1type != e2type) { if (e1type->ty == Tpointer && e1type->next->ty == Tstruct) { - //assert(l->field); - assert(r->type == elem::CONST); - llvm::ConstantInt* cofs = llvm::cast(r->val); + assert(r->isConst()); + llvm::ConstantInt* cofs = llvm::cast(r->isConst()->c); TypeStruct* ts = (TypeStruct*)e1type->next; std::vector offsets; - e->mem = DtoIndexStruct(l->getValue(), ts->sym, t->next, cofs->getZExtValue(), offsets); - e->type = elem::VAR; - e->field = true; + llvm::Value* v = DtoIndexStruct(l->getRVal(), ts->sym, t->next, cofs->getZExtValue(), offsets); + return new DFieldValue(type, v, true); } else if (e1->type->ty == Tpointer) { - e->val = new llvm::GetElementPtrInst(l->getValue(), r->getValue(), "tmp", p->scopebb()); - e->type = elem::VAR; - } - else { - assert(0); + llvm::Value* v = new llvm::GetElementPtrInst(l->getRVal(), r->getRVal(), "tmp", p->scopebb()); + return new DImValue(type, v); } + assert(0); } else { - e->val = llvm::BinaryOperator::createAdd(l->getValue(), r->getValue(), "tmp", p->scopebb()); - e->type = elem::VAL; + return DtoBinAdd(l,r); } - delete l; - delete r; - return e; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* AddAssignExp::toElem(IRState* p) +DValue* AddAssignExp::toElem(IRState* p) { Logger::print("AddAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + p->exps.push_back(IRExp(e1,e2,NULL)); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + p->exps.pop_back(); + + DValue* res; + if (DtoDType(e1->type)->ty == Tpointer) { + llvm::Value* gep = new llvm::GetElementPtrInst(l->getRVal(),r->getRVal(),"tmp",p->scopebb()); + res = new DImValue(type, gep); + } + else { + res = DtoBinAdd(l,r); + } + DtoAssign(l, res); + + return l; + + /* Type* e1type = DtoDType(e1->type); - elem* e = new elem; + DValue* e = new DValue(this); llvm::Value* val = 0; if (e1type->ty == Tpointer) { val = e->mem = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb()); @@ -661,31 +676,39 @@ elem* AddAssignExp::toElem(IRState* p) val = e->val = llvm::BinaryOperator::createAdd(l->getValue(),r->getValue(),"tmp",p->scopebb()); } - /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; - if (llvm::isa(storeVal->getType()) && storeVal->getType()->getContainedType(0) != tmp->getType()) - { - tmp = DtoPointedType(storeVal, tmp); - }*/ - assert(l->mem); new llvm::StoreInst(val,l->mem,p->scopebb()); - e->type = elem::VAR; + e->type = DValue::VAR; delete l; delete r; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* MinExp::toElem(IRState* p) +DValue* MinExp::toElem(IRState* p) { Logger::print("MinExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + if (DtoDType(e1->type)->ty == Tpointer) { + llvm::Value* left = p->ir->CreatePtrToInt(l->getRVal(), DtoSize_t(), "tmp"); + llvm::Value* right = p->ir->CreatePtrToInt(r->getRVal(), DtoSize_t(), "tmp"); + llvm::Value* diff = p->ir->CreateSub(left,right,"tmp"); + if (diff->getType() != DtoType(type)) + diff = p->ir->CreateIntToPtr(diff, DtoType(type)); + return new DImValue(type, diff); + } + else { + return DtoBinSub(l,r); + } + + /* llvm::Value* left = l->getValue(); if (llvm::isa(left->getType())) left = new llvm::PtrToIntInst(left,DtoSize_t(),"tmp",p->scopebb()); @@ -695,7 +718,7 @@ elem* MinExp::toElem(IRState* p) right = new llvm::PtrToIntInst(right,DtoSize_t(),"tmp",p->scopebb()); e->val = llvm::BinaryOperator::createSub(left,right,"tmp",p->scopebb()); - e->type = elem::VAL; + e->type = DValue::VAL; const llvm::Type* totype = DtoType(type); if (e->val->getType() != totype) { @@ -708,17 +731,35 @@ elem* MinExp::toElem(IRState* p) delete l; delete r; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* MinAssignExp::toElem(IRState* p) +DValue* MinAssignExp::toElem(IRState* p) { - Logger::print("MinAssignExp::toElem: %s\n", toChars()); + Logger::print("MinAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + DValue* res; + if (DtoDType(e1->type)->ty == Tpointer) { + llvm::Value* tmp = r->getRVal(); + llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false); + tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb()); + tmp = new llvm::GetElementPtrInst(l->getRVal(),tmp,"tmp",p->scopebb()); + res = new DImValue(type, tmp); + } + else { + res = DtoBinSub(l,r); + } + DtoAssign(l, res); + + return l; + + /* Type* e1type = DtoDType(e1->type); @@ -733,84 +774,96 @@ elem* MinAssignExp::toElem(IRState* p) tmp = llvm::BinaryOperator::createSub(l->getValue(),r->getValue(),"tmp",p->scopebb()); } - /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; - if (storeVal->getType()->getContainedType(0) != tmp->getType()) - { - tmp = DtoPointedType(storeVal, tmp); - }*/ - assert(l->mem); new llvm::StoreInst(tmp, l->mem, p->scopebb()); delete l; delete r; - elem* e = new elem; + DValue* e = new DValue(this); e->val = tmp; - e->type = elem::VAR; + e->type = DValue::VAR; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* MulExp::toElem(IRState* p) +DValue* MulExp::toElem(IRState* p) { Logger::print("MulExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); - llvm::Value* vl = l->getValue(); - llvm::Value* vr = r->getValue(); - Logger::cout() << "mul: " << *vl << ", " << *vr << '\n'; - e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb()); - e->type = elem::VAL; + + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + return DtoBinMul(l,r); + /* + if (l->dvalue && r->dvalue) { + Logger::println("DVALUE PATH"); + e->dvalue = DtoBinMul(l->dvalue, r->dvalue); + e->val = e->dvalue->getRVal(); + } + else { + llvm::Value* vl = l->getValue(); + llvm::Value* vr = r->getValue(); + Logger::cout() << "mul: " << *vl << ", " << *vr << '\n'; + e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb()); + e->dvalue = new DImValue(type, e->val); + } + e->type = DValue::VAL; delete l; delete r; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* MulAssignExp::toElem(IRState* p) +DValue* MulAssignExp::toElem(IRState* p) { Logger::print("MulAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + DValue* res = DtoBinMul(l,r); + DtoAssign(l, res); + + return l; + + /* llvm::Value* vl = l->getValue(); llvm::Value* vr = r->getValue(); Logger::cout() << "mulassign: " << *vl << ", " << *vr << '\n'; llvm::Value* tmp = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb()); - /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; - if (storeVal->getType()->getContainedType(0) != tmp->getType()) - { - tmp = DtoPointedType(storeVal, tmp); - }*/ - assert(l->mem); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; - elem* e = new elem; + DValue* e = new DValue(this); e->val = tmp; - e->type = elem::VAR; + e->type = DValue::VAR; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* DivExp::toElem(IRState* p) +DValue* DivExp::toElem(IRState* p) { Logger::print("DivExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + return DtoBinDiv(l, r); + /* Type* t = DtoDType(type); @@ -822,21 +875,29 @@ elem* DivExp::toElem(IRState* p) e->val = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); - e->type = elem::VAL; + e->type = DValue::VAL; delete l; delete r; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* DivAssignExp::toElem(IRState* p) +DValue* DivAssignExp::toElem(IRState* p) { Logger::print("DivAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + DValue* res = DtoBinDiv(l,r); + DtoAssign(l, res); + + return l; + + /* Type* t = DtoDType(type); @@ -850,34 +911,31 @@ elem* DivAssignExp::toElem(IRState* p) else assert(0); - /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; - if (storeVal->getType()->getContainedType(0) != tmp->getType()) - { - tmp = DtoPointedType(storeVal, tmp); - }*/ - assert(l->mem); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; - elem* e = new elem; + DValue* e = new DValue(this); e->val = tmp; - e->type = elem::VAR; + e->type = DValue::VAR; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* ModExp::toElem(IRState* p) +DValue* ModExp::toElem(IRState* p) { Logger::print("ModExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + return DtoBinRem(l, r); + /* Type* t = DtoDType(type); if (t->isunsigned()) @@ -888,21 +946,29 @@ elem* ModExp::toElem(IRState* p) e->val = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb()); else assert(0); - e->type = elem::VAL; + e->type = DValue::VAL; delete l; delete r; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* ModAssignExp::toElem(IRState* p) +DValue* ModAssignExp::toElem(IRState* p) { Logger::print("ModAssignExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); + + DValue* res = DtoBinRem(l, r); + DtoAssign(l, res); + + return l; + + /* Type* t = DtoDType(type); @@ -916,33 +982,27 @@ elem* ModAssignExp::toElem(IRState* p) else assert(0); - /*llvm::Value* storeVal = l->storeVal ? l->storeVal : l->val; - if (storeVal->getType()->getContainedType(0) != tmp->getType()) - { - tmp = DtoPointedType(storeVal, tmp); - }*/ - assert(l->mem); new llvm::StoreInst(tmp,l->mem,p->scopebb()); delete l; delete r; - elem* e = new elem; + DValue* e = new DValue(this); e->val = tmp; - e->type = elem::VAR; + e->type = DValue::VAR; return e; + */ } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CallExp::toElem(IRState* p) +DValue* CallExp::toElem(IRState* p) { Logger::print("CallExp::toElem: %s\n", toChars()); LOG_SCOPE; - elem* e = new elem; - elem* fn = e1->toElem(p); + DValue* fn = e1->toElem(p); TypeFunction* tf = 0; Type* e1type = DtoDType(e1->type); @@ -984,41 +1044,39 @@ elem* CallExp::toElem(IRState* p) // va args bool va_magic = false; bool va_intrinsic = false; - if (fn->funcdecl) { - if (fn->funcdecl->llvmInternal == LLVMva_intrinsic) { + DFuncValue* dfv = fn->isFunc(); + if (dfv && dfv->func) { + FuncDeclaration* fndecl = dfv->func; + if (fndecl->llvmInternal == LLVMva_intrinsic) { va_magic = true; va_intrinsic = true; } - else if (fn->funcdecl->llvmInternal == LLVMva_start) { + else if (fndecl->llvmInternal == LLVMva_start) { va_magic = true; } - else if (fn->funcdecl->llvmInternal == LLVMva_arg) { + else if (fndecl->llvmInternal == LLVMva_arg) { //Argument* fnarg = Argument::getNth(tf->parameters, 0); Expression* exp = (Expression*)arguments->data[0]; - elem* expelem = exp->toElem(p); - assert(expelem->mem); - elem* e = new elem; + DValue* expelem = exp->toElem(p); Type* t = DtoDType(type); const llvm::Type* llt = DtoType(type); if (DtoIsPassedByRef(t)) llt = llvm::PointerType::get(llt); - e->type = elem::VAL; - e->val = p->ir->CreateVAArg(expelem->mem,llt,"tmp"); - delete expelem; - return e; + return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp")); } } // args size_t n = arguments->dim; - if (fn->funcdecl && fn->funcdecl->llvmInternal == LLVMva_start) + DFuncValue* dfn = fn->isFunc(); + if (dfn && dfn->func && dfn->func->llvmInternal == LLVMva_start) n = 1; - if (fn->arg || delegateCall) n++; + if (delegateCall || (dfn && dfn->vthis)) n++; if (retinptr) n++; if (tf->linkage == LINKd && tf->varargs == 1) n+=2; - if (fn->funcdecl && fn->funcdecl->isNested()) n++; + if (dfn && dfn->func && dfn->func->isNested()) n++; - llvm::Value* funcval = fn->getValue(); + llvm::Value* funcval = fn->getRVal(); assert(funcval != 0); std::vector llargs(n, 0); @@ -1064,14 +1122,17 @@ elem* CallExp::toElem(IRState* p) IRExp* topexp = p->topexp(); + bool isInPlace = false; + // hidden struct return arguments if (retinptr) { if (topexp && topexp->e2 == this) { assert(topexp->v); - assert(llvm::isa(topexp->v->getType()->getContainedType(0))); - llargs[j] = topexp->v; + llvm::Value* tlv = topexp->v->getLVal(); + assert(llvm::isa(tlv->getType()->getContainedType(0))); + llargs[j] = tlv; if (DtoIsPassedByRef(tf->next)) { - e->inplace = true; + isInPlace = true; } else assert(0); @@ -1081,21 +1142,17 @@ elem* CallExp::toElem(IRState* p) } ++j; ++argiter; - e->type = elem::VAR; - } - else { - e->type = elem::VAL; } // this arguments - if (fn->arg) { + if (dfn && dfn->vthis) { Logger::println("This Call"); - if (fn->arg->getType() != argiter->get()) { + if (dfn->vthis->getType() != argiter->get()) { //Logger::cout() << *fn->thisparam << '|' << *argiter->get() << '\n'; - llargs[j] = new llvm::BitCastInst(fn->arg, argiter->get(), "tmp", p->scopebb()); + llargs[j] = new llvm::BitCastInst(dfn->vthis, argiter->get(), "tmp", p->scopebb()); } else { - llargs[j] = fn->arg; + llargs[j] = dfn->vthis; } ++j; ++argiter; @@ -1103,13 +1160,13 @@ elem* CallExp::toElem(IRState* p) // delegate context arguments else if (delegateCall) { Logger::println("Delegate Call"); - llvm::Value* contextptr = DtoGEP(fn->mem,zero,zero,"tmp",p->scopebb()); + llvm::Value* contextptr = DtoGEP(fn->getRVal(),zero,zero,"tmp",p->scopebb()); llargs[j] = new llvm::LoadInst(contextptr,"tmp",p->scopebb()); ++j; ++argiter; } // nested call - else if (fn->funcdecl && fn->funcdecl->isNested()) { + else if (dfn && dfn->func && dfn->func->isNested()) { Logger::println("Nested Call"); llvm::Value* contextptr = p->func().decl->llvmNested; assert(contextptr); @@ -1125,10 +1182,8 @@ elem* CallExp::toElem(IRState* p) { Argument* fnarg = Argument::getNth(tf->parameters, i); Expression* exp = (Expression*)arguments->data[i]; - elem* expelem = exp->toElem(p); - assert(expelem->mem); - llargs[j] = p->ir->CreateBitCast(expelem->mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp"); - delete expelem; + DValue* expelem = exp->toElem(p); + llargs[j] = p->ir->CreateBitCast(expelem->getLVal(), llvm::PointerType::get(llvm::Type::Int8Ty), "tmp"); } } // regular arguments @@ -1185,9 +1240,15 @@ elem* CallExp::toElem(IRState* p) for (int i=0; idim; i++,j++) { Argument* fnarg = Argument::getNth(tf->parameters, i); llargs[j] = DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]); + // this hack is necessary :/ + if (dfn && dfn->func && dfn->func->llvmRunTimeHack) { + if (llargs[j]->getType() != llfnty->getParamType(j)) + llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j)); + } } Logger::println("%d params passed", n); for (int i=0; iscopebb()); - if (retinptr) - e->mem = llargs[0]; - else - e->val = call; + llvm::Value* retllval = (retinptr) ? llargs[0] : call; // set calling convention - if (fn->funcdecl) { - int li = fn->funcdecl->llvmInternal; + if (dfn && dfn->func) { + int li = dfn->func->llvmInternal; if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) { call->setCallingConv(DtoCallingConv(dlink)); } @@ -1217,22 +1275,22 @@ elem* CallExp::toElem(IRState* p) else if (delegateCall) { call->setCallingConv(DtoCallingConv(dlink)); } - else if (fn->callconv != (unsigned)-1) { - call->setCallingConv(fn->callconv); + else if (dfn && dfn->cc != (unsigned)-1) { + call->setCallingConv(dfn->cc); } - delete fn; - return e; + return new DImValue(type, retllval, isInPlace); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CastExp::toElem(IRState* p) +DValue* CastExp::toElem(IRState* p) { Logger::print("CastExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* u = e1->toElem(p); + + DValue* u = e1->toElem(p); + const llvm::Type* tolltype = DtoType(to); Type* fromtype = DtoDType(e1->type); Type* totype = DtoDType(to); @@ -1240,52 +1298,52 @@ elem* CastExp::toElem(IRState* p) int rsz = totype->size(); // this makes sure the strange lvalue casts don't screw things up - e->mem = u->mem; + llvm::Value* rval = 0; + llvm::Value* rval2 = 0; + bool isslice = false; if (fromtype->isintegral()) { if (totype->isintegral()) { if (lsz < rsz) { - Logger::cout() << *tolltype << '\n'; + Logger::cout() << "cast to: " << *tolltype << '\n'; if (fromtype->isunsigned() || fromtype->ty == Tbool) { - e->val = new llvm::ZExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::ZExtInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else { - e->val = new llvm::SExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::SExtInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } } else if (lsz > rsz) { - e->val = new llvm::TruncInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::TruncInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else { - e->val = new llvm::BitCastInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::BitCastInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } } else if (totype->isfloating()) { if (fromtype->isunsigned()) { - e->val = new llvm::UIToFPInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::UIToFPInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else { - e->val = new llvm::SIToFPInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::SIToFPInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } } else if (totype->ty == Tpointer) { - e->val = p->ir->CreateIntToPtr(u->getValue(), tolltype, "tmp"); + rval = p->ir->CreateIntToPtr(u->getRVal(), tolltype, "tmp"); } else { assert(0); } - //e->storeVal = u->storeVal ? u->storeVal : u->val; - e->type = elem::VAL; } else if (fromtype->isfloating()) { if (totype->isfloating()) { if ((fromtype->ty == Tfloat80 || fromtype->ty == Tfloat64) && (totype->ty == Tfloat80 || totype->ty == Tfloat64)) { - e->val = u->getValue(); + rval = u->getRVal(); } else if (lsz < rsz) { - e->val = new llvm::FPExtInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::FPExtInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else if (lsz > rsz) { - e->val = new llvm::FPTruncInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::FPTruncInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else { assert(0); @@ -1293,21 +1351,19 @@ elem* CastExp::toElem(IRState* p) } else if (totype->isintegral()) { if (totype->isunsigned()) { - e->val = new llvm::FPToUIInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::FPToUIInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else { - e->val = new llvm::FPToSIInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::FPToSIInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } } else { assert(0); } - e->type = elem::VAL; } else if (fromtype->ty == Tclass) { //assert(to->ty == Tclass); - e->val = new llvm::BitCastInst(u->getValue(), tolltype, "tmp", p->scopebb()); - e->type = elem::VAL; + rval = new llvm::BitCastInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else if (fromtype->ty == Tarray || fromtype->ty == Tsarray) { Logger::cout() << "from array or sarray" << '\n'; @@ -1316,11 +1372,10 @@ elem* CastExp::toElem(IRState* p) assert(fromtype->next == totype->next || totype->next->ty == Tvoid); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); - llvm::Value* ptr = DtoGEP(u->getValue(),zero,one,"tmp",p->scopebb()); - e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb()); + llvm::Value* ptr = DtoGEP(u->getRVal(),zero,one,"tmp",p->scopebb()); + rval = new llvm::LoadInst(ptr, "tmp", p->scopebb()); if (fromtype->next != totype->next) - e->val = p->ir->CreateBitCast(e->val, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp"); - e->type = elem::VAL; + rval = p->ir->CreateBitCast(rval, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp"); } else if (totype->ty == Tarray) { Logger::cout() << "to array" << '\n'; @@ -1333,37 +1388,37 @@ elem* CastExp::toElem(IRState* p) if (ety == llvm::Type::VoidTy) ety = llvm::Type::Int8Ty; - if (u->type == elem::SLICE) { - e->mem = new llvm::BitCastInst(u->mem, ptrty, "tmp", p->scopebb()); + if (DSliceValue* usl = u->isSlice()) { + rval = new llvm::BitCastInst(usl->ptr, ptrty, "tmp", p->scopebb()); if (fromtype->next->size() == totype->next->size()) - e->arg = u->arg; + rval2 = usl->len; else - e->arg = DtoArrayCastLength(u->arg, ety, ptrty->getContainedType(0)); + rval2 = DtoArrayCastLength(usl->len, ety, ptrty->getContainedType(0)); } else { - llvm::Value* uval = u->getValue(); + llvm::Value* uval = u->getRVal(); if (fromtype->ty == Tsarray) { Logger::cout() << "uvalTy = " << *uval->getType() << '\n'; assert(llvm::isa(uval->getType())); const llvm::ArrayType* arrty = llvm::cast(uval->getType()->getContainedType(0)); - e->arg = llvm::ConstantInt::get(DtoSize_t(), arrty->getNumElements(), false); - e->arg = DtoArrayCastLength(e->arg, ety, ptrty->getContainedType(0)); - e->mem = new llvm::BitCastInst(uval, ptrty, "tmp", p->scopebb()); + rval2 = llvm::ConstantInt::get(DtoSize_t(), arrty->getNumElements(), false); + rval2 = DtoArrayCastLength(rval2, ety, ptrty->getContainedType(0)); + rval = new llvm::BitCastInst(uval, ptrty, "tmp", p->scopebb()); } else { llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); - e->arg = DtoGEP(uval,zero,zero,"tmp",p->scopebb()); - e->arg = new llvm::LoadInst(e->arg, "tmp", p->scopebb()); - e->arg = DtoArrayCastLength(e->arg, ety, ptrty->getContainedType(0)); + rval2 = DtoGEP(uval,zero,zero,"tmp",p->scopebb()); + rval2 = new llvm::LoadInst(rval2, "tmp", p->scopebb()); + rval2 = DtoArrayCastLength(rval2, ety, ptrty->getContainedType(0)); - e->mem = DtoGEP(uval,zero,one,"tmp",p->scopebb()); - e->mem = new llvm::LoadInst(e->mem, "tmp", p->scopebb()); + rval = DtoGEP(uval,zero,one,"tmp",p->scopebb()); + rval = new llvm::LoadInst(rval, "tmp", p->scopebb()); //Logger::cout() << *e->mem->getType() << '|' << *ptrty << '\n'; - e->mem = new llvm::BitCastInst(e->mem, ptrty, "tmp", p->scopebb()); + rval = new llvm::BitCastInst(rval, ptrty, "tmp", p->scopebb()); } } - e->type = elem::SLICE; + isslice = true; } else if (totype->ty == Tsarray) { Logger::cout() << "to sarray" << '\n'; @@ -1375,40 +1430,56 @@ elem* CastExp::toElem(IRState* p) } else if (fromtype->ty == Tpointer) { if (totype->ty == Tpointer || totype->ty == Tclass) { - llvm::Value* src = u->getValue(); - Logger::cout() << *src << '|' << *tolltype << '\n'; - e->val = new llvm::BitCastInst(src, tolltype, "tmp", p->scopebb()); + llvm::Value* src = u->getRVal(); + Logger::cout() << "src: " << *src << "to type: " << *tolltype << '\n'; + rval = new llvm::BitCastInst(src, tolltype, "tmp", p->scopebb()); } else if (totype->isintegral()) { - e->val = new llvm::PtrToIntInst(u->getValue(), tolltype, "tmp", p->scopebb()); + rval = new llvm::PtrToIntInst(u->getRVal(), tolltype, "tmp", p->scopebb()); } else assert(0); - e->type = elem::VAL; } else { assert(0); } - delete u; - return e; + + if (isslice) { + return new DSliceValue(type, rval2, rval); + } + else if (u->isLValueCast() || u->isVar()) { + return new DLValueCast(type, u->getLVal(), rval); + } + else if (p->topexp() && p->topexp()->e1 == this) { + llvm::Value* lval = u->getLVal(); + Logger::cout() << "lval: " << *lval << "rval: " << *rval << '\n'; + return new DLValueCast(type, lval, rval); + } + else { + Logger::cout() << "im rval: " << *rval << '\n'; + return new DImValue(type, rval); + } } ////////////////////////////////////////////////////////////////////////////////////////// -elem* SymOffExp::toElem(IRState* p) +DValue* SymOffExp::toElem(IRState* p) { Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = 0; + if (VarDeclaration* vd = var->isVarDeclaration()) { Logger::println("VarDeclaration"); if (!vd->llvmTouched && vd->isDataseg()) vd->toObjFile(); + // TODO + /* if (vd->isTypedefDeclaration()) { e->istypeinfo = true; } + */ assert(vd->llvmValue); Type* t = DtoDType(type); @@ -1416,29 +1487,27 @@ elem* SymOffExp::toElem(IRState* p) Type* vdtype = DtoDType(vd->type); llvm::Value* llvalue = vd->nestedref ? DtoNestedVariable(vd) : vd->llvmValue; + llvm::Value* varmem = 0; if (vdtype->ty == Tstruct && !(t->ty == Tpointer && t->next == vdtype)) { Logger::println("struct"); TypeStruct* vdt = (TypeStruct*)vdtype; assert(vdt->sym); - e = new elem; + const llvm::Type* llt = DtoType(t); if (offset == 0) { - e->mem = p->ir->CreateBitCast(llvalue, llt, "tmp"); + varmem = p->ir->CreateBitCast(llvalue, llt, "tmp"); } else { std::vector dst; - e->mem = DtoIndexStruct(llvalue,vdt->sym, tnext, offset, dst); + varmem = DtoIndexStruct(llvalue,vdt->sym, tnext, offset, dst); } - e->type = elem::VAL; - e->field = true; } else if (vdtype->ty == Tsarray) { Logger::println("sarray"); - e = new elem; + assert(llvalue); - e->arg = llvalue; - e->type = elem::VAL; + //e->arg = llvalue; // TODO const llvm::Type* llt = DtoType(t); llvm::Value* off = 0; @@ -1446,78 +1515,74 @@ elem* SymOffExp::toElem(IRState* p) Logger::println("offset = %d\n", offset); } if (llvalue->getType() != llt) { - e->mem = p->ir->CreateBitCast(llvalue, llt, "tmp"); + varmem = p->ir->CreateBitCast(llvalue, llt, "tmp"); if (offset != 0) - e->mem = DtoGEPi(e->mem, offset, "tmp"); + varmem = DtoGEPi(varmem, offset, "tmp"); } else { assert(offset == 0); - e->mem = DtoGEPi(llvalue,0,0,"tmp"); + varmem = DtoGEPi(llvalue,0,0,"tmp"); } } else if (offset == 0) { Logger::println("normal symoff"); - e = new elem; - e->type = elem::VAL; + assert(llvalue); - e->mem = llvalue; + varmem = llvalue; const llvm::Type* llt = DtoType(t); if (llvalue->getType() != llt) { - e->mem = p->ir->CreateBitCast(e->mem, llt, "tmp"); + varmem = p->ir->CreateBitCast(varmem, llt, "tmp"); } } else { assert(0); } + return new DFieldValue(type, varmem, true); } else if (FuncDeclaration* fd = var->isFuncDeclaration()) { Logger::println("FuncDeclaration"); - e = new elem; + if (fd->llvmValue == 0) fd->toObjFile(); - e->val = fd->llvmValue; - e->type = elem::FUNC; + return new DFuncValue(fd, fd->llvmValue); } - assert(e != 0); - assert(e->type != elem::NONE); - return e; + + assert(0); + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* PtrExp::toElem(IRState* p) +DValue* PtrExp::toElem(IRState* p) { Logger::print("PtrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* a = e1->toElem(p); - if (a->mem) - Logger::cout() << "mem: " << *a->mem << '\n'; - if (a->val) - Logger::cout() << "val: " << *a->val << '\n'; + DValue* a = e1->toElem(p); - if (a->field) - e->mem = a->mem; - else - e->mem = a->getValue(); - e->type = elem::VAR; + if (p->topexp() && p->topexp()->e1 == this) { + Logger::println("lval PtrExp"); + //if (a->isField()) return a; + return new DVarValue(type, a->getRVal(), true); + } - delete a; - return e; + llvm::Value* lv = a->getRVal(); + llvm::Value* v = lv; + if (DtoCanLoad(v)) + v = DtoLoad(v); + return new DLValueCast(type, lv, v); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* DotVarExp::toElem(IRState* p) +DValue* DotVarExp::toElem(IRState* p) { Logger::print("DotVarExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); + DValue* l = e1->toElem(p); Type* t = DtoDType(type); Type* e1type = DtoDType(e1->type); @@ -1530,7 +1595,7 @@ elem* DotVarExp::toElem(IRState* p) assert(e1type->next->ty == Tstruct); TypeStruct* ts = (TypeStruct*)e1type->next; Logger::println("Struct member offset:%d", vd->offset); - llvm::Value* src = l->val ? l->val : l->mem; + llvm::Value* src = l->getRVal(); std::vector vdoffsets; arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets); } @@ -1539,15 +1604,15 @@ elem* DotVarExp::toElem(IRState* p) Logger::println("Class member offset: %d", vd->offset); std::vector vdoffsets(1,0); tc->sym->offsetToIndex(vd->type, vd->offset, vdoffsets); - llvm::Value* src = l->getValue(); + llvm::Value* src = l->getRVal(); Logger::cout() << "src: " << *src << '\n'; arrptr = DtoGEP(src,vdoffsets,"tmp",p->scopebb()); } else assert(0); - e->mem = arrptr; - Logger::cout() << "mem: " << *e->mem << '\n'; - e->type = elem::VAR; + + Logger::cout() << "mem: " << *arrptr << '\n'; + return new DVarValue(vd, arrptr, true); } else if (FuncDeclaration* fdecl = var->isFuncDeclaration()) { @@ -1557,7 +1622,8 @@ elem* DotVarExp::toElem(IRState* p) } llvm::Value* funcval = fdecl->llvmValue; - e->arg = l->getValue(); + llvm::Value* vthis = l->getRVal(); + unsigned cc = (unsigned)-1; // virtual call if (fdecl->isVirtual()) { @@ -1566,177 +1632,66 @@ elem* DotVarExp::toElem(IRState* p) llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* vtblidx = llvm::ConstantInt::get(llvm::Type::Int32Ty, (size_t)fdecl->vtblIndex, false); - funcval = DtoGEP(e->arg, zero, zero, "tmp", p->scopebb()); + funcval = DtoGEP(vthis, zero, zero, "tmp", p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); funcval = DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb()); funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb()); assert(funcval->getType() == fdecl->llvmValue->getType()); - e->callconv = DtoCallingConv(fdecl->linkage); + cc = DtoCallingConv(fdecl->linkage); } - e->val = funcval; - e->type = elem::FUNC; - e->funcdecl = fdecl; + return new DFuncValue(fdecl, funcval, vthis); } else { printf("unknown: %s\n", var->toChars()); - assert(0); } - delete l; - - return e; + assert(0); + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* ThisExp::toElem(IRState* p) +DValue* ThisExp::toElem(IRState* p) { Logger::print("ThisExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; if (VarDeclaration* vd = var->isVarDeclaration()) { llvm::Value* v = p->func().decl->llvmThisVar; if (llvm::isa(v)) v = new llvm::LoadInst(v, "tmp", p->scopebb()); - e->mem = v; - e->type = elem::VAL; - e->isthis = true; - } - else { - assert(0); + return new DThisValue(vd, v); } - return e; + assert(0); + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* AddrExp::toElem(IRState* p) +DValue* AddrExp::toElem(IRState* p) { Logger::print("AddrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = e1->toElem(p); - e->field = true; - return e; + DValue* v = e1->toElem(p); + if (v->isField()) + return v; + return new DFieldValue(type, v->getLVal(), false); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* StructLiteralExp::toElem(IRState* p) -{ - Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); - LOG_SCOPE; - elem* e = new elem; - - llvm::Value* sptr; - const llvm::Type* llt = DtoType(type); - - // temporary struct literal - if (!p->topexp() || p->topexp()->e2 != this) - { - sptr = new llvm::AllocaInst(llt,"tmpstructliteral",p->topallocapoint()); - e->mem = sptr; - e->type = elem::VAR; - } - // already has memory - else - { - assert(p->topexp()->e2 == this); - sptr = p->topexp()->v; - } - - // num elements in literal - unsigned n = elements->dim; - - // unions might have different types for each literal - if (sd->llvmHasUnions) { - // build the type of the literal - std::vector tys; - for (unsigned i=0; idata[i]; - if (!vx) continue; - tys.push_back(DtoType(vx->type)); - } - const llvm::StructType* t = llvm::StructType::get(tys); - if (t != llt) { - if (gTargetData->getTypeSize(t) != gTargetData->getTypeSize(llt)) { - Logger::cout() << "got size " << gTargetData->getTypeSize(t) << ", expected " << gTargetData->getTypeSize(llt) << '\n'; - assert(0 && "type size mismatch"); - } - sptr = p->ir->CreateBitCast(sptr, llvm::PointerType::get(t), "tmp"); - Logger::cout() << "sptr type is now: " << *t << '\n'; - } - } - - // build - unsigned j = 0; - for (unsigned i=0; idata[i]; - if (!vx) continue; - - Logger::cout() << "getting index " << j << " of " << *sptr << '\n'; - llvm::Value* arrptr = DtoGEPi(sptr,0,j,"tmp",p->scopebb()); - - p->exps.push_back(IRExp(NULL,vx,arrptr)); - elem* ve = vx->toElem(p); - p->exps.pop_back(); - - if (!ve->inplace) { - llvm::Value* val = ve->getValue(); - Logger::cout() << *val << " | " << *arrptr << '\n'; - - Type* vxtype = DtoDType(vx->type); - DtoAssign(vxtype, arrptr, val); - } - delete ve; - - j++; - } - - e->inplace = true; - - return e; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -llvm::Constant* StructLiteralExp::toConstElem(IRState* p) -{ - Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); - LOG_SCOPE; - - unsigned n = elements->dim; - std::vector vals(n, NULL); - - for (unsigned i=0; idata[i]; - vals[i] = vx->toConstElem(p); - } - - assert(DtoDType(type)->ty == Tstruct); - const llvm::Type* t = DtoType(type); - const llvm::StructType* st = llvm::cast(t); - return llvm::ConstantStruct::get(st,vals); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -elem* IndexExp::toElem(IRState* p) +DValue* IndexExp::toElem(IRState* p) { Logger::print("IndexExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - - elem* l = e1->toElem(p); + DValue* l = e1->toElem(p); Type* e1type = DtoDType(e1->type); - p->arrays.push_back(l->mem); // if $ is used it must be an array so this is fine. - elem* r = e2->toElem(p); + p->arrays.push_back(l); // if $ is used it must be an array so this is fine. + DValue* r = e2->toElem(p); p->arrays.pop_back(); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); @@ -1744,90 +1699,82 @@ elem* IndexExp::toElem(IRState* p) llvm::Value* arrptr = 0; if (e1type->ty == Tpointer) { - arrptr = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb()); + arrptr = new llvm::GetElementPtrInst(l->getRVal(),r->getRVal(),"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { - arrptr = DtoGEP(l->getValue(), zero, r->getValue(),"tmp",p->scopebb()); + arrptr = DtoGEP(l->getRVal(), zero, r->getRVal(),"tmp",p->scopebb()); } else if (e1type->ty == Tarray) { - arrptr = DtoGEP(l->mem,zero,one,"tmp",p->scopebb()); + arrptr = DtoGEP(l->getLVal(),zero,one,"tmp",p->scopebb()); arrptr = new llvm::LoadInst(arrptr,"tmp",p->scopebb()); - arrptr = new llvm::GetElementPtrInst(arrptr,r->getValue(),"tmp",p->scopebb()); + arrptr = new llvm::GetElementPtrInst(arrptr,r->getRVal(),"tmp",p->scopebb()); } assert(arrptr); - - e->mem = arrptr; - e->type = elem::VAR; - - delete l; - delete r; - - return e; + return new DVarValue(type, arrptr, true); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* SliceExp::toElem(IRState* p) +DValue* SliceExp::toElem(IRState* p) { Logger::print("SliceExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; Type* t = DtoDType(type); - assert(t->ty == Tarray); - - elem* v = e1->toElem(p); Type* e1type = DtoDType(e1->type); - elem* e = new elem; - assert(v->mem); - e->type = elem::SLICE; + DValue* v = e1->toElem(p); + llvm::Value* vmem = v->getLVal(); + assert(vmem); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); + llvm::Value* emem = 0; + llvm::Value* earg = 0; + // partial slice if (lwr) { assert(upr); - p->arrays.push_back(v->mem); - elem* lo = lwr->toElem(p); + p->arrays.push_back(v); + DValue* lo = lwr->toElem(p); bool lwr_is_zero = false; - if (lo->type == elem::CONST) + if (DConstValue* cv = lo->isConst()) { - assert(lo->val); - assert(llvm::isa(lo->val)); + assert(llvm::isa(cv->c)); if (e1type->ty == Tpointer) { - e->mem = v->getValue(); + emem = v->getRVal(); } else if (e1type->ty == Tarray) { - llvm::Value* tmp = DtoGEP(v->mem,zero,one,"tmp",p->scopebb()); - e->mem = new llvm::LoadInst(tmp,"tmp",p->scopebb()); + llvm::Value* tmp = DtoGEP(vmem,zero,one,"tmp",p->scopebb()); + emem = new llvm::LoadInst(tmp,"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { - e->mem = DtoGEP(v->mem,zero,zero,"tmp",p->scopebb()); + emem = DtoGEP(vmem,zero,zero,"tmp",p->scopebb()); } else - assert(e->mem); + assert(emem); - llvm::ConstantInt* c = llvm::cast(lo->val); + llvm::ConstantInt* c = llvm::cast(cv->c); if (!(lwr_is_zero = c->isZero())) { - e->mem = new llvm::GetElementPtrInst(e->mem,lo->val,"tmp",p->scopebb()); + emem = new llvm::GetElementPtrInst(emem,cv->c,"tmp",p->scopebb()); } } else { if (e1type->ty == Tarray) { - llvm::Value* tmp = DtoGEP(v->mem,zero,one,"tmp",p->scopebb()); + llvm::Value* tmp = DtoGEP(vmem,zero,one,"tmp",p->scopebb()); tmp = new llvm::LoadInst(tmp,"tmp",p->scopebb()); - e->mem = new llvm::GetElementPtrInst(tmp,lo->getValue(),"tmp",p->scopebb()); + emem = new llvm::GetElementPtrInst(tmp,lo->getRVal(),"tmp",p->scopebb()); } else if (e1type->ty == Tsarray) { - e->mem = DtoGEP(v->mem,zero,lo->getValue(),"tmp",p->scopebb()); + emem = DtoGEP(vmem,zero,lo->getRVal(),"tmp",p->scopebb()); } else if (e1type->ty == Tpointer) { - e->mem = new llvm::GetElementPtrInst(v->getValue(),lo->getValue(),"tmp",p->scopebb()); + emem = new llvm::GetElementPtrInst(v->getRVal(),lo->getRVal(),"tmp",p->scopebb()); } else { Logger::println("type = %s", e1type->toChars()); @@ -1835,77 +1782,61 @@ elem* SliceExp::toElem(IRState* p) } } - elem* up = upr->toElem(p); + DValue* up = upr->toElem(p); p->arrays.pop_back(); - if (up->type == elem::CONST) + if (DConstValue* cv = up->isConst()) { - assert(up->val); - assert(llvm::isa(up->val)); + assert(llvm::isa(cv->c)); if (lwr_is_zero) { - e->arg = up->val; + earg = cv->c; } else { - if (lo->type == elem::CONST) { - llvm::Constant* clo = llvm::cast(lo->val); - llvm::Constant* cup = llvm::cast(up->val); - e->arg = llvm::ConstantExpr::getSub(cup, clo); + if (lo->isConst()) { + llvm::Constant* clo = llvm::cast(lo->getRVal()); + llvm::Constant* cup = llvm::cast(cv->c); + earg = llvm::ConstantExpr::getSub(cup, clo); } else { - e->arg = llvm::BinaryOperator::createSub(up->val, lo->getValue(), "tmp", p->scopebb()); + earg = llvm::BinaryOperator::createSub(cv->c, lo->getRVal(), "tmp", p->scopebb()); } } } else { if (lwr_is_zero) { - e->arg = up->getValue(); + earg = up->getRVal(); } else { - e->arg = llvm::BinaryOperator::createSub(up->getValue(), lo->getValue(), "tmp", p->scopebb()); + earg = llvm::BinaryOperator::createSub(up->getRVal(), lo->getRVal(), "tmp", p->scopebb()); } } - - delete lo; - delete up; - - /* - llvm::Value* tmpmem = new llvm::AllocaInst(DtoType(t),"tmp",p->topallocapoint()); - llvm::Value* ptr = DtoGEPi(tmpmem,0,0,"tmp"); - p->ir->CreateStore(e->arg, ptr); - ptr = DtoGEPi(tmpmem,0,1,"tmp"); - p->ir->CreateStore(e->mem, ptr); - e->arg = NULL; - e->mem = tmpmem; - */ } // full slice else { - e->mem = v->mem; + emem = vmem; } - delete v; - - return e; + return new DSliceValue(type,earg,emem); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CmpExp::toElem(IRState* p) +DValue* CmpExp::toElem(IRState* p) { Logger::print("CmpExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); Type* t = DtoDType(e1->type); Type* e2t = DtoDType(e2->type); assert(t == e2t); + llvm::Value* eval = 0; + if (t->isintegral() || t->ty == Tpointer) { llvm::ICmpInst::Predicate cmpop; @@ -1936,11 +1867,11 @@ elem* CmpExp::toElem(IRState* p) break; case TOKleg: skip = true; - e->val = llvm::ConstantInt::getTrue(); + eval = llvm::ConstantInt::getTrue(); break; case TOKunord: skip = true; - e->val = llvm::ConstantInt::getFalse(); + eval = llvm::ConstantInt::getFalse(); break; default: @@ -1948,7 +1879,7 @@ elem* CmpExp::toElem(IRState* p) } if (!skip) { - e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); + eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb()); } } else if (t->isfloating()) @@ -1984,37 +1915,32 @@ elem* CmpExp::toElem(IRState* p) default: assert(0); } - e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); + eval = new llvm::FCmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb()); } else { assert(0 && "Unsupported CmpExp type"); } - delete l; - delete r; - - e->type = elem::VAL; - - return e; + return new DImValue(type, eval); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* EqualExp::toElem(IRState* p) +DValue* EqualExp::toElem(IRState* p) { Logger::print("EqualExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); Type* t = DtoDType(e1->type); Type* e2t = DtoDType(e2->type); assert(t == e2t); + llvm::Value* eval = 0; + if (t->isintegral() || t->ty == Tpointer) { Logger::println("integral or pointer"); @@ -2030,7 +1956,7 @@ elem* EqualExp::toElem(IRState* p) default: assert(0); } - e->val = new llvm::ICmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); + eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb()); } else if (t->isfloating()) { @@ -2047,52 +1973,42 @@ elem* EqualExp::toElem(IRState* p) default: assert(0); } - e->val = new llvm::FCmpInst(cmpop, l->getValue(), r->getValue(), "tmp", p->scopebb()); + eval = new llvm::FCmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb()); } else if (t->ty == Tsarray) { Logger::println("static array"); - e->val = DtoStaticArrayCompare(op,l->mem,r->mem); + eval = DtoStaticArrayCompare(op,l->getRVal(),r->getRVal()); } else if (t->ty == Tarray) { Logger::println("dynamic array"); - e->val = DtoDynArrayCompare(op,l->mem,r->mem); + eval = DtoDynArrayCompare(op,l->getRVal(),r->getRVal()); } else if (t->ty == Tdelegate) { Logger::println("delegate"); - e->val = DtoCompareDelegate(op,l->mem,r->mem); + eval = DtoCompareDelegate(op,l->getRVal(),r->getRVal()); } else { assert(0 && "Unsupported EqualExp type"); } - delete l; - delete r; - - e->type = elem::VAL; - - return e; + return new DImValue(type, eval); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* PostExp::toElem(IRState* p) +DValue* PostExp::toElem(IRState* p) { Logger::print("PostExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - elem* r = e2->toElem(p); + DValue* l = e1->toElem(p); + DValue* r = e2->toElem(p); - elem* e = new elem; - e->mem = l->mem; - e->val = l->getValue(); - e->type = elem::VAL; - - llvm::Value* val = e->val; + llvm::Value* val = l->getRVal(); llvm::Value* post = 0; Type* e1type = DtoDType(e1->type); @@ -2131,18 +2047,14 @@ elem* PostExp::toElem(IRState* p) else assert(post); - assert(l->mem); - new llvm::StoreInst(post,l->mem,p->scopebb()); + DtoStore(post,l->getLVal()); - delete l; - delete r; - - return e; + return new DImValue(type,val,true); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* NewExp::toElem(IRState* p) +DValue* NewExp::toElem(IRState* p) { Logger::print("NewExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2152,58 +2064,56 @@ elem* NewExp::toElem(IRState* p) assert(newtype); assert(!allocator); - elem* e = new elem; - e->inplace = true; - Type* ntype = DtoDType(newtype); const llvm::Type* t = DtoType(ntype); + llvm::Value* emem = 0; + bool inplace = true; + if (onstack) { assert(ntype->ty == Tclass); - e->mem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint()); + emem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint()); } else { if (ntype->ty == Tclass) { - e->mem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb()); + emem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb()); } else if (ntype->ty == Tarray) { assert(arguments); if (arguments->dim == 1) { - elem* sz = ((Expression*)arguments->data[0])->toElem(p); - llvm::Value* dimval = sz->getValue(); + DValue* sz = ((Expression*)arguments->data[0])->toElem(p); + llvm::Value* dimval = sz->getRVal(); Type* nnt = DtoDType(ntype->next); if (nnt->ty == Tvoid) nnt = Type::tint8; if (!p->topexp() || p->topexp()->e2 != this) { const llvm::Type* restype = DtoType(type); Logger::cout() << "restype = " << *restype << '\n'; - e->mem = new llvm::AllocaInst(restype,"tmp",p->topallocapoint()); - DtoNewDynArray(e->mem, dimval, nnt); - e->inplace = false; + emem = new llvm::AllocaInst(restype,"tmp",p->topallocapoint()); + DtoNewDynArray(emem, dimval, nnt); + inplace = false; } else if (p->topexp() || p->topexp()->e2 != this) { assert(p->topexp()->v); - e->mem = p->topexp()->v; - DtoNewDynArray(e->mem, dimval, nnt); + emem = p->topexp()->v->getLVal(); + DtoNewDynArray(emem, dimval, nnt); } else assert(0); - delete sz; } else { assert(0); } } else { - e->mem = new llvm::MallocInst(t,"tmp",p->scopebb()); + emem = new llvm::MallocInst(t,"tmp",p->scopebb()); } } if (ntype->ty == Tclass) { // first apply the static initializer - assert(e->mem); - DtoInitClass((TypeClass*)ntype, e->mem); + DtoInitClass((TypeClass*)ntype, emem); // then call constructor if (arguments) { @@ -2213,7 +2123,7 @@ elem* NewExp::toElem(IRState* p) TypeFunction* tf = (TypeFunction*)DtoDType(member->type); std::vector ctorargs; - ctorargs.push_back(e->mem); + ctorargs.push_back(emem); for (size_t i=0; idim; ++i) { Expression* ex = (Expression*)arguments->data[i]; @@ -2221,35 +2131,36 @@ elem* NewExp::toElem(IRState* p) llvm::Value* a = DtoArgument(fn->getFunctionType()->getParamType(i+1), fnarg, ex); ctorargs.push_back(a); } - e->mem = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb()); + emem = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb()); } } else if (ntype->ty == Tstruct) { TypeStruct* ts = (TypeStruct*)ntype; if (ts->isZeroInit()) { - DtoStructZeroInit(e->mem); + DtoStructZeroInit(emem); } else { - DtoStructCopy(e->mem,ts->llvmInit); + DtoStructCopy(emem,ts->llvmInit); } } - e->type = elem::VAR; + if (inplace) + return new DImValue(type, emem, true); - return e; + return new DVarValue(type, emem, true); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* DeleteExp::toElem(IRState* p) +DValue* DeleteExp::toElem(IRState* p) { Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; //assert(e1->type->ty != Tclass); - elem* v = e1->toElem(p); - llvm::Value* val = v->getValue(); + DValue* v = e1->toElem(p); + llvm::Value* val = v->getRVal(); llvm::Value* ldval = 0; const llvm::Type* t = val->getType(); @@ -2258,30 +2169,26 @@ elem* DeleteExp::toElem(IRState* p) Type* e1type = DtoDType(e1->type); if (e1type->ty == Tpointer) { - ldval = v->getValue(); - new llvm::FreeInst(ldval, p->scopebb()); - Logger::cout() << *z << '\n'; Logger::cout() << *val << '\n'; - new llvm::StoreInst(z, v->mem, p->scopebb()); + new llvm::FreeInst(val, p->scopebb()); + new llvm::StoreInst(z, v->getLVal(), p->scopebb()); } else if (e1type->ty == Tclass) { TypeClass* tc = (TypeClass*)e1type; DtoCallClassDtors(tc, val); - if (v->vardecl && !v->vardecl->onstack) { - new llvm::FreeInst(val, p->scopebb()); + if (DVarValue* vv = v->isVar()) { + if (vv->var && !vv->var->onstack) + new llvm::FreeInst(val, p->scopebb()); } - new llvm::StoreInst(z, v->mem, p->scopebb()); + new llvm::StoreInst(z, v->getLVal(), p->scopebb()); } else if (e1type->ty == Tarray) { // must be on the heap (correct?) - ldval = v->getValue(); - llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); - - llvm::Value* ptr = DtoGEP(ldval,zero,one,"tmp",p->scopebb()); + llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb()); ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb()); new llvm::FreeInst(ptr, p->scopebb()); DtoNullArray(val); @@ -2290,83 +2197,68 @@ elem* DeleteExp::toElem(IRState* p) assert(0); } - delete v; - // this expression produces no useful data return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* ArrayLengthExp::toElem(IRState* p) +DValue* ArrayLengthExp::toElem(IRState* p) { Logger::print("ArrayLengthExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* u = e1->toElem(p); + DValue* u = e1->toElem(p); if (p->topexp() && p->topexp()->e1 == this) { - e->mem = u->mem; - e->type = elem::ARRAYLEN; + return new DArrayLenValue(type, u->getLVal()); } else { llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); - llvm::Value* ptr = DtoGEP(u->mem,zero,zero,"tmp",p->scopebb()); - e->val = new llvm::LoadInst(ptr, "tmp", p->scopebb()); - e->type = elem::VAL; + llvm::Value* ptr = DtoGEP(u->getRVal(),zero,zero,"tmp",p->scopebb()); + ptr = new llvm::LoadInst(ptr, "tmp", p->scopebb()); + return new DImValue(type, ptr); } - delete u; - - return e; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* AssertExp::toElem(IRState* p) +DValue* AssertExp::toElem(IRState* p) { Logger::print("AssertExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* u = e1->toElem(p); - elem* m = msg ? msg->toElem(p) : NULL; + DValue* u = e1->toElem(p); + DValue* m = msg ? msg->toElem(p) : NULL; llvm::Value* loca = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false); - DtoAssert(u->getValue(), loca, m ? m->val : NULL); + DtoAssert(u->getRVal(), loca, m ? m->getRVal() : NULL); - delete m; - delete u; - - return new elem; + return 0; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* NotExp::toElem(IRState* p) +DValue* NotExp::toElem(IRState* p) { Logger::print("NotExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* u = e1->toElem(p); + DValue* u = e1->toElem(p); - llvm::Value* b = DtoBoolean(u->getValue()); + llvm::Value* b = DtoBoolean(u->getRVal()); - llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, true); - e->val = p->ir->CreateICmpEQ(b,zero); - //e->val = new llvm::ICmpInst(llvm::ICmpInst::ICMP_EQ,b,zero,"tmp",p->scopebb()); - e->type = elem::VAL; + llvm::Constant* zero = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, true); + b = p->ir->CreateICmpEQ(b,zero); - delete u; - - return e; + return new DImValue(type, b); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* AndAndExp::toElem(IRState* p) +DValue* AndAndExp::toElem(IRState* p) { Logger::print("AndAndExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2375,40 +2267,34 @@ elem* AndAndExp::toElem(IRState* p) llvm::Value* resval = 0; llvm::BasicBlock* entryblock = &p->topfunc()->front(); resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"andandtmp",p->topallocapoint()); - - elem* e = new elem; - elem* u = e1->toElem(p); + + DValue* u = e1->toElem(p); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* andand = new llvm::BasicBlock("andand", gIR->topfunc(), oldend); llvm::BasicBlock* andandend = new llvm::BasicBlock("andandend", gIR->topfunc(), oldend); - - llvm::Value* ubool = DtoBoolean(u->getValue()); + + llvm::Value* ubool = DtoBoolean(u->getRVal()); new llvm::StoreInst(ubool,resval,p->scopebb()); new llvm::BranchInst(andand,andandend,ubool,p->scopebb()); - - p->scope() = IRScope(andand, andandend); - elem* v = e2->toElem(p); - llvm::Value* vbool = DtoBoolean(v->getValue()); + p->scope() = IRScope(andand, andandend); + DValue* v = e2->toElem(p); + + llvm::Value* vbool = DtoBoolean(v->getRVal()); llvm::Value* uandvbool = llvm::BinaryOperator::create(llvm::BinaryOperator::And, ubool, vbool,"tmp",p->scopebb()); new llvm::StoreInst(uandvbool,resval,p->scopebb()); new llvm::BranchInst(andandend,p->scopebb()); - delete u; - delete v; - p->scope() = IRScope(andandend, oldend); - - e->val = new llvm::LoadInst(resval,"tmp",p->scopebb()); - e->type = elem::VAL; - return e; + resval = new llvm::LoadInst(resval,"tmp",p->scopebb()); + return new DImValue(type, resval); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* OrOrExp::toElem(IRState* p) +DValue* OrOrExp::toElem(IRState* p) { Logger::print("OrOrExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2417,73 +2303,57 @@ elem* OrOrExp::toElem(IRState* p) llvm::Value* resval = 0; llvm::BasicBlock* entryblock = &p->topfunc()->front(); resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"orortmp",p->topallocapoint()); - - elem* e = new elem; - elem* u = e1->toElem(p); + + DValue* u = e1->toElem(p); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* oror = new llvm::BasicBlock("oror", gIR->topfunc(), oldend); llvm::BasicBlock* ororend = new llvm::BasicBlock("ororend", gIR->topfunc(), oldend); - - llvm::Value* ubool = DtoBoolean(u->getValue()); + + llvm::Value* ubool = DtoBoolean(u->getRVal()); new llvm::StoreInst(ubool,resval,p->scopebb()); new llvm::BranchInst(ororend,oror,ubool,p->scopebb()); - - p->scope() = IRScope(oror, ororend); - elem* v = e2->toElem(p); - llvm::Value* vbool = DtoBoolean(v->getValue()); + p->scope() = IRScope(oror, ororend); + DValue* v = e2->toElem(p); + + llvm::Value* vbool = DtoBoolean(v->getRVal()); new llvm::StoreInst(vbool,resval,p->scopebb()); new llvm::BranchInst(ororend,p->scopebb()); - delete u; - delete v; - p->scope() = IRScope(ororend, oldend); - - e->val = new llvm::LoadInst(resval,"tmp",p->scopebb()); - e->type = elem::VAL; - return e; + resval = new llvm::LoadInst(resval,"tmp",p->scopebb()); + return new DImValue(type, resval); } ////////////////////////////////////////////////////////////////////////////////////////// #define BinBitExp(X,Y) \ -elem* X##Exp::toElem(IRState* p) \ +DValue* X##Exp::toElem(IRState* p) \ { \ Logger::print("%sExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ LOG_SCOPE; \ - elem* e = new elem; \ - elem* u = e1->toElem(p); \ - elem* v = e2->toElem(p); \ - e->val = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getValue(), v->getValue(), "tmp", p->scopebb()); \ - e->type = elem::VAL; \ - delete u; \ - delete v; \ - return e; \ + DValue* u = e1->toElem(p); \ + DValue* v = e2->toElem(p); \ + llvm::Value* x = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getRVal(), v->getRVal(), "tmp", p->scopebb()); \ + return new DImValue(type, x); \ } \ \ -elem* X##AssignExp::toElem(IRState* p) \ +DValue* X##AssignExp::toElem(IRState* p) \ { \ Logger::print("%sAssignExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \ LOG_SCOPE; \ - elem* u = e1->toElem(p); \ - elem* v = e2->toElem(p); \ - llvm::Value* uval = u->getValue(); \ - assert(uval); \ - llvm::Value* vval = v->getValue(); \ - assert(vval); \ + p->exps.push_back(IRExp(e1,e2,NULL)); \ + DValue* u = e1->toElem(p); \ + p->topexp()->v = u; \ + DValue* v = e2->toElem(p); \ + p->exps.pop_back(); \ + llvm::Value* uval = u->getRVal(); \ + llvm::Value* vval = v->getRVal(); \ llvm::Value* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, uval, vval, "tmp", p->scopebb()); \ - assert(u->mem); \ - Logger::cout() << *tmp << '|' << *u->mem << '\n'; \ - new llvm::StoreInst(DtoPointedType(u->mem, tmp), u->mem, p->scopebb()); \ - delete u; \ - delete v; \ - elem* e = new elem; \ - e->mem = u->mem; \ - e->type = elem::VAR; \ - return e; \ + new llvm::StoreInst(DtoPointedType(u->getLVal(), tmp), u->getLVal(), p->scopebb()); \ + return u; \ } BinBitExp(And,And); @@ -2495,7 +2365,7 @@ BinBitExp(Ushr,LShr); ////////////////////////////////////////////////////////////////////////////////////////// -elem* HaltExp::toElem(IRState* p) +DValue* HaltExp::toElem(IRState* p) { Logger::print("HaltExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2509,13 +2379,12 @@ elem* HaltExp::toElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* DelegateExp::toElem(IRState* p) +DValue* DelegateExp::toElem(IRState* p) { Logger::print("DelegateExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* u = e1->toElem(p); + DValue* u = e1->toElem(p); llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false); @@ -2523,10 +2392,10 @@ elem* DelegateExp::toElem(IRState* p) const llvm::Type* int8ptrty = llvm::PointerType::get(llvm::Type::Int8Ty); assert(p->topexp() && p->topexp()->e2 == this && p->topexp()->v); - llvm::Value* lval = p->topexp()->v; + llvm::Value* lval = p->topexp()->v->getLVal(); llvm::Value* context = DtoGEP(lval,zero,zero,"tmp",p->scopebb()); - llvm::Value* castcontext = new llvm::BitCastInst(u->getValue(),int8ptrty,"tmp",p->scopebb()); + llvm::Value* castcontext = new llvm::BitCastInst(u->getRVal(),int8ptrty,"tmp",p->scopebb()); new llvm::StoreInst(castcontext, context, p->scopebb()); llvm::Value* fptr = DtoGEP(lval,zero,one,"tmp",p->scopebb()); @@ -2535,70 +2404,61 @@ elem* DelegateExp::toElem(IRState* p) llvm::Value* castfptr = new llvm::BitCastInst(func->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb()); new llvm::StoreInst(castfptr, fptr, p->scopebb()); - e->inplace = true; - - delete u; - return e; + return new DImValue(type, u->getRVal(), true); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* IdentityExp::toElem(IRState* p) +DValue* IdentityExp::toElem(IRState* p) { Logger::print("IdentityExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* u = e1->toElem(p); - elem* v = e2->toElem(p); + DValue* u = e1->toElem(p); + DValue* v = e2->toElem(p); - elem* e = new elem; - - llvm::Value* l = u->field ? u->mem : u->getValue(); - llvm::Value* r = v->field ? v->mem : v->getValue(); + llvm::Value* l = u->getRVal(); + llvm::Value* r = v->getRVal(); Type* t1 = DtoDType(e1->type); + llvm::Value* eval = 0; + if (t1->ty == Tarray) { - if (v->type == elem::NUL) { + if (v->isNull()) { r = NULL; } else { assert(l->getType() == r->getType()); } - e->val = DtoDynArrayIs(op,l,r); + eval = DtoDynArrayIs(op,l,r); } else { llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE; - if (t1->ty == Tpointer && v->type == elem::NUL && l->getType() != r->getType()) { + if (t1->ty == Tpointer && v->isNull() && l->getType() != r->getType()) { r = llvm::ConstantPointerNull::get(llvm::cast(l->getType())); } Logger::cout() << "l = " << *l << " r = " << *r << '\n'; - e->val = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb()); + eval = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb()); } - e->type = elem::VAL; - - delete u; - delete v; - - return e; + return new DImValue(type, eval); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CommaExp::toElem(IRState* p) +DValue* CommaExp::toElem(IRState* p) { Logger::print("CommaExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* u = e1->toElem(p); - elem* v = e2->toElem(p); - delete u; + DValue* u = e1->toElem(p); + DValue* v = e2->toElem(p); return v; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CondExp::toElem(IRState* p) +DValue* CondExp::toElem(IRState* p) { Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2609,68 +2469,56 @@ elem* CondExp::toElem(IRState* p) // allocate a temporary for the final result. failed to come up with a better way :/ llvm::BasicBlock* entryblock = &p->topfunc()->front(); llvm::Value* resval = new llvm::AllocaInst(resty,"condtmp",p->topallocapoint()); + DVarValue* dvv = new DVarValue(type, resval, true); llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* condtrue = new llvm::BasicBlock("condtrue", gIR->topfunc(), oldend); llvm::BasicBlock* condfalse = new llvm::BasicBlock("condfalse", gIR->topfunc(), oldend); llvm::BasicBlock* condend = new llvm::BasicBlock("condend", gIR->topfunc(), oldend); - elem* c = econd->toElem(p); - llvm::Value* cond_val = DtoBoolean(c->getValue()); - delete c; + DValue* c = econd->toElem(p); + llvm::Value* cond_val = DtoBoolean(c->getRVal()); new llvm::BranchInst(condtrue,condfalse,cond_val,p->scopebb()); p->scope() = IRScope(condtrue, condfalse); - elem* u = e1->toElem(p); - DtoAssign(dtype, resval, u->getValue()); + DValue* u = e1->toElem(p); + DtoAssign(dvv, u); new llvm::BranchInst(condend,p->scopebb()); - delete u; p->scope() = IRScope(condfalse, condend); - elem* v = e2->toElem(p); - DtoAssign(dtype, resval, v->getValue()); + DValue* v = e2->toElem(p); + DtoAssign(dvv, v); new llvm::BranchInst(condend,p->scopebb()); - delete v; p->scope() = IRScope(condend, oldend); - - elem* e = new elem; - e->mem = resval; - e->type = elem::VAR; - return e; + return dvv; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* ComExp::toElem(IRState* p) +DValue* ComExp::toElem(IRState* p) { Logger::print("ComExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* u = e1->toElem(p); + DValue* u = e1->toElem(p); - llvm::Value* value = u->getValue(); + llvm::Value* value = u->getRVal(); llvm::Value* minusone = llvm::ConstantInt::get(value->getType(), -1, true); - e->val = llvm::BinaryOperator::create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb()); + value = llvm::BinaryOperator::create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb()); - delete u; - - e->type = elem::VAL; - - return e; + return new DImValue(type, value); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* NegExp::toElem(IRState* p) +DValue* NegExp::toElem(IRState* p) { Logger::print("NegExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* e = new elem; - elem* l = e1->toElem(p); - llvm::Value* val = l->getValue(); - delete l; + + DValue* l = e1->toElem(p); + llvm::Value* val = l->getRVal(); Type* t = DtoDType(type); @@ -2688,61 +2536,52 @@ elem* NegExp::toElem(IRState* p) else assert(0); - e->val = llvm::BinaryOperator::createSub(zero,val,"tmp",p->scopebb()); - e->type = elem::VAL; - - return e; + val = llvm::BinaryOperator::createSub(zero,val,"tmp",p->scopebb()); + return new DImValue(type, val); } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CatExp::toElem(IRState* p) +DValue* CatExp::toElem(IRState* p) { Logger::print("CatExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; Type* t = DtoDType(type); - bool inplace = false; - llvm::Value* dst = 0; IRExp* ex = p->topexp(); if (ex && ex->e2 == this) { assert(ex->v); - dst = ex->v; - inplace = true; + DtoCatArrays(ex->v->getLVal(),e1,e2); + return new DImValue(type, ex->v->getLVal(), true); } else { assert(t->ty == Tarray); const llvm::Type* arrty = DtoType(t); - dst = new llvm::AllocaInst(arrty, "tmpmem", p->topallocapoint()); + llvm::Value* dst = new llvm::AllocaInst(arrty, "tmpmem", p->topallocapoint()); + DtoCatArrays(dst,e1,e2); + return new DVarValue(type, dst, true); } - - DtoCatArrays(dst,e1,e2); - - elem* e = new elem; - e->mem = dst; - e->type = elem::VAR; - e->inplace = inplace; - - return e; } ////////////////////////////////////////////////////////////////////////////////////////// -elem* CatAssignExp::toElem(IRState* p) +DValue* CatAssignExp::toElem(IRState* p) { Logger::print("CatAssignExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - elem* l = e1->toElem(p); - assert(l->mem); + DValue* l = e1->toElem(p); Type* e1type = DtoDType(e1->type); Type* elemtype = DtoDType(e1type->next); Type* e2type = DtoDType(e2->type); if (e2type == elemtype) { - DtoCatAssignElement(l->mem,e2); + DtoCatAssignElement(l->getLVal(),e2); + } + else if (e1type == e2type) { + DtoCatAssignArray(l->getLVal(),e2); } else assert(0 && "only one element at a time right now"); @@ -2752,7 +2591,55 @@ elem* CatAssignExp::toElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* ArrayLiteralExp::toElem(IRState* p) +DValue* FuncExp::toElem(IRState* p) +{ + Logger::print("FuncExp::toElem: %s | %s\n", toChars(), type->toChars()); + LOG_SCOPE; + + assert(fd); + + if (fd->isNested()) Logger::println("nested"); + Logger::println("kind = %s\n", fd->kind()); + + fd->toObjFile(); + + llvm::Value* lval = NULL; + if (!p->topexp() || p->topexp()->e2 != this) { + const llvm::Type* dgty = DtoType(type); + Logger::cout() << "delegate without explicit storage:" << '\n' << *dgty << '\n'; + lval = new llvm::AllocaInst(dgty,"dgstorage",p->topallocapoint()); + } + else if (p->topexp()->e2 == this) { + assert(p->topexp()->v); + lval = p->topexp()->v->getLVal();; + } + else + assert(0); + + llvm::Value* context = DtoGEPi(lval,0,0,"tmp",p->scopebb()); + const llvm::PointerType* pty = llvm::cast(context->getType()->getContainedType(0)); + llvm::Value* llvmNested = p->func().decl->llvmNested; + if (llvmNested == NULL) { + llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty); + p->ir->CreateStore(nullcontext, context); + } + else { + llvm::Value* nestedcontext = p->ir->CreateBitCast(llvmNested, pty, "tmp"); + p->ir->CreateStore(nestedcontext, context); + } + + llvm::Value* fptr = DtoGEPi(lval,0,1,"tmp",p->scopebb()); + + assert(fd->llvmValue); + llvm::Value* castfptr = new llvm::BitCastInst(fd->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb()); + new llvm::StoreInst(castfptr, fptr, p->scopebb()); + + return new DImValue(type, lval, true); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +DValue* ArrayLiteralExp::toElem(IRState* p) { Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -2766,7 +2653,14 @@ elem* ArrayLiteralExp::toElem(IRState* p) mem = new llvm::AllocaInst(t,"tmparrayliteral",p->topallocapoint()); } else if (p->topexp()->e2 == this) { - mem = p->topexp()->v; + DValue* tlv = p->topexp()->v; + if (DSliceValue* sv = tlv->isSlice()) { + assert(sv->len == 0); + mem = sv->ptr; + } + else { + mem = p->topexp()->v->getLVal(); + } assert(mem); if (!llvm::isa(mem->getType()) || !llvm::isa(mem->getType()->getContainedType(0))) @@ -2782,16 +2676,11 @@ elem* ArrayLiteralExp::toElem(IRState* p) { Expression* expr = (Expression*)elements->data[i]; llvm::Value* elemAddr = DtoGEPi(mem,0,i,"tmp",p->scopebb()); - elem* e = expr->toElem(p); - new llvm::StoreInst(e->getValue(), elemAddr, p->scopebb()); + DValue* e = expr->toElem(p); + new llvm::StoreInst(e->getRVal(), elemAddr, p->scopebb()); } - elem* e = new elem; - e->mem = mem; - e->type = elem::VAL; - e->inplace = true; - - return e; + return new DImValue(type, mem, true); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2819,61 +2708,100 @@ llvm::Constant* ArrayLiteralExp::toConstElem(IRState* p) ////////////////////////////////////////////////////////////////////////////////////////// -elem* FuncExp::toElem(IRState* p) +DValue* StructLiteralExp::toElem(IRState* p) { - Logger::print("FuncExp::toElem: %s | %s\n", toChars(), type->toChars()); + Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - assert(fd); + llvm::Value* sptr; + const llvm::Type* llt = DtoType(type); - if (fd->isNested()) Logger::println("nested"); - Logger::println("kind = %s\n", fd->kind()); + llvm::Value* mem = 0; - fd->toObjFile(); - - llvm::Value* lval = NULL; - if (!p->topexp() || p->topexp()->e2 != this) { - const llvm::Type* dgty = DtoType(type); - Logger::cout() << "delegate without explicit storage:" << '\n' << *dgty << '\n'; - lval = new llvm::AllocaInst(dgty,"dgstorage",p->topallocapoint()); - } - else if (p->topexp()->e2 == this) { - lval = p->topexp()->v; - assert(lval); + // temporary struct literal + if (!p->topexp() || p->topexp()->e2 != this) + { + sptr = new llvm::AllocaInst(llt,"tmpstructliteral",p->topallocapoint()); } + // already has memory else - assert(0); - - elem* e = new elem; - - llvm::Value* context = DtoGEPi(lval,0,0,"tmp",p->scopebb()); - const llvm::PointerType* pty = llvm::cast(context->getType()->getContainedType(0)); - llvm::Value* llvmNested = p->func().decl->llvmNested; - if (llvmNested == NULL) { - llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty); - p->ir->CreateStore(nullcontext, context); - } - else { - llvm::Value* nestedcontext = p->ir->CreateBitCast(llvmNested, pty, "tmp"); - p->ir->CreateStore(nestedcontext, context); + { + assert(p->topexp()->e2 == this); + sptr = p->topexp()->v->getLVal(); } - llvm::Value* fptr = DtoGEPi(lval,0,1,"tmp",p->scopebb()); + // num elements in literal + unsigned n = elements->dim; - assert(fd->llvmValue); - llvm::Value* castfptr = new llvm::BitCastInst(fd->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb()); - new llvm::StoreInst(castfptr, fptr, p->scopebb()); + // unions might have different types for each literal + if (sd->llvmHasUnions) { + // build the type of the literal + std::vector tys; + for (unsigned i=0; idata[i]; + if (!vx) continue; + tys.push_back(DtoType(vx->type)); + } + const llvm::StructType* t = llvm::StructType::get(tys); + if (t != llt) { + if (gTargetData->getTypeSize(t) != gTargetData->getTypeSize(llt)) { + Logger::cout() << "got size " << gTargetData->getTypeSize(t) << ", expected " << gTargetData->getTypeSize(llt) << '\n'; + assert(0 && "type size mismatch"); + } + sptr = p->ir->CreateBitCast(sptr, llvm::PointerType::get(t), "tmp"); + Logger::cout() << "sptr type is now: " << *t << '\n'; + } + } - e->inplace = true; - e->mem = lval; - e->type = elem::VAR; + // build + unsigned j = 0; + for (unsigned i=0; idata[i]; + if (!vx) continue; - return e; + Logger::cout() << "getting index " << j << " of " << *sptr << '\n'; + llvm::Value* arrptr = DtoGEPi(sptr,0,j,"tmp",p->scopebb()); + DValue* darrptr = new DVarValue(vx->type, arrptr, true); + + p->exps.push_back(IRExp(NULL,vx,darrptr)); + DValue* ve = vx->toElem(p); + p->exps.pop_back(); + + if (!ve->inPlace()) + DtoAssign(darrptr, ve); + + j++; + } + + return new DImValue(type, sptr, true); } ////////////////////////////////////////////////////////////////////////////////////////// -#define STUB(x) elem *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } +llvm::Constant* StructLiteralExp::toConstElem(IRState* p) +{ + Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); + LOG_SCOPE; + + unsigned n = elements->dim; + std::vector vals(n, NULL); + + for (unsigned i=0; idata[i]; + vals[i] = vx->toConstElem(p); + } + + assert(DtoDType(type)->ty == Tstruct); + const llvm::Type* t = DtoType(type); + const llvm::StructType* st = llvm::cast(t); + return llvm::ConstantStruct::get(st,vals); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +#define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; } //STUB(IdentityExp); //STUB(CondExp); //STUB(EqualExp); diff --git a/gen/tollvm.c b/gen/tollvm.cpp similarity index 90% rename from gen/tollvm.c rename to gen/tollvm.cpp index f58b926d..f99b1611 100644 --- a/gen/tollvm.c +++ b/gen/tollvm.cpp @@ -12,13 +12,13 @@ #include "gen/irstate.h" #include "gen/logger.h" #include "gen/runtime.h" -#include "gen/elem.h" #include "gen/arrays.h" +#include "gen/dvalue.h" bool DtoIsPassedByRef(Type* type) { TY t = DtoDType(type)->ty; - return (t == Tstruct || t == Tarray || t == Tdelegate); + return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray); } Type* DtoDType(Type* t) @@ -890,7 +890,7 @@ llvm::Constant* DtoConstInitializer(Type* type, Initializer* init) ////////////////////////////////////////////////////////////////////////////////////////// -elem* DtoInitializer(Initializer* init) +DValue* DtoInitializer(Initializer* init) { if (ExpInitializer* ex = init->isExpInitializer()) { @@ -1069,7 +1069,7 @@ llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl) { Argument* arg = Argument::getNth(f->parameters, k++); //arg->llvmValue = iarg; - //printf("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident); + //Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident); if (arg && arg->ident != 0) { if (arg->vardecl) { arg->vardecl->llvmValue = iarg; @@ -1094,6 +1094,8 @@ llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl) } } + Logger::cout() << "func decl: " << *func << '\n'; + return func; } @@ -1163,15 +1165,13 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio if (haslvals) gIR->exps.push_back(IRExp(NULL,NULL,NULL)); - elem* arg = argexp->toElem(gIR); + DValue* arg = argexp->toElem(gIR); if (haslvals) gIR->exps.pop_back(); - if (arg->inplace) { - assert(arg->mem != 0); - retval = arg->mem; - delete arg; + if (arg->inPlace()) { + retval = arg->getRVal(); return retval; } @@ -1179,8 +1179,13 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio TY argty = realtype->ty; if (DtoIsPassedByRef(realtype)) { if (!fnarg || !fnarg->llvmCopy) { - retval = arg->getValue(); - assert(retval != 0); + if (DSliceValue* sv = arg->isSlice()) { + retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint()); + DtoSetArray(retval, DtoArrayLen(sv), DtoArrayPtr(sv)); + } + else { + retval = arg->getRVal(); + } } else { llvm::Value* allocaInst = 0; @@ -1190,54 +1195,61 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio const llvm::PointerType* pty = llvm::PointerType::get(realtypell); if (argty == Tstruct) { allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint()); - DtoStructCopy(allocaInst,arg->mem); + DValue* dst = new DVarValue(realtype, allocaInst, true); + DtoAssign(dst,arg); + delete dst; } else if (argty == Tdelegate) { allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint()); - DtoDelegateCopy(allocaInst,arg->mem); + DValue* dst = new DVarValue(realtype, allocaInst, true); + DtoAssign(dst,arg); + delete dst; } else if (argty == Tarray) { - if (arg->type == elem::SLICE) { + if (arg->isSlice()) { allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint()); - DtoSetArray(allocaInst, arg->arg, arg->mem); - } - else if (arg->temp) { - allocaInst = arg->mem; } else { allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint()); - DtoArrayAssign(allocaInst,arg->mem); } } else assert(0); + DValue* dst = new DVarValue(realtype, allocaInst, true); + DtoAssign(dst,arg); + delete dst; + retval = allocaInst; } } else if (!fnarg || fnarg->llvmCopy) { Logger::println("regular arg"); - assert(arg->type != elem::SLICE); - if (arg->mem) Logger::cout() << "mem = " << *arg->mem << '\n'; - if (arg->val) Logger::cout() << "val = " << *arg->val << '\n'; - if (arg->arg) Logger::cout() << "arg = " << *arg->arg << '\n'; - retval = arg->arg ? arg->arg : arg->field ? arg->mem : arg->getValue(); + if (DSliceValue* sl = arg->isSlice()) { + if (sl->ptr) Logger::cout() << "ptr = " << *sl->ptr << '\n'; + if (sl->len) Logger::cout() << "len = " << *sl->len << '\n'; + assert(0); + } + else { + retval = arg->getRVal(); + } } else { Logger::println("as ptr arg"); - retval = arg->mem ? arg->mem : arg->val; + retval = arg->getLVal(); if (paramtype && retval->getType() != paramtype) { - assert(retval->getType() == paramtype->getContainedType(0)); - new llvm::StoreInst(retval, arg->mem, gIR->scopebb()); - retval = arg->mem; + assert(0); + /*assert(retval->getType() == paramtype->getContainedType(0)); + new llvm::StoreInst(retval, arg->getLVal(), gIR->scopebb()); + retval = arg->getLVal();*/ } } if (fnarg && paramtype && retval->getType() != paramtype) { // this is unfortunately needed with the way SymOffExp is overused // and static arrays can end up being a pointer to their element type - if (arg->field) { + if (arg->isField()) { retval = gIR->ir->CreateBitCast(retval, paramtype, "tmp"); } else { @@ -1307,29 +1319,78 @@ llvm::Value* DtoNestedVariable(VarDeclaration* vd) ////////////////////////////////////////////////////////////////////////////////////////// -void DtoAssign(Type* t, llvm::Value* lhs, llvm::Value* rhs) +void DtoAssign(DValue* lhs, DValue* rhs) { - Logger::cout() << "assignment:" << '\n' << *lhs << *rhs << '\n'; + Type* t = DtoDType(lhs->getType()); + Type* t2 = DtoDType(rhs->getType()); if (t->ty == Tstruct) { - assert(lhs->getType() == rhs->getType()); - DtoStructCopy(lhs,rhs); + if (t2 != t) { + // TODO: fix this, use 'rhs' for something + DtoStructZeroInit(lhs->getLVal()); + } + else if (!rhs->inPlace()) { + DtoStructCopy(lhs->getLVal(),rhs->getRVal()); + } } else if (t->ty == Tarray) { - assert(lhs->getType() == rhs->getType()); - DtoArrayAssign(lhs,rhs); + // lhs is slice + if (DSliceValue* s = lhs->isSlice()) { + if (DSliceValue* s2 = rhs->isSlice()) { + DtoArrayCopy(s, s2); + } + else if (t->next == t2) { + if (s->len) + DtoArrayInit(s->ptr, s->len, rhs->getRVal()); + else + DtoArrayInit(s->ptr, rhs->getRVal()); + } + else + assert(rhs->inPlace()); + } + // rhs is slice + else if (DSliceValue* s = rhs->isSlice()) { + DtoSetArray(lhs->getLVal(),s->len,s->ptr); + } + // null + else if (rhs->isNull()) { + DtoNullArray(lhs->getLVal()); + } + // reference assignment + else { + DtoArrayAssign(lhs->getLVal(), rhs->getRVal()); + } } else if (t->ty == Tsarray) { - assert(lhs->getType() == rhs->getType()); - DtoStaticArrayCopy(lhs,rhs); + DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal()); } else if (t->ty == Tdelegate) { - assert(lhs->getType() == rhs->getType()); - DtoDelegateCopy(lhs,rhs); + if (rhs->isNull()) + DtoNullDelegate(lhs->getLVal()); + else if (!rhs->inPlace()) + DtoDelegateCopy(lhs->getLVal(), rhs->getRVal()); + } + else if (t->ty == Tclass) { + assert(t2->ty == Tclass); + // assignment to this in constructor special case + if (lhs->isThis()) { + llvm::Value* tmp = rhs->getRVal(); + FuncDeclaration* fdecl = gIR->func().decl; + // respecify the this param + if (!llvm::isa(fdecl->llvmThisVar)) + fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint()); + DtoStore(tmp, fdecl->llvmThisVar); + } + // regular class ref -> class ref assignment + else { + DtoStore(rhs->getRVal(), lhs->getLVal()); + } } else { - assert(lhs->getType()->getContainedType(0) == rhs->getType()); - gIR->ir->CreateStore(rhs, lhs); + llvm::Value* r = rhs->getRVal(); + llvm::Value* l = lhs->getLVal(); + Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n'; + gIR->ir->CreateStore(r, l); } } @@ -1409,6 +1470,31 @@ void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes) ////////////////////////////////////////////////////////////////////////////////////////// +llvm::Value* DtoLoad(llvm::Value* src) +{ + return gIR->ir->CreateLoad(src,"tmp"); +} + +void DtoStore(llvm::Value* src, llvm::Value* dst) +{ + gIR->ir->CreateStore(src,dst); +} + +bool DtoCanLoad(llvm::Value* ptr) +{ + if (llvm::isa(ptr->getType())) { + return ptr->getType()->getContainedType(0)->isFirstClassType(); + } + return false; +} + +llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t) +{ + return gIR->ir->CreateBitCast(v, t, "tmp"); +} + +////////////////////////////////////////////////////////////////////////////////////////// + llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs) { Logger::println("checking for offset %u type %s:", os, t->toChars()); @@ -1470,7 +1556,7 @@ llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, un bool DtoIsTemplateInstance(Dsymbol* s) { - assert(s); + if (!s) return false; if (s->isTemplateInstance() && !s->isTemplateMixin()) return true; else if (s->parent) diff --git a/gen/tollvm.h b/gen/tollvm.h index 353818a1..c7233ade 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -1,6 +1,10 @@ +#ifndef LLVMDC_GEN_TOLLVM_H +#define LLVMDC_GEN_TOLLVM_H + // D -> LLVM helpers struct StructInitializer; +struct DValue; const llvm::Type* DtoType(Type* t); bool DtoIsPassedByRef(Type* type); @@ -55,8 +59,6 @@ llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expressio llvm::Value* DtoNestedVariable(VarDeclaration* vd); -void DtoAssign(Type* lhsType, llvm::Value* lhs, llvm::Value* rhs); - llvm::ConstantInt* DtoConstSize_t(size_t); llvm::ConstantInt* DtoConstUint(unsigned i); llvm::ConstantInt* DtoConstInt(int i); @@ -64,10 +66,27 @@ llvm::Constant* DtoConstString(const char*); llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0); llvm::Constant* DtoConstBool(bool); -void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes); - llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector& idxs); bool DtoIsTemplateInstance(Dsymbol* s); +// llvm wrappers +void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes); +bool DtoCanLoad(llvm::Value* ptr); +llvm::Value* DtoLoad(llvm::Value* src); +void DtoStore(llvm::Value* src, llvm::Value* dst); +llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t); + +// basic operations +void DtoAssign(DValue* lhs, DValue* rhs); + +// binary operations +DValue* DtoBinAdd(DValue* lhs, DValue* rhs); +DValue* DtoBinSub(DValue* lhs, DValue* rhs); +DValue* DtoBinMul(DValue* lhs, DValue* rhs); +DValue* DtoBinDiv(DValue* lhs, DValue* rhs); +DValue* DtoBinRem(DValue* lhs, DValue* rhs); + #include "enums.h" + +#endif // LLVMDC_GEN_TOLLVM_H diff --git a/gen/toobj.c b/gen/toobj.cpp similarity index 95% rename from gen/toobj.c rename to gen/toobj.cpp index cf043a8b..1d6b96d1 100644 --- a/gen/toobj.c +++ b/gen/toobj.cpp @@ -37,6 +37,7 @@ #include "gen/tollvm.h" #include "gen/arrays.h" #include "gen/todebug.h" +#include "gen/runtime.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -628,8 +629,11 @@ void VarDeclaration::toObjFile() gIR->ir->CreateCondBr(cond, initbb, endinitbb); gIR->scope() = IRScope(initbb,endinitbb); elem* ie = DtoInitializer(init); - if (!ie->inplace) - DtoAssign(t, gvar, ie->getValue()); + 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); @@ -754,6 +758,13 @@ void FuncDeclaration::toObjFile() return; } + if (llvmRunTimeHack) { + Logger::println("runtime hack func chars: %s", toChars()); + if (!llvmValue) + llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars()); + return; + } + if (isUnitTestDeclaration()) { Logger::println("*** ATTENTION: ignoring unittest declaration: %s", toChars()); return; @@ -763,6 +774,8 @@ void FuncDeclaration::toObjFile() TypeFunction* f = (TypeFunction*)t; bool declareOnly = false; + if (parent) + { if (TemplateInstance* tinst = parent->isTemplateInstance()) { TemplateDeclaration* tempdecl = tinst->tempdecl; if (tempdecl->llvmInternal == LLVMva_start) @@ -778,6 +791,7 @@ void FuncDeclaration::toObjFile() return; } } + } llvm::Function* func = DtoDeclareFunction(this); @@ -802,8 +816,7 @@ void FuncDeclaration::toObjFile() const llvm::FunctionType* functype = llvm::cast(llvmValue->getType()->getContainedType(0)); // template instances should have weak linkage - assert(parent); - if (DtoIsTemplateInstance(parent)) { + if (parent && DtoIsTemplateInstance(parent)) { func->setLinkage(llvm::GlobalValue::WeakLinkage); } diff --git a/gen/typinf.c b/gen/typinf.cpp similarity index 100% rename from gen/typinf.c rename to gen/typinf.cpp diff --git a/lphobos/build.sh b/lphobos/build.sh index 0b38812c..dd41a418 100755 --- a/lphobos/build.sh +++ b/lphobos/build.sh @@ -12,7 +12,7 @@ echo "compiling common runtime" rebuild internal/arrays.d \ internal/mem.d \ internal/moduleinit.d \ - -c -oqobj -dc=llvmdc-posix || exit 1 + -c -oqobj -dc=llvmdc-posix -explicit || exit 1 echo "compiling module init backend" llvm-as -f -o=obj/moduleinit_backend.bc internal/moduleinit_backend.ll || exit 1 @@ -30,18 +30,21 @@ echo "compiling typeinfo 2" rebuild typeinfos2.d -c -oqobj -dc=llvmdc-posix || exit 1 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo2.*.bc` ../lib/llvmdcore.bc || exit 1 +echo "compiling string foreach runtime support" +llvmdc internal/aApply.d -c -odobj || exit 1 +llvmdc internal/aApplyR.d -c -odobj || exit 1 +llvm-link -f -o=../lib/llvmdcore.bc obj/aApply.bc obj/aApplyR.bc ../lib/llvmdcore.bc || exit 1 echo "compiling llvm runtime support" rebuild llvmsupport.d -c -oqobj -dc=llvmdc-posix || exit llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1 +echo "compiling phobos" +rebuild phobos.d -c -oqobj -dc=llvmdc-posix || exit 1 +llvm-link -f -o=../lib/llvmdcore.bc `ls obj/std.*.bc` ../lib/llvmdcore.bc || exit 1 + echo "optimizing" opt -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1 -# build phobos -echo "compiling phobos" -rebuild phobos.d -c -oqobj -dc=llvmdc-posix || exit 1 -llvm-link -f -o=../lib/lphobos.bc `ls obj/std.*.bc` || exit 1 -opt -f -std-compile-opts -o=../lib/lphobos.bc ../lib/lphobos.bc || exit 1 echo "SUCCESS" diff --git a/lphobos/internal/aApply.d b/lphobos/internal/aApply.d new file mode 100644 index 00000000..019b4781 --- /dev/null +++ b/lphobos/internal/aApply.d @@ -0,0 +1,410 @@ + +/** + * Part of the D programming language runtime library. + */ + +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* This code handles decoding UTF strings for foreach loops. + * There are 6 combinations of conversions between char, wchar, + * and dchar, and 2 of each of those. + */ + +import std.utf; + +//debug=apply; + +/********************************************** + */ + +// dg is D, but _aApplycd() is C +extern (D) typedef int delegate(void *) dg_t; + +extern (C) int _aApplycd1(char[] aa, dg_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplycd1(), len = %d\n", len); + for (i = 0; i < len; ) + { dchar d; + + d = aa[i]; + if (d & 0x80) + d = std.utf.decode(aa, i); + else + i++; + result = dg(cast(void *)&d); + if (result) + break; + } + return result; +} + +extern (C) int _aApplywd1(wchar[] aa, dg_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplywd1(), len = %d\n", len); + for (i = 0; i < len; ) + { dchar d; + + d = aa[i]; + if (d & ~0x7F) + d = std.utf.decode(aa, i); + else + i++; + result = dg(cast(void *)&d); + if (result) + break; + } + return result; +} + +extern (C) int _aApplycw1(char[] aa, dg_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplycw1(), len = %d\n", len); + for (i = 0; i < len; ) + { dchar d; + wchar w; + + w = aa[i]; + if (w & 0x80) + { d = std.utf.decode(aa, i); + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(cast(void *)&w); + if (result) + break; + w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00); + } + } + else + i++; + result = dg(cast(void *)&w); + if (result) + break; + } + return result; +} + +extern (C) int _aApplywc1(wchar[] aa, dg_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplywc1(), len = %d\n", len); + for (i = 0; i < len; ) + { dchar d; + wchar w; + char c; + + w = aa[i]; + if (w & ~0x7F) + { + char[4] buf; + char[] b; + + d = std.utf.decode(aa, i); + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { c = cast(char)w; + i++; + } + result = dg(cast(void *)&c); + if (result) + break; + } + return result; +} + +extern (C) int _aApplydc1(dchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplydc1(), len = %d\n", aa.length); + foreach (dchar d; aa) + { + char c; + + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { + c = cast(char)d; + } + result = dg(cast(void *)&c); + if (result) + break; + } + return result; +} + +extern (C) int _aApplydw1(dchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplydw1(), len = %d\n", aa.length); + foreach (dchar d; aa) + { + wchar w; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(cast(void *)&w); + if (result) + break; + w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00); + } + result = dg(cast(void *)&w); + if (result) + break; + } + return result; +} + + +/****************************************************************************/ + +// dg is D, but _aApplycd2() is C +extern (D) typedef int delegate(void *, void *) dg2_t; + +extern (C) int _aApplycd2(char[] aa, dg2_t dg) +{ int result; + size_t i; + size_t n; + size_t len = aa.length; + + debug(apply) printf("_aApplycd2(), len = %d\n", len); + for (i = 0; i < len; i += n) + { dchar d; + + d = aa[i]; + if (d & 0x80) + { + n = i; + d = std.utf.decode(aa, n); + n -= i; + } + else + n = 1; + result = dg(&i, cast(void *)&d); + if (result) + break; + } + return result; +} + +extern (C) int _aApplywd2(wchar[] aa, dg2_t dg) +{ int result; + size_t i; + size_t n; + size_t len = aa.length; + + debug(apply) printf("_aApplywd2(), len = %d\n", len); + for (i = 0; i < len; i += n) + { dchar d; + + d = aa[i]; + if (d & ~0x7F) + { + n = i; + d = std.utf.decode(aa, n); + n -= i; + } + else + n = 1; + result = dg(&i, cast(void *)&d); + if (result) + break; + } + return result; +} + +extern (C) int _aApplycw2(char[] aa, dg2_t dg) +{ int result; + size_t i; + size_t n; + size_t len = aa.length; + + debug(apply) printf("_aApplycw2(), len = %d\n", len); + for (i = 0; i < len; i += n) + { dchar d; + wchar w; + + w = aa[i]; + if (w & 0x80) + { n = i; + d = std.utf.decode(aa, n); + n -= i; + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(&i, cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + } + else + n = 1; + result = dg(&i, cast(void *)&w); + if (result) + break; + } + return result; +} + +extern (C) int _aApplywc2(wchar[] aa, dg2_t dg) +{ int result; + size_t i; + size_t n; + size_t len = aa.length; + + debug(apply) printf("_aApplywc2(), len = %d\n", len); + for (i = 0; i < len; i += n) + { dchar d; + wchar w; + char c; + + w = aa[i]; + if (w & ~0x7F) + { + char[4] buf; + char[] b; + + n = i; + d = std.utf.decode(aa, n); + n -= i; + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(&i, cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { c = cast(char)w; + n = 1; + } + result = dg(&i, cast(void *)&c); + if (result) + break; + } + return result; +} + +extern (C) int _aApplydc2(dchar[] aa, dg2_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplydc2(), len = %d\n", len); + for (i = 0; i < len; i++) + { dchar d; + char c; + + d = aa[i]; + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(&i, cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { c = cast(char)d; + } + result = dg(&i, cast(void *)&c); + if (result) + break; + } + return result; +} + +extern (C) int _aApplydw2(dchar[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplydw2(), len = %d\n", aa.length); + foreach (size_t i, dchar d; aa) + { + wchar w; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(&i, cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + result = dg(&i, cast(void *)&w); + if (result) + break; + } + return result; +} + + diff --git a/lphobos/internal/aApplyR.d b/lphobos/internal/aApplyR.d new file mode 100644 index 00000000..c419ab84 --- /dev/null +++ b/lphobos/internal/aApplyR.d @@ -0,0 +1,977 @@ + +/** + * Part of the D programming language runtime library. + */ + +/* + * Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* This code handles decoding UTF strings for foreach_reverse loops. + * There are 6 combinations of conversions between char, wchar, + * and dchar, and 2 of each of those. + */ + +import std.utf; + +//debug=apply; + +/**********************************************/ +/* 1 argument versions */ + +// dg is D, but _aApplyRcd() is C +extern (D) typedef int delegate(void *) dg_t; + +extern (C) int _aApplyRcd1(char[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + + i--; + d = aa[i]; + if (d & 0x80) + { char c = cast(char)d; + uint j; + uint m = 0x3F; + d = 0; + while ((c & 0xC0) != 0xC0) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-8 sequence", 0); + i--; + d |= (c & 0x3F) << j; + j += 6; + m >>= 1; + c = aa[i]; + } + d |= (c & m) << j; + } + result = dg(cast(void *)&d); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRcd1.unittest\n"); + + char[] s = "hello"; + int i; + + foreach_reverse(dchar d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(dchar d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == '\U00100456'); break; + case 2: assert(d == '\u1234'); break; + case 3: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 4); +} + +/*****************************/ + +extern (C) int _aApplyRwd1(wchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + + i--; + d = aa[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-16 sequence", 0); + i--; + d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); + } + result = dg(cast(void *)&d); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRwd1.unittest\n"); + + wchar[] s = "hello"; + int i; + + foreach_reverse(dchar d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(dchar d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == '\U00100456'); break; + case 2: assert(d == '\u1234'); break; + case 3: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 4); +} + +/*****************************/ + +extern (C) int _aApplyRcw1(char[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + wchar w; + + i--; + w = aa[i]; + if (w & 0x80) + { char c = cast(char)w; + uint j; + uint m = 0x3F; + d = 0; + while ((c & 0xC0) != 0xC0) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-8 sequence", 0); + i--; + d |= (c & 0x3F) << j; + j += 6; + m >>= 1; + c = aa[i]; + } + d |= (c & m) << j; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + } + result = dg(cast(void *)&w); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRcw1.unittest\n"); + + char[] s = "hello"; + int i; + + foreach_reverse(wchar d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(wchar d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == 0xDBC1); break; + case 2: assert(d == 0xDC56); break; + case 3: assert(d == 0x1234); break; + case 4: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 5); +} + +/*****************************/ + +extern (C) int _aApplyRwc1(wchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + char c; + + i--; + d = aa[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-16 sequence", 0); + i--; + d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); + } + + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(cast(void *)&c2); + if (result) + return result; + } + continue; + } + c = cast(char)d; + result = dg(cast(void *)&c); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRwc1.unittest\n"); + + wchar[] s = "hello"; + int i; + + foreach_reverse(char d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(char d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == 0xF4); break; + case 2: assert(d == 0x80); break; + case 3: assert(d == 0x91); break; + case 4: assert(d == 0x96); break; + case 5: assert(d == 0xE1); break; + case 6: assert(d == 0x88); break; + case 7: assert(d == 0xB4); break; + case 8: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 9); +} + +/*****************************/ + +extern (C) int _aApplyRdc1(dchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0;) + { dchar d = aa[--i]; + char c; + + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { + c = cast(char)d; + } + result = dg(cast(void *)&c); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRdc1.unittest\n"); + + dchar[] s = "hello"; + int i; + + foreach_reverse(char d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(char d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == 0xF4); break; + case 2: assert(d == 0x80); break; + case 3: assert(d == 0x91); break; + case 4: assert(d == 0x96); break; + case 5: assert(d == 0xE1); break; + case 6: assert(d == 0x88); break; + case 7: assert(d == 0xB4); break; + case 8: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 9); +} + +/*****************************/ + +extern (C) int _aApplyRdw1(dchar[] aa, dg_t dg) +{ int result; + + debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d = aa[--i]; + wchar w; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + result = dg(cast(void *)&w); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRdw1.unittest\n"); + + dchar[] s = "hello"; + int i; + + foreach_reverse(wchar d; s) + { + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(wchar d; s) + { + //printf("i = %d, d = %x\n", i, d); + switch (i) + { + case 0: assert(d == 'b'); break; + case 1: assert(d == 0xDBC1); break; + case 2: assert(d == 0xDC56); break; + case 3: assert(d == 0x1234); break; + case 4: assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 5); +} + + +/****************************************************************************/ +/* 2 argument versions */ + +// dg is D, but _aApplyRcd2() is C +extern (D) typedef int delegate(void *, void *) dg2_t; + +extern (C) int _aApplyRcd2(char[] aa, dg2_t dg) +{ int result; + size_t i; + size_t len = aa.length; + + debug(apply) printf("_aApplyRcd2(), len = %d\n", len); + for (i = len; i != 0; ) + { dchar d; + + i--; + d = aa[i]; + if (d & 0x80) + { char c = cast(char)d; + uint j; + uint m = 0x3F; + d = 0; + while ((c & 0xC0) != 0xC0) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-8 sequence", 0); + i--; + d |= (c & 0x3F) << j; + j += 6; + m >>= 1; + c = aa[i]; + } + d |= (c & m) << j; + } + result = dg(&i, cast(void *)&d); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRcd2.unittest\n"); + + char[] s = "hello"; + int i; + + foreach_reverse(k, dchar d; s) + { + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, dchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(d == 'b'); assert(k == 8); break; + case 1: assert(d == '\U00100456'); assert(k == 4); break; + case 2: assert(d == '\u1234'); assert(k == 1); break; + case 3: assert(d == 'a'); assert(k == 0); break; + default: assert(0); + } + i++; + } + assert(i == 4); +} + +/*****************************/ + +extern (C) int _aApplyRwd2(wchar[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + + i--; + d = aa[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-16 sequence", 0); + i--; + d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); + } + result = dg(&i, cast(void *)&d); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRwd2.unittest\n"); + + wchar[] s = "hello"; + int i; + + foreach_reverse(k, dchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, dchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(k == 4); assert(d == 'b'); break; + case 1: assert(k == 2); assert(d == '\U00100456'); break; + case 2: assert(k == 1); assert(d == '\u1234'); break; + case 3: assert(k == 0); assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 4); +} + +/*****************************/ + +extern (C) int _aApplyRcw2(char[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + wchar w; + + i--; + w = aa[i]; + if (w & 0x80) + { char c = cast(char)w; + uint j; + uint m = 0x3F; + d = 0; + while ((c & 0xC0) != 0xC0) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-8 sequence", 0); + i--; + d |= (c & 0x3F) << j; + j += 6; + m >>= 1; + c = aa[i]; + } + d |= (c & m) << j; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(&i, cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + } + result = dg(&i, cast(void *)&w); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRcw2.unittest\n"); + + char[] s = "hello"; + int i; + + foreach_reverse(k, wchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, wchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(k == 8); assert(d == 'b'); break; + case 1: assert(k == 4); assert(d == 0xDBC1); break; + case 2: assert(k == 4); assert(d == 0xDC56); break; + case 3: assert(k == 1); assert(d == 0x1234); break; + case 4: assert(k == 0); assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 5); +} + +/*****************************/ + +extern (C) int _aApplyRwc2(wchar[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d; + char c; + + i--; + d = aa[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { if (i == 0) + throw new std.utf.UtfException("Invalid UTF-16 sequence", 0); + i--; + d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); + } + + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(&i, cast(void *)&c2); + if (result) + return result; + } + continue; + } + c = cast(char)d; + result = dg(&i, cast(void *)&c); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRwc2.unittest\n"); + + wchar[] s = "hello"; + int i; + + foreach_reverse(k, char d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, char d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(k == 4); assert(d == 'b'); break; + case 1: assert(k == 2); assert(d == 0xF4); break; + case 2: assert(k == 2); assert(d == 0x80); break; + case 3: assert(k == 2); assert(d == 0x91); break; + case 4: assert(k == 2); assert(d == 0x96); break; + case 5: assert(k == 1); assert(d == 0xE1); break; + case 6: assert(k == 1); assert(d == 0x88); break; + case 7: assert(k == 1); assert(d == 0xB4); break; + case 8: assert(k == 0); assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 9); +} + +/*****************************/ + +extern (C) int _aApplyRdc2(dchar[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d = aa[--i]; + char c; + + if (d & ~0x7F) + { + char[4] buf; + char[] b; + + b = std.utf.toUTF8(buf, d); + foreach (char c2; b) + { + result = dg(&i, cast(void *)&c2); + if (result) + return result; + } + continue; + } + else + { c = cast(char)d; + } + result = dg(&i, cast(void *)&c); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRdc2.unittest\n"); + + dchar[] s = "hello"; + int i; + + foreach_reverse(k, char d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, char d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(k == 3); assert(d == 'b'); break; + case 1: assert(k == 2); assert(d == 0xF4); break; + case 2: assert(k == 2); assert(d == 0x80); break; + case 3: assert(k == 2); assert(d == 0x91); break; + case 4: assert(k == 2); assert(d == 0x96); break; + case 5: assert(k == 1); assert(d == 0xE1); break; + case 6: assert(k == 1); assert(d == 0x88); break; + case 7: assert(k == 1); assert(d == 0xB4); break; + case 8: assert(k == 0); assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 9); +} + +/*****************************/ + +extern (C) int _aApplyRdw2(dchar[] aa, dg2_t dg) +{ int result; + + debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length); + for (size_t i = aa.length; i != 0; ) + { dchar d = aa[--i]; + wchar w; + + if (d <= 0xFFFF) + w = cast(wchar) d; + else + { + w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); + result = dg(&i, cast(void *)&w); + if (result) + break; + w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); + } + result = dg(&i, cast(void *)&w); + if (result) + break; + } + return result; +} + +unittest +{ + debug(apply) printf("_aApplyRdw2.unittest\n"); + + dchar[] s = "hello"; + int i; + + foreach_reverse(k, wchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + assert(k == 4 - i); + switch (i) + { + case 0: assert(d == 'o'); break; + case 1: assert(d == 'l'); break; + case 2: assert(d == 'l'); break; + case 3: assert(d == 'e'); break; + case 4: assert(d == 'h'); break; + default: assert(0); + } + i++; + } + assert(i == 5); + + s = "a\u1234\U00100456b"; + i = 0; + foreach_reverse(k, wchar d; s) + { + //printf("i = %d, k = %d, d = %x\n", i, k, d); + switch (i) + { + case 0: assert(k == 3); assert(d == 'b'); break; + case 1: assert(k == 2); assert(d == 0xDBC1); break; + case 2: assert(k == 2); assert(d == 0xDC56); break; + case 3: assert(k == 1); assert(d == 0x1234); break; + case 4: assert(k == 0); assert(d == 'a'); break; + default: assert(0); + } + i++; + } + assert(i == 5); +} + + diff --git a/lphobos/internal/objectimpl.d b/lphobos/internal/objectimpl.d index f63b23ab..b0f762d9 100644 --- a/lphobos/internal/objectimpl.d +++ b/lphobos/internal/objectimpl.d @@ -1135,6 +1135,12 @@ class Exception : Object this.msg = msg; } + void print() + { + char[] s = toString(); + printf("%.*s\n", s.length, s.ptr); + } + char[] toString() { return msg; } } diff --git a/lphobos/phobos.d b/lphobos/phobos.d index 2767647e..7dfd2dda 100644 --- a/lphobos/phobos.d +++ b/lphobos/phobos.d @@ -1,5 +1,9 @@ module phobos; import +std.array, +std.ctype, std.stdio, -std.stdarg; +std.stdarg, +std.uni, +std.utf; \ No newline at end of file diff --git a/lphobos/std/array.d b/lphobos/std/array.d new file mode 100644 index 00000000..c3af5e44 --- /dev/null +++ b/lphobos/std/array.d @@ -0,0 +1,38 @@ + +module std.array; + +private import std.c.stdio; + +class ArrayBoundsError : Error +{ + private: + + uint linnum; + char[] filename; + + public: + this(char[] filename, uint linnum) + { + this.linnum = linnum; + this.filename = filename; + + char[] buffer = new char[19 + filename.length + linnum.sizeof * 3 + 1]; + int len; + len = sprintf(buffer.ptr, "ArrayBoundsError %.*s(%u)", filename, linnum); + super(buffer[0..len]); + } +} + + +/******************************************** + * Called by the compiler generated module assert function. + * Builds an ArrayBoundsError exception and throws it. + */ + +extern (C) static void _d_array_bounds(char[] filename, uint line) +{ + //printf("_d_assert(%s, %d)\n", (char *)filename, line); + ArrayBoundsError a = new ArrayBoundsError(filename, line); + //printf("assertion %p created\n", a); + throw a; +} diff --git a/lphobos/std/ctype.d b/lphobos/std/ctype.d new file mode 100644 index 00000000..6335e950 --- /dev/null +++ b/lphobos/std/ctype.d @@ -0,0 +1,154 @@ +/* + * Placed into the Public Domain. + * Digital Mars, www.digitalmars.com + * Written by Walter Bright + */ + +/** + * Simple ASCII character classification functions. + * For Unicode classification, see $(LINK2 std_uni.html, std.uni). + * References: + * $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table), + * $(LINK2 http://en.wikipedia.org/wiki/Ascii, Wikipedia) + * Macros: + * WIKI=Phobos/StdCtype + */ + +module std.ctype; + +/** + * Returns !=0 if c is a letter in the range (0..9, a..z, A..Z). + */ +int isalnum(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; } + +/** + * Returns !=0 if c is an ascii upper or lower case letter. + */ +int isalpha(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP) : 0; } + +/** + * Returns !=0 if c is a control character. + */ +int iscntrl(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_CTL) : 0; } + +/** + * Returns !=0 if c is a digit. + */ +int isdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_DIG) : 0; } + +/** + * Returns !=0 if c is lower case ascii letter. + */ +int islower(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_LC) : 0; } + +/** + * Returns !=0 if c is a punctuation character. + */ +int ispunct(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_PNC) : 0; } + +/** + * Returns !=0 if c is a space, tab, vertical tab, form feed, + * carriage return, or linefeed. + */ +int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; } + +/** + * Returns !=0 if c is an upper case ascii character. + */ +int isupper(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_UC) : 0; } + +/** + * Returns !=0 if c is a hex digit (0..9, a..f, A..F). + */ +int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX) : 0; } + +/** + * Returns !=0 if c is a printing character except for the space character. + */ +int isgraph(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; } + +/** + * Returns !=0 if c is a printing character including the space character. + */ +int isprint(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; } + +/** + * Returns !=0 if c is in the ascii character set, i.e. in the range 0..0x7F. + */ +int isascii(dchar c) { return c <= 0x7F; } + + +/** + * If c is an upper case ascii character, + * return the lower case equivalent, otherwise return c. + */ +dchar tolower(dchar c) + out (result) + { + assert(!isupper(result)); + } + body + { + return isupper(c) ? c + (cast(dchar)'a' - 'A') : c; + } + + +/** + * If c is a lower case ascii character, + * return the upper case equivalent, otherwise return c. + */ +dchar toupper(dchar c) + out (result) + { + assert(!islower(result)); + } + body + { + return islower(c) ? c - (cast(dchar)'a' - 'A') : c; + } + +private: + +enum +{ + _SPC = 8, + _CTL = 0x20, + _BLK = 0x40, + _HEX = 0x80, + _UC = 1, + _LC = 2, + _PNC = 0x10, + _DIG = 4, + _ALP = _UC|_LC, +} + +ubyte _ctype[128] = +[ + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL +]; + + +unittest +{ + assert(isspace(' ')); + assert(!isspace('z')); + assert(toupper('a') == 'A'); + assert(tolower('Q') == 'q'); + assert(!isxdigit('G')); +} diff --git a/lphobos/std/uni.d b/lphobos/std/uni.d new file mode 100644 index 00000000..e4ce1e5d --- /dev/null +++ b/lphobos/std/uni.d @@ -0,0 +1,630 @@ + +// Written in the D programming language. + +/* + * Placed into the Public Domain. + * Digital Mars, www.digitalmars.com + * Written by Walter Bright + */ + +/** + * Simple Unicode character classification functions. + * For ASCII classification, see $(LINK2 std_ctype.html, std.ctype). + * Macros: + * WIKI=Phobos/StdUni + * References: + * $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table), + * $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia), + * $(LINK2 http://www.unicode.org, The Unicode Consortium) + * Trademarks: + * Unicode(tm) is a trademark of Unicode, Inc. + */ + + +module std.uni; + +/** + * Returns !=0 if c is a Unicode lower case character. + */ +int isUniLower(dchar c) +{ + if (c <= 0x7F) + return (c >= 'a' && c <= 'z'); + + return isUniAlpha(c) && c == toUniLower(c); +} + +/** + * Returns !=0 if c is a Unicode upper case character. + */ +int isUniUpper(dchar c) +{ + if (c <= 0x7F) + return (c >= 'A' && c <= 'Z'); + + return isUniAlpha(c) && c == toUniUpper(c); +} + +/** + * If c is a Unicode upper case character, return the lower case + * equivalent, otherwise return c. + */ +dchar toUniLower(dchar c) +{ + if (c >= 'A' && c <= 'Z') + { + c += 32; + } + else if (c >= 0x00C0) + { + if ((c >= 0x00C0 && c <= 0x00D6) || (c >= 0x00D8 && c<=0x00DE)) + { + c += 32; + } + else if ((c >= 0x0100 && c < 0x0138) || (c > 0x0149 && c < 0x0178)) + { + if (c == 0x0130) + c = 0x0069; + else if ((c & 1) == 0) + c += 1; + } + else if (c == 0x0178) + { + c = 0x00FF; + } + else if ((c >= 0x0139 && c < 0x0149) || (c > 0x0178 && c < 0x017F)) + { + if (c & 1) + c += 1; + } + else if (c >= 0x0200 && c <= 0x0217) + { + if ((c & 1) == 0) + c += 1; + } + else if ((c >= 0x0401 && c <= 0x040C) || (c>= 0x040E && c <= 0x040F)) + { + c += 80; + } + else if (c >= 0x0410 && c <= 0x042F) + { + c += 32; + } + else if (c >= 0x0460 && c <= 0x047F) + { + if ((c & 1) == 0) + c += 1; + } + else if (c >= 0x0531 && c <= 0x0556) + { + c += 48; + } + else if (c >= 0x10A0 && c <= 0x10C5) + { + c += 48; + } + else if (c >= 0xFF21 && c <= 0xFF3A) + { + c += 32; + } + } + return c; +} + +/** + * If c is a Unicode lower case character, return the upper case + * equivalent, otherwise return c. + */ +dchar toUniUpper(dchar c) +{ + if (c >= 'a' && c <= 'z') + { + c -= 32; + } + else if (c >= 0x00E0) + { + if ((c >= 0x00E0 && c <= 0x00F6) || (c >= 0x00F8 && c <= 0x00FE)) + { + c -= 32; + } + else if (c == 0x00FF) + { + c = 0x0178; + } + else if ((c >= 0x0100 && c < 0x0138) || (c > 0x0149 && c < 0x0178)) + { + if (c == 0x0131) + c = 0x0049; + else if (c & 1) + c -= 1; + } + else if ((c >= 0x0139 && c < 0x0149) || (c > 0x0178 && c < 0x017F)) + { + if ((c & 1) == 0) + c = c-1; + } + else if (c == 0x017F) + { + c = 0x0053; + } + else if (c >= 0x0200 && c <= 0x0217) + { + if (c & 1) + c = c-1; + } + else if (c >= 0x0430 && c<= 0x044F) + { + c -= 32; + } + else if ((c >= 0x0451 && c <= 0x045C) || (c >=0x045E && c<= 0x045F)) + { + c -= 80; + } + else if (c >= 0x0460 && c <= 0x047F) + { + if (c & 1) + c -= 1; + } + else if (c >= 0x0561 && c < 0x0587) + { + c -= 48; + } + else if (c >= 0xFF41 && c <= 0xFF5A) + { + c -= 32; + } + } + return c; +} + + +/******************************* + * Return !=0 if u is a Unicode alpha character. + * (general Unicode category: Lu, Ll, Lt, Lm and Lo) + * + * Standards: Unicode 5.0.0 + */ + +int isUniAlpha(dchar u) +{ + static dchar table[][2] = + [ + [ 'A', 'Z' ], + [ 'a', 'z' ], + [ 0x00AA, 0x00AA ], + [ 0x00B5, 0x00B5 ], + [ 0x00BA, 0x00BA ], + [ 0x00C0, 0x00D6 ], + [ 0x00D8, 0x00F6 ], + [ 0x00F8, 0x02C1 ], + [ 0x02C6, 0x02D1 ], + [ 0x02E0, 0x02E4 ], + [ 0x02EE, 0x02EE ], + [ 0x037A, 0x037D ], + [ 0x0386, 0x0386 ], + [ 0x0388, 0x038A ], + [ 0x038C, 0x038C ], + [ 0x038E, 0x03A1 ], + [ 0x03A3, 0x03CE ], + [ 0x03D0, 0x03F5 ], + [ 0x03F7, 0x0481 ], + [ 0x048A, 0x0513 ], + [ 0x0531, 0x0556 ], + [ 0x0559, 0x0559 ], + [ 0x0561, 0x0587 ], + [ 0x05D0, 0x05EA ], + [ 0x05F0, 0x05F2 ], + [ 0x0621, 0x063A ], + [ 0x0640, 0x064A ], + [ 0x066E, 0x066F ], + [ 0x0671, 0x06D3 ], + [ 0x06D5, 0x06D5 ], + [ 0x06E5, 0x06E6 ], + [ 0x06EE, 0x06EF ], + [ 0x06FA, 0x06FC ], + [ 0x06FF, 0x06FF ], + [ 0x0710, 0x0710 ], + [ 0x0712, 0x072F ], + [ 0x074D, 0x076D ], + [ 0x0780, 0x07A5 ], + [ 0x07B1, 0x07B1 ], + [ 0x07CA, 0x07EA ], + [ 0x07F4, 0x07F5 ], + [ 0x07FA, 0x07FA ], + [ 0x0904, 0x0939 ], + [ 0x093D, 0x093D ], + [ 0x0950, 0x0950 ], + [ 0x0958, 0x0961 ], + [ 0x097B, 0x097F ], + [ 0x0985, 0x098C ], + [ 0x098F, 0x0990 ], + [ 0x0993, 0x09A8 ], + [ 0x09AA, 0x09B0 ], + [ 0x09B2, 0x09B2 ], + [ 0x09B6, 0x09B9 ], + [ 0x09BD, 0x09BD ], + [ 0x09CE, 0x09CE ], + [ 0x09DC, 0x09DD ], + [ 0x09DF, 0x09E1 ], + [ 0x09F0, 0x09F1 ], + [ 0x0A05, 0x0A0A ], + [ 0x0A0F, 0x0A10 ], + [ 0x0A13, 0x0A28 ], + [ 0x0A2A, 0x0A30 ], + [ 0x0A32, 0x0A33 ], + [ 0x0A35, 0x0A36 ], + [ 0x0A38, 0x0A39 ], + [ 0x0A59, 0x0A5C ], + [ 0x0A5E, 0x0A5E ], + [ 0x0A72, 0x0A74 ], + [ 0x0A85, 0x0A8D ], + [ 0x0A8F, 0x0A91 ], + [ 0x0A93, 0x0AA8 ], + [ 0x0AAA, 0x0AB0 ], + [ 0x0AB2, 0x0AB3 ], + [ 0x0AB5, 0x0AB9 ], + [ 0x0ABD, 0x0ABD ], + [ 0x0AD0, 0x0AD0 ], + [ 0x0AE0, 0x0AE1 ], + [ 0x0B05, 0x0B0C ], + [ 0x0B0F, 0x0B10 ], + [ 0x0B13, 0x0B28 ], + [ 0x0B2A, 0x0B30 ], + [ 0x0B32, 0x0B33 ], + [ 0x0B35, 0x0B39 ], + [ 0x0B3D, 0x0B3D ], + [ 0x0B5C, 0x0B5D ], + [ 0x0B5F, 0x0B61 ], + [ 0x0B71, 0x0B71 ], + [ 0x0B83, 0x0B83 ], + [ 0x0B85, 0x0B8A ], + [ 0x0B8E, 0x0B90 ], + [ 0x0B92, 0x0B95 ], + [ 0x0B99, 0x0B9A ], + [ 0x0B9C, 0x0B9C ], + [ 0x0B9E, 0x0B9F ], + [ 0x0BA3, 0x0BA4 ], + [ 0x0BA8, 0x0BAA ], + [ 0x0BAE, 0x0BB9 ], + [ 0x0C05, 0x0C0C ], + [ 0x0C0E, 0x0C10 ], + [ 0x0C12, 0x0C28 ], + [ 0x0C2A, 0x0C33 ], + [ 0x0C35, 0x0C39 ], + [ 0x0C60, 0x0C61 ], + [ 0x0C85, 0x0C8C ], + [ 0x0C8E, 0x0C90 ], + [ 0x0C92, 0x0CA8 ], + [ 0x0CAA, 0x0CB3 ], + [ 0x0CB5, 0x0CB9 ], + [ 0x0CBD, 0x0CBD ], + [ 0x0CDE, 0x0CDE ], + [ 0x0CE0, 0x0CE1 ], + [ 0x0D05, 0x0D0C ], + [ 0x0D0E, 0x0D10 ], + [ 0x0D12, 0x0D28 ], + [ 0x0D2A, 0x0D39 ], + [ 0x0D60, 0x0D61 ], + [ 0x0D85, 0x0D96 ], + [ 0x0D9A, 0x0DB1 ], + [ 0x0DB3, 0x0DBB ], + [ 0x0DBD, 0x0DBD ], + [ 0x0DC0, 0x0DC6 ], + [ 0x0E01, 0x0E30 ], + [ 0x0E32, 0x0E33 ], + [ 0x0E40, 0x0E46 ], + [ 0x0E81, 0x0E82 ], + [ 0x0E84, 0x0E84 ], + [ 0x0E87, 0x0E88 ], + [ 0x0E8A, 0x0E8A ], + [ 0x0E8D, 0x0E8D ], + [ 0x0E94, 0x0E97 ], + [ 0x0E99, 0x0E9F ], + [ 0x0EA1, 0x0EA3 ], + [ 0x0EA5, 0x0EA5 ], + [ 0x0EA7, 0x0EA7 ], + [ 0x0EAA, 0x0EAB ], + [ 0x0EAD, 0x0EB0 ], + [ 0x0EB2, 0x0EB3 ], + [ 0x0EBD, 0x0EBD ], + [ 0x0EC0, 0x0EC4 ], + [ 0x0EC6, 0x0EC6 ], + [ 0x0EDC, 0x0EDD ], + [ 0x0F00, 0x0F00 ], + [ 0x0F40, 0x0F47 ], + [ 0x0F49, 0x0F6A ], + [ 0x0F88, 0x0F8B ], + [ 0x1000, 0x1021 ], + [ 0x1023, 0x1027 ], + [ 0x1029, 0x102A ], + [ 0x1050, 0x1055 ], + [ 0x10A0, 0x10C5 ], + [ 0x10D0, 0x10FA ], + [ 0x10FC, 0x10FC ], + [ 0x1100, 0x1159 ], + [ 0x115F, 0x11A2 ], + [ 0x11A8, 0x11F9 ], + [ 0x1200, 0x1248 ], + [ 0x124A, 0x124D ], + [ 0x1250, 0x1256 ], + [ 0x1258, 0x1258 ], + [ 0x125A, 0x125D ], + [ 0x1260, 0x1288 ], + [ 0x128A, 0x128D ], + [ 0x1290, 0x12B0 ], + [ 0x12B2, 0x12B5 ], + [ 0x12B8, 0x12BE ], + [ 0x12C0, 0x12C0 ], + [ 0x12C2, 0x12C5 ], + [ 0x12C8, 0x12D6 ], + [ 0x12D8, 0x1310 ], + [ 0x1312, 0x1315 ], + [ 0x1318, 0x135A ], + [ 0x1380, 0x138F ], + [ 0x13A0, 0x13F4 ], + [ 0x1401, 0x166C ], + [ 0x166F, 0x1676 ], + [ 0x1681, 0x169A ], + [ 0x16A0, 0x16EA ], + [ 0x1700, 0x170C ], + [ 0x170E, 0x1711 ], + [ 0x1720, 0x1731 ], + [ 0x1740, 0x1751 ], + [ 0x1760, 0x176C ], + [ 0x176E, 0x1770 ], + [ 0x1780, 0x17B3 ], + [ 0x17D7, 0x17D7 ], + [ 0x17DC, 0x17DC ], + [ 0x1820, 0x1877 ], + [ 0x1880, 0x18A8 ], + [ 0x1900, 0x191C ], + [ 0x1950, 0x196D ], + [ 0x1970, 0x1974 ], + [ 0x1980, 0x19A9 ], + [ 0x19C1, 0x19C7 ], + [ 0x1A00, 0x1A16 ], + [ 0x1B05, 0x1B33 ], + [ 0x1B45, 0x1B4B ], + [ 0x1D00, 0x1DBF ], + [ 0x1E00, 0x1E9B ], + [ 0x1EA0, 0x1EF9 ], + [ 0x1F00, 0x1F15 ], + [ 0x1F18, 0x1F1D ], + [ 0x1F20, 0x1F45 ], + [ 0x1F48, 0x1F4D ], + [ 0x1F50, 0x1F57 ], + [ 0x1F59, 0x1F59 ], + [ 0x1F5B, 0x1F5B ], + [ 0x1F5D, 0x1F5D ], + [ 0x1F5F, 0x1F7D ], + [ 0x1F80, 0x1FB4 ], + [ 0x1FB6, 0x1FBC ], + [ 0x1FBE, 0x1FBE ], + [ 0x1FC2, 0x1FC4 ], + [ 0x1FC6, 0x1FCC ], + [ 0x1FD0, 0x1FD3 ], + [ 0x1FD6, 0x1FDB ], + [ 0x1FE0, 0x1FEC ], + [ 0x1FF2, 0x1FF4 ], + [ 0x1FF6, 0x1FFC ], + [ 0x2071, 0x2071 ], + [ 0x207F, 0x207F ], + [ 0x2090, 0x2094 ], + [ 0x2102, 0x2102 ], + [ 0x2107, 0x2107 ], + [ 0x210A, 0x2113 ], + [ 0x2115, 0x2115 ], + [ 0x2119, 0x211D ], + [ 0x2124, 0x2124 ], + [ 0x2126, 0x2126 ], + [ 0x2128, 0x2128 ], + [ 0x212A, 0x212D ], + [ 0x212F, 0x2139 ], + [ 0x213C, 0x213F ], + [ 0x2145, 0x2149 ], + [ 0x214E, 0x214E ], + [ 0x2183, 0x2184 ], + [ 0x2C00, 0x2C2E ], + [ 0x2C30, 0x2C5E ], + [ 0x2C60, 0x2C6C ], + [ 0x2C74, 0x2C77 ], + [ 0x2C80, 0x2CE4 ], + [ 0x2D00, 0x2D25 ], + [ 0x2D30, 0x2D65 ], + [ 0x2D6F, 0x2D6F ], + [ 0x2D80, 0x2D96 ], + [ 0x2DA0, 0x2DA6 ], + [ 0x2DA8, 0x2DAE ], + [ 0x2DB0, 0x2DB6 ], + [ 0x2DB8, 0x2DBE ], + [ 0x2DC0, 0x2DC6 ], + [ 0x2DC8, 0x2DCE ], + [ 0x2DD0, 0x2DD6 ], + [ 0x2DD8, 0x2DDE ], + [ 0x3005, 0x3006 ], + [ 0x3031, 0x3035 ], + [ 0x303B, 0x303C ], + [ 0x3041, 0x3096 ], + [ 0x309D, 0x309F ], + [ 0x30A1, 0x30FA ], + [ 0x30FC, 0x30FF ], + [ 0x3105, 0x312C ], + [ 0x3131, 0x318E ], + [ 0x31A0, 0x31B7 ], + [ 0x31F0, 0x31FF ], + [ 0x3400, 0x4DB5 ], + [ 0x4E00, 0x9FBB ], + [ 0xA000, 0xA48C ], + [ 0xA717, 0xA71A ], + [ 0xA800, 0xA801 ], + [ 0xA803, 0xA805 ], + [ 0xA807, 0xA80A ], + [ 0xA80C, 0xA822 ], + [ 0xA840, 0xA873 ], + [ 0xAC00, 0xD7A3 ], + [ 0xF900, 0xFA2D ], + [ 0xFA30, 0xFA6A ], + [ 0xFA70, 0xFAD9 ], + [ 0xFB00, 0xFB06 ], + [ 0xFB13, 0xFB17 ], + [ 0xFB1D, 0xFB1D ], + [ 0xFB1F, 0xFB28 ], + [ 0xFB2A, 0xFB36 ], + [ 0xFB38, 0xFB3C ], + [ 0xFB3E, 0xFB3E ], + [ 0xFB40, 0xFB41 ], + [ 0xFB43, 0xFB44 ], + [ 0xFB46, 0xFBB1 ], + [ 0xFBD3, 0xFD3D ], + [ 0xFD50, 0xFD8F ], + [ 0xFD92, 0xFDC7 ], + [ 0xFDF0, 0xFDFB ], + [ 0xFE70, 0xFE74 ], + [ 0xFE76, 0xFEFC ], + [ 0xFF21, 0xFF3A ], + [ 0xFF41, 0xFF5A ], + [ 0xFF66, 0xFFBE ], + [ 0xFFC2, 0xFFC7 ], + [ 0xFFCA, 0xFFCF ], + [ 0xFFD2, 0xFFD7 ], + [ 0xFFDA, 0xFFDC ], + [ 0x10000, 0x1000B ], + [ 0x1000D, 0x10026 ], + [ 0x10028, 0x1003A ], + [ 0x1003C, 0x1003D ], + [ 0x1003F, 0x1004D ], + [ 0x10050, 0x1005D ], + [ 0x10080, 0x100FA ], + [ 0x10300, 0x1031E ], + [ 0x10330, 0x10340 ], + [ 0x10342, 0x10349 ], + [ 0x10380, 0x1039D ], + [ 0x103A0, 0x103C3 ], + [ 0x103C8, 0x103CF ], + [ 0x10400, 0x1049D ], + [ 0x10800, 0x10805 ], + [ 0x10808, 0x10808 ], + [ 0x1080A, 0x10835 ], + [ 0x10837, 0x10838 ], + [ 0x1083C, 0x1083C ], + [ 0x1083F, 0x1083F ], + [ 0x10900, 0x10915 ], + [ 0x10A00, 0x10A00 ], + [ 0x10A10, 0x10A13 ], + [ 0x10A15, 0x10A17 ], + [ 0x10A19, 0x10A33 ], + [ 0x12000, 0x1236E ], + [ 0x1D400, 0x1D454 ], + [ 0x1D456, 0x1D49C ], + [ 0x1D49E, 0x1D49F ], + [ 0x1D4A2, 0x1D4A2 ], + [ 0x1D4A5, 0x1D4A6 ], + [ 0x1D4A9, 0x1D4AC ], + [ 0x1D4AE, 0x1D4B9 ], + [ 0x1D4BB, 0x1D4BB ], + [ 0x1D4BD, 0x1D4C3 ], + [ 0x1D4C5, 0x1D505 ], + [ 0x1D507, 0x1D50A ], + [ 0x1D50D, 0x1D514 ], + [ 0x1D516, 0x1D51C ], + [ 0x1D51E, 0x1D539 ], + [ 0x1D53B, 0x1D53E ], + [ 0x1D540, 0x1D544 ], + [ 0x1D546, 0x1D546 ], + [ 0x1D54A, 0x1D550 ], + [ 0x1D552, 0x1D6A5 ], + [ 0x1D6A8, 0x1D6C0 ], + [ 0x1D6C2, 0x1D6DA ], + [ 0x1D6DC, 0x1D6FA ], + [ 0x1D6FC, 0x1D714 ], + [ 0x1D716, 0x1D734 ], + [ 0x1D736, 0x1D74E ], + [ 0x1D750, 0x1D76E ], + [ 0x1D770, 0x1D788 ], + [ 0x1D78A, 0x1D7A8 ], + [ 0x1D7AA, 0x1D7C2 ], + [ 0x1D7C4, 0x1D7CB ], + [ 0x20000, 0x2A6D6 ], + [ 0x2F800, 0x2FA1D ], + ]; + + debug + { + for (int i = 0; i < table.length; i++) + { + assert(table[i][0] <= table[i][1]); + if (i < table.length - 1) + { + if (table[i][1] >= table[i + 1][0]) + printf("table[%d][1] = x%x, table[%d][0] = x%x\n", i, table[i][1], i + 1, table[i + 1][0]); + assert(table[i][1] < table[i + 1][0]); + } + } + } + + if (u < 0xAA) + { + if (u < 'A') + goto Lisnot; + if (u <= 'Z') + goto Lis; + if (u < 'a') + goto Lisnot; + if (u <= 'z') + goto Lis; + goto Lisnot; + } + + // Binary search + uint mid; + uint low; + uint high; + + low = 0; + high = table.length - 1; + while (cast(int)low <= cast(int)high) + { + mid = (low + high) >> 1; + if (u < table[mid][0]) + high = mid - 1; + else if (u > table[mid][1]) + low = mid + 1; + else + goto Lis; + } + +Lisnot: + debug + { + for (int i = 0; i < table.length; i++) + { + assert(u < table[i][0] || u > table[i][1]); + } + } + return 0; + +Lis: + debug + { + for (int i = 0; i < table.length; i++) + { + if (u >= table[i][0] && u <= table[i][1]) + return 1; + } + assert(0); // should have been in table + } + return 1; +} + +unittest +{ + for (uint i = 0; i < 0x80; i++) + { + if (i >= 'A' && i <= 'Z') + assert(isUniAlpha(i)); + else if (i >= 'a' && i <= 'z') + assert(isUniAlpha(i)); + else + assert(!isUniAlpha(i)); + } +} diff --git a/lphobos/std/utf.d b/lphobos/std/utf.d new file mode 100644 index 00000000..6b82b0ea --- /dev/null +++ b/lphobos/std/utf.d @@ -0,0 +1,969 @@ +// utf.d + +/* + * Copyright (C) 2003-2004 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/******************************************** + * Encode and decode UTF-8, UTF-16 and UTF-32 strings. + * + * For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D + * wchar type. + * For linux systems, the C wchar_t type is UTF-32 and corresponds to + * the D utf.dchar type. + * + * UTF character support is restricted to (\u0000 <= character <= \U0010FFFF). + * + * See_Also: + * $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)
+ * $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
+ * $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335) + * Macros: + * WIKI = Phobos/StdUtf + */ + +module std.utf; + +private import std.stdio; + +//debug=utf; // uncomment to turn on debugging printf's + +deprecated class UtfError : Error +{ + size_t idx; // index in string of where error occurred + + this(char[] s, size_t i) + { + idx = i; + super(s); + } +} + +/********************************** + * Exception class that is thrown upon any errors. + */ + +class UtfException : Exception +{ + size_t idx; /// index in string of where error occurred + + this(char[] s, size_t i) + { + idx = i; + super(s); + } +} + +/******************************* + * Test if c is a valid UTF-32 character. + * + * \uFFFE and \uFFFF are considered valid by this function, + * as they are permitted for internal use by an application, + * but they are not allowed for interchange by the Unicode standard. + * + * Returns: true if it is, false if not. + */ + +bool isValidDchar(dchar c) +{ + /* Note: FFFE and FFFF are specifically permitted by the + * Unicode standard for application internal use, but are not + * allowed for interchange. + * (thanks to Arcane Jill) + */ + + return c < 0xD800 || + (c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/); +} + +unittest +{ + debug(utf) printf("utf.isValidDchar.unittest\n"); + assert(isValidDchar(cast(dchar)'a') == true); + assert(isValidDchar(cast(dchar)0x1FFFFF) == false); +} + + +ubyte[256] UTF8stride = +[ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, +]; + +/** + * stride() returns the length of a UTF-8 sequence starting at index i + * in string s. + * Returns: + * The number of bytes in the UTF-8 sequence or + * 0xFF meaning s[i] is not the start of of UTF-8 sequence. + */ + +uint stride(char[] s, size_t i) +{ + return UTF8stride[s[i]]; +} + +/** + * stride() returns the length of a UTF-16 sequence starting at index i + * in string s. + */ + +uint stride(wchar[] s, size_t i) +{ uint u = s[i]; + return 1 + (u >= 0xD800 && u <= 0xDBFF); +} + +/** + * stride() returns the length of a UTF-32 sequence starting at index i + * in string s. + * Returns: The return value will always be 1. + */ + +uint stride(dchar[] s, size_t i) +{ + return 1; +} + +/******************************************* + * Given an index i into an array of characters s[], + * and assuming that index i is at the start of a UTF character, + * determine the number of UCS characters up to that index i. + */ + +size_t toUCSindex(char[] s, size_t i) +{ + size_t n; + size_t j; + size_t stride; + + for (j = 0; j < i; j += stride) + { + stride = UTF8stride[s[j]]; + if (stride == 0xFF) + goto Lerr; + n++; + } + if (j > i) + { + Lerr: + throw new UtfException("1invalid UTF-8 sequence", j); + } + return n; +} + +/** ditto */ + +size_t toUCSindex(wchar[] s, size_t i) +{ + size_t n; + size_t j; + + for (j = 0; j < i; ) + { uint u = s[j]; + + j += 1 + (u >= 0xD800 && u <= 0xDBFF); + n++; + } + if (j > i) + { + Lerr: + throw new UtfException("2invalid UTF-16 sequence", j); + } + return n; +} + +/** ditto */ + +size_t toUCSindex(dchar[] s, size_t i) +{ + return i; +} + +/****************************************** + * Given a UCS index n into an array of characters s[], return the UTF index. + */ + +size_t toUTFindex(char[] s, size_t n) +{ + size_t i; + + while (n--) + { + uint j = UTF8stride[s[i]]; + if (j == 0xFF) + throw new UtfException("3invalid UTF-8 sequence", i); + i += j; + } + return i; +} + +/** ditto */ + +size_t toUTFindex(wchar[] s, size_t n) +{ + size_t i; + + while (n--) + { wchar u = s[i]; + + i += 1 + (u >= 0xD800 && u <= 0xDBFF); + } + return i; +} + +/** ditto */ + +size_t toUTFindex(dchar[] s, size_t n) +{ + return n; +} + +/* =================== Decode ======================= */ + +/*************** + * Decodes and returns character starting at s[idx]. idx is advanced past the + * decoded character. If the character is not well formed, a UtfException is + * thrown and idx remains unchanged. + */ + +dchar decode(char[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + out (result) + { + assert(isValidDchar(result)); + } + body + { + size_t len = s.length; + dchar V; + size_t i = idx; + char u = s[i]; + + if (u & 0x80) + { uint n; + char u2; + + /* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + for (n = 1; ; n++) + { + if (n > 4) + goto Lerr; // only do the first 4 of 6 encodings + if (((u << n) & 0x80) == 0) + { + if (n == 1) + goto Lerr; + break; + } + } + + // Pick off (7 - n) significant bits of B from first byte of octet + V = cast(dchar)(u & ((1 << (7 - n)) - 1)); + + if (i + (n - 1) >= len) + goto Lerr; // off end of string + + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + u2 = s[i + 1]; + if ((u & 0xFE) == 0xC0 || + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + goto Lerr; // overlong combination + + for (uint j = 1; j != n; j++) + { + u = s[i + j]; + if ((u & 0xC0) != 0x80) + goto Lerr; // trailing bytes are 10xxxxxx + V = (V << 6) | (u & 0x3F); + } + if (!isValidDchar(V)) + goto Lerr; + i += n; + } + else + { + V = cast(dchar) u; + i++; + } + + idx = i; + return V; + + Lerr: + //printf("\ndecode: idx = %d, i = %d, length = %d s = \n'%.*s'\n%x\n'%.*s'\n", idx, i, s.length, s, s[i], s[i .. length]); + throw new UtfException("4invalid UTF-8 sequence", i); + } + +unittest +{ size_t i; + dchar c; + + debug(utf) printf("utf.decode.unittest\n"); + + static char[] s1 = "abcd"; + i = 0; + c = decode(s1, i); + assert(c == cast(dchar)'a'); + assert(i == 1); + c = decode(s1, i); + assert(c == cast(dchar)'b'); + assert(i == 2); + + static char[] s2 = "\xC2\xA9"; + i = 0; + c = decode(s2, i); + assert(c == cast(dchar)'\u00A9'); + assert(i == 2); + + static char[] s3 = "\xE2\x89\xA0"; + i = 0; + c = decode(s3, i); + assert(c == cast(dchar)'\u2260'); + assert(i == 3); + + static char[][] s4 = + [ "\xE2\x89", // too short + "\xC0\x8A", + "\xE0\x80\x8A", + "\xF0\x80\x80\x8A", + "\xF8\x80\x80\x80\x8A", + "\xFC\x80\x80\x80\x80\x8A", + ]; + + for (int j = 0; j < s4.length; j++) + { + try + { + i = 0; + c = decode(s4[j], i); + assert(0); + } + catch (UtfException u) + { + i = 23; + delete u; + } + assert(i == 23); + } +} + +/** ditto */ + +dchar decode(wchar[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + out (result) + { + assert(isValidDchar(result)); + } + body + { + char[] msg; + dchar V; + size_t i = idx; + uint u = s[i]; + + if (u & ~0x7F) + { if (u >= 0xD800 && u <= 0xDBFF) + { uint u2; + + if (i + 1 == s.length) + { msg = "surrogate UTF-16 high value past end of string"; + goto Lerr; + } + u2 = s[i + 1]; + if (u2 < 0xDC00 || u2 > 0xDFFF) + { msg = "surrogate UTF-16 low value out of range"; + goto Lerr; + } + u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); + i += 2; + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { msg = "unpaired surrogate UTF-16 value"; + goto Lerr; + } + else if (u == 0xFFFE || u == 0xFFFF) + { msg = "illegal UTF-16 value"; + goto Lerr; + } + else + i++; + } + else + { + i++; + } + + idx = i; + return cast(dchar)u; + + Lerr: + throw new UtfException(msg, i); + } + +/** ditto */ + +dchar decode(dchar[] s, inout size_t idx) + in + { + assert(idx >= 0 && idx < s.length); + } + body + { + size_t i = idx; + dchar c = s[i]; + + if (!isValidDchar(c)) + goto Lerr; + idx = i + 1; + return c; + + Lerr: + throw new UtfException("5invalid UTF-32 value", i); + } + + +/* =================== Encode ======================= */ + +/******************************* + * Encodes character c and appends it to array s[]. + */ + +void encode(inout char[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + char[] r = s; + + if (c <= 0x7F) + { + r ~= cast(char) c; + } + else + { + char[4] buf; + uint L; + + if (c <= 0x7FF) + { + buf[0] = cast(char)(0xC0 | (c >> 6)); + buf[1] = cast(char)(0x80 | (c & 0x3F)); + L = 2; + } + else if (c <= 0xFFFF) + { + buf[0] = cast(char)(0xE0 | (c >> 12)); + buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[2] = cast(char)(0x80 | (c & 0x3F)); + L = 3; + } + else if (c <= 0x10FFFF) + { + buf[0] = cast(char)(0xF0 | (c >> 18)); + buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); + buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[3] = cast(char)(0x80 | (c & 0x3F)); + L = 4; + } + else + { + assert(0); + } + r ~= buf[0 .. L]; + } + s = r; + } + +unittest +{ + debug(utf) printf("utf.encode.unittest\n"); + + char[] s = "abcd"; + encode(s, cast(dchar)'a'); + assert(s.length == 5); + assert(s == "abcda"); + + encode(s, cast(dchar)'\u00A9'); + assert(s.length == 7); + assert(s == "abcda\xC2\xA9"); + //assert(s == "abcda\u00A9"); // BUG: fix compiler + + encode(s, cast(dchar)'\u2260'); + assert(s.length == 10); + assert(s == "abcda\xC2\xA9\xE2\x89\xA0"); +} + +/** ditto */ + +void encode(inout wchar[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + wchar[] r = s; + + if (c <= 0xFFFF) + { + r ~= cast(wchar) c; + } + else + { + wchar[2] buf; + + buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); + buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); + r ~= buf; + } + s = r; + } + +/** ditto */ + +void encode(inout dchar[] s, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + s ~= c; + } + +/* =================== Validation ======================= */ + +/*********************************** + * Checks to see if string is well formed or not. Throws a UtfException if it is + * not. Use to check all untrusted input for correctness. + */ + +void validate(char[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +/** ditto */ + +void validate(wchar[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +/** ditto */ + +void validate(dchar[] s) +{ + size_t len = s.length; + size_t i; + + for (i = 0; i < len; ) + { + decode(s, i); + } +} + +/* =================== Conversion to UTF8 ======================= */ + +char[] toUTF8(char[4] buf, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + if (c <= 0x7F) + { + buf[0] = cast(char) c; + return buf[0 .. 1]; + } + else if (c <= 0x7FF) + { + buf[0] = cast(char)(0xC0 | (c >> 6)); + buf[1] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 2]; + } + else if (c <= 0xFFFF) + { + buf[0] = cast(char)(0xE0 | (c >> 12)); + buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[2] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 3]; + } + else if (c <= 0x10FFFF) + { + buf[0] = cast(char)(0xF0 | (c >> 18)); + buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); + buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); + buf[3] = cast(char)(0x80 | (c & 0x3F)); + return buf[0 .. 4]; + } + assert(0); + } + +/******************* + * Encodes string s into UTF-8 and returns the encoded string. + */ + +char[] toUTF8(char[] s) + in + { + validate(s); + } + body + { + return s; + } + +/** ditto */ + +char[] toUTF8(wchar[] s) +{ + char[] r; + size_t i; + size_t slen = s.length; + + r.length = slen; + + for (i = 0; i < slen; i++) + { wchar c = s[i]; + + if (c <= 0x7F) + r[i] = cast(char)c; // fast path for ascii + else + { + r.length = i; + foreach (dchar c; s[i .. slen]) + { + encode(r, c); + } + break; + } + } + return r; +} + +/** ditto */ + +char[] toUTF8(dchar[] s) +{ + char[] r; + size_t i; + size_t slen = s.length; + + r.length = slen; + + for (i = 0; i < slen; i++) + { dchar c = s[i]; + + if (c <= 0x7F) + r[i] = cast(char)c; // fast path for ascii + else + { + r.length = i; + foreach (dchar d; s[i .. slen]) + { + encode(r, d); + } + break; + } + } + return r; +} + +/* =================== Conversion to UTF16 ======================= */ + +wchar[] toUTF16(wchar[2] buf, dchar c) + in + { + assert(isValidDchar(c)); + } + body + { + if (c <= 0xFFFF) + { + buf[0] = cast(wchar) c; + return buf[0 .. 1]; + } + else + { + buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); + buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00); + return buf[0 .. 2]; + } + } + +/**************** + * Encodes string s into UTF-16 and returns the encoded string. + * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take + * an LPWSTR or LPCWSTR argument. + */ + +wchar[] toUTF16(char[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen; + r.length = 0; + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c <= 0x7F) + { + i++; + r ~= cast(wchar)c; + } + else + { + c = decode(s, i); + encode(r, c); + } + } + return r; +} + +/** ditto */ + +wchar* toUTF16z(char[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen + 1; + r.length = 0; + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c <= 0x7F) + { + i++; + r ~= cast(wchar)c; + } + else + { + c = decode(s, i); + encode(r, c); + } + } + r ~= "\000"; + return r.ptr; +} + +/** ditto */ + +wchar[] toUTF16(wchar[] s) + in + { + validate(s); + } + body + { + return s; + } + +/** ditto */ + +wchar[] toUTF16(dchar[] s) +{ + wchar[] r; + size_t slen = s.length; + + r.length = slen; + r.length = 0; + for (size_t i = 0; i < slen; i++) + { + encode(r, s[i]); + } + return r; +} + +/* =================== Conversion to UTF32 ======================= */ + +/***** + * Encodes string s into UTF-32 and returns the encoded string. + */ + +dchar[] toUTF32(char[] s) +{ + dchar[] r; + size_t slen = s.length; + size_t j = 0; + + r.length = slen; // r[] will never be longer than s[] + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c >= 0x80) + c = decode(s, i); + else + i++; // c is ascii, no need for decode + r[j++] = c; + } + return r[0 .. j]; +} + +/** ditto */ + +dchar[] toUTF32(wchar[] s) +{ + dchar[] r; + size_t slen = s.length; + size_t j = 0; + + r.length = slen; // r[] will never be longer than s[] + for (size_t i = 0; i < slen; ) + { + dchar c = s[i]; + if (c >= 0x80) + c = decode(s, i); + else + i++; // c is ascii, no need for decode + r[j++] = c; + } + return r[0 .. j]; +} + +/** ditto */ + +dchar[] toUTF32(dchar[] s) + in + { + validate(s); + } + body + { + return s; + } + +/* ================================ tests ================================== */ + +unittest +{ + debug(utf) printf("utf.toUTF.unittest\n"); + + char[] c; + wchar[] w; + dchar[] d; + + c = "hello"; + w = toUTF16(c); + assert(w == "hello"); + d = toUTF32(c); + assert(d == "hello"); + + c = toUTF8(w); + assert(c == "hello"); + d = toUTF32(w); + assert(d == "hello"); + + c = toUTF8(d); + assert(c == "hello"); + w = toUTF16(d); + assert(w == "hello"); + + + c = "hel\u1234o"; + w = toUTF16(c); + assert(w == "hel\u1234o"); + d = toUTF32(c); + assert(d == "hel\u1234o"); + + c = toUTF8(w); + assert(c == "hel\u1234o"); + d = toUTF32(w); + assert(d == "hel\u1234o"); + + c = toUTF8(d); + assert(c == "hel\u1234o"); + w = toUTF16(d); + assert(w == "hel\u1234o"); + + + c = "he\U0010AAAAllo"; + w = toUTF16(c); + //foreach (wchar c; w) printf("c = x%x\n", c); + //foreach (wchar c; cast(wchar[])"he\U0010AAAAllo") printf("c = x%x\n", c); + assert(w == "he\U0010AAAAllo"); + d = toUTF32(c); + assert(d == "he\U0010AAAAllo"); + + c = toUTF8(w); + assert(c == "he\U0010AAAAllo"); + d = toUTF32(w); + assert(d == "he\U0010AAAAllo"); + + c = toUTF8(d); + assert(c == "he\U0010AAAAllo"); + w = toUTF16(d); + assert(w == "he\U0010AAAAllo"); +} diff --git a/premake.lua b/premake.lua index d98bf7b7..5f2f9191 100644 --- a/premake.lua +++ b/premake.lua @@ -21,13 +21,13 @@ package.bindir = "bin" package.name = "llvmdc" package.kind = "exe" package.language = "c++" -package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.c") } +package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.cpp") } package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" } package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" } package.linkoptions = { "`llvm-config --libs native bitwriter bitreader`", "`llvm-config --ldflags`" } package.defines = { "IN_LLVM", "_DH" } package.config.Release.defines = { "LLVMD_NO_LOGGER" } -package.config.Debug.buildoptions = { "-g" } +package.config.Debug.buildoptions = { "-g -O0" } --package.targetprefix = "llvm" package.includepaths = { ".", "dmd" } --package.postbuildcommands = { "cd runtime; ./build.sh; cd .." } diff --git a/test/arrays10.d b/test/arrays10.d new file mode 100644 index 00000000..9ee7311e --- /dev/null +++ b/test/arrays10.d @@ -0,0 +1,7 @@ +module arrays10; + +void main() +{ + int[] a = new int[10]; + a[] = 3; +} \ No newline at end of file diff --git a/test/arrays7.d b/test/arrays7.d index aa241ba1..6ae2163c 100644 --- a/test/arrays7.d +++ b/test/arrays7.d @@ -1,18 +1,29 @@ module arrays7; +pragma(LLVM_internal, "notypeinfo") struct S { int i; float f; long l; + + void print() + { + printf("%d %f %lx\n", i, f, l); + } } void main() { S[] arr; S s; + assert(arr.length == 0); arr ~= s; + assert(arr.length == 1); arr ~= S(1,2.64,0xFFFF_FFFF_FFFF); + assert(arr.length == 2); + arr[0].print(); + arr[1].print(); assert(arr[1].i == 1); assert(arr[1].f > 2.63 && arr[1].f < 2.65); assert(arr[1].l == 0xFFFF_FFFF_FFFF); diff --git a/test/arrays9.d b/test/arrays9.d new file mode 100644 index 00000000..afc2034e --- /dev/null +++ b/test/arrays9.d @@ -0,0 +1,8 @@ +module arrays9; + +const int[] g = [1,2,3,4]; + +void main() +{ + +} diff --git a/test/b.d b/test/b.d index 564b861d..ba239094 100644 --- a/test/b.d +++ b/test/b.d @@ -10,7 +10,7 @@ void main() { S s; int i = s.i; - int* p = &s.i; + /*int* p = &s.i; *p = 42; printf("%d == %d\n", *p, s.i); @@ -19,5 +19,5 @@ void main() *f = 3.1415; printf("%f == %f\n", *f, s.f[0]); s.f[0] = 123.456; - printf("%f == %f\n", *f, s.f[0]); + printf("%f == %f\n", *f, s.f[0]);*/ } diff --git a/test/bitops.d b/test/bitops.d index 5796e63a..8f706733 100644 --- a/test/bitops.d +++ b/test/bitops.d @@ -19,7 +19,7 @@ void main() assert((s>>1) == -5); assert((s>>>1) != -5); } - + { ushort a = 0xFFF0; ushort b = 0x0FFF; auto t = a; @@ -70,6 +70,6 @@ void main() s.i &= s.l; assert(s.i == 0x00FF_FF00); } - + printf(" SUCCESS\n"); } diff --git a/test/bug48.d b/test/bug48.d new file mode 100644 index 00000000..86169136 --- /dev/null +++ b/test/bug48.d @@ -0,0 +1,10 @@ +module bug48; + +size_t func(void *p) +{ + return cast(size_t)*cast(void* *)p; +} + +void main() +{ +} diff --git a/test/bug49.d b/test/bug49.d new file mode 100644 index 00000000..553971e9 --- /dev/null +++ b/test/bug49.d @@ -0,0 +1,16 @@ +module bug49; + +pragma(LLVM_internal, "notypeinfo") +struct S +{ + int i; + long l; +} + +void main() +{ + S s; + s.i = 0x__FFFF_FF00; + s.l = 0xFF00FF_FF00; + s.i &= s.l; +} diff --git a/test/bug50.d b/test/bug50.d new file mode 100644 index 00000000..5aca4ada --- /dev/null +++ b/test/bug50.d @@ -0,0 +1,28 @@ +module bug50; + +pragma(LLVM_internal, "notypeinfo") +struct S +{ + int i; + float f; + long l; + + void print() + { + printf("%d %f %lx\n", i, f, l); + } +} + +void main() +{ + S s; + s.print(); + s = S(1,2,3); + s.print(); + + S[] arr; + {arr ~= s;} + {arr[0].print();} + {arr ~= S(1,2,3);} + {arr[1].print();} +}