예제 #1
0
//
// Method: visitAllocaInst()
//
// Description:
//  This method instruments an alloca instruction so that it is zero'ed out
//  before any data is loaded from it.
//
void
InitAllocas::visitAllocaInst (AllocaInst & AI) {
  //
  // Scan for a place to insert the instruction to initialize the
  // allocated memory.
  //
  Instruction * InsertPt = getInsertionPoint (AI);

  //
  // Zero the alloca with a memset.  If this is done more efficiently with stores
  // SelectionDAG will lower it appropriately based on target information.
  //
  const DataLayout & TD = AI.getModule()->getDataLayout();

  //
  // Get various types that we'll need.
  //
  Type * Int1Type    = IntegerType::getInt1Ty(AI.getContext());
  Type * Int8Type    = IntegerType::getInt8Ty(AI.getContext());
  Type * Int32Type   = IntegerType::getInt32Ty(AI.getContext());
  Type * VoidPtrType = getVoidPtrType (AI.getContext());
  Type * AllocType = AI.getAllocatedType();

  //
  // Create a call to memset.
  //
  Module * M = AI.getParent()->getParent()->getParent();
  Function * Memset = cast<Function>(M->getFunction ("llvm.memset.p0i8.i32"));
  std::vector<Value *> args;
  args.push_back (castTo (&AI, VoidPtrType, AI.getName().str(), InsertPt));
  args.push_back (ConstantInt::get(Int8Type, 0));
  args.push_back (ConstantInt::get(Int32Type,TD.getTypeAllocSize(AllocType)));
  args.push_back (ConstantInt::get(Int32Type,
                                   TD.getABITypeAlignment(AllocType)));
  args.push_back (ConstantInt::get(Int1Type, 0));
  CallInst::Create (Memset, args, "", InsertPt);

  //
  // Update statistics.
  //
  ++InitedAllocas;
  return;
}
예제 #2
0
//
// Method: doInitialization()
//
// Description:
//  Perform module-level initialization before the pass is run.  For this
//  pass, we need to create a function prototype for the GEP check function.
//
// Inputs:
//  M - A reference to the LLVM module to modify.
//
// Return value:
//  true - This LLVM module has been modified.
//
bool
InsertGEPChecks::doInitialization (Module & M) {
  //
  // Create a function prototype for the function that performs incomplete
  // pointer arithmetic (GEP) checks.
  //
  Type * VoidPtrTy = getVoidPtrType (M.getContext());
  Constant * F = M.getOrInsertFunction ("boundscheckui",
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        VoidPtrTy,
                                        NULL);

  //
  // Mark the function as readonly; that will enable it to be hoisted out of
  // loops by the standard loop optimization passes.
  //
  (cast<Function>(F))->addFnAttr (Attribute::ReadOnly);
  return true;
}
예제 #3
0
IrTypeDelegate* IrTypeDelegate::get(Type* t)
{
    assert(!t->irtype);
    assert(t->ty == Tdelegate);
    assert(t->nextOf()->ty == Tfunction);

    TypeDelegate *dt = (TypeDelegate*)t;

    if (!dt->irtype)
    {
        TypeFunction* tf = static_cast<TypeFunction*>(dt->nextOf());
        llvm::Type* ltf = DtoFunctionType(tf, dt->irFty, NULL, Type::tvoid->pointerTo());

        llvm::Type *types[] = { getVoidPtrType(), 
                                getPtrToType(ltf) };
        LLStructType* lt = LLStructType::get(gIR->context(), types, false);
        dt->irtype = new IrTypeDelegate(dt, lt);
    }

    return dt->irtype->isDelegate();
}
예제 #4
0
파일: tollvm.cpp 프로젝트: Doeme/ldc
LLValue *DtoMemCmp(LLValue *lhs, LLValue *rhs, LLValue *nbytes) {
  // int memcmp ( const void * ptr1, const void * ptr2, size_t num );

  LLType *VoidPtrTy = getVoidPtrType();
  LLFunction *fn = gIR->module.getFunction("memcmp");
  if (!fn) {
    LLType *Tys[] = {VoidPtrTy, VoidPtrTy, DtoSize_t()};
    LLFunctionType *fty =
        LLFunctionType::get(LLType::getInt32Ty(gIR->context()), Tys, false);
    fn = LLFunction::Create(fty, LLGlobalValue::ExternalLinkage, "memcmp",
                            &gIR->module);
  }

  lhs = DtoBitCast(lhs, VoidPtrTy);
  rhs = DtoBitCast(rhs, VoidPtrTy);

#if LDC_LLVM_VER >= 307
  return gIR->ir->CreateCall(fn, {lhs, rhs, nbytes});
#else
  return gIR->ir->CreateCall3(fn, lhs, rhs, nbytes);
#endif
}
예제 #5
0
파일: irtypeclass.cpp 프로젝트: smunix/ldc
std::vector<llvm::Type*> IrTypeClass::buildVtblType(Type* first, Array* vtbl_array)
{
    IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars());
    LOG_SCOPE;

    std::vector<llvm::Type*> types;
    types.reserve(vtbl_array->dim);

    // first comes the classinfo
    types.push_back(DtoType(first));

    // then come the functions
    ArrayIter<Dsymbol> it(*vtbl_array);
    it.index = 1;

    for (; !it.done(); it.next())
    {
        Dsymbol* dsym = it.get();
        if (dsym == NULL)
        {
            // FIXME
            // why is this null?
            // happens for mini/s.d
            types.push_back(getVoidPtrType());
            continue;
        }

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "invalid vtbl entry");

        IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars());

        types.push_back(DtoType(fd->type->pointerTo()));
    }

    return types;
}
예제 #6
0
파일: structs.cpp 프로젝트: Samana/ldc
LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd)
{
    Logger::println("indexing struct field %s:", vd->toPrettyChars());
    LOG_SCOPE;

    DtoResolveStruct(sd);

    // vd must be a field
    IrField* field = vd->ir.irField;
    assert(field);

    // get the start pointer
    LLType* st = getPtrToType(DtoType(sd->type));

    // cast to the formal struct type
    src = DtoBitCast(src, st);

    // gep to the index
    LLValue* val = DtoGEPi(src, 0, field->index);

    // do we need to offset further? (union area)
    if (field->unionOffset)
    {
        // cast to void*
        val = DtoBitCast(val, getVoidPtrType());
        // offset
        val = DtoGEPi1(val, field->unionOffset);
    }

    // cast it to the right type
    val = DtoBitCast(val, getPtrToType(i1ToI8(DtoType(vd->type))));

    if (Logger::enabled())
        Logger::cout() << "value: " << *val << '\n';

    return val;
}
예제 #7
0
파일: tollvm.cpp 프로젝트: Syniurge/Calypso
LLType *DtoType(Type *t) {
  t = stripModifiers(t);

  if (t->ctype) {
    return t->ctype->getLLType();
  }

  IF_LOG Logger::println("Building type: %s", t->toChars());
  LOG_SCOPE;

  assert(t);
  switch (t->ty) {
  // basic types
  case Tvoid:
  case Tint8:
  case Tuns8:
  case Tint16:
  case Tuns16:
  case Tint32:
  case Tuns32:
  case Tint64:
  case Tuns64:
  case Tint128:
  case Tuns128:
  case Tfloat32:
  case Tfloat64:
  case Tfloat80:
  case Timaginary32:
  case Timaginary64:
  case Timaginary80:
  case Tcomplex32:
  case Tcomplex64:
  case Tcomplex80:
  // case Tbit:
  case Tbool:
  case Tchar:
  case Twchar:
  case Tdchar: {
    return IrTypeBasic::get(t)->getLLType();
  }

  // pointers
  case Tnull:
  case Tpointer:
  case Treference: { // CALYPSO
    return IrTypePointer::get(t)->getLLType();
  }

  // arrays
  case Tarray: {
    return IrTypeArray::get(t)->getLLType();
  }

  case Tsarray: {
    return IrTypeSArray::get(t)->getLLType();
  }

  // aggregates
  case Tstruct: {
    TypeStruct *ts = static_cast<TypeStruct *>(t);
    if (ts->sym->type->ctype) {
      // This should not happen, but the frontend seems to be buggy. Not
      // sure if this is the best way to handle the situation, but we
      // certainly don't want to override ts->sym->type->ctype.
      IF_LOG Logger::cout()
          << "Struct with multiple Types detected: " << ts->toChars() << " ("
          << ts->sym->locToChars() << ")" << std::endl;
      return ts->sym->type->ctype->getLLType();
    }
    return IrTypeStruct::get(ts->sym)->getLLType();
  }
  case Tclass: {
    TypeClass *tc = static_cast<TypeClass *>(t);
    if (tc->sym->type->ctype) {
      // See Tstruct case.
      IF_LOG Logger::cout()
          << "Class with multiple Types detected: " << tc->toChars() << " ("
          << tc->sym->locToChars() << ")" << std::endl;
      return tc->sym->type->ctype->getLLType();
    }
    return IrTypeClass::get(tc->sym)->getLLType();
  }

  // functions
  case Tfunction: {
    return IrTypeFunction::get(t)->getLLType();
  }

  // delegates
  case Tdelegate: {
    return IrTypeDelegate::get(t)->getLLType();
  }

  // typedefs
  // enum

  // FIXME: maybe just call toBasetype first ?
  case Tenum: {
    Type *bt = t->toBasetype();
    assert(bt);
    if (t == bt) {
      // This is an enum forward reference that is only legal when referenced
      // through an indirection (e.g. "enum E; void foo(E* p);"). For lack of a
      // better choice, make the outer indirection a void pointer.
      return getVoidPtrType()->getContainedType(0);
    }
    return DtoType(bt);
  }

  // associative arrays
  case Taarray:
    return getVoidPtrType();

  case Tvector: {
    return IrTypeVector::get(t)->getLLType();
  }

  default:
    llvm_unreachable("Unknown class of D Type!");
  }
  return nullptr;
}
예제 #8
0
파일: classes.cpp 프로젝트: NilsBossung/ldc
LLConstant* DtoDefineClassInfo(ClassDeclaration* cd)
{
//     The layout is:
//        {
//         void **vptr;
//         monitor_t monitor;
//         byte[] initializer;     // static initialization data
//         char[] name;        // class name
//         void *[] vtbl;
//         Interface[] interfaces;
//         ClassInfo *base;        // base class
//         void *destructor;
//         void *invariant;        // class invariant
//         uint flags;
//         void *deallocator;
//         OffsetTypeInfo[] offTi;
//         void *defaultConstructor;
//         version(D_Version2)
//              immutable(void)* m_RTInfo;
//         else
//              TypeInfo typeinfo; // since dmd 1.045
//        }

    Logger::println("DtoDefineClassInfo(%s)", cd->toChars());
    LOG_SCOPE;

    assert(cd->type->ty == Tclass);
    TypeClass* cdty = static_cast<TypeClass*>(cd->type);

    IrStruct* ir = cd->ir.irStruct;
    assert(ir);

    ClassDeclaration* cinfo = ClassDeclaration::classinfo;

    if (cinfo->fields.dim != 12)
    {
        error("object.d ClassInfo class is incorrect");
        fatal();
    }

    // use the rtti builder
    RTTIBuilder b(ClassDeclaration::classinfo);

    LLConstant* c;

    LLType* voidPtr = getVoidPtrType();
    LLType* voidPtrPtr = getPtrToType(voidPtr);

    // byte[] init
    if (cd->isInterfaceDeclaration())
    {
        b.push_null_void_array();
    }
    else
    {
        LLType* cd_type = cdty->irtype->isClass()->getMemoryLLType();
        size_t initsz = getTypePaddedSize(cd_type);
        b.push_void_array(initsz, ir->getInitSymbol());
    }

    // class name
    // code from dmd
    const char *name = cd->ident->toChars();
    size_t namelen = strlen(name);
    if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0))
    {
        name = cd->toPrettyChars();
        namelen = strlen(name);
    }
    b.push_string(name);

    // vtbl array
    if (cd->isInterfaceDeclaration())
    {
        b.push_array(0, getNullValue(voidPtrPtr));
    }
    else
    {
        c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr);
        b.push_array(cd->vtbl.dim, c);
    }

    // interfaces array
    b.push(ir->getClassInfoInterfaces());

    // base classinfo
    // interfaces never get a base , just the interfaces[]
    if (cd->baseClass && !cd->isInterfaceDeclaration())
        b.push_classinfo(cd->baseClass);
    else
        b.push_null(cinfo->type);

    // destructor
    if (cd->isInterfaceDeclaration())
        b.push_null_vp();
    else
        b.push(build_class_dtor(cd));

    // invariant
    VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]);
    b.push_funcptr(cd->inv, invVar->type);

    // uint flags
    unsigned flags;
    if (cd->isInterfaceDeclaration())
        flags = 4 | cd->isCOMinterface() | 32;
    else
        flags = build_classinfo_flags(cd);
    b.push_uint(flags);

    // deallocator
    b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo());

    // offset typeinfo
    VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]);

