Ejemplo n.º 1
0
  /**
   * Ensures that LLVM code exists for all dependencies of a main-method- containing class/file.This
   * involves either finding an existing .ll file (which has been updated more recently than the
   * corresponding source file or building a new one
   *
   * @throws CompileException
   */
  private static void generateLLVM(
      List<String> linkCommand, Set<String> generics, Set<String> arrays)
      throws IOException, ShadowException, ParseException, ConfigurationException,
          TypeCheckException, CompileException {
    Type.clearTypes();

    Path mainFile = currentJob.getMainFile();
    String mainFileName = stripExt(mainFile.toString());

    List<Node> nodes;

    try {
      nodes = TypeChecker.typeCheck(mainFile.toFile(), currentJob.isForceRecompile());
    } catch (TypeCheckException e) {
      logger.error(mainFile + " FAILED TO TYPE CHECK");
      throw e;
    }

    if (!currentJob.isCheckOnly()) {
      for (Node node : nodes) {
        File file = node.getFile();
        String name = stripExt(file.getName());
        String path = stripExt(file.getCanonicalPath());
        File llvmFile = new File(path + ".ll");

        Type type = node.getType();

        // set data for main class
        if (path.equals(mainFileName)) {
          mainClass = type.toString(Type.MANGLE);
          SequenceType arguments = new SequenceType(new ArrayType(Type.STRING));
          if (type.getMatchingMethod("main", arguments) != null) mainArguments = true;
          else if (type.getMatchingMethod("main", new SequenceType()) != null)
            mainArguments = false;
          else
            throw new ShadowException(
                "File " + file.getPath() + " does not contain an appropriate main() method");
        }

        // if the LLVM didn't exist, the full .shadow file would have been used
        if (file.getPath().endsWith(".meta")) {
          logger.info("Using pre-existing LLVM code for " + name);
          addToLink(node.getType(), file, linkCommand);
          LLVMOutput.readGenericAndArrayClasses(llvmFile, generics, arrays);
        } else {
          logger.info("Generating LLVM code for " + name);
          // gets top level class
          TACModule module = new TACBuilder().build(node);
          logger.debug(module.toString());

          // Write to file
          String className = typeToFileName(type);
          llvmFile = new File(file.getParentFile(), className + ".ll");
          File nativeFile = new File(file.getParentFile(), className + ".native.ll");
          LLVMOutput output = new LLVMOutput(llvmFile);
          try {
            output.build(module);
          } catch (ShadowException e) {
            logger.error(file + " FAILED TO COMPILE");
            output.close();
            if (llvmFile.exists()) llvmFile.delete();
            throw new CompileException(e.getMessage());
          }

          if (llvmFile.exists()) linkCommand.add(llvmFile.getCanonicalPath());
          else throw new ShadowException("Failed to generate " + llvmFile.getPath());

          if (nativeFile.exists()) linkCommand.add(nativeFile.getCanonicalPath());

          // it's important to add generics after generating the LLVM, since more are made
          generics.addAll(output.getGenericClasses());
          arrays.addAll(output.getArrayClasses());
        }
      }
    }
  }
Ejemplo n.º 2
0
  public static void run(String[] args)
      throws FileNotFoundException, ParseException, ShadowException, IOException,
          org.apache.commons.cli.ParseException, ConfigurationException, TypeCheckException,
          CompileException {
    // Detect and establish the current settings and arguments
    Arguments compilerArgs = new Arguments(args);

    // Exit if help was requested (Arguments handles printing)
    if (compilerArgs.hasOption(Arguments.HELP)) return;

    // Exit if information was requested (Arguments handles printing)
    if (compilerArgs.hasOption(Arguments.INFORMATION)) return;

    // Detect and establish the current settings based on the arguments
    config =
        Configuration.buildConfiguration(
            compilerArgs.getMainFileArg(), compilerArgs.getConfigFileArg(), false);
    currentJob = new Job(compilerArgs);

    Path system = config.getSystemImport();

    Path unwindFile = Paths.get("shadow", "Unwind" + config.getArch() + ".ll");
    unwindFile = system.resolve(unwindFile);

    // Locate the file defining platform-specific system calls
    Path OsFile = Paths.get("shadow" + File.separator + config.getOs() + ".ll");
    OsFile = system.resolve(OsFile);

    List<String> linkCommand = new ArrayList<String>();
    linkCommand.add("llvm-link");
    linkCommand.add("-");
    linkCommand.add(unwindFile.toString());
    linkCommand.add(OsFile.toString());

    // Begin the checking/compilation process
    long startTime = System.currentTimeMillis();

    Set<String> generics = new HashSet<String>();
    Set<String> arrays = new HashSet<String>();

    generateLLVM(linkCommand, generics, arrays);

    if (!currentJob.isCheckOnly() && !currentJob.isNoLink()) {
      // any output after this point is important, avoid getting it mixed in with previous output
      System.out.println();
      System.out.flush();
      try {
        Thread.sleep(500);
      } catch (InterruptedException ex) {
      }

      logger.info("Building for target \"" + config.getTarget() + "\"");

      List<String> assembleCommand = config.getLinkCommand(currentJob);

      Path mainLL;

      if (mainArguments) mainLL = Paths.get("shadow", "Main.ll");
      else mainLL = Paths.get("shadow", "NoArguments.ll");

      mainLL = system.resolve(mainLL);
      BufferedReader main = Files.newBufferedReader(mainLL, UTF8);

      String endian = "e"; // little Endian
      String pointerAlignment =
          "p:" + config.getArch() + ":" + config.getArch() + ":" + config.getArch();
      String dataAlignment =
          "i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64";
      String aggregateAlignment = "a:0:" + config.getArch();
      String nativeIntegers = "n8:16:32:64";
      String dataLayout =
          "-default-data-layout="
              + endian
              + "-"
              + pointerAlignment
              + "-"
              + dataAlignment
              + "-"
              + aggregateAlignment
              + "-"
              + nativeIntegers;

      Process link = new ProcessBuilder(linkCommand).redirectError(Redirect.INHERIT).start();
      Process optimize =
          new ProcessBuilder("opt", "-mtriple", config.getTarget(), "-O3", dataLayout)
              .redirectError(Redirect.INHERIT)
              .start();
      Process compile =
          new ProcessBuilder(
                  "llc", "-mtriple", config.getTarget(), "-O3") /*.redirectOutput(new File("a.s"))*/
              .redirectError(Redirect.INHERIT)
              .start();
      Process assemble =
          new ProcessBuilder(assembleCommand)
              .redirectOutput(Redirect.INHERIT)
              .redirectError(Redirect.INHERIT)
              .start();

      try {
        new Pipe(link.getInputStream(), optimize.getOutputStream()).start();
        new Pipe(optimize.getInputStream(), compile.getOutputStream()).start();
        new Pipe(compile.getInputStream(), assemble.getOutputStream()).start();
        String line = main.readLine();
        final OutputStream out = link.getOutputStream();
        while (line != null) {

          if (line.contains("@main")) { // declare externally defined generics
            for (String generic : generics)
              out.write(LLVMOutput.declareGeneric(generic).getBytes());
            for (String array : arrays) out.write(LLVMOutput.declareArray(array).getBytes());

            out.write(System.lineSeparator().getBytes());
          } else if (line.trim().startsWith("%genericSet"))
            line = line.replace("%genericSize", "" + generics.size() * 2);
          else if (line.trim().startsWith("%arraySet"))
            line = line.replace("%arraySize", "" + arrays.size() * 2);
          else if (line.trim().startsWith("invoke")) {
            // add in all externally declared generics
            LLVMOutput.addGenerics("%genericSet", generics, false, out);
            LLVMOutput.addGenerics("%arraySet", arrays, true, out);
          }

          line = line.replace("shadow.test..Test", mainClass) + System.lineSeparator();
          out.write(line.getBytes());
          line = main.readLine();
        }

        try {
          main.close();
        } catch (IOException ex) {
        }
        try {
          link.getOutputStream().flush();
        } catch (IOException ex) {
        }
        try {
          link.getOutputStream().close();
        } catch (IOException ex) {
        }
        if (link.waitFor() != 0) throw new CompileException("FAILED TO LINK");
        if (optimize.waitFor() != 0) throw new CompileException("FAILED TO OPTIMIZE");
        if (compile.waitFor() != 0) throw new CompileException("FAILED TO COMPILE");
        if (assemble.waitFor() != 0) throw new CompileException("FAILED TO ASSEMBLE");
      } catch (InterruptedException ex) {
      } finally {
        link.destroy();
        optimize.destroy();
        compile.destroy();
        assemble.destroy();
      }

      logger.info("SUCCESS: Built in " + (System.currentTimeMillis() - startTime) + "ms");
    }
  }