Ejemplo n.º 1
0
void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl, IRState *p) {
  IF_LOG Logger::println("TypeInfoDeclaration_codegen(%s)",
                         decl->toPrettyChars());
  LOG_SCOPE;

  if (decl->ir->isDefined()) {
    return;
  }
  decl->ir->setDefined();

  OutBuffer mangleBuf;
  mangleToBuffer(decl, &mangleBuf);
  const char *mangled = mangleBuf.peekString();

  IF_LOG {
    Logger::println("type = '%s'", decl->tinfo->toChars());
    Logger::println("typeinfo mangle: %s", mangled);
  }

  // Only declare the symbol if it isn't yet, otherwise the subtype of built-in
  // TypeInfos (rt.typeinfo.*) may clash with the base type when compiling the
  // rt.typeinfo.* modules.
  const auto irMangle = getIRMangledVarName(mangled, LINKd);
  llvm::GlobalVariable *gvar = gIR->module.getGlobalVariable(irMangle);
  if (!gvar) {
    LLType *type = DtoType(decl->type)->getPointerElementType();
    // We need to keep the symbol mutable as the type is not declared as
    // immutable on the D side, and e.g. synchronized() can be used on the
    // implicit monitor.
    gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, false);
  }

  IrGlobal *irg = getIrGlobal(decl, true);
  irg->value = gvar;

  emitTypeMetadata(decl);

  // check if the definition can be elided
  if (!global.params.useTypeInfo || !Type::dtypeinfo ||
      isSpeculativeType(decl->tinfo) || builtinTypeInfo(decl->tinfo)) {
    return;
  }

  // define the TypeInfo global
  LLVMDefineVisitor v(gvar);
  decl->accept(&v);

  setLinkage({TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()}, gvar);
}
Ejemplo n.º 2
0
void ldc::DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar,
                                        VarDeclaration *vd) {
  if (!mustEmitFullDebugInfo())
    return;

  Logger::println("D to dwarf global_variable");
  LOG_SCOPE;

  assert(vd->isDataseg() ||
         (vd->storage_class & (STCconst | STCimmutable) && vd->_init));

  OutBuffer mangleBuf;
  mangleToBuffer(vd, &mangleBuf);

#if LDC_LLVM_VER >= 400
  auto DIVar = DBuilder.createGlobalVariableExpression(
#else
  DBuilder.createGlobalVariable(
#endif
#if LDC_LLVM_VER >= 306
      GetCU(), // context
#endif
      vd->toChars(),                          // name
      mangleBuf.peekString(),                 // linkage name
      CreateFile(vd),                         // file
      vd->loc.linnum,                         // line num
      CreateTypeDescription(vd->type, false), // type
      vd->protection.kind == PROTprivate,     // is local to unit
#if LDC_LLVM_VER >= 400
      nullptr // relative location of field
#else
      llVar // value
#endif
      );

#if LDC_LLVM_VER >= 400
  llVar->addDebugInfo(DIVar);
#endif
}
Ejemplo n.º 3
0
        /**
         * Creates the data symbol used to initialize a TLS variable for Mach-O.
         *
         * Params:
         *      vd = the variable declaration for the symbol
         *      s = the back end symbol corresponding to vd
         *
         * Returns: the newly created symbol
         */
        Symbol *createTLVDataSymbol(VarDeclaration *vd, Symbol *s)
        {
            assert(config.objfmt == OBJ_MACH && I64 && (s->ty() & mTYLINK) == mTYthread);

            // Compute identifier for tlv symbol
            OutBuffer buffer;
            buffer.writestring(s->Sident);
            buffer.write("$tlv$init", 9);
            const char *tlvInitName = buffer.peekString();

            // Compute type for tlv symbol
            type *t = type_fake(vd->type->ty);
            type_setty(&t, t->Tty | mTYthreadData);
            type_setmangle(&t, mangle(vd));

            Symbol *tlvInit = symbol_name(tlvInitName, SCstatic, t);
            tlvInit->Sdt = NULL;
            tlvInit->Salignment = type_alignsize(s->Stype);
            if (vd->linkage == LINKcpp)
                tlvInit->Sflags |= SFLpublic;

            return tlvInit;
        }
Ejemplo n.º 4
0
void obj_write_deferred(Library *library)
{
    for (size_t i = 0; i < obj_symbols_towrite.dim; i++)
    {
        Dsymbol *s = obj_symbols_towrite[i];
        Module *m = s->getModule();

        char *mname;
        if (m)
        {
            mname = m->srcfile->toChars();
            lastmname = mname;
        }
        else
        {
            //mname = s->ident->toChars();
            mname = lastmname;
            assert(mname);
        }

        obj_start(mname);

        static int count;
        count++;                // sequence for generating names

        /* Create a module that's a doppelganger of m, with just
         * enough to be able to create the moduleinfo.
         */
        OutBuffer idbuf;
        idbuf.printf("%s.%d", m ? m->ident->toChars() : mname, count);
        char *idstr = idbuf.peekString();

        if (!m)
        {
            // it doesn't make sense to make up a module if we don't know where to put the symbol
            //  so output it into it's own object file without ModuleInfo
            objmod->initfile(idstr, NULL, mname);
            toObjFile(s, false);
            objmod->termfile();
        }
        else
        {
            idbuf.data = NULL;
            Identifier *id = Identifier::create(idstr, TOKidentifier);

            Module *md = Module::create(mname, id, 0, 0);
            md->members = Dsymbols_create();
            md->members->push(s);   // its only 'member' is s
            md->doppelganger = 1;       // identify this module as doppelganger
            md->md = m->md;
            md->aimports.push(m);       // it only 'imports' m
            md->massert = m->massert;
            md->munittest = m->munittest;
            md->marray = m->marray;

            genObjFile(md, false);
        }

        /* Set object file name to be source name with sequence number,
         * as mangled symbol names get way too long.
         */
        const char *fname = FileName::removeExt(mname);
        OutBuffer namebuf;
        unsigned hash = 0;
        for (char *p = s->toChars(); *p; p++)
            hash += *p;
        namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext);
        FileName::free((char *)fname);
        fname = namebuf.extractString();

        //printf("writing '%s'\n", fname);
        File *objfile = File::create(fname);
        obj_end(library, objfile);
    }
    obj_symbols_towrite.dim = 0;
}
Ejemplo n.º 5
0
int runLINK()
{
#if _WIN32
    if (global.params.is64bit)
    {
        OutBuffer cmdbuf;

        cmdbuf.writestring("/NOLOGO ");

        for (size_t i = 0; i < global.params.objfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte(' ');
            const char *p = (*global.params.objfiles)[i];
            const char *basename = FileName::removeExt(FileName::name(p));
            const char *ext = FileName::ext(p);
            if (ext && !strchr(basename, '.'))
            {
                // Write name sans extension (but not if a double extension)
                writeFilename(&cmdbuf, p, ext - p - 1);
            }
            else
                writeFilename(&cmdbuf, p);
            FileName::free(basename);
        }

        if (global.params.resfile)
        {
            cmdbuf.writeByte(' ');
            writeFilename(&cmdbuf, global.params.resfile);
        }

        cmdbuf.writeByte(' ');
        if (global.params.exefile)
        {   cmdbuf.writestring("/OUT:");
            writeFilename(&cmdbuf, global.params.exefile);
        }
        else
        {   /* Generate exe file name from first obj name.
             * No need to add it to cmdbuf because the linker will default to it.
             */
            const char *n = (*global.params.objfiles)[0];
            n = FileName::name(n);
            global.params.exefile = (char *)FileName::forceExt(n, "exe");
        }

        // Make sure path to exe file exists
        ensurePathToNameExists(Loc(), global.params.exefile);

        cmdbuf.writeByte(' ');
        if (global.params.mapfile)
        {   cmdbuf.writestring("/MAP:");
            writeFilename(&cmdbuf, global.params.mapfile);
        }
        else if (global.params.map)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            cmdbuf.writestring("/MAP:");
            writeFilename(&cmdbuf, p);
        }

        for (size_t i = 0; i < global.params.libfiles->dim; i++)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEFAULTLIB:");
            writeFilename(&cmdbuf, (*global.params.libfiles)[i]);
        }

        if (global.params.deffile)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEF:");
            writeFilename(&cmdbuf, global.params.deffile);
        }

        if (global.params.symdebug)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DEBUG");

            // in release mode we need to reactivate /OPT:REF after /DEBUG
            if (global.params.release)
                cmdbuf.writestring(" /OPT:REF");
        }

        if (global.params.dll)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring("/DLL");
        }

        for (size_t i = 0; i < global.params.linkswitches->dim; i++)
        {
            cmdbuf.writeByte(' ');
            cmdbuf.writestring((*global.params.linkswitches)[i]);
        }

        /* Append the path to the VC lib files, and then the SDK lib files
         */
        const char *vcinstalldir = getenv("VCINSTALLDIR");
        if (vcinstalldir)
        {   cmdbuf.writestring(" \"/LIBPATH:");
            cmdbuf.writestring(vcinstalldir);
            cmdbuf.writestring("lib\\amd64\"");
        }

        const char *windowssdkdir = getenv("WindowsSdkDir");
        if (windowssdkdir)
        {   cmdbuf.writestring(" \"/LIBPATH:");
            cmdbuf.writestring(windowssdkdir);
            cmdbuf.writestring("lib\\x64\"");
        }

        char *p = cmdbuf.peekString();

        const char *lnkfilename = NULL;
        size_t plen = strlen(p);
        if (plen > 7000)
        {
            lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
            File flnk(lnkfilename);
            flnk.setbuffer(p, plen);
            flnk.ref = 1;
            if (flnk.write())
                error(Loc(), "error writing file %s", lnkfilename);
            if (strlen(lnkfilename) < plen)
                sprintf(p, "@%s", lnkfilename);
        }

        const char *linkcmd = getenv("LINKCMD64");
        if (!linkcmd)
            linkcmd = getenv("LINKCMD"); // backward compatible
        if (!linkcmd)
        {
            if (vcinstalldir)
            {
                OutBuffer linkcmdbuf;
                linkcmdbuf.writestring(vcinstalldir);
                linkcmdbuf.writestring("bin\\amd64\\link");
                linkcmd = linkcmdbuf.extractString();
            }
            else
                linkcmd = "link";
        }
        int status = executecmd(linkcmd, p);
        if (lnkfilename)
        {
            remove(lnkfilename);
            FileName::free(lnkfilename);
        }
        return status;
    }
    else
    {
        OutBuffer cmdbuf;

        global.params.libfiles->push("user32");
        global.params.libfiles->push("kernel32");

        for (size_t i = 0; i < global.params.objfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte('+');
            const char *p = (*global.params.objfiles)[i];
            const char *basename = FileName::removeExt(FileName::name(p));
            const char *ext = FileName::ext(p);
            if (ext && !strchr(basename, '.'))
            {
                // Write name sans extension (but not if a double extension)
                writeFilename(&cmdbuf, p, ext - p - 1);
            }
            else
                writeFilename(&cmdbuf, p);
            FileName::free(basename);
        }
        cmdbuf.writeByte(',');
        if (global.params.exefile)
            writeFilename(&cmdbuf, global.params.exefile);
        else
        {   /* Generate exe file name from first obj name.
             * No need to add it to cmdbuf because the linker will default to it.
             */
            const char *n = (*global.params.objfiles)[0];
            n = FileName::name(n);
            global.params.exefile = (char *)FileName::forceExt(n, "exe");
        }

        // Make sure path to exe file exists
        ensurePathToNameExists(Loc(), global.params.exefile);

        cmdbuf.writeByte(',');
        if (global.params.mapfile)
            writeFilename(&cmdbuf, global.params.mapfile);
        else if (global.params.map)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            writeFilename(&cmdbuf, p);
        }
        else
            cmdbuf.writestring("nul");
        cmdbuf.writeByte(',');

        for (size_t i = 0; i < global.params.libfiles->dim; i++)
        {
            if (i)
                cmdbuf.writeByte('+');
            writeFilename(&cmdbuf, (*global.params.libfiles)[i]);
        }

        if (global.params.deffile)
        {
            cmdbuf.writeByte(',');
            writeFilename(&cmdbuf, global.params.deffile);
        }

        /* Eliminate unnecessary trailing commas    */
        while (1)
        {   size_t i = cmdbuf.offset;
            if (!i || cmdbuf.data[i - 1] != ',')
                break;
            cmdbuf.offset--;
        }

        if (global.params.resfile)
        {
            cmdbuf.writestring("/RC:");
            writeFilename(&cmdbuf, global.params.resfile);
        }

        if (global.params.map || global.params.mapfile)
            cmdbuf.writestring("/m");