#if GENERATE_OFFTI

    if (cd->isInterfaceDeclaration())
        b.push_null(offTiVar->type);
    else
        b.push(build_offti_array(cd, DtoType(offTiVar->type)));

#else // GENERATE_OFFTI

    b.push_null(offTiVar->type);

#endif // GENERATE_OFFTI

    // default constructor
    VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]);
    b.push_funcptr(cd->defaultCtor, defConstructorVar->type);

#if DMDV2
    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (cd->getRTInfo)
        b.push(cd->getRTInfo->toConstElem(gIR));
    else if (flags & 2)
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers
#else
    // typeinfo - since 1.045
    b.push_typeinfo(cd->type);
#endif

    /*size_t n = inits.size();
    for (size_t i=0; i<n; ++i)
    {
        Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n';
    }*/

    // build the initializer
    LLType *initType = ir->classInfo->getType()->getContainedType(0);
    LLConstant* finalinit = b.get_constant(isaStruct(initType));

    //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n';
    ir->constClassInfo = finalinit;

    // sanity check
    assert(finalinit->getType() == initType &&
        "__ClassZ initializer does not match the ClassInfo type");

    // return initializer
    return finalinit;
}
예제 #9
0
파일: module.cpp 프로젝트: gedaiu/ldc
static void build_dso_registry_calls(std::string moduleMangle,
                                     llvm::Constant *thisModuleInfo) {
  // Build the ModuleInfo reference and bracketing symbols.
  llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type);

  // Order is important here: We must create the symbols in the
  // bracketing sections right before/after the ModuleInfo reference
  // so that they end up in the correct order in the object file.
  auto minfoBeg =
      new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy,
                               false, // FIXME: mRelocModel != llvm::Reloc::PIC_
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(moduleInfoPtrTy), "_minfo_beg");
  minfoBeg->setSection(".minfo_beg");
  minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility);

  std::string thismrefname = "_D";
  thismrefname += moduleMangle;
  thismrefname += "11__moduleRefZ";
  auto thismref = new llvm::GlobalVariable(
      gIR->module, moduleInfoPtrTy,
      false, // FIXME: mRelocModel != llvm::Reloc::PIC_
      llvm::GlobalValue::LinkOnceODRLinkage,
      DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname);
  thismref->setSection(".minfo");
  gIR->usedArray.push_back(thismref);

  auto minfoEnd =
      new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy,
                               false, // FIXME: mRelocModel != llvm::Reloc::PIC_
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(moduleInfoPtrTy), "_minfo_end");
  minfoEnd->setSection(".minfo_end");
  minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // Build the ctor to invoke _d_dso_registry.

  // This is the DSO slot for use by the druntime implementation.
  auto dsoSlot =
      new llvm::GlobalVariable(gIR->module, getVoidPtrType(), false,
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(getVoidPtrType()), "ldc.dso_slot");
  dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // Okay, so the theory is easy: We want to have one global constructor and
  // destructor per object (i.e. executable/shared library) that calls
  // _d_dso_registry with the respective DSO record. However, there are a
  // couple of issues that make this harder than necessary:
  //
  //  1) The natural way to implement the "one-per-image" part would be to
  //     emit a weak reference to a weak function into a .ctors.<somename>
  //     section (llvm.global_ctors doesn't support the necessary
  //     functionality, so we'd use our knowledge of the linker script to work
  //     around that). But as of LLVM 3.4, emitting a symbol both as weak and
  //     into a custom section is not supported by the MC layer. Thus, we have
  //     to use a normal ctor/dtor and manually ensure that we only perform
  //     the call once. This is done by introducing ldc.dso_initialized.
  //
  //  2) To make sure the .minfo section isn't removed by the linker when
  //     using --gc-sections, we need to keep a reference to it around in
  //     _every_ object file (as --gc-sections works per object file). The
  //     natural place for this is the ctor, where we just load a reference
  //     on the stack after the DSO record (to ensure LLVM doesn't optimize
  //     it out). However, this way, we need to have at least one ctor
  //     instance per object file be pulled into the final executable. We
  //     do this here by making the module mangle string part of its name,
  //     even thoguht this is slightly wasteful on -singleobj builds.
  //
  // It might be a better idea to simply use a custom linker script (using
  // INSERT AFTER… so as to still keep the default one) to avoid all these
  // problems. This would mean that it is no longer safe to link D objects
  // directly using e.g. "g++ dcode.o cppcode.o", though.

  auto dsoInitialized = new llvm::GlobalVariable(
      gIR->module, llvm::Type::getInt8Ty(gIR->context()), false,
      llvm::GlobalValue::LinkOnceODRLinkage,
      llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0),
      "ldc.dso_initialized");
  dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // There is no reason for this cast to void*, other than that removing it
  // seems to trigger a bug in the llvm::Linker (at least on LLVM 3.4)
  // causing it to not merge the %object.ModuleInfo types properly. This
  // manifests itself in a type mismatch assertion being triggered on the
  // minfoUsedPointer store in the ctor as soon as the optimizer runs.
  llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType());

  std::string ctorName = "ldc.dso_ctor.";
  ctorName += moduleMangle;
  llvm::Function *dsoCtor = llvm::Function::Create(
      llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false),
      llvm::GlobalValue::LinkOnceODRLinkage, ctorName, &gIR->module);
  dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility);
  build_dso_ctor_dtor_body(dsoCtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd,
                           minfoRefPtr, false);
  llvm::appendToGlobalCtors(gIR->module, dsoCtor, 65535);

  std::string dtorName = "ldc.dso_dtor.";
  dtorName += moduleMangle;
  llvm::Function *dsoDtor = llvm::Function::Create(
      llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false),
      llvm::GlobalValue::LinkOnceODRLinkage, dtorName, &gIR->module);
  dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility);
  build_dso_ctor_dtor_body(dsoDtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd,
                           minfoRefPtr, true);
  llvm::appendToGlobalDtors(gIR->module, dsoDtor, 65535);
}
예제 #10
0
파일: irclass.cpp 프로젝트: WebDrake/ldc
llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index)
{
    ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base);
    if (it != interfaceVtblMap.end())
        return it->second;

    IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
        b->base->toPrettyChars(), aggrdecl->toPrettyChars());
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd && "not a class aggregate");

    FuncDeclarations vtbl_array;
    b->fillVtbl(cd, &vtbl_array, new_instance);

    std::vector<llvm::Constant*> constants;
    constants.reserve(vtbl_array.dim);

    if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces
        // start with the interface info
        VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);

        // index into the interfaces array
        llvm::Constant* idxs[2] = {
            DtoConstSize_t(0),
            DtoConstSize_t(interfaces_index)
        };

        llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
            getInterfaceArraySymbol(), idxs, true);

        constants.push_back(c);
    }

    // add virtual function pointers
    size_t n = vtbl_array.dim;
    for (size_t i = b->base->vtblOffset(); i < n; i++)
    {
        Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]);
        if (dsym == NULL)
        {
            // FIXME
            // why is this null?
            // happens for mini/s.d
            constants.push_back(getNullValue(getVoidPtrType()));
            continue;
        }

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "vtbl entry not a function");

        assert((!fd->isAbstract() || fd->fbody) &&
            "null symbol in interface implementation vtable");

        fd->codegen(Type::sir);
        assert(fd->ir.irFunc && "invalid vtbl function");

        LLFunction *fn = fd->ir.irFunc->func;

        // If the base is a cpp interface, 'this' parameter is a pointer to
        // the interface not the underlying object as expected. Instead of
        // the function, we place into the vtable a small wrapper, called thunk,
        // that casts 'this' to the object and then pass it to the real function.
        if (b->base->isCPPinterface()) {
            TypeFunction *f = (TypeFunction*)fd->type->toBasetype();
            assert(f->fty.arg_this);

            // create the thunk function
            OutBuffer name;
            name.writestring("Th");
            name.printf("%i", b->offset);
            name.writestring(fd->mangle());
            LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)),
                                                 DtoLinkage(fd), name.toChars(), gIR->module);

            // create entry and end blocks
            llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "entry", thunk);
            llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", thunk);
            gIR->scopes.push_back(IRScope(beginbb, endbb));

            // copy the function parameters, so later we can pass them to the real function
            std::vector<LLValue*> args;
            llvm::Function::arg_iterator iarg = thunk->arg_begin();
            for (; iarg != thunk->arg_end(); ++iarg)
                args.push_back(iarg);

            // cast 'this' to Object
            LLValue* &thisArg = args[(f->fty.arg_sret == 0) ? 0 : 1];
            LLType* thisType = thisArg->getType();
            thisArg = DtoBitCast(thisArg, getVoidPtrType());
            thisArg = DtoGEP1(thisArg, DtoConstInt(-b->offset));
            thisArg = DtoBitCast(thisArg, thisType);

            // call the real vtbl function.
            LLValue *retVal = gIR->ir->CreateCall(fn, args);

            // return from the thunk
            if (thunk->getReturnType() == LLType::getVoidTy(gIR->context()))
                llvm::ReturnInst::Create(gIR->context(), beginbb);
            else
                llvm::ReturnInst::Create(gIR->context(), retVal, beginbb);

            // clean up
            gIR->scopes.pop_back();
            thunk->getBasicBlockList().pop_back();

            fn = thunk;
        }

        constants.push_back(fn);
    }

    // build the vtbl constant
    llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false);

    // create the global variable to hold it
    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);

    std::string mangle("_D");
    mangle.append(cd->mangle());
    mangle.append("11__interface");
    mangle.append(b->base->mangle());
    mangle.append("6__vtblZ");

    llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc,
        *gIR->module,
        vtbl_constant->getType(),
        true,
        _linkage,
        vtbl_constant,
        mangle
    );

    // insert into the vtbl map
    interfaceVtblMap.insert(std::make_pair(b->base, GV));

    return GV;
}
예제 #11
0
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) {
  IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(),
                         _to->toChars());
  LOG_SCOPE;

  Type *to = _to->toBasetype();

  // class -> pointer
  if (to->ty == Tpointer) {
    IF_LOG Logger::println("to pointer");
    LLType *tolltype = DtoType(_to);
    LLValue *rval = DtoBitCast(DtoRVal(val), tolltype);
    return new DImValue(_to, rval);
  }
  // class -> bool
  if (to->ty == Tbool) {
    IF_LOG Logger::println("to bool");
    LLValue *llval = DtoRVal(val);
    LLValue *zero = LLConstant::getNullValue(llval->getType());
    return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero));
  }
  // class -> integer
  if (to->isintegral()) {
    IF_LOG Logger::println("to %s", to->toChars());

    // get class ptr
    LLValue *v = DtoRVal(val);
    // cast to size_t
    v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), "");
    // cast to the final int type
    DImValue im(Type::tsize_t, v);
    return DtoCastInt(loc, &im, _to);
  }
  // class -> typeof(null)
  if (to->ty == Tnull) {
    IF_LOG Logger::println("to %s", to->toChars());
    return new DImValue(_to, LLConstant::getNullValue(DtoType(_to)));
  }

  // must be class/interface
  assert(to->ty == Tclass);
  TypeClass *tc = static_cast<TypeClass *>(to);

  // from type
  Type *from = val->type->toBasetype();
  TypeClass *fc = static_cast<TypeClass *>(from);

  // copy DMD logic:
  // if to isBaseOf from with offset:   (to ? to + offset : null)
  // else if from is C++ and to is C++:  to
  // else if from is C++ and to is D:    null
  // else if from is interface:          _d_interface_cast(to)
  // else if from is class:              _d_dynamic_cast(to)

  LLType *toType = DtoType(_to);
  int offset = 0;
  if (tc->sym->isBaseOf(fc->sym, &offset)) {
    Logger::println("static down cast");
    // interface types don't cover the full object in case of multiple inheritence
    //  so GEP on the original type is inappropriate

    // offset pointer
    LLValue *orig = DtoRVal(val);
    LLValue *v = orig;
    if (offset != 0) {
      v = DtoBitCast(v, getVoidPtrType());
      LLValue *off =
          LLConstantInt::get(LLType::getInt32Ty(gIR->context()), offset);
      v = gIR->ir->CreateGEP(v, off);
    }
    IF_LOG {
      Logger::cout() << "V = " << *v << std::endl;
      Logger::cout() << "T = " << *toType << std::endl;
    }
    v = DtoBitCast(v, toType);

    // Check whether the original value was null, and return null if so.
    // Sure we could have jumped over the code above in this case, but
    // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it
    // should be pretty cheap and perfectly safe even if the original was
    // null.
    LLValue *isNull = gIR->ir->CreateICmpEQ(
        orig, LLConstant::getNullValue(orig->getType()), ".nullcheck");
    v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(toType), v,
                              ".interface");
    // return r-value
    return new DImValue(_to, v);
  }
예제 #12
0
파일: nested.cpp 프로젝트: torje/ldc
DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref)
{
    Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars());
    LOG_SCOPE;

    ////////////////////////////////////
    // Locate context value

    Dsymbol* vdparent = vd->toParent2();
    assert(vdparent);

    IrFunction* irfunc = gIR->func();

    // Check whether we can access the needed frame
    FuncDeclaration *fd = irfunc->decl;
    while (fd != vdparent) {
        if (fd->isStatic()) {
            error(loc, "function %s cannot access frame of function %s", irfunc->decl->toPrettyChars(), vdparent->toPrettyChars());
            return new DVarValue(astype, vd, llvm::UndefValue::get(getPtrToType(DtoType(astype))));
        }
        fd = getParentFunc(fd, false);
        assert(fd);
    }

    // is the nested variable in this scope?
    if (vdparent == irfunc->decl)
    {
        LLValue* val = vd->ir.getIrValue();
        return new DVarValue(astype, vd, val);
    }

    LLValue *dwarfValue = 0;
    std::vector<LLValue*> dwarfAddr;
    LLType *int64Ty = LLType::getInt64Ty(gIR->context());

    // get the nested context
    LLValue* ctx = 0;
    if (irfunc->decl->isMember2())
    {
    #if DMDV2
        AggregateDeclaration* cd = irfunc->decl->isMember2();
        LLValue* val = irfunc->thisArg;
        if (cd->isClassDeclaration())
            val = DtoLoad(val);
    #else
        ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
        LLValue* val = DtoLoad(irfunc->thisArg);
    #endif
        ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
    }
    else if (irfunc->nestedVar) {
        ctx = irfunc->nestedVar;
        dwarfValue = ctx;
    } else {
        ctx = DtoLoad(irfunc->nestArg);
        dwarfValue = irfunc->nestArg;
        if (global.params.symdebug)
            dwarfOpDeref(dwarfAddr);
    }
    assert(ctx);

    DtoCreateNestedContextType(vdparent->isFuncDeclaration());
    assert(vd->ir.irLocal);

    ////////////////////////////////////
    // Extract variable from nested context

    if (nestedCtx == NCArray) {
        LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
        val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
        val = DtoAlignedLoad(val);
        assert(vd->ir.irLocal->value);
        val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
        return new DVarValue(astype, vd, val);
    }
    else if (nestedCtx == NCHybrid) {
        LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType));
        Logger::cout() << "Context: " << *val << '\n';
        Logger::cout() << "of type: " << *val->getType() << '\n';

        unsigned vardepth = vd->ir.irLocal->nestedDepth;
        unsigned funcdepth = irfunc->depth;

        Logger::cout() << "Variable: " << vd->toChars() << '\n';
        Logger::cout() << "Variable depth: " << vardepth << '\n';
        Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n';
        Logger::cout() << "Function depth: " << funcdepth << '\n';

        if (vardepth == funcdepth) {
            // This is not always handled above because functions without
            // variables accessed by nested functions don't create new frames.
            Logger::println("Same depth");
        } else {
            // Load frame pointer and index that...
            if (dwarfValue && global.params.symdebug) {
                dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth);
                dwarfOpDeref(dwarfAddr);
            }
            Logger::println("Lower depth");
            val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
            Logger::cout() << "Frame index: " << *val << '\n';
            val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str());
            Logger::cout() << "Frame: " << *val << '\n';
        }

        if (dwarfValue && global.params.symdebug)
            dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex);
        val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
        Logger::cout() << "Addr: " << *val << '\n';
        Logger::cout() << "of type: " << *val->getType() << '\n';
        if (vd->ir.irLocal->byref || byref) {
            val = DtoAlignedLoad(val);
            //dwarfOpDeref(dwarfAddr);
            Logger::cout() << "Was byref, now: " << *val << '\n';
            Logger::cout() << "of type: " << *val->getType() << '\n';
        }

        if (dwarfValue && global.params.symdebug)
            DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr);

        return new DVarValue(astype, vd, val);
    }
    else {
        assert(0 && "Not implemented yet");
    }
}
예제 #13
0
llvm::BasicBlock *ScopeStack::emitLandingPad() {
  // save and rewrite scope
  IRScope savedIRScope = irs->scope();

  llvm::BasicBlock *beginBB =
      llvm::BasicBlock::Create(irs->context(), "landingPad", irs->topfunc());
  irs->scope() = IRScope(beginBB);

  llvm::LandingPadInst *landingPad = createLandingPadInst(irs);

  // Stash away the exception object pointer and selector value into their
  // stack slots.
  llvm::Value *ehPtr = DtoExtractValue(landingPad, 0);
  irs->ir->CreateStore(ehPtr, irs->func()->getOrCreateEhPtrSlot());

  llvm::Value *ehSelector = DtoExtractValue(landingPad, 1);
  if (!irs->func()->ehSelectorSlot) {
    irs->func()->ehSelectorSlot =
        DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
  }
  irs->ir->CreateStore(ehSelector, irs->func()->ehSelectorSlot);

  // Add landingpad clauses, emit finallys and 'if' chain to catch the
  // exception.
  CleanupCursor lastCleanup = currentCleanupScope();
  for (auto it = catchScopes.rbegin(), end = catchScopes.rend(); it != end;
       ++it) {
    // Insert any cleanups in between the last catch we ran (i.e. tested for
    // and found that the type does not match) and this one.
    assert(lastCleanup >= it->cleanupScope);
    if (lastCleanup > it->cleanupScope) {
      landingPad->setCleanup(true);
      llvm::BasicBlock *afterCleanupBB = llvm::BasicBlock::Create(
          irs->context(), beginBB->getName() + llvm::Twine(".after.cleanup"),
          irs->topfunc());
      runCleanups(lastCleanup, it->cleanupScope, afterCleanupBB);
      irs->scope() = IRScope(afterCleanupBB);
      lastCleanup = it->cleanupScope;
    }

    // Add the ClassInfo reference to the landingpad instruction so it is
    // emitted to the EH tables.
    landingPad->addClause(it->classInfoPtr);

    llvm::BasicBlock *mismatchBB = llvm::BasicBlock::Create(
        irs->context(), beginBB->getName() + llvm::Twine(".mismatch"),
        irs->topfunc());

    // "Call" llvm.eh.typeid.for, which gives us the eh selector value to
    // compare the landing pad selector value with.
    llvm::Value *ehTypeId =
        irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
                            DtoBitCast(it->classInfoPtr, getVoidPtrType()));

    // Compare the selector value from the unwinder against the expected
    // one and branch accordingly.
    irs->ir->CreateCondBr(
        irs->ir->CreateICmpEQ(irs->ir->CreateLoad(irs->func()->ehSelectorSlot),
                              ehTypeId),
        it->bodyBlock, mismatchBB);
    irs->scope() = IRScope(mismatchBB);
  }

  // No catch matched. Execute all finallys and resume unwinding.
  if (lastCleanup > 0) {
    landingPad->setCleanup(true);
    runCleanups(lastCleanup, 0, irs->func()->getOrCreateResumeUnwindBlock());
  } else if (!catchScopes.empty()) {
    // Directly convert the last mismatch branch into a branch to the
    // unwind resume block.
    irs->scopebb()->replaceAllUsesWith(
        irs->func()->getOrCreateResumeUnwindBlock());
    irs->scopebb()->eraseFromParent();
  } else {
    irs->ir->CreateBr(irs->func()->getOrCreateResumeUnwindBlock());
  }

  irs->scope() = savedIRScope;
  return beginBB;
}
예제 #14
0
llvm::BasicBlock *
TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
                                     llvm::BasicBlock *unwindTo) {
  // a catch switch never needs to be cloned and is an unwind target itself
  if (isCatchSwitchBlock(cleanupScopes[scope].beginBlock()))
    return cleanupScopes[scope].beginBlock();

  // each cleanup block is bracketed by a pair of cleanuppad/cleanupret
  // instructions, any unwinding should also just continue at the next
  // cleanup block, e.g.:
  //
  // cleanuppad:
  //   %0 = cleanuppad within %funclet[]
  //   %frame = nullptr
  //   if (!_d_enter_cleanup(%frame)) br label %cleanupret
  //                                  else br label %copy
  //
  // copy:
  //   invoke _dtor to %cleanupret unwind %unwindTo [ "funclet"(token %0) ]
  //
  // cleanupret:
  //   _d_leave_cleanup(%frame)
  //   cleanupret %0 unwind %unwindTo
  //
  llvm::BasicBlock *cleanupbb = irs.insertBB("cleanuppad");
  auto funcletToken = llvm::ConstantTokenNone::get(irs.context());
  auto cleanuppad =
      llvm::CleanupPadInst::Create(funcletToken, {}, "", cleanupbb);

  llvm::BasicBlock *cleanupret = irs.insertBBAfter(cleanupbb, "cleanupret");

  // preparation to allocate some space on the stack where _d_enter_cleanup
  //  can place an exception frame (but not done here)
  auto frame = getNullPtr(getVoidPtrType());

  auto savedInsertBlock = irs.ir->GetInsertBlock();
  auto savedInsertPoint = irs.ir->GetInsertPoint();
  auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();

  auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
  irs.ir->SetInsertPoint(cleanupret);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  irs.ir->CreateCall(endFn, frame,
                     {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::CleanupReturnInst::Create(cleanuppad, unwindTo, cleanupret);

  auto copybb = cleanupScopes[scope].runCopying(irs, cleanupbb, cleanupret,
                                                unwindTo, cleanuppad);

  auto beginFn = getRuntimeFunction(Loc(), irs.module, "_d_enter_cleanup");
  irs.ir->SetInsertPoint(cleanupbb);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  auto exec = irs.ir->CreateCall(
      beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);

  irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint);
  irs.DBuilder.EmitStopPoint(savedDbgLoc);

  return cleanupbb;
}
예제 #15
0
llvm::AllocaInst *TryCatchFinallyScopes::getOrCreateEhPtrSlot() {
  if (!ehPtrSlot)
    ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
  return ehPtrSlot;
}
예제 #16
0
llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
#if LDC_LLVM_VER >= 308
  if (useMSVCEH()) {
    assert(currentCleanupScope() > 0);
    return emitLandingPadMSVC(currentCleanupScope() - 1);
  }
#endif

  // save and rewrite scope
  IRScope savedIRScope = irs.scope();

  // insert landing pads at the end of the function, in emission order,
  // to improve human-readability of the IR
  llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad");
  irs.scope() = IRScope(beginBB);

  llvm::LandingPadInst *landingPad = createLandingPadInst(irs);

  // Stash away the exception object pointer and selector value into their
  // stack slots.
  llvm::Value *ehPtr = DtoExtractValue(landingPad, 0);
  irs.ir->CreateStore(ehPtr, getOrCreateEhPtrSlot());

  llvm::Value *ehSelector = DtoExtractValue(landingPad, 1);
  if (!ehSelectorSlot)
    ehSelectorSlot = DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
  irs.ir->CreateStore(ehSelector, ehSelectorSlot);

  // Add landingpad clauses, emit finallys and 'if' chain to catch the
  // exception.
  CleanupCursor lastCleanup = currentCleanupScope();
  for (auto it = tryCatchScopes.rbegin(), end = tryCatchScopes.rend();
       it != end; ++it) {
    const auto &tryCatchScope = *it;

    // Insert any cleanups in between the previous (inner-more) try-catch scope
    // and this one.
    const auto newCleanup = tryCatchScope.getCleanupScope();
    assert(lastCleanup >= newCleanup);
    if (lastCleanup > newCleanup) {
      landingPad->setCleanup(true);
      llvm::BasicBlock *afterCleanupBB =
          irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup"));
      runCleanups(lastCleanup, newCleanup, afterCleanupBB);
      irs.scope() = IRScope(afterCleanupBB);
      lastCleanup = newCleanup;
    }

    for (const auto &cb : tryCatchScope.getCatchBlocks()) {
      // Add the ClassInfo reference to the landingpad instruction so it is
      // emitted to the EH tables.
      landingPad->addClause(cb.classInfoPtr);

      llvm::BasicBlock *mismatchBB =
          irs.insertBB(beginBB->getName() + llvm::Twine(".mismatch"));

      // "Call" llvm.eh.typeid.for, which gives us the eh selector value to
      // compare the landing pad selector value with.
      llvm::Value *ehTypeId =
          irs.ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
                             DtoBitCast(cb.classInfoPtr, getVoidPtrType()));

      // Compare the selector value from the unwinder against the expected
      // one and branch accordingly.
      irs.ir->CreateCondBr(
          irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId),
          cb.bodyBB, mismatchBB, cb.branchWeights);
      irs.scope() = IRScope(mismatchBB);
    }
  }

  // No catch matched. Execute all finallys and resume unwinding.
  auto resumeUnwindBlock = getOrCreateResumeUnwindBlock();
  if (lastCleanup > 0) {
    landingPad->setCleanup(true);
    runCleanups(lastCleanup, 0, resumeUnwindBlock);
  } else if (!tryCatchScopes.empty()) {
    // Directly convert the last mismatch branch into a branch to the
    // unwind resume block.
    irs.scopebb()->replaceAllUsesWith(resumeUnwindBlock);
    irs.scopebb()->eraseFromParent();
  } else {
    irs.ir->CreateBr(resumeUnwindBlock);
  }

  irs.scope() = savedIRScope;
  return beginBB;
}
예제 #17
0
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
  assert(catchBlocks.empty());

  auto &PGO = irs.funcGen().pgo;
  const auto entryCount = PGO.setCurrentStmt(stmt);

  struct CBPrototype {
    Type *t;
    llvm::BasicBlock *catchBB;
    uint64_t catchCount;
    uint64_t uncaughtCount;
  };
  llvm::SmallVector<CBPrototype, 8> cbPrototypes;
  cbPrototypes.reserve(stmt->catches->dim);

  for (auto c : *stmt->catches) {
    auto catchBB =
        irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
    irs.scope() = IRScope(catchBB);
    irs.DBuilder.EmitBlockStart(c->loc);
    PGO.emitCounterIncrement(c);

    bool isCPPclass = false;

    if (auto lp = c->langPlugin()) // CALYPSO
      lp->codegen()->toBeginCatch(irs, c);
    else
    {

    const auto cd = c->type->toBasetype()->isClassHandle();
    isCPPclass = cd->isCPPclass();

    const auto enterCatchFn = getRuntimeFunction(
        Loc(), irs.module,
        isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch");
    const auto ptr = DtoLoad(ehPtrSlot);
    const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr);

    // For catches that use the Throwable object, create storage for it.
    // We will set it in the code that branches from the landing pads
    // (there might be more than one) to catchBB.
    if (c->var) {
      // This will alloca if we haven't already and take care of nested refs
      // if there are any.
      DtoDeclarationExp(c->var);

      // Copy the exception reference over from the _d_eh_enter_catch return
      // value.
      DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)),
               getIrLocal(c->var)->value);
    }
    }

    // Emit handler, if there is one. The handler is zero, for instance,
    // when building 'catch { debug foo(); }' in non-debug mode.
    if (isCPPclass) {
      // from DMD:

      /* C++ catches need to end with call to __cxa_end_catch().
       * Create:
       *   try { handler } finally { __cxa_end_catch(); }
       * Note that this is worst case code because it always sets up an
       * exception handler. At some point should try to do better.
       */
      FuncDeclaration *fdend =
          FuncDeclaration::genCfunc(nullptr, Type::tvoid, "__cxa_end_catch");
      Expression *efunc = VarExp::create(Loc(), fdend);
      Expression *ecall = CallExp::create(Loc(), efunc);
      ecall->type = Type::tvoid;
      Statement *call = ExpStatement::create(Loc(), ecall);
      Statement *stmt =
          c->handler ? TryFinallyStatement::create(Loc(), c->handler, call)
                     : call;
      Statement_toIR(stmt, &irs);
    } else {
      if (c->handler)
        Statement_toIR(c->handler, &irs);
    }

    if (!irs.scopereturned())
    {
      // CALYPSO FIXME: _cxa_end_catch won't be called if it has already returned
      if (auto lp = c->langPlugin())
        lp->codegen()->toEndCatch(irs, c);
      irs.ir->CreateBr(endbb);
    }

    irs.DBuilder.EmitBlockEnd();

    // PGO information, currently unused
    auto catchCount = PGO.getRegionCount(c);
    // uncaughtCount is handled in a separate pass below

    cbPrototypes.push_back({c->type->toBasetype(), catchBB, catchCount, 0}); // CALYPSO
  }

  // Total number of uncaught exceptions is equal to the execution count at
  // the start of the try block minus the one after the continuation.
  // uncaughtCount keeps track of the exception type mismatch count while
  // iterating through the catch block prototypes in reversed order.
  auto uncaughtCount = entryCount - PGO.getRegionCount(stmt);
  for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end;
       ++it) {
    it->uncaughtCount = uncaughtCount;
    // Add this catch block's match count to the uncaughtCount, because these
    // failed to match the remaining (lexically preceding) catch blocks.
    uncaughtCount += it->catchCount;
  }

  catchBlocks.reserve(stmt->catches->dim);

  auto c_it = stmt->catches->begin(); // CALYPSO
  for (const auto &p : cbPrototypes) {
    auto branchWeights =
        PGO.createProfileWeights(p.catchCount, p.uncaughtCount);
    LLGlobalVariable *ci;
    if (auto lp = (*c_it)->langPlugin()) // CALYPSO
      ci = lp->codegen()->toCatchScopeType(irs, p.t);
    else {
      ClassDeclaration *cd = p.t->isClassHandle();
      DtoResolveClass(cd);
      if (cd->isCPPclass()) {
        const char *name = Target::cppTypeInfoMangle(cd);
        auto cpp_ti = getOrCreateGlobal(
            cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true,
            LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name);

        // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that
        // the personality routine may differentiate C++ catch clauses from D ones.
        OutBuffer mangleBuf;
        mangleBuf.writestring("_D");
        mangleToBuffer(cd, &mangleBuf);
        mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr");
        const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd);

        RTTIBuilder b(ClassDeclaration::cpp_type_info_ptr);
        b.push(cpp_ti);

        auto wrapperType = llvm::cast<llvm::StructType>(
            static_cast<IrTypeClass*>(ClassDeclaration::cpp_type_info_ptr->type->ctype)->getMemoryLLType());
        auto wrapperInit = b.get_constant(wrapperType);

        ci = getOrCreateGlobal(
            cd->loc, irs.module, wrapperType, /*isConstant=*/true,
            LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle);
      } else {
        ci = getIrAggr(cd)->getClassInfoSymbol();
      }
    }
    catchBlocks.push_back({ci, p.catchBB, branchWeights});
    c_it++;
  }
}
예제 #18
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';
    }
}
예제 #19
0
void RTTIBuilder::push_size_as_vp(uint64_t s)
{
    inits.push_back(llvm::ConstantExpr::getIntToPtr(DtoConstSize_t(s), getVoidPtrType()));
}
예제 #20
0
파일: irclass.cpp 프로젝트: NilsBossung/ldc
llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index)
{
    ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base);
    if (it != interfaceVtblMap.end())
        return it->second;

    IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
        b->base->toPrettyChars(), aggrdecl->toPrettyChars());
    LOG_SCOPE;

    ClassDeclaration* cd = aggrdecl->isClassDeclaration();
    assert(cd && "not a class aggregate");

    FuncDeclarations vtbl_array;
    b->fillVtbl(cd, &vtbl_array, new_instance);

    std::vector<llvm::Constant*> constants;
    constants.reserve(vtbl_array.dim);

    // start with the interface info
    VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);

    // index into the interfaces array
    llvm::Constant* idxs[2] = {
        DtoConstSize_t(0),
        DtoConstSize_t(interfaces_index)
    };

    llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
        getInterfaceArraySymbol(), idxs, true);

    constants.push_back(c);

    // add virtual function pointers
    size_t n = vtbl_array.dim;
    for (size_t i = 1; i < n; i++)
    {
        Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]);
        if (dsym == NULL)
        {
            // FIXME
            // why is this null?
            // happens for mini/s.d
            constants.push_back(getNullValue(getVoidPtrType()));
            continue;
        }

        FuncDeclaration* fd = dsym->isFuncDeclaration();
        assert(fd && "vtbl entry not a function");

        assert((!fd->isAbstract() || fd->fbody) &&
            "null symbol in interface implementation vtable");

        fd->codegen(Type::sir);
        assert(fd->ir.irFunc && "invalid vtbl function");

        constants.push_back(fd->ir.irFunc->func);
    }

    // build the vtbl constant
    llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false);

    // create the global variable to hold it
    llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);

    std::string mangle("_D");
    mangle.append(cd->mangle());
    mangle.append("11__interface");
    mangle.append(b->base->mangle());
    mangle.append("6__vtblZ");

    llvm::GlobalVariable* GV = new llvm::GlobalVariable(
        *gIR->module,
        vtbl_constant->getType(),
        true,
        _linkage,
        vtbl_constant,
        mangle
    );

    // insert into the vtbl map
    interfaceVtblMap.insert(std::make_pair(b->base, GV));

    return GV;
}
예제 #21
0
파일: nested.cpp 프로젝트: OpenFlex/ldc
LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
{
    Logger::println("DtoNestedContext for %s", sym->toPrettyChars());
    LOG_SCOPE;

    IrFunction* irfunc = gIR->func();
    bool fromParent = true;

    LLValue* val;
    // if this func has its own vars that are accessed by nested funcs
    // use its own context
    if (irfunc->nestedVar) {
        val = irfunc->nestedVar;
        fromParent = false;
    }
    // otherwise, it may have gotten a context from the caller
    else if (irfunc->nestArg)
        val = DtoLoad(irfunc->nestArg);
    // or just have a this argument
    else if (irfunc->thisArg)
    {
        AggregateDeclaration* ad = irfunc->decl->isMember2();
        val = ad->isClassDeclaration() ? DtoLoad(irfunc->thisArg) : irfunc->thisArg;
        if (!ad->vthis)
        {
            // This is just a plain 'outer' reference of a class nested in a
            // function (but without any variables in the nested context).
            return val;
        }
        val = DtoLoad(DtoGEPi(val, 0, ad->vthis->ir.irField->index, ".vthis"));
    }
    else
    {
        // Use null instead of e.g. LLVM's undef to not break bitwise
        // comparison for instances of nested struct types which don't have any
        // nested references.
        return llvm::ConstantPointerNull::get(getVoidPtrType());
    }

    struct FuncDeclaration* fd = 0;
    if (AggregateDeclaration *ad = sym->isAggregateDeclaration())
        // If sym is a nested struct or a nested class, pass the frame
        // of the function where sym is declared.
        fd = ad->toParent()->isFuncDeclaration();
    else
    if (FuncDeclaration* symfd = sym->isFuncDeclaration()) {
        // Make sure we've had a chance to analyze nested context usage
        DtoCreateNestedContextType(symfd);

        // if this is for a function that doesn't access variables from
        // enclosing scopes, it doesn't matter what we pass.
        // Tell LLVM about it by passing an 'undef'.
        if (symfd && symfd->ir.irFunc->depth == -1)
            return llvm::UndefValue::get(getVoidPtrType());

        // If sym is a nested function, and it's parent context is different than the
        // one we got, adjust it.
        fd = getParentFunc(symfd, true);
    }
    if (fd) {
        Logger::println("For nested function, parent is %s", fd->toChars());
        FuncDeclaration* ctxfd = irfunc->decl;
        Logger::println("Current function is %s", ctxfd->toChars());
        if (fromParent) {
            ctxfd = getParentFunc(ctxfd, true);
            assert(ctxfd && "Context from outer function, but no outer function?");
        }
        Logger::println("Context is from %s", ctxfd->toChars());

        unsigned neededDepth = fd->ir.irFunc->depth;
        unsigned ctxDepth = ctxfd->ir.irFunc->depth;

        Logger::cout() << "Needed depth: " << neededDepth << '\n';
        Logger::cout() << "Context depth: " << ctxDepth << '\n';

        if (neededDepth >= ctxDepth) {
            // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?");
            // fd needs the same context as we do, so all is well
            Logger::println("Calling sibling function or directly nested function");
        } else {
            val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType));
            val = DtoGEPi(val, 0, neededDepth);
            val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str());
        }
    }

    Logger::cout() << "result = " << *val << '\n';
    Logger::cout() << "of type " << *val->getType() << '\n';
    return val;
}
예제 #22
0
파일: tollvm.cpp 프로젝트: mleise/ldc
LLStructType* DtoMutexType()
{
    if (gIR->mutexType)
        return gIR->mutexType;

    // The structures defined here must be the same as in druntime/src/rt/critical.c

    // Windows
    if (global.params.targetTriple.isOSWindows())
    {
        llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(gIR->context());
        llvm::Type *Int32Ty = llvm::Type::getInt32Ty(gIR->context());

        // Build RTL_CRITICAL_SECTION; size is 24 (32bit) or 40 (64bit)
        LLType *rtl_types[] = {
            VoidPtrTy, // Pointer to DebugInfo
            Int32Ty,   // LockCount
            Int32Ty,   // RecursionCount
            VoidPtrTy, // Handle of OwningThread
            VoidPtrTy, // Handle of LockSemaphore
            VoidPtrTy  // SpinCount
        };
        LLStructType* rtl = LLStructType::create(gIR->context(), rtl_types, "RTL_CRITICAL_SECTION");

        // Build D_CRITICAL_SECTION; size is 28 (32bit) or 48 (64bit)
        LLStructType *mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION");
        LLType *types[] = { getPtrToType(mutex), rtl };
        mutex->setBody(types);

        // Cache type
        gIR->mutexType = mutex;

        return mutex;
    }

    // FreeBSD
    else if (global.params.targetTriple.getOS() == llvm::Triple::FreeBSD) {
        // Just a pointer
        return LLStructType::get(gIR->context(), DtoSize_t());
    }

    // pthread_fastlock
    LLType *types2[] = {
        DtoSize_t(),
        LLType::getInt32Ty(gIR->context()) 
    };
    LLStructType* fastlock = LLStructType::get(gIR->context(), types2, false);

    // pthread_mutex
    LLType *types1[] = {
        LLType::getInt32Ty(gIR->context()),
        LLType::getInt32Ty(gIR->context()),
        getVoidPtrType(),
        LLType::getInt32Ty(gIR->context()),
        fastlock
    };
    LLStructType* pmutex = LLStructType::get(gIR->context(), types1, false);

    // D_CRITICAL_SECTION
    LLStructType* mutex = LLStructType::create(gIR->context(), "D_CRITICAL_SECTION");
    LLType *types[] = { getPtrToType(mutex), pmutex };
    mutex->setBody(types);

    // Cache type
    gIR->mutexType = mutex;

    return pmutex;
}
예제 #23
0
llvm::AllocaInst *IrFunction::getOrCreateEhPtrSlot() {
  if (!ehPtrSlot) {
    ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
  }
  return ehPtrSlot;
}
예제 #24
0
파일: nested.cpp 프로젝트: OpenFlex/ldc
void DtoCreateNestedContext(FuncDeclaration* fd) {
    Logger::println("DtoCreateNestedContext for %s", fd->toChars());
    LOG_SCOPE

    DtoCreateNestedContextType(fd);

    // construct nested variables array
    if (!fd->nestedVars.empty())
    {
        IrFunction* irfunction = fd->ir.irFunc;
        unsigned depth = irfunction->depth;
        LLStructType *frameType = irfunction->frameType;
        // Create frame for current function and append to frames list
        // FIXME: alignment ?
        LLValue* frame = 0;
        if (fd->needsClosure())
            frame = DtoGcMalloc(frameType, ".frame");
        else
            frame = DtoRawAlloca(frameType, 0, ".frame");

        // copy parent frames into beginning
        if (depth != 0) {
            LLValue* src = irfunction->nestArg;
            if (!src) {
                assert(irfunction->thisArg);
                assert(fd->isMember2());
                LLValue* thisval = DtoLoad(irfunction->thisArg);
                AggregateDeclaration* cd = fd->isMember2();
                assert(cd);
                assert(cd->vthis);
                Logger::println("Indexing to 'this'");
                if (cd->isStructDeclaration())
                    src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis");
                else
                    src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
            } else {
                src = DtoLoad(src);
            }
            if (depth > 1) {
                src = DtoBitCast(src, getVoidPtrType());
                LLValue* dst = DtoBitCast(frame, getVoidPtrType());
                DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE),
                    getABITypeAlign(getVoidPtrType()));
            }
            // Copy nestArg into framelist; the outer frame is not in the list of pointers
            src = DtoBitCast(src, frameType->getContainedType(depth-1));
            LLValue* gep = DtoGEPi(frame, 0, depth-1);
            DtoAlignedStore(src, gep);
        }

        // store context in IrFunction
        irfunction->nestedVar = frame;

        // go through all nested vars and assign addresses where possible.
        for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
        {
            VarDeclaration* vd = *i;

            LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
            if (vd->isParameter()) {
                Logger::println("nested param: %s", vd->toChars());
                LOG_SCOPE
                IrParameter* parm = vd->ir.irParam;

                if (parm->arg->byref)
                {
                    storeVariable(vd, gep);
                }
                else
                {
                    Logger::println("Copying to nested frame");
                    // The parameter value is an alloca'd stack slot.
                    // Copy to the nesting frame and leave the alloca for
                    // the optimizers to clean up.
                    DtoStore(DtoLoad(parm->value), gep);
                    gep->takeName(parm->value);
                    parm->value = gep;
                }
            } else {
                Logger::println("nested var:   %s", vd->toChars());
                assert(!vd->ir.irLocal->value);
                vd->ir.irLocal->value = gep;
            }

            if (global.params.symdebug) {
                LLSmallVector<LLValue*, 2> addr;
                dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex);
                DtoDwarfLocalVariable(frame, vd, addr);
            }
        }
    }
}
예제 #25
0
void RTTIBuilder::push_null_vp()
{
    inits.push_back(getNullValue(getVoidPtrType()));
}
예제 #26
0
//
// Method: addGetActualValue()
//
// Description:
//  Insert a call to the getactualvalue() run-time function to convert the
//  potentially Out of Bound pointer back into its original value.
//
// Inputs:
//  SCI     - The instruction that has arguments requiring conversion.
//  operand - The index of the operand to the instruction that requires
//            conversion.
//
void
RewriteOOB::addGetActualValue (Instruction *SCI, unsigned operand) {
  //
  // Get a reference to the getactualvalue() function.
  //
  Module * M = SCI->getParent()->getParent()->getParent();
  Type * VoidPtrTy = getVoidPtrType (M->getContext());
  Constant * GAVConst = M->getOrInsertFunction ("pchk_getActualValue",
                                                VoidPtrTy,
                                                VoidPtrTy,
                                                VoidPtrTy,
                                                NULL);
  Function * GetActualValue = cast<Function>(GAVConst);

  //
  // Get the operand that needs to be replaced.
  //
  Value * Operand = SCI->getOperand(operand);

  //
  //
  // Rewrite pointers are generated from calls to the SAFECode run-time
  // checks.  Therefore, constants and return values from allocation
  // functions are known to be the original value and do not need to be
  // rewritten back into their orignal values.
  //
  // FIXME:
  //  Add a case for calls to heap allocation functions.
  //
  Value * PeeledOperand = Operand->stripPointerCasts();
  if (isa<Constant>(PeeledOperand) || isa<AllocaInst>(PeeledOperand)) {
    return;
  }

  //
  // Get the pool handle associated with the pointer.
  //
  Value *PH = ConstantPointerNull::get (getVoidPtrType(Operand->getContext()));

  //
  // Create a call to getActualValue() to convert the pointer back to its
  // original value.
  //

  //
  // Update the number of calls to getActualValue() that we inserted.
  //
  ++GetActuals;

  //
  // Insert the call to getActualValue()
  //
  Type * VoidPtrType = getVoidPtrType(Operand->getContext());
  Value * OpVptr = castTo (Operand,
                           VoidPtrType,
                           Operand->getName() + ".casted",
                           SCI);

  std::vector<Value *> args;
  args.push_back (PH);
  args.push_back (OpVptr);
  CallInst *CI = CallInst::Create (GetActualValue,
                                   args,
                                   "getval",
                                   SCI);
  Instruction *CastBack = castTo (CI,
                                  Operand->getType(),
                                  Operand->getName()+".castback",
                                  SCI);
  SCI->setOperand (operand, CastBack);
  return;
}
예제 #27
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);
        }
    }
}
//
// Method: registerAllocaInst()
//
// Description:
//  Register a single alloca instruction.
//
// Inputs:
//  AI - The alloca which requires registration.
//
// Return value:
//  NULL - The alloca was not registered.
//  Otherwise, the call to poolregister() is returned.
//
CallInst *
RegisterStackObjPass::registerAllocaInst (AllocaInst *AI) {
  //
  // Determine if any use (direct or indirect) escapes this function.  If
  // not, then none of the checks will consult the MetaPool, and we can
  // forego registering the alloca.
  //
#if 0
  bool MustRegisterAlloca = false;
#else
  //
  // FIXME: For now, register all allocas.  The reason is that this
  // optimization requires that other optimizations be executed, and those are
  // not integrated into LLVM yet.
  //
  bool MustRegisterAlloca = true;
#endif
  std::vector<Value *> AllocaWorkList;
  AllocaWorkList.push_back (AI);
  while ((!MustRegisterAlloca) && (AllocaWorkList.size())) {
    Value * V = AllocaWorkList.back();
    AllocaWorkList.pop_back();
    Value::use_iterator UI = V->use_begin();
    for (; UI != V->use_end(); ++UI) {
      // We cannot handle PHI nodes or Select instructions
      if (isa<PHINode>(*UI) || isa<SelectInst>(*UI)) {
        MustRegisterAlloca = true;
        continue;
      }

      // The pointer escapes if it's stored to memory somewhere.
      StoreInst * SI;
      if ((SI = dyn_cast<StoreInst>(*UI)) && (SI->getOperand(0) == V)) {
        MustRegisterAlloca = true;
        continue;
      }

      // GEP instructions are okay, but need to be added to the worklist
      if (isa<GetElementPtrInst>(*UI)) {
        AllocaWorkList.push_back (*UI);
        continue;
      }

      // Cast instructions are okay as long as they cast to another pointer
      // type
      if (CastInst * CI = dyn_cast<CastInst>(*UI)) {
        if (isa<PointerType>(CI->getType())) {
          AllocaWorkList.push_back (*UI);
          continue;
        } else {
          MustRegisterAlloca = true;
          continue;
        }
      }

#if 0
      if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(*UI)) {
        if (cExpr->getOpcode() == Instruction::Cast) {
          AllocaWorkList.push_back (*UI);
          continue;
        } else {
          MustRegisterAlloca = true;
          continue;
        }
      }
#endif

      CallInst * CI1;
      if ((CI1 = dyn_cast<CallInst>(*UI))) {
        if (!(CI1->getCalledFunction())) {
          MustRegisterAlloca = true;
          continue;
        }

        std::string FuncName = CI1->getCalledFunction()->getName();
        if (FuncName == "exactcheck3") {
          AllocaWorkList.push_back (*UI);
          continue;
        } else if ((FuncName == "llvm.memcpy.i32")    || 
                   (FuncName == "llvm.memcpy.i64")    ||
                   (FuncName == "llvm.memset.i32")    ||
                   (FuncName == "llvm.memset.i64")    ||
                   (FuncName == "llvm.memmove.i32")   ||
                   (FuncName == "llvm.memmove.i64")   ||
                   (FuncName == "llva_memcpy")        ||
                   (FuncName == "llva_memset")        ||
                   (FuncName == "llva_strncpy")       ||
                   (FuncName == "llva_invokememcpy")  ||
                   (FuncName == "llva_invokestrncpy") ||
                   (FuncName == "llva_invokememset")  ||
                   (FuncName == "memcmp")) {
          continue;
        } else {
          MustRegisterAlloca = true;
          continue;
        }
      }
    }
  }

  if (!MustRegisterAlloca) {
    ++SavedRegAllocs;
    return 0;
  }

  //
  // Insert the alloca registration.
  //

  //
  // Create an LLVM Value for the allocation size.  Insert a multiplication
  // instruction if the allocation allocates an array.
  //
  Type * Int32Type = IntegerType::getInt32Ty(AI->getContext());
  unsigned allocsize = TD->getTypeAllocSize(AI->getAllocatedType());
  Value *AllocSize = ConstantInt::get (AI->getOperand(0)->getType(), allocsize);
  if (AI->isArrayAllocation()) {
    Value * Operand = AI->getOperand(0);
    AllocSize = BinaryOperator::Create(Instruction::Mul,
                                       AllocSize,
                                       Operand,
                                       "sizetmp",
                                       AI);
  }
  AllocSize = castTo (AllocSize, Int32Type, "sizetmp", AI);

  //
  // Attempt to insert the call to register the alloca'ed object after all of
  // the alloca instructions in the basic block.
  //
  Instruction *iptI = AI;
  BasicBlock::iterator InsertPt = AI;
  iptI = ++InsertPt;
  if (AI->getParent() == (&(AI->getParent()->getParent()->getEntryBlock()))) {
    InsertPt = AI->getParent()->begin();
    while (&(*(InsertPt)) != AI)
      ++InsertPt;
    while (isa<AllocaInst>(InsertPt))
      ++InsertPt;
    iptI = InsertPt;
  }

  //
  // Insert a call to register the object.
  //
  PointerType * VoidPtrTy = getVoidPtrType(AI->getContext());
  Instruction *Casted = castTo (AI, VoidPtrTy, AI->getName()+".casted", iptI);
  Value * CastedPH    = ConstantPointerNull::get (VoidPtrTy);
  std::vector<Value *> args;
  args.push_back (CastedPH);
  args.push_back (Casted);
  args.push_back (AllocSize);

  // Update statistics
  ++StackRegisters;
  return CallInst::Create (PoolRegister, args, "", iptI);
}
예제 #29
0
파일: tollvm.cpp 프로젝트: mleise/ldc
LLType* DtoType(Type* t)
{
    t = stripModifiers( t );

    if (t->ctype)
    {
        return t->ctype->getLLType();
    }

    IF_LOG Logger::println("Building type: %s", t->toChars());
    LOG_SCOPE;

    assert(t);
    switch (t->ty)
    {
    // basic types
    case Tvoid:
    case Tint8:
    case Tuns8:
    case Tint16:
    case Tuns16:
    case Tint32:
    case Tuns32:
    case Tint64:
    case Tuns64:
    case Tint128:
    case Tuns128:
    case Tfloat32:
    case Tfloat64:
    case Tfloat80:
    case Timaginary32:
    case Timaginary64:
    case Timaginary80:
    case Tcomplex32:
    case Tcomplex64:
    case Tcomplex80:
    //case Tbit:
    case Tbool:
    case Tchar:
    case Twchar:
    case Tdchar:
    {
        return IrTypeBasic::get(t)->getLLType();
    }

    // pointers
    case Tnull:
    case Tpointer:
    {
        return IrTypePointer::get(t)->getLLType();
    }

    // arrays
    case Tarray:
    {
        return IrTypeArray::get(t)->getLLType();
    }

    case Tsarray:
    {
        return IrTypeSArray::get(t)->getLLType();
    }

    // aggregates
    case Tstruct:
    {
        TypeStruct* ts = static_cast<TypeStruct*>(t);
        if (ts->sym->type->ctype)
        {
            // This should not happen, but the frontend seems to be buggy. Not
            // sure if this is the best way to handle the situation, but we
            // certainly don't want to override ts->sym->type->ctype.
            IF_LOG Logger::cout() << "Struct with multiple Types detected: " <<
                ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl;
            return ts->sym->type->ctype->getLLType();
        }
        return IrTypeStruct::get(ts->sym)->getLLType();
    }
    case Tclass:
    {
        TypeClass* tc = static_cast<TypeClass*>(t);
        if (tc->sym->type->ctype)
        {
            // See Tstruct case.
            IF_LOG Logger::cout() << "Class with multiple Types detected: " <<
                tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl;
            return tc->sym->type->ctype->getLLType();
        }
        return IrTypeClass::get(tc->sym)->getLLType();
    }

    // functions
    case Tfunction:
    {
        return IrTypeFunction::get(t)->getLLType();
    }

    // delegates
    case Tdelegate:
    {
        return IrTypeDelegate::get(t)->getLLType();
    }

    // typedefs
    // enum

    // FIXME: maybe just call toBasetype first ?
    case Tenum:
    {
        Type* bt = t->toBasetype();
        assert(bt);
        return DtoType(bt);
    }

    // associative arrays
    case Taarray:
        return getVoidPtrType();

    case Tvector:
    {
        return IrTypeVector::get(t)->getLLType();
    }

/*
    Not needed atm as VarDecls for tuples are rewritten as a string of
    VarDecls for the fields (u -> _u_field_0, ...)

    case Ttuple:
    {
        TypeTuple* ttupl = static_cast<TypeTuple*>(t);
        return DtoStructTypeFromArguments(ttupl->arguments);
    }
*/

    default:
        llvm_unreachable("Unknown class of D Type!");
    }
    return 0;
}
//
// Function: insertPoolFrees()
//
// Description:
//  This function takes a list of alloca instructions and inserts code to
//  unregister them at every unwind and return instruction.
//
// Inputs:
//  PoolRegisters - The list of calls to poolregister() inserted for stack
//                  objects.
//  ExitPoints    - The list of instructions that can cause the function to
//                  return.
//  Context       - The LLVM Context in which to insert instructions.
//
void
RegisterStackObjPass::insertPoolFrees
  (const std::vector<CallInst *> & PoolRegisters,
   const std::vector<Instruction *> & ExitPoints,
   LLVMContext * Context) {
  // List of alloca instructions we create to store the pointers to be
  // deregistered.
  std::vector<AllocaInst *> PtrList;

  // List of pool handles; this is a parallel array to PtrList
  std::vector<Value *> PHList;

  // The infamous void pointer type
  PointerType * VoidPtrTy = getVoidPtrType(*Context);

  //
  // Create alloca instructions for every registered alloca.  These will hold
  // a pointer to the registered stack objects and will be referenced by
  // poolunregister().
  //
  for (unsigned index = 0; index < PoolRegisters.size(); ++index) {
    //
    // Take the first element off of the worklist.
    //
    CallInst * CI = PoolRegisters[index];
    CallSite CS(CI);

    //
    // Get the pool handle and allocated pointer from the poolregister() call.
    //
    Value * PH  = CS.getArgument(0);
    Value * Ptr = CS.getArgument(1);

    //
    // Create a place to store the pointer returned from alloca.  Initialize it
    // with a null pointer.
    //
    BasicBlock & EntryBB = CI->getParent()->getParent()->getEntryBlock();
    Instruction * InsertPt = &(EntryBB.front());
    AllocaInst * PtrLoc = new AllocaInst (VoidPtrTy,
                                          Ptr->getName() + ".st",
                                          InsertPt);
    Value * NullPointer = ConstantPointerNull::get(VoidPtrTy);
    new StoreInst (NullPointer, PtrLoc, InsertPt);

    //
    // Store the registered pointer into the memory we allocated in the entry
    // block.
    //
    new StoreInst (Ptr, PtrLoc, CI);

    //
    // Record the alloca that stores the pointer to deregister.
    // Record the pool handle with it.
    //
    PtrList.push_back (PtrLoc);
    PHList.push_back (PH);
  }

  //
  // For each point where the function can exit, insert code to deregister all
  // stack objects.
  //
  for (unsigned index = 0; index < ExitPoints.size(); ++index) {
    //
    // Take the first element off of the worklist.
    //
    Instruction * Return = ExitPoints[index];

    //
    // Deregister each registered stack object.
    //
    for (unsigned i = 0; i < PtrList.size(); ++i) {
      //
      // Get the location holding the pointer and the pool handle associated
      // with it.
      //
      AllocaInst * PtrLoc = PtrList[i];
      Value * PH = PHList[i];

      //
      // Generate a load instruction to get the registered pointer.
      //
      LoadInst * Ptr = new LoadInst (PtrLoc, "", Return);

      //
      // Create the call to poolunregister().
      //
      std::vector<Value *> args;
      args.push_back (PH);
      args.push_back (Ptr);
      CallInst::Create (StackFree, args, "", Return);
    }
  }

  //
  // Lastly, promote the allocas we created into LLVM virtual registers.
  //
  PromoteMemToReg(PtrList, *DT);
}