Example #1
0
std::vector<llvm::Type *>
IrTypeClass::buildVtblType(Type *first, FuncDeclarations *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);

  auto I = vtbl_array->begin();
  // first comes the classinfo for D interfaces
  if (first) {
    types.push_back(DtoType(first));
    ++I;
  }

  // then come the functions
  for (auto E = vtbl_array->end(); I != E; ++I) {
    FuncDeclaration *fd = *I;
    if (fd == nullptr) {
      // FIXME: This stems from the ancient D1 days – can it still happen?
      types.push_back(getVoidPtrType());
      continue;
    }

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

    // If inferring return type and semantic3 has not been run, do it now.
    // This pops up in some other places in the frontend as well, however
    // it is probably a bug that it still occurs that late.
    if (!fd->type->nextOf() && fd->inferRetType) {
      Logger::println("Running late semantic3 to infer return type.");
      TemplateInstance *spec = fd->isSpeculative();
      unsigned int olderrs = global.errors;
      fd->semantic3(fd->_scope);
      if (spec && global.errors != olderrs) {
        spec->errors = global.errors - olderrs;
      }
    }

    if (!fd->type->nextOf()) {
      // Return type of the function has not been inferred. This seems to
      // happen with virtual functions and is probably a frontend bug.
      IF_LOG Logger::println("Broken function type, semanticRun: %d",
                             fd->semanticRun);
      types.push_back(getVoidPtrType());
      continue;
    }

    types.push_back(getPtrToType(DtoFunctionType(fd)));
  }

  return types;
}
Example #2
0
IrTypeFunction* IrTypeFunction::get(Type* dt, Type* nestedContextOverride)
{
    assert(!dt->irtype);
    assert(dt->ty == Tfunction);

    TypeFunction* tf = static_cast<TypeFunction*>(dt);
    llvm::Type* lt = DtoFunctionType(tf, tf->irFty, NULL, nestedContextOverride);

    if (!dt->irtype)
        dt->irtype = new IrTypeFunction(dt, lt);
    return dt->irtype->isFunction();
}
Example #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();
}
Example #4
0
llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
{
    // handle for C vararg intrinsics
    if (DtoIsVaIntrinsic(fdecl))
        return DtoVaFunctionType(fdecl);

    Type *dthis=0, *dnest=0;

    if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) {
        FuncDeclaration *p = fdecl->parent->isFuncDeclaration();
        assert(p);
        AggregateDeclaration *ad = p->isMember2();
        assert(ad);
        dnest = Type::tvoid->pointerTo();
    } else
    if (fdecl->needThis()) {
        if (AggregateDeclaration* ad = fdecl->isMember2()) {
            IF_LOG Logger::println("isMember = this is: %s", ad->type->toChars());
            dthis = ad->type;
            LLType* thisty = DtoType(dthis);
            //Logger::cout() << "this llvm type: " << *thisty << '\n';
            if (ad->isStructDeclaration())
                thisty = getPtrToType(thisty);
        }
        else {
            IF_LOG Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind());
            llvm_unreachable("needThis, but invalid parent declaration.");
        }
    }
    else if (fdecl->isNested()) {
        dnest = Type::tvoid->pointerTo();
    }

    LLFunctionType* functype = DtoFunctionType(fdecl->type, getIrFunc(fdecl, true)->irFty, dthis, dnest,
                                               fdecl->isMain(), fdecl->isCtorDeclaration(),
                                               fdecl->llvmInternal == LLVMintrinsic);

    return functype;
}
Example #5
0
void DtoDeclareFunction(FuncDeclaration* fdecl)
{
    DtoResolveFunction(fdecl);

    if (fdecl->ir.isDeclared()) return;
    fdecl->ir.setDeclared();

    IF_LOG Logger::println("DtoDeclareFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars());
    LOG_SCOPE;

    if (fdecl->isUnitTestDeclaration() && !global.params.useUnitTests)
    {
        Logger::println("unit tests not enabled");
        return;
    }

    //printf("declare function: %s\n", fdecl->toPrettyChars());

    // intrinsic sanity check
    if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) {
        error(fdecl->loc, "intrinsics cannot have function bodies");
        fatal();
    }

    // get TypeFunction*
    Type* t = fdecl->type->toBasetype();
    TypeFunction* f = static_cast<TypeFunction*>(t);

    // create IrFunction
    IrFunction *irFunc = getIrFunc(fdecl, true);

    LLFunction* vafunc = 0;
    if (DtoIsVaIntrinsic(fdecl))
        vafunc = DtoDeclareVaFunction(fdecl);

    // calling convention
    LINK link = f->linkage;
    if (vafunc || fdecl->llvmInternal == LLVMintrinsic
        // DMD treats _Dmain as having C calling convention and this has been
        // hardcoded into druntime, even if the frontend type has D linkage.
        // See Bugzilla issue 9028.
        || fdecl->isMain()
    )
    {
        link = LINKc;
    }

    // mangled name
    std::string mangledName(mangleExact(fdecl));
    mangledName = gABI->mangleForLLVM(mangledName, link);

    // construct function
    LLFunctionType* functype = DtoFunctionType(fdecl);
    LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName);
    if (!func) {
        if(fdecl->llvmInternal == LLVMinline_ir)
        {
            func = DtoInlineIRFunction(fdecl);
        }
        else
        {
            // All function declarations are "external" - any other linkage type
            // is set when actually defining the function.
            func = LLFunction::Create(functype,
                llvm::GlobalValue::ExternalLinkage, mangledName, gIR->module);
        }
    } else if (func->getFunctionType() != functype) {
        error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", mangleExact(fdecl));
        fatal();
    }

    func->setCallingConv(gABI->callingConv(link));

    IF_LOG Logger::cout() << "func = " << *func << std::endl;

    // add func to IRFunc
    irFunc->func = func;

    // parameter attributes
    if (!DtoIsIntrinsic(fdecl)) {
        set_param_attrs(f, func, fdecl);
        if (global.params.disableRedZone) {
            func->addFnAttr(LDC_ATTRIBUTE(NoRedZone));
        }
    }

    // main
    if (fdecl->isMain()) {
        // Detect multiple main functions, which is disallowed. DMD checks this
        // in the glue code, so we need to do it here as well.
        if (gIR->mainFunc) {
            error(fdecl->loc, "only one main function allowed");
        }
        gIR->mainFunc = func;
    }

    if (fdecl->neverInline)
    {
        irFunc->setNeverInline();
    }

    if (fdecl->llvmInternal == LLVMglobal_crt_ctor || fdecl->llvmInternal == LLVMglobal_crt_dtor)
    {
        AppendFunctionToLLVMGlobalCtorsDtors(func, fdecl->priority, fdecl->llvmInternal == LLVMglobal_crt_ctor);
    }

    IrFuncTy &irFty = irFunc->irFty;

    // if (!declareOnly)
    {
        // name parameters
        llvm::Function::arg_iterator iarg = func->arg_begin();

        if (irFty.arg_sret) {
            iarg->setName(".sret_arg");
            irFunc->retArg = iarg;
            ++iarg;
        }

        if (irFty.arg_this) {
            iarg->setName(".this_arg");
            irFunc->thisArg = iarg;

            VarDeclaration* v = fdecl->vthis;
            if (v) {
                // We already build the this argument here if we will need it
                // later for codegen'ing the function, just as normal
                // parameters below, because it can be referred to in nested
                // context types. Will be given storage in DtoDefineFunction.
                assert(!isIrParameterCreated(v));
                IrParameter *irParam = getIrParameter(v, true);
                irParam->value = iarg;
                irParam->arg = irFty.arg_this;
                irParam->isVthis = true;
            }

            ++iarg;
        }
        else if (irFty.arg_nest) {
            iarg->setName(".nest_arg");
            irFunc->nestArg = iarg;
            assert(irFunc->nestArg);
            ++iarg;
        }

        if (irFty.arg_arguments) {
            iarg->setName("._arguments");
            irFunc->_arguments = iarg;
            ++iarg;
        }

        // we never reference parameters of function prototypes
        unsigned int k = 0;
        for (; iarg != func->arg_end(); ++iarg)
        {
            if (fdecl->parameters && fdecl->parameters->dim > k)
            {
                int paramIndex = irFty.reverseParams ? fdecl->parameters->dim-k-1 : k;
                Dsymbol* argsym = static_cast<Dsymbol*>(fdecl->parameters->data[paramIndex]);

                VarDeclaration* argvd = argsym->isVarDeclaration();
                assert(argvd);
                assert(!isIrLocalCreated(argvd));
                std::string str(argvd->ident->toChars());
                str.append("_arg");
                iarg->setName(str);

                IrParameter *irParam = getIrParameter(argvd, true);
                irParam->value = iarg;
                irParam->arg = irFty.args[paramIndex];

                k++;
            }
            else
            {
                iarg->setName("unnamed");
            }
        }
    }
}
Example #6
0
void DtoResolveFunction(FuncDeclaration* fdecl)
{
    if ((!global.params.useUnitTests || !fdecl->type) && fdecl->isUnitTestDeclaration()) {
        IF_LOG Logger::println("Ignoring unittest %s", fdecl->toPrettyChars());
        return; // ignore declaration completely
    }

    if (fdecl->ir.isResolved()) return;
    fdecl->ir.setResolved();

    Type *type = fdecl->type;
    // If errors occurred compiling it, such as bugzilla 6118
    if (type && type->ty == Tfunction) {
        Type *next = static_cast<TypeFunction *>(type)->next;
        if (!next || next->ty == Terror)
            return;
    }

    //printf("resolve function: %s\n", fdecl->toPrettyChars());

    if (fdecl->parent)
    if (TemplateInstance* tinst = fdecl->parent->isTemplateInstance())
    {
        if (TemplateDeclaration* tempdecl = tinst->tempdecl->isTemplateDeclaration())
        {
            if (tempdecl->llvmInternal == LLVMva_arg)
            {
                Logger::println("magic va_arg found");
                fdecl->llvmInternal = LLVMva_arg;
                fdecl->ir.setDefined();
                return; // this gets mapped to an instruction so a declaration makes no sence
            }
            else if (tempdecl->llvmInternal == LLVMva_start)
            {
                Logger::println("magic va_start found");
                fdecl->llvmInternal = LLVMva_start;
            }
            else if (tempdecl->llvmInternal == LLVMintrinsic)
            {
                Logger::println("overloaded intrinsic found");
                assert(fdecl->llvmInternal == LLVMintrinsic);
                assert(fdecl->mangleOverride);
            }
            else if (tempdecl->llvmInternal == LLVMinline_asm)
            {
                Logger::println("magic inline asm found");
                TypeFunction* tf = static_cast<TypeFunction*>(fdecl->type);
                if (tf->varargs != 1 || (fdecl->parameters && fdecl->parameters->dim != 0))
                {
                    tempdecl->error("invalid __asm declaration, must be a D style variadic with no explicit parameters");
                    fatal();
                }
                fdecl->llvmInternal = LLVMinline_asm;
                fdecl->ir.setDefined();
                return; // this gets mapped to a special inline asm call, no point in going on.
            }
            else if (tempdecl->llvmInternal == LLVMinline_ir)
            {
                Logger::println("magic inline ir found");
                fdecl->llvmInternal = LLVMinline_ir;
                fdecl->linkage = LINKc;
                Type* type = fdecl->type;
                assert(type->ty == Tfunction);
                static_cast<TypeFunction*>(type)->linkage = LINKc;

                DtoFunctionType(fdecl);
                DtoDeclareFunction(fdecl);
                fdecl->ir.setDefined();
                return;
            }
        }
    }

    DtoFunctionType(fdecl);

    IF_LOG Logger::println("DtoResolveFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars());
    LOG_SCOPE;

    // queue declaration unless the function is abstract without body
    if (!fdecl->isAbstract() || fdecl->fbody)
    {
        DtoDeclareFunction(fdecl);
    }
}