diff gen/toobj.c @ 73:b706170e24a9 trunk

[svn r77] Fixed foreach on slice. Fixed some nested function problems when accessing outer function parameters. Major changes to handling of structs. Initial support for unions. Probably more...
author lindquist
date Wed, 31 Oct 2007 03:11:32 +0100
parents d7e764e62462
children eb379601d445
line wrap: on
line diff
--- a/gen/toobj.c	Mon Oct 29 03:28:12 2007 +0100
+++ b/gen/toobj.c	Wed Oct 31 03:11:32 2007 +0100
@@ -65,7 +65,15 @@
     ir.module->setTargetTriple(target_triple);
     ir.module->setDataLayout(global.params.data_layout);
 
-    gTargetData = new llvm::TargetData(ir.module);
+    // heavily inspired by tools/llc/llc.cpp:200-230
+    const llvm::TargetMachineRegistry::Entry* targetEntry;
+    std::string targetError;
+    targetEntry = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(*ir.module, targetError);
+    assert(targetEntry && "Failed to find a static target for module");
+    std::auto_ptr<llvm::TargetMachine> targetPtr(targetEntry->CtorFn(*ir.module, "")); // TODO: replace "" with features
+    assert(targetPtr.get() && "Could not allocate target machine!");
+    llvm::TargetMachine &targetMachine = *targetPtr.get();
+    gTargetData = targetMachine.getTargetData();
 
     // process module members
     for (int k=0; k < members->dim; k++) {
@@ -74,7 +82,6 @@
         dsym->toObjFile();
     }
 
-    delete gTargetData;
     gTargetData = 0;
 
     // emit the llvm main function if necessary
@@ -142,7 +149,7 @@
 /* ================================================================== */
 
 /// Returns the LLVM style index from a DMD style offset
-void AggregateDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
+size_t AggregateDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
 {
     Logger::println("checking for offset %u type %s:", os, t->toChars());
     LOG_SCOPE;
@@ -151,18 +158,19 @@
         Type* vdtype = LLVM_DtoDType(vd->type);
         Logger::println("found %u type %s", vd->offset, vdtype->toChars());
         if (os == vd->offset && vdtype == t) {
-            result.push_back(i);
-            return;
+            assert(vd->llvmFieldIndex >= 0);
+            result.push_back(vd->llvmFieldIndex);
+            return vd->llvmFieldIndexOffset;
         }
         else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) {
             TypeStruct* ts = (TypeStruct*)vdtype;
             StructDeclaration* sd = ts->sym;
             result.push_back(i);
-            sd->offsetToIndex(t, os - vd->offset, result);
-            return;
+            return sd->offsetToIndex(t, os - vd->offset, result);
         }
     }
-    assert(0 && "Offset not found in any aggregate field");
+    //assert(0 && "Offset not found in any aggregate field");
+    return (size_t)-1;
 }
 
 /* ================================================================== */
@@ -190,12 +198,13 @@
 
 /// Returns the LLVM style index from a DMD style offset
 /// Handles class inheritance
-void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
+size_t ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
 {
     unsigned idx = 0;
     unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
     assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
     result.push_back(r+1); // vtable is 0
+    return 0;
 }
 
 /* ================================================================== */
@@ -224,14 +233,98 @@
         dsym->toObjFile();
     }
 
-    if (gIR->topstruct().fields.empty())
+    Logger::println("doing struct fields");
+
+    llvm::StructType* structtype = 0;
+    std::vector<llvm::Constant*> fieldinits;
+
+    if (gIR->topstruct().offsets.empty())
+    {
+        std::vector<const llvm::Type*> fieldtypes;
+        Logger::println("has no fields");
+        fieldtypes.push_back(llvm::Type::Int8Ty);
+        fieldinits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
+        structtype = llvm::StructType::get(fieldtypes);
+    }
+    else
     {
-        gIR->topstruct().fields.push_back(llvm::Type::Int8Ty);
-        gIR->topstruct().inits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
+        Logger::println("has fields");
+        std::vector<const llvm::Type*> fieldtypes;
+        unsigned prevsize = (unsigned)-1;
+        unsigned lastoffset = (unsigned)-1;
+        const llvm::Type* fieldtype = NULL;
+        llvm::Constant* fieldinit = NULL;
+        size_t fieldpad = 0;
+        int idx = 0;
+        for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
+            // first iteration
+            if (lastoffset == (unsigned)-1) {
+                lastoffset = i->first;
+                assert(lastoffset == 0);
+                fieldtype = LLVM_DtoType(i->second.var->type);
+                fieldinit = i->second.init;
+                prevsize = gTargetData->getTypeSize(fieldtype);
+                i->second.var->llvmFieldIndex = idx;
+            }
+            // colliding offset?
+            else if (lastoffset == i->first) {
+                const llvm::Type* t = LLVM_DtoType(i->second.var->type);
+                size_t s = gTargetData->getTypeSize(t);
+                if (s > prevsize) {
+                    fieldpad = s - prevsize;
+                    prevsize = s;
+                }
+                llvmHasUnions = true;
+                i->second.var->llvmFieldIndex = idx;
+            }
+            // intersecting offset?
+            else if (i->first < (lastoffset + prevsize)) {
+                const llvm::Type* t = LLVM_DtoType(i->second.var->type);
+                size_t s = gTargetData->getTypeSize(t);
+                assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
+                llvmHasUnions = true;
+                i->second.var->llvmFieldIndex = idx;
+                i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s;
+            }
+            // fresh offset
+            else {
+                // commit the field
+                fieldtypes.push_back(fieldtype);
+                fieldinits.push_back(fieldinit);
+                if (fieldpad) {
+                    // match up with below
+                    std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
+                    llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
+                    fieldtypes.push_back(c->getType());
+                    fieldinits.push_back(c);
+                    idx++;
+                }
+
+                idx++;
+
+                // start new
+                lastoffset = i->first;
+                fieldtype = LLVM_DtoType(i->second.var->type);
+                fieldinit = i->second.init;
+                prevsize = gTargetData->getTypeSize(fieldtype);
+                i->second.var->llvmFieldIndex = idx;
+                fieldpad = 0;
+            }
+        }
+        fieldtypes.push_back(fieldtype);
+        fieldinits.push_back(fieldinit);
+        if (fieldpad) {
+            // match up with above
+            std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
+            llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
+            fieldtypes.push_back(c->getType());
+            fieldinits.push_back(c);
+        }
+
+        Logger::println("creating struct type");
+        structtype = llvm::StructType::get(fieldtypes);
     }
 
-    llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields);
-
     // refine abstract types for stuff like: struct S{S* next;}
     if (gIR->topstruct().recty != 0)
     {
@@ -254,18 +347,18 @@
     // always generate the constant initalizer
     if (!zeroInit) {
         Logger::println("Not zero initialized");
-        //assert(tk == gIR->topstruct().size());
+        //assert(tk == gIR->gIR->topstruct()().size());
         #ifndef LLVMD_NO_LOGGER
-        Logger::cout() << *structtype << '\n';
-        for (size_t k=0; k<gIR->topstruct().inits.size(); ++k) {
+        Logger::cout() << "struct type: " << *structtype << '\n';
+        for (size_t k=0; k<fieldinits.size(); ++k) {
             Logger::cout() << "Type:" << '\n';
-            Logger::cout() << *gIR->topstruct().inits[k]->getType() << '\n';
+            Logger::cout() << *fieldinits[k]->getType() << '\n';
             Logger::cout() << "Value:" << '\n';
-            Logger::cout() << *gIR->topstruct().inits[k] << '\n';
+            Logger::cout() << *fieldinits[k] << '\n';
         }
         Logger::cout() << "Initializer printed" << '\n';
         #endif
-        llvmInitZ = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits);
+        llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits);
     }
     else {
         Logger::println("Zero initialized");
@@ -278,14 +371,15 @@
         _init = llvmInitZ;
     }
 
-    std::string initname(mangle());
-    initname.append("__initZ");
+    std::string initname("_D");
+    initname.append(mangle());
+    initname.append("6__initZ");
     llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module);
     ts->llvmInit = initvar;
 
     // generate member function definitions
     gIR->topstruct().queueFuncs = false;
-    IRStruct::FuncDeclVec& mfs = gIR->topstruct().funcs;
+    IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
     size_t n = mfs.size();
     for (size_t i=0; i<n; ++i) {
         mfs[i]->toObjFile();
@@ -296,7 +390,7 @@
     gIR->structs.pop_back();
 
     // generate typeinfo
-    if (getModule() == gIR->dmodule)
+    if (getModule() == gIR->dmodule && llvmInternal != LLVMnotypeinfo)
         type->getTypeInfo(NULL);
 }
 
@@ -341,8 +435,12 @@
     // add vtable
     llvm::PATypeHolder pa = llvm::OpaqueType::get();
     const llvm::Type* vtabty = llvm::PointerType::get(pa);
-    gIR->topstruct().fields.push_back(vtabty);
-    gIR->topstruct().inits.push_back(0);
+
+    std::vector<const llvm::Type*> fieldtypes;
+    fieldtypes.push_back(vtabty);
+
+    std::vector<llvm::Constant*> fieldinits;
+    fieldinits.push_back(0);
 
     // base classes first
     LLVM_AddBaseClassData(&baseclasses);
@@ -353,7 +451,13 @@
         dsym->toObjFile();
     }
 
-    llvm::StructType* structtype = llvm::StructType::get(gIR->topstruct().fields);
+    // fill out fieldtypes/inits
+    for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
+        fieldtypes.push_back(LLVM_DtoType(i->second.var->type));
+        fieldinits.push_back(i->second.init);
+    }
+
+    llvm::StructType* structtype = llvm::StructType::get(fieldtypes);
     // refine abstract types for stuff like: class C {C next;}
     if (gIR->topstruct().recty != 0)
     {
@@ -441,9 +545,9 @@
 
     // first field is always the vtable
     assert(svtblVar != 0);
-    gIR->topstruct().inits[0] = svtblVar;
+    fieldinits[0] = svtblVar;
 
-    llvmInitZ = _init = llvm::ConstantStruct::get(structtype,gIR->topstruct().inits);
+    llvmInitZ = _init = llvm::ConstantStruct::get(structtype,fieldinits);
     assert(_init);
 
     std::string initname("_D");
@@ -457,7 +561,7 @@
         initvar->setInitializer(_init);
         // generate member functions
         gIR->topstruct().queueFuncs = false;
-        IRStruct::FuncDeclVec& mfs = gIR->topstruct().funcs;
+        IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
         size_t n = mfs.size();
         for (size_t i=0; i<n; ++i) {
             mfs[i]->toObjFile();
@@ -573,7 +677,6 @@
 
         Type* t = LLVM_DtoDType(type);
         const llvm::Type* _type = LLVM_DtoType(t);
-        gIR->topstruct().fields.push_back(_type);
 
         llvm::Constant*_init = LLVM_DtoConstInitializer(t, init);
         assert(_init);
@@ -610,7 +713,9 @@
                 assert(0);
             }
         }
-        gIR->topstruct().inits.push_back(_init);
+
+        // add the field in the IRStruct
+        gIR->topstruct().offsets.insert(std::make_pair(offset, IRStruct::Offset(this,_init)));
     }
 
     Logger::println("VarDeclaration::toObjFile is done");