# HG changeset patch # User Christian Kamm # Date 1241722917 -7200 # Node ID 09c79cae1b86590d5070be147173798e3fd1abfa # Parent 0c03ba6f7c243590e7e203bcee4e1f77ae369e68# Parent 85b80c4fe48aade80a32cd3e69abedf4d440cda8 Automated merge with http://hg.dsource.org/projects/ldc diff -r 85b80c4fe48a -r 09c79cae1b86 dmd/declaration.c --- a/dmd/declaration.c Thu May 07 21:01:44 2009 +0200 +++ b/dmd/declaration.c Thu May 07 21:01:57 2009 +0200 @@ -624,10 +624,15 @@ canassign = 0; value = NULL; +#if IN_LLVM + aggrIndex = 0; + // LDC anonDecl = NULL; offset2 = 0; + nakedUse = false; +#endif } Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) diff -r 85b80c4fe48a -r 09c79cae1b86 dmd/declaration.h --- a/dmd/declaration.h Thu May 07 21:01:44 2009 +0200 +++ b/dmd/declaration.h Thu May 07 21:01:57 2009 +0200 @@ -290,9 +290,15 @@ /// Codegen traversal virtual void codegen(Ir* ir); - // LDC + /// Index into parent aggregate. + /// Set during type generation. + unsigned aggrIndex; + + // FIXME: we're not using these anymore! AnonDeclaration* anonDecl; unsigned offset2; + + /// This var is used by a naked function. bool nakedUse; #endif }; diff -r 85b80c4fe48a -r 09c79cae1b86 gen/classes.cpp --- a/gen/classes.cpp Thu May 07 21:01:44 2009 +0200 +++ b/gen/classes.cpp Thu May 07 21:01:57 2009 +0200 @@ -53,6 +53,18 @@ IrStruct* irstruct = new IrStruct(cd); cd->ir.irStruct = irstruct; + // make sure all fields really get their ir field + ArrayIter it(cd->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + if (vd->ir.irField == NULL) { + new IrField(vd); + } else { + IF_LOG Logger::println("class field already exists!!!"); + } + } + bool needs_def = mustDefineSymbol(cd); // emit the ClassZ symbol diff -r 85b80c4fe48a -r 09c79cae1b86 gen/passes/GarbageCollect2Stack.cpp --- a/gen/passes/GarbageCollect2Stack.cpp Thu May 07 21:01:44 2009 +0200 +++ b/gen/passes/GarbageCollect2Stack.cpp Thu May 07 21:01:57 2009 +0200 @@ -25,6 +25,7 @@ #include "llvm/Pass.h" #include "llvm/Module.h" +#include "llvm/Intrinsics.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/IRBuilder.h" @@ -43,31 +44,167 @@ STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); //===----------------------------------------------------------------------===// +// Helper functions +//===----------------------------------------------------------------------===// + +void EmitMemSet(IRBuilder<>& B, Value* Dst, Value* Val, Value* Len) { + Dst = B.CreateBitCast(Dst, PointerType::getUnqual(Type::Int8Ty)); + + Module *M = B.GetInsertBlock()->getParent()->getParent(); + const Type* Tys[1]; + Tys[0] = Len->getType(); + Value *MemSet = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys, 1); + Value *Align = ConstantInt::get(Type::Int32Ty, 1); + + B.CreateCall4(MemSet, Dst, Val, Len, Align); +} + +static void EmitMemZero(IRBuilder<>& B, Value* Dst, Value* Len) { + EmitMemSet(B, Dst, ConstantInt::get(Type::Int8Ty, 0), Len); +} + + +//===----------------------------------------------------------------------===// +// Helpers for specific types of GC calls. +//===----------------------------------------------------------------------===// + +namespace { + struct Analysis { + TargetData& TD; + const Module& M; + + const Type* getTypeFor(Value* typeinfo) const; + }; + + class FunctionInfo { + protected: + const Type* Ty; + + public: + unsigned TypeInfoArgNr; + bool SafeToDelete; + + // Analyze the current call, filling in some fields. Returns true if + // this is an allocation we can stack-allocate. + virtual bool analyze(CallSite CS, const Analysis& A) { + Value* TypeInfo = CS.getArgument(TypeInfoArgNr); + Ty = A.getTypeFor(TypeInfo); + return (Ty != NULL); + } + + // Returns the alloca to replace this call. + // It will always be inserted before the call. + virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { + NumGcToStack++; + + Instruction* Begin = CS.getCaller()->getEntryBlock().begin(); + return new AllocaInst(Ty, ".nongc_mem", Begin); + } + + FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete) + : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {} + }; + + class ArrayFI : public FunctionInfo { + Value* arrSize; + int ArrSizeArgNr; + bool Initialized; + + public: + ArrayFI(unsigned tiArgNr, bool safeToDelete, bool initialized, + unsigned arrSizeArgNr) + : FunctionInfo(tiArgNr, safeToDelete), + ArrSizeArgNr(arrSizeArgNr), + Initialized(initialized) + {} + + virtual bool analyze(CallSite CS, const Analysis& A) { + if (!FunctionInfo::analyze(CS, A)) + return false; + + arrSize = CS.getArgument(ArrSizeArgNr); + const IntegerType* SizeType = + dyn_cast(arrSize->getType()); + if (!SizeType) + return false; + unsigned bits = SizeType->getBitWidth(); + if (bits > 32) { + // The array size of an alloca must be an i32, so make sure + // the conversion is safe. + APInt Mask = APInt::getHighBitsSet(bits, bits - 32); + APInt KnownZero(bits, 0), KnownOne(bits, 0); + ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &A.TD); + if ((KnownZero & Mask) != Mask) + return false; + } + // Extract the element type from the array type. + const StructType* ArrTy = dyn_cast(Ty); + assert(ArrTy && "Dynamic array type not a struct?"); + assert(isa(ArrTy->getElementType(0))); + const PointerType* PtrTy = + cast(ArrTy->getElementType(1)); + Ty = PtrTy->getElementType(); + return true; + } + + virtual AllocaInst* promote(CallSite CS, IRBuilder<>& B, const Analysis& A) { + IRBuilder<> Builder = B; + // If the allocation is of constant size it's best to put it in the + // entry block, so do so if we're not already there. + // For dynamically-sized allocations it's best to avoid the overhead + // of allocating them if possible, so leave those where they are. + // While we're at it, update statistics too. + if (isa(arrSize)) { + BasicBlock& Entry = CS.getCaller()->getEntryBlock(); + if (Builder.GetInsertBlock() != &Entry) + Builder.SetInsertPoint(&Entry, Entry.begin()); + NumGcToStack++; + } else { + NumToDynSize++; + } + + // Convert array size to 32 bits if necessary + Value* count = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); + AllocaInst* alloca = Builder.CreateAlloca(Ty, count, ".nongc_mem"); + + if (Initialized) { + // For now, only zero-init is supported. + uint64_t size = A.TD.getTypeStoreSize(Ty); + Value* TypeSize = ConstantInt::get(arrSize->getType(), size); + // Use the original B to put initialization at the + // allocation site. + Value* Size = B.CreateMul(TypeSize, arrSize); + EmitMemZero(B, alloca, Size); + } + + return alloca; + } + }; +} + + +//===----------------------------------------------------------------------===// // GarbageCollect2Stack Pass Implementation //===----------------------------------------------------------------------===// namespace { - struct FunctionInfo { - unsigned TypeInfoArgNr; - int ArrSizeArgNr; - bool SafeToDelete; - - FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) - : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), - SafeToDelete(safeToDelete) {} - }; - /// This pass replaces GC calls with alloca's /// class VISIBILITY_HIDDEN GarbageCollect2Stack : public FunctionPass { StringMap KnownFunctions; Module* M; - public: + FunctionInfo AllocMemoryT; + ArrayFI NewArrayVT; + ArrayFI NewArrayT; + + public: static char ID; // Pass identification - GarbageCollect2Stack() : FunctionPass(&ID) {} + GarbageCollect2Stack(); - bool doInitialization(Module &M); + bool doInitialization(Module &M) { + this->M = &M; + } bool runOnFunction(Function &F); @@ -75,9 +212,6 @@ AU.addRequired(); AU.addRequired(); } - - private: - const Type* getTypeFor(Value* typeinfo); }; char GarbageCollect2Stack::ID = 0; } // end anonymous namespace. @@ -90,10 +224,15 @@ return new GarbageCollect2Stack(); } -bool GarbageCollect2Stack::doInitialization(Module &M) { - this->M = &M; - KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); - KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); +GarbageCollect2Stack::GarbageCollect2Stack() +: FunctionPass(&ID), + AllocMemoryT(0, true), + NewArrayVT(0, true, false, 1), + NewArrayT(0, true, true, 1) +{ + KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; + KnownFunctions["_d_newarrayvT"] = &NewArrayVT; + KnownFunctions["_d_newarrayT"] = &NewArrayT; } static void RemoveCall(Instruction* Inst) { @@ -119,6 +258,8 @@ TargetData &TD = getAnalysis(); const LoopInfo &LI = getAnalysis(); + Analysis A = { TD, *M }; + BasicBlock& Entry = F.getEntryBlock(); IRBuilder<> AllocaBuilder(&Entry, Entry.begin()); @@ -167,65 +308,14 @@ DEBUG(DOUT << "GarbageCollect2Stack inspecting: " << *Inst); - if (PointerMayBeCaptured(Inst, true)) { - continue; - } - - Value* TypeInfo = CS.getArgument(info->TypeInfoArgNr); - const Type* Ty = getTypeFor(TypeInfo); - if (!Ty) { + if (!info->analyze(CS, A) || PointerMayBeCaptured(Inst, true)) continue; - } - - Value* arrSize = 0; - if (info->ArrSizeArgNr != -1) { - arrSize = CS.getArgument(info->ArrSizeArgNr); - const IntegerType* SizeType = - dyn_cast(arrSize->getType()); - if (!SizeType) - continue; - unsigned bits = SizeType->getBitWidth(); - if (bits > 32) { - // The array size of an alloca must be an i32, so make sure - // the conversion is safe. - APInt Mask = APInt::getHighBitsSet(bits, bits - 32); - APInt KnownZero(bits, 0), KnownOne(bits, 0); - ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &TD); - if ((KnownZero & Mask) != Mask) - continue; - } - // Extract the element type from the array type. - const StructType* ArrTy = dyn_cast(Ty); - assert(ArrTy && "Dynamic array type not a struct?"); - assert(isa(ArrTy->getElementType(0))); - const PointerType* PtrTy = - cast(ArrTy->getElementType(1)); - Ty = PtrTy->getElementType(); - } // Let's alloca this! Changed = true; - IRBuilder<> Builder(BB, I); - - // If the allocation is of constant size it's best to put it in the - // entry block, so do so if we're not already there. - // For dynamically-sized allocations it's best to avoid the overhead - // of allocating them if possible, so leave those where they are. - // While we're at it, update statistics too. - if (!arrSize || isa(arrSize)) { - if (&*BB != &Entry) - Builder = AllocaBuilder; - NumGcToStack++; - } else { - NumToDynSize++; - } - - // Convert array size to 32 bits if necessary - if (arrSize) - arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); - - Value* newVal = Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); + IRBuilder<> Builder(BB, Inst); + Value* newVal = info->promote(CS, Builder, A); // Make sure the type is the same as it was before, and replace all // uses of the runtime call with the alloca. @@ -240,7 +330,7 @@ return Changed; } -const Type* GarbageCollect2Stack::getTypeFor(Value* typeinfo) { +const Type* Analysis::getTypeFor(Value* typeinfo) const { GlobalVariable* ti_global = dyn_cast(typeinfo->stripPointerCasts()); if (!ti_global) return NULL; @@ -248,7 +338,7 @@ std::string metaname = TD_PREFIX; metaname.append(ti_global->getNameStart(), ti_global->getNameEnd()); - GlobalVariable* global = M->getGlobalVariable(metaname); + GlobalVariable* global = M.getGlobalVariable(metaname); if (!global || !global->hasInitializer()) return NULL; diff -r 85b80c4fe48a -r 09c79cae1b86 gen/structs.cpp --- a/gen/structs.cpp Thu May 07 21:01:44 2009 +0200 +++ b/gen/structs.cpp Thu May 07 21:01:57 2009 +0200 @@ -44,6 +44,18 @@ IrStruct* irstruct = new IrStruct(sd); sd->ir.irStruct = irstruct; + // make sure all fields really get their ir field + ArrayIter it(sd->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + if (vd->ir.irField == NULL) { + new IrField(vd); + } else { + IF_LOG Logger::println("struct field already exists!!!"); + } + } + // perform definition bool needs_def = mustDefineSymbol(sd); if (needs_def) diff -r 85b80c4fe48a -r 09c79cae1b86 ir/irtypeclass.cpp --- a/ir/irtypeclass.cpp Thu May 07 21:01:44 2009 +0200 +++ b/ir/irtypeclass.cpp Thu May 07 21:01:57 2009 +0200 @@ -159,22 +159,8 @@ offset = vd->offset + vd->type->size(); // create ir field - if (vd->ir.irField == NULL) - new IrField(vd, field_index); - else - assert(vd->ir.irField->index == field_index && - vd->ir.irField->unionOffset == 0 && - "inconsistent field data"); - field_index++; - } - - // make sure all fields really get their ir field - ArrayIter it(base->fields); - for (; !it.done(); it.next()) - { - VarDeclaration* vd = it.get(); - if (vd->ir.irField == NULL) - new IrField(vd, 0, vd->offset); + vd->aggrIndex = (unsigned)field_index; + ++field_index; } // any interface implementations? diff -r 85b80c4fe48a -r 09c79cae1b86 ir/irtypestruct.cpp --- a/ir/irtypestruct.cpp Thu May 07 21:01:44 2009 +0200 +++ b/ir/irtypestruct.cpp Thu May 07 21:01:57 2009 +0200 @@ -208,14 +208,8 @@ // advance offset to right past this field offset = vd->offset + vd->type->size(); - // create ir field - if (vd->ir.irField == NULL) - new IrField(vd, field_index); - else - assert(vd->ir.irField->index == field_index && - vd->ir.irField->unionOffset == 0 && - "inconsistent field data"); - field_index++; + // set the field index + vd->aggrIndex = (unsigned)field_index++; } // tail padding? @@ -224,15 +218,6 @@ add_zeros(defaultTypes, sd->structsize - offset); } - // make sure all fields really get their ir field - ArrayIter it(sd->fields); - for (; !it.done(); it.next()) - { - VarDeclaration* vd = it.get(); - if (vd->ir.irField == NULL) - new IrField(vd, 0, vd->offset); - } - // build the llvm type const llvm::Type* st = llvm::StructType::get(defaultTypes, packed); diff -r 85b80c4fe48a -r 09c79cae1b86 ir/irvar.cpp --- a/ir/irvar.cpp Thu May 07 21:01:44 2009 +0200 +++ b/ir/irvar.cpp Thu May 07 21:01:57 2009 +0200 @@ -36,14 +36,22 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -IrField::IrField(VarDeclaration* v, size_t idx, size_t offset) : IrVar(v) +IrField::IrField(VarDeclaration* v) : IrVar(v) { - index = idx; - unionOffset = offset; - constInit = NULL; - assert(V->ir.irField == NULL && "field for this variable already exists"); V->ir.irField = this; + + if (v->aggrIndex) + { + index = v->aggrIndex; + unionOffset = 0; + } + else + { + index = 0; + unionOffset = v->offset; + } + constInit = NULL; } extern LLConstant* get_default_initializer( diff -r 85b80c4fe48a -r 09c79cae1b86 ir/irvar.h --- a/ir/irvar.h Thu May 07 21:01:44 2009 +0200 +++ b/ir/irvar.h Thu May 07 21:01:57 2009 +0200 @@ -34,7 +34,7 @@ // represents an aggregate field variable struct IrField : IrVar { - IrField(VarDeclaration* v, size_t idx, size_t offset = 0); + IrField(VarDeclaration* v); unsigned index; unsigned unionOffset;