#if 0
        if (debuginfo)
            cmdbuf.writestring("/li");
        if (codeview)
        {
            cmdbuf.writestring("/co");
            if (codeview3)
                cmdbuf.writestring(":3");
        }
#else
        if (global.params.symdebug)
            cmdbuf.writestring("/co");
#endif

        cmdbuf.writestring("/noi");
        for (size_t i = 0; i < global.params.linkswitches->dim; i++)
        {
            cmdbuf.writestring((*global.params.linkswitches)[i]);
        }
        cmdbuf.writeByte(';');

        char *p = cmdbuf.peekString();

        const char *lnkfilename = NULL;
        size_t plen = strlen(p);
        if (plen > 7000)
        {
            lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
            File flnk(lnkfilename);
            flnk.setbuffer(p, plen);
            flnk.ref = 1;
            if (flnk.write())
                error(Loc(), "error writing file %s", lnkfilename);
            if (strlen(lnkfilename) < plen)
                sprintf(p, "@%s", lnkfilename);
        }

        const char *linkcmd = getenv("LINKCMD");
        if (!linkcmd)
            linkcmd = "link";
        int status = executecmd(linkcmd, p);
        if (lnkfilename)
        {
            remove(lnkfilename);
            FileName::free(lnkfilename);
        }
        return status;
    }
#elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
    pid_t childpid;
    int status;

    // Build argv[]
    Strings argv;

    const char *cc = getenv("CC");
    if (!cc)
        cc = "gcc";
    argv.push(cc);
    argv.insert(1, global.params.objfiles);

#if __APPLE__
    // If we are on Mac OS X and linking a dynamic library,
    // add the "-dynamiclib" flag
    if (global.params.dll)
        argv.push("-dynamiclib");
#elif __linux__ || __FreeBSD__ || __OpenBSD__ || __sun
    if (global.params.dll)
        argv.push("-shared");
#endif

    // None of that a.out stuff. Use explicit exe file name, or
    // generate one from name of first source file.
    argv.push("-o");
    if (global.params.exefile)
    {
        argv.push(global.params.exefile);
    }
    else if (global.params.run)
    {
#if 1
        char name[L_tmpnam + 14 + 1];
        strcpy(name, P_tmpdir);
        strcat(name, "/dmd_runXXXXXX");
        int fd = mkstemp(name);
        if (fd == -1)
        {   error(Loc(), "error creating temporary file");
            return 1;
        }
        else
            close(fd);
        global.params.exefile = mem.strdup(name);
        argv.push(global.params.exefile);
#else
        /* The use of tmpnam raises the issue of "is this a security hole"?
         * The hole is that after tmpnam and before the file is opened,
         * the attacker modifies the file system to get control of the
         * file with that name. I do not know if this is an issue in
         * this context.
         * We cannot just replace it with mkstemp, because this name is
         * passed to the linker that actually opens the file and writes to it.
         */
        char s[L_tmpnam + 1];
        char *n = tmpnam(s);
        global.params.exefile = mem.strdup(n);
        argv.push(global.params.exefile);
#endif
    }
    else
    {   // Generate exe file name from first obj name
        const char *n = (*global.params.objfiles)[0];
        char *ex;

        n = FileName::name(n);
        const char *e = FileName::ext(n);
        if (e)
        {
            e--;                        // back up over '.'
            ex = (char *)mem.malloc(e - n + 1);
            memcpy(ex, n, e - n);
            ex[e - n] = 0;
            // If generating dll then force dll extension
            if (global.params.dll)
                ex = (char *)FileName::forceExt(ex, global.dll_ext);
        }
        else
            ex = (char *)"a.out";       // no extension, so give up
        argv.push(ex);
        global.params.exefile = ex;
    }

    // Make sure path to exe file exists
    ensurePathToNameExists(Loc(), global.params.exefile);

    if (global.params.symdebug)
        argv.push("-g");

    if (global.params.is64bit)
        argv.push("-m64");
    else
        argv.push("-m32");

    if (global.params.map || global.params.mapfile)
    {
        argv.push("-Xlinker");
#if __APPLE__
        argv.push("-map");
#else
        argv.push("-Map");
#endif
        if (!global.params.mapfile)
        {
            const char *fn = FileName::forceExt(global.params.exefile, "map");

            const char *path = FileName::path(global.params.exefile);
            const char *p;
            if (path[0] == '\0')
                p = FileName::combine(global.params.objdir, fn);
            else
                p = fn;

            global.params.mapfile = (char *)p;
        }
        argv.push("-Xlinker");
        argv.push(global.params.mapfile);
    }

    if (0 && global.params.exefile)
    {
        /* This switch enables what is known as 'smart linking'
         * in the Windows world, where unreferenced sections
         * are removed from the executable. It eliminates unreferenced
         * functions, essentially making a 'library' out of a module.
         * Although it is documented to work with ld version 2.13,
         * in practice it does not, but just seems to be ignored.
         * Thomas Kuehne has verified that it works with ld 2.16.1.
         * BUG: disabled because it causes exception handling to fail
         * because EH sections are "unreferenced" and elided
         */
        argv.push("-Xlinker");
        argv.push("--gc-sections");
    }

    for (size_t i = 0; i < global.params.linkswitches->dim; i++)
    {   const char *p = (*global.params.linkswitches)[i];
        if (!p || !p[0] || !(p[0] == '-' && (p[1] == 'l' || p[1] == 'L')))
            // Don't need -Xlinker if switch starts with -l or -L.
            // Eliding -Xlinker is significant for -L since it allows our paths
            // to take precedence over gcc defaults.
            argv.push("-Xlinker");
        argv.push(p);
    }

    /* Add each library, prefixing it with "-l".
     * The order of libraries passed is:
     *  1. any libraries passed with -L command line switch
     *  2. libraries specified on the command line
     *  3. libraries specified by pragma(lib), which were appended
     *     to global.params.libfiles.
     *  4. standard libraries.
     */
    for (size_t i = 0; i < global.params.libfiles->dim; i++)
    {   const char *p = (*global.params.libfiles)[i];
        size_t plen = strlen(p);
        if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a')
            argv.push(p);
        else
        {
            char *s = (char *)mem.malloc(plen + 3);
            s[0] = '-';
            s[1] = 'l';
            memcpy(s + 2, p, plen + 1);
            argv.push(s);
        }
    }

    for (size_t i = 0; i < global.params.dllfiles->dim; i++)
    {
        const char *p = (*global.params.dllfiles)[i];
        argv.push(p);
    }

    /* Standard libraries must go after user specified libraries
     * passed with -l.
     */
    const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;
    size_t slen = strlen(libname);
    if (slen)
    {
        char *buf = (char *)malloc(3 + slen + 1);
        strcpy(buf, "-l");
        /* Use "-l:libname.a" if the library name is complete
         */
        if (slen > 3 + 2 &&
            memcmp(libname, "lib", 3) == 0 &&
            (memcmp(libname + slen - 2, ".a", 2) == 0 ||
             memcmp(libname + slen - 3, ".so", 3) == 0)
           )
        {
            strcat(buf, ":");
        }
        strcat(buf, libname);
        argv.push(buf);             // turns into /usr/lib/libphobos2.a
    }

#ifdef __sun
    argv.push("-mt");
#endif

//    argv.push("-ldruntime");
    argv.push("-lpthread");
    argv.push("-lm");
#if __linux__
    // Changes in ld for Ubuntu 11.10 require this to appear after phobos2
    argv.push("-lrt");
#endif

    if (global.params.verbose)
    {
        // Print it
        for (size_t i = 0; i < argv.dim; i++)
            fprintf(global.stdmsg, "%s ", argv[i]);
        fprintf(global.stdmsg, "\n");
    }

    argv.push(NULL);

    // set up pipes
    int fds[2];

    if (pipe(fds) == -1)
    {
        perror("Unable to create pipe to linker");
        return -1;
    }

    childpid = fork();
    if (childpid == 0)
    {
        // pipe linker stderr to fds[0]
        dup2(fds[1], STDERR_FILENO);
        close(fds[0]);

        execvp(argv[0], (char **)argv.tdata());
        perror(argv[0]);           // failed to execute
        return -1;
    }
    else if (childpid == -1)
    {
        perror("Unable to fork");
        return -1;
    }
    close(fds[1]);
    const int nme = findNoMainError(fds[0]);
    waitpid(childpid, &status, 0);

    if (WIFEXITED(status))
    {
        status = WEXITSTATUS(status);
        if (status)
        {
            if (nme == -1)
            {
                perror("Error with the linker pipe");
                return -1;
            }
            else
            {
                printf("--- errorlevel %d\n", status);
                if (nme == 1) error(Loc(), "no main function specified");
            }
        }
    }
    else if (WIFSIGNALED(status))
    {
        printf("--- killed by signal %d\n", WTERMSIG(status));
        status = 1;
    }
    return status;
#else
    printf ("Linking is not yet supported for this version of DMD.\n");
    return -1;
#endif
}
Ejemplo n.º 6
0
Expression *arrayOp(BinExp *e, Scope *sc)
{
    //printf("BinExp::arrayOp() %s\n", toChars());

    Type *tb = e->type->toBasetype();
    assert(tb->ty == Tarray || tb->ty == Tsarray);
    Type *tbn = tb->nextOf()->toBasetype();
    if (tbn->ty == Tvoid)
    {
        e->error("cannot perform array operations on void[] arrays");
        return new ErrorExp();
    }
    if (!isArrayOpValid(e))
    {
        e->error("invalid array operation %s (possible missing [])", e->toChars());
        return new ErrorExp();
    }

    Expressions *arguments = new Expressions();

    /* The expression to generate an array operation for is mangled
     * into a name to use as the array operation function name.
     * Mangle in the operands and operators in RPN order, and type.
     */
    OutBuffer buf;
    buf.writestring("_array");
    buildArrayIdent(e, &buf, arguments);
    buf.writeByte('_');

    /* Append deco of array element type
     */
    buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);

    char *name = buf.peekString();
    Identifier *ident = Identifier::idPool(name);

    FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
    FuncDeclaration *fd = *pFd;

    if (!fd)
        fd = buildArrayOp(ident, e, sc);

    if (fd && fd->errors)
    {
        const char *fmt;
        if (tbn->ty == Tstruct || tbn->ty == Tclass)
            fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
        else if (!tbn->isscalar())
            fmt = "invalid array operation '%s' because %s is not a scalar type";
        else
            fmt = "invalid array operation '%s' for element type %s";

        e->error(fmt, e->toChars(), tbn->toChars());
        return new ErrorExp();
    }

    *pFd = fd;

    Expression *ev = new VarExp(e->loc, fd);
    Expression *ec = new CallExp(e->loc, ev, arguments);

    return semantic(ec, sc);
}
Ejemplo n.º 7
0
const char *inifile(const char *argv0x, const char *inifilex, const char *envsectionname)
{
    char *argv0 = (char *)argv0x;
    char *inifile = (char *)inifilex;   // do const-correct later
    char *path;         // need path for @P macro
    char *filename;
    OutBuffer buf;
    int envsection = 0;
    size_t envsectionnamelen = strlen(envsectionname);

#if LOG
    printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
#endif
    if (FileName::absolute(inifile))
    {
        filename = inifile;
    }
    else
    {
        /* Look for inifile in the following sequence of places:
         *      o current directory
         *      o home directory
         *      o directory off of argv0
         *      o SYSCONFDIR (default=/etc/)
         */
        if (FileName::exists(inifile))
        {
            filename = inifile;
        }
        else
        {
            filename = (char *)FileName::combine(getenv("HOME"), inifile);
            if (!FileName::exists(filename))
            {
#if _WIN32 // This fix by Tim Matthews
                char resolved_name[MAX_PATH + 1];
                if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name))
                {
                        filename = (char *)FileName::replaceName(resolved_name, inifile);
                        if(FileName::exists(filename))
                                goto Ldone;
                }
#endif
                filename = (char *)FileName::replaceName(argv0, inifile);
                if (!FileName::exists(filename))
                {
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun   // This fix by Thomas Kuehne
                    /* argv0 might be a symbolic link,
                     * so try again looking past it to the real path
                     */
#if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
                    char resolved_name[PATH_MAX + 1];
                    char* real_argv0 = realpath(argv0, resolved_name);
#else
                    char* real_argv0 = realpath(argv0, NULL);
#endif
                    //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0);
                    if (real_argv0)
                    {
                        filename = (char *)FileName::replaceName(real_argv0, inifile);
#if __linux__
                        free(real_argv0);
#endif
                        if (FileName::exists(filename))
                            goto Ldone;
                    }
#else
#error use of glibc non-standard extension realpath(char*, NULL)
#endif
                    if (1){
                    // Search PATH for argv0
                    const char *p = getenv("PATH");
#if LOG
                    printf("\tPATH='%s'\n", p);
#endif
                    Strings *paths = FileName::splitPath(p);
                    filename = (char *)FileName::searchPath(paths, argv0, 0);
                    if (!filename)
                        goto Letc;              // argv0 not found on path
                    filename = (char *)FileName::replaceName(filename, inifile);
                    if (FileName::exists(filename))
                        goto Ldone;
                    }
                    // Search /etc/ for inifile
                Letc:
#ifndef SYSCONFDIR
# error SYSCONFDIR not defined
#endif
                    assert(SYSCONFDIR != NULL && strlen(SYSCONFDIR));
                    filename = (char *)FileName::combine((char *)SYSCONFDIR, inifile);
#endif // __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
                Ldone:
                    ;
                }
            }
        }
    }
    path = (char *)FileName::path(filename);
#if LOG
    printf("\tpath = '%s', filename = '%s'\n", path, filename);
#endif

    File file(filename);

    if (file.read())
        return filename;                        // error reading file

    // Parse into lines
    int eof = 0;
    for (size_t i = 0; i < file.len && !eof; i++)
    {
        size_t linestart = i;

        for (; i < file.len; i++)
        {
            switch (file.buffer[i])
            {
                case '\r':
                    break;

                case '\n':
                    // Skip if it was preceded by '\r'
                    if (i && file.buffer[i - 1] == '\r')
                        goto Lskip;
                    break;

                case 0:
                case 0x1A:
                    eof = 1;
                    break;

                default:
                    continue;
            }
            break;
        }

        buf.reset();

        // First, expand the macros.
        // Macros are bracketed by % characters.

        for (size_t k = 0; k < i - linestart; k++)
        {
            // The line is file.buffer[linestart..i]
            char *line = (char *)&file.buffer[linestart];
            if (line[k] == '%')
            {
                for (size_t j = k + 1; j < i - linestart; j++)
                {
                    if (line[j] == '%')
                    {
                        char *p = NULL;
                        char *palloc = NULL;
                        if (j - k == 3 && Port::memicmp(&line[k + 1], "@P", 2) == 0)
                        {
                            // %@P% is special meaning the path to the .ini file
                            p = path;
                            if (!*p)
                                p = (char *)".";
                        }
                        else
                        {   size_t len2 = j - k;
                            char tmp[10];       // big enough most of the time

                            if (len2 <= sizeof(tmp))
                                p = tmp;
                            else
                            {   p = (char *)malloc(len2);
                                palloc = p;
                            }
                            len2--;
                            memcpy(p, &line[k + 1], len2);
                            p[len2] = 0;
                            Port::strupr(p);
                            p = getenv(p);
                            if (!p)
                                p = (char *)"";
                        }
                        buf.writestring(p);
                        if (palloc)
                            free(palloc);
                        k = j;
                        goto L1;
                    }
                }
            }
            buf.writeByte(line[k]);
         L1:
            ;
        }

        // Remove trailing spaces
        while (buf.offset && isspace(buf.data[buf.offset - 1]))
            buf.offset--;

        {
        char *p = buf.peekString();

        // The expanded line is in p.
        // Now parse it for meaning.

        p = skipspace(p);
        switch (*p)
        {
            case ';':           // comment
            case 0:             // blank
                break;

            case '[':           // look for [Environment]
                p = skipspace(p + 1);
                char *pn;
                for (pn = p; isalnum((utf8_t)*pn); pn++)
                    ;
                if (pn - p == envsectionnamelen &&
                    Port::memicmp(p, envsectionname, envsectionnamelen) == 0 &&
                    *skipspace(pn) == ']'
                   )
                    envsection = 1;
                else
                    envsection = 0;
                break;

            default:
                if (envsection)
                {
                    char *pn = p;

                    // Convert name to upper case;
                    // remove spaces bracketing =
                    for (p = pn; *p; p++)
                    {   if (islower((utf8_t)*p))
                            *p &= ~0x20;
                        else if (isspace((utf8_t)*p))
                            memmove(p, p + 1, strlen(p));
                        else if (*p == '=')
                        {
                            p++;
                            while (isspace((utf8_t)*p))
                                memmove(p, p + 1, strlen(p));
                            break;
                        }
                    }

                    putenv(strdup(pn));
#if LOG
                    printf("\tputenv('%s')\n", pn);
                    //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
#endif
                }
                break;
        }
        }

     Lskip:
        ;
    }
    return filename;
}
Ejemplo n.º 8
0
void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
  IF_LOG Logger::println("CompoundAsmStatement::toIR(): %s",
                         stmt->loc.toChars());
  LOG_SCOPE;

  // disable inlining by default
  if (!p->func()->decl->allowInlining) {
    p->func()->setNeverInline();
  }

  // create asm block structure
  assert(!p->asmBlock);
  auto asmblock = new IRAsmBlock(stmt);
  assert(asmblock);
  p->asmBlock = asmblock;

  // do asm statements
  for (unsigned i = 0; i < stmt->statements->dim; i++) {
    if (Statement *s = (*stmt->statements)[i]) {
      Statement_toIR(s, p);
    }
  }

  // build forwarder for in-asm branches to external labels
  // this additional asm code sets the __llvm_jump_target variable
  // to a unique value that will identify the jump target in
  // a post-asm switch

  // maps each goto destination to its special value
  std::map<LabelDsymbol *, int> gotoToVal;

  // location of the special value determining the goto label
  // will be set if post-asm dispatcher block is needed
  LLValue *jump_target = nullptr;

  {
    FuncDeclaration *fd = gIR->func()->decl;
    OutBuffer mangleBuf;
    mangleToBuffer(fd, &mangleBuf);
    const char *fdmangle = mangleBuf.peekString();

    // we use a simple static counter to make sure the new end labels are unique
    static size_t uniqueLabelsId = 0;
    std::ostringstream asmGotoEndLabel;
    printLabelName(asmGotoEndLabel, fdmangle, "_llvm_asm_end");
    asmGotoEndLabel << uniqueLabelsId++;

    // initialize the setter statement we're going to build
    auto outSetterStmt = new IRAsmStmt;
    std::string asmGotoEnd = "\n\tjmp " + asmGotoEndLabel.str() + "\n";
    std::ostringstream code;
    code << asmGotoEnd;

    int n_goto = 1;

    size_t n = asmblock->s.size();
    for (size_t i = 0; i < n; ++i) {
      IRAsmStmt *a = asmblock->s[i];

      // skip non-branch statements
      if (!a->isBranchToLabel) {
        continue;
      }

      // if internal, no special handling is necessary, skip
      std::vector<Identifier *>::const_iterator it, end;
      end = asmblock->internalLabels.end();
      bool skip = false;
      for (auto il : asmblock->internalLabels) {
        if (il->equals(a->isBranchToLabel->ident)) {
          skip = true;
        }
      }
      if (skip) {
        continue;
      }

      // if we already set things up for this branch target, skip
      if (gotoToVal.find(a->isBranchToLabel) != gotoToVal.end()) {
        continue;
      }

      // record that the jump needs to be handled in the post-asm dispatcher
      gotoToVal[a->isBranchToLabel] = n_goto;

      // provide an in-asm target for the branch and set value
      IF_LOG Logger::println(
          "statement '%s' references outer label '%s': creating forwarder",
          a->code.c_str(), a->isBranchToLabel->ident->toChars());
      printLabelName(code, fdmangle, a->isBranchToLabel->ident->toChars());
      code << ":\n\t";
      code << "movl $<<in" << n_goto << ">>, $<<out0>>\n";
      // FIXME: Store the value -> label mapping somewhere, so it can be
      // referenced later
      outSetterStmt->in.push_back(DtoConstUint(n_goto));
      outSetterStmt->in_c += "i,";
      code << asmGotoEnd;

      ++n_goto;
    }
    if (code.str() != asmGotoEnd) {
      // finalize code
      outSetterStmt->code = code.str();
      outSetterStmt->code += asmGotoEndLabel.str() + ":\n";

      // create storage for and initialize the temporary
      jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target");
      // setup variable for output from asm
      outSetterStmt->out_c = "=*m,";
      outSetterStmt->out.push_back(jump_target);

      asmblock->s.push_back(outSetterStmt);
    } else {
      delete outSetterStmt;
    }
  }

  // build a fall-off-end-properly asm statement

  FuncDeclaration *thisfunc = p->func()->decl;
  bool useabiret = false;
  p->asmBlock->asmBlock->abiret = nullptr;
  if (thisfunc->fbody->endsWithAsm() == stmt &&
      thisfunc->type->nextOf()->ty != Tvoid) {
    // there can't be goto forwarders in this case
    assert(gotoToVal.empty());
    emitABIReturnAsmStmt(asmblock, stmt->loc, thisfunc);
    useabiret = true;
  }

  // build asm block
  std::vector<LLValue *> outargs;
  std::vector<LLValue *> inargs;
  std::vector<LLType *> outtypes;
  std::vector<LLType *> intypes;
  std::string out_c;
  std::string in_c;
  std::string clobbers;
  std::string code;
  size_t asmIdx = asmblock->retn;

  Logger::println("do outputs");
  size_t n = asmblock->s.size();
  for (size_t i = 0; i < n; ++i) {
    IRAsmStmt *a = asmblock->s[i];
    assert(a);
    size_t onn = a->out.size();
    for (size_t j = 0; j < onn; ++j) {
      outargs.push_back(a->out[j]);
      outtypes.push_back(a->out[j]->getType());
    }
    if (!a->out_c.empty()) {
      out_c += a->out_c;
    }
    remap_outargs(a->code, onn + a->in.size(), asmIdx);
    asmIdx += onn;
  }

  Logger::println("do inputs");
  for (size_t i = 0; i < n; ++i) {
    IRAsmStmt *a = asmblock->s[i];
    assert(a);
    size_t inn = a->in.size();
    for (size_t j = 0; j < inn; ++j) {
      inargs.push_back(a->in[j]);
      intypes.push_back(a->in[j]->getType());
    }
    if (!a->in_c.empty()) {
      in_c += a->in_c;
    }
    remap_inargs(a->code, inn + a->out.size(), asmIdx);
    asmIdx += inn;
    if (!code.empty()) {
      code += "\n\t";
    }
    code += a->code;
  }
  asmblock->s.clear();

  // append inputs
  out_c += in_c;

  // append clobbers
  for (const auto &c : asmblock->clobs) {
    out_c += c;
  }

  // remove excessive comma
  if (!out_c.empty()) {
    out_c.resize(out_c.size() - 1);
  }

  IF_LOG {
    Logger::println("code = \"%s\"", code.c_str());
    Logger::println("constraints = \"%s\"", out_c.c_str());
  }

  // build return types
  LLType *retty;
  if (asmblock->retn) {
    retty = asmblock->retty;
  } else {
    retty = llvm::Type::getVoidTy(gIR->context());
  }

  // build argument types
  std::vector<LLType *> types;
  types.insert(types.end(), outtypes.begin(), outtypes.end());
  types.insert(types.end(), intypes.begin(), intypes.end());
  llvm::FunctionType *fty = llvm::FunctionType::get(retty, types, false);
  IF_LOG Logger::cout() << "function type = " << *fty << '\n';

  std::vector<LLValue *> args;
  args.insert(args.end(), outargs.begin(), outargs.end());
  args.insert(args.end(), inargs.begin(), inargs.end());

  IF_LOG {
    Logger::cout() << "Arguments:" << '\n';
    Logger::indent();
    size_t i = 0;
    for (auto arg : args) {
      Stream cout = Logger::cout();
      cout << '$' << i << " ==> " << *arg;
      if (!llvm::isa<llvm::Instruction>(arg) &&
          !llvm::isa<LLGlobalValue>(arg)) {
        cout << '\n';
      }
      ++i;
    }
    Logger::undent();
  }

  llvm::InlineAsm *ia = llvm::InlineAsm::get(fty, code, out_c, true);

  llvm::CallInst *call = p->ir->CreateCall(
      ia, args, retty == LLType::getVoidTy(gIR->context()) ? "" : "asm");

  IF_LOG Logger::cout() << "Complete asm statement: " << *call << '\n';

  // capture abi return value
  if (useabiret) {
    IRAsmBlock *block = p->asmBlock;
    if (block->retfixup) {
      block->asmBlock->abiret = (*block->retfixup)(p->ir, call);
    } else if (p->asmBlock->retemu) {
      block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret);
    } else {
      block->asmBlock->abiret = call;
    }
  }

  p->asmBlock = nullptr;

  // if asm contained external branches, emit goto forwarder code
  if (!gotoToVal.empty()) {
    assert(jump_target);

    // make new blocks
    llvm::BasicBlock *bb = p->insertBB("afterasmgotoforwarder");

    llvm::LoadInst *val =
        p->ir->CreateLoad(jump_target, "__llvm_jump_target_value");
    llvm::SwitchInst *sw = p->ir->CreateSwitch(val, bb, gotoToVal.size());

    // add all cases
    for (const auto &pair : gotoToVal) {
      llvm::BasicBlock *casebb = p->insertBBBefore(bb, "case");
      sw->addCase(LLConstantInt::get(llvm::IntegerType::get(gIR->context(), 32),
                                     pair.second),
                  casebb);

      p->scope() = IRScope(casebb);
      DtoGoto(stmt->loc, pair.first);
    }

    p->scope() = IRScope(bb);
  }
}
Ejemplo n.º 9
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++;
  }
}
Ejemplo n.º 10
0
void StaticAssert::semantic2(Scope *sc)
{
    //printf("StaticAssert::semantic2() %s\n", toChars());
    ScopeDsymbol *sd = new ScopeDsymbol();
    sc = sc->push(sd);
    sc->flags |= SCOPEstaticassert;

    sc = sc->startCTFE();
    Expression *e = exp->semantic(sc);
    e = resolveProperties(sc, e);
    sc = sc->endCTFE();
    sc = sc->pop();

    // Simplify expression, to make error messages nicer if CTFE fails
    e = e->optimize(0);

    if (!e->type->checkBoolean())
    {
        if (e->type->toBasetype() != Type::terror)
            exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars());
        return;
    }
    unsigned olderrs = global.errors;
    e = e->ctfeInterpret();
    if (global.errors != olderrs)
    {
        errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars());
    }
    else if (e->isBool(false))
    {
        if (msg)
        {
            HdrGenState hgs;
            OutBuffer buf;

            sc = sc->startCTFE();
            msg = msg->semantic(sc);
            msg = resolveProperties(sc, msg);
            sc = sc->endCTFE();
            msg = msg->ctfeInterpret();
            hgs.console = 1;
            StringExp * s = msg->toStringExp();
            if (s)
            {   s->postfix = 0; // Don't display a trailing 'c'
                msg = s;
            }
            msg->toCBuffer(&buf, &hgs);
            error("%s", buf.peekString());
        }
        else
            error("(%s) is false", exp->toChars());
        if (sc->tinst)
            sc->tinst->printInstantiationTrace();
        if (!global.gag)
              fatal();
    }
    else if (!e->isBool(true))
    {
        error("(%s) is not evaluatable at compile time", exp->toChars());
    }
}