Esempio n. 1
0
void VarDeclaration::codegen(Ir* p)
{
    Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars());
    LOG_SCOPE;

    if (type->ty == Terror)
    {   error("had semantic errors when compiling");
        return;
    }

    // just forward aliases
    if (aliassym)
    {
        Logger::println("alias sym");
        toAlias()->codegen(p);
        return;
    }

    // output the parent aggregate first
    if (AggregateDeclaration* ad = isMember())
        ad->codegen(p);

    // global variable
    // taken from dmd2/structs
    if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init))
    {
        Logger::println("data segment");

    #if 0 // TODO:
        assert(!(storage_class & STCmanifest) &&
            "manifest constant being codegen'd!");
    #endif

        // don't duplicate work
        if (this->ir.resolved) return;
        this->ir.resolved = true;
        this->ir.declared = true;

        this->ir.irGlobal = new IrGlobal(this);

        Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());

        // not sure why this is only needed for d2
        bool _isconst = isConst() && init;

        Logger::println("Creating global variable");

        assert(!ir.initialized);
        ir.initialized = gIR->dmodule;
        std::string _name(mangle());

        LLType *_type = DtoConstInitializerType(type, init);

        // create the global variable
#if LDC_LLVM_VER >= 302
        // FIXME: clang uses a command line option for the thread model
        LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst,
                                                      DtoLinkage(this), NULL, _name, 0,
                                                      isThreadlocal() ? LLGlobalVariable::GeneralDynamicTLSModel
                                                                      : LLGlobalVariable::NotThreadLocal);
#else
        LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst,
                                                      DtoLinkage(this), NULL, _name, 0, isThreadlocal());
#endif
        this->ir.irGlobal->value = gvar;

        // Set the alignment (it is important not to use type->alignsize because
        // VarDeclarations can have an align() attribute independent of the type
        // as well).
        if (alignment != STRUCTALIGN_DEFAULT)
            gvar->setAlignment(alignment);

        if (Logger::enabled())
            Logger::cout() << *gvar << '\n';

        // if this global is used from a nested function, this is necessary or
        // optimization could potentially remove the global (if it's the only use)
        if (nakedUse)
            gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType()));

        // assign the initializer
        if (!(storage_class & STCextern) && mustDefineSymbol(this))
        {
            if (Logger::enabled())
            {
                Logger::println("setting initializer");
                Logger::cout() << "global: " << *gvar << '\n';
    #if 0
                Logger::cout() << "init:   " << *initVal << '\n';
    #endif
            }
            // build the initializer
            LLConstant *initVal = DtoConstInitializer(loc, type, init);

            // set the initializer
            assert(!ir.irGlobal->constInit);
            ir.irGlobal->constInit = initVal;
            gvar->setInitializer(initVal);

            // do debug info
            DtoDwarfGlobalVariable(gvar, this);
        }
    }
}
Esempio n. 2
0
void VarDeclaration::codegen(Ir* p)
{
    Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars());
    LOG_SCOPE;

    if (type->ty == Terror)
    {   error("had semantic errors when compiling");
        return;
    }

    // just forward aliases
    if (aliassym)
    {
        Logger::println("alias sym");
        toAlias()->codegen(p);
        return;
    }

    // output the parent aggregate first
    if (AggregateDeclaration* ad = isMember())
        ad->codegen(p);

    // global variable
    if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init))
    {
        Logger::println("data segment");

    #if 0 // TODO:
        assert(!(storage_class & STCmanifest) &&
            "manifest constant being codegen'd!");
    #endif

        // don't duplicate work
        if (this->ir.resolved) return;
        this->ir.resolved = true;
        this->ir.declared = true;

        this->ir.irGlobal = new IrGlobal(this);

        Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());

        const bool isLLConst = isConst() && init;
        const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this);

        assert(!ir.initialized);
        ir.initialized = gIR->dmodule;
        std::string llName(mangle());

        // Since the type of a global must exactly match the type of its
        // initializer, we cannot know the type until after we have emitted the
        // latter (e.g. in case of unions, …). However, it is legal for the
        // initializer to refer to the address of the variable. Thus, we first
        // create a global with the generic type (note the assignment to
        // this->ir.irGlobal->value!), and in case we also do an initializer
        // with a different type later, swap it out and replace any existing
        // uses with bitcasts to the previous type.
        llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module,
            i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName,
            isThreadlocal());
        this->ir.irGlobal->value = gvar;

        // Check if we are defining or just declaring the global in this module.
        if (!(storage_class & STCextern) && mustDefineSymbol(this))
        {
            // Build the initializer. Might use this->ir.irGlobal->value!
            LLConstant *initVal = DtoConstInitializer(loc, type, init);

            // In case of type mismatch, swap out the variable.
            if (initVal->getType() != gvar->getType()->getElementType())
            {
                llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc,
                    *gIR->module, initVal->getType(), isLLConst, llLinkage, 0,
                    "", // We take on the name of the old global below.
                    isThreadlocal());

                newGvar->takeName(gvar);

                llvm::Constant* newValue =
                    llvm::ConstantExpr::getBitCast(newGvar, gvar->getType());
                gvar->replaceAllUsesWith(newValue);

                gvar->eraseFromParent();
                gvar = newGvar;
                this->ir.irGlobal->value = newGvar;
            }

            // Now, set the initializer.
            assert(!ir.irGlobal->constInit);
            ir.irGlobal->constInit = initVal;
            gvar->setInitializer(initVal);

            // Also set up the edbug info.
            DtoDwarfGlobalVariable(gvar, this);
        }

        // Set the alignment (it is important not to use type->alignsize because
        // VarDeclarations can have an align() attribute independent of the type
        // as well).
        if (alignment != STRUCTALIGN_DEFAULT)
            gvar->setAlignment(alignment);

        // If this global is used from a naked function, we need to create an
        // artificial "use" for it, or it could be removed by the optimizer if
        // the only reference to it is in inline asm.
        if (nakedUse)
            gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType()));

        if (Logger::enabled())
            Logger::cout() << *gvar << '\n';
    }
}