Search in sources :

Example 1 with TargetMachine

use of org.robovm.llvm.TargetMachine in project robovm by robovm.

the class Linker method generateMachineCode.

private File generateMachineCode(final Config config, final ModuleBuilder mb, final int num) throws IOException {
    File linkerO = new File(config.getTmpDir(), "linker" + num + ".o");
    linkerO.getParentFile().mkdirs();
    try (Context context = new Context()) {
        String ir = mb.build().toString();
        if (config.isDumpIntermediates()) {
            File linkerLl = new File(config.getTmpDir(), "linker" + num + ".ll");
            FileUtils.writeStringToFile(linkerLl, ir, "utf-8");
        }
        try (Module module = Module.parseIR(context, ir, "linker" + num + ".ll")) {
            try (PassManager passManager = new PassManager()) {
                passManager.addAlwaysInlinerPass();
                passManager.addPromoteMemoryToRegisterPass();
                passManager.run(module);
            }
            if (config.isDumpIntermediates()) {
                File linkerBc = new File(config.getTmpDir(), "linker" + num + ".bc");
                module.writeBitcode(linkerBc);
            }
            String triple = config.getTriple();
            Target target = Target.lookupTarget(triple);
            try (TargetMachine targetMachine = target.createTargetMachine(triple, null, null, null, RelocMode.RelocPIC, null)) {
                targetMachine.setAsmVerbosityDefault(true);
                targetMachine.setFunctionSections(true);
                targetMachine.setDataSections(true);
                targetMachine.getOptions().setNoFramePointerElim(true);
                // NOTE: Doesn't have any effect on x86. See #503.
                targetMachine.getOptions().setPositionIndependentExecutable(true);
                if (config.isDumpIntermediates()) {
                    File linkerS = new File(config.getTmpDir(), "linker" + num + ".s");
                    try (OutputStream outS = new BufferedOutputStream(new FileOutputStream(linkerS))) {
                        targetMachine.emit(module, outS, CodeGenFileType.AssemblyFile);
                    }
                }
                try (OutputStream outO = new BufferedOutputStream(new FileOutputStream(linkerO))) {
                    targetMachine.emit(module, outO, CodeGenFileType.ObjectFile);
                }
            }
        }
    }
    return linkerO;
}
Also used : Context(org.robovm.llvm.Context) Target(org.robovm.llvm.Target) TargetMachine(org.robovm.llvm.TargetMachine) BufferedOutputStream(java.io.BufferedOutputStream) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) FileOutputStream(java.io.FileOutputStream) Module(org.robovm.llvm.Module) File(java.io.File) BufferedOutputStream(java.io.BufferedOutputStream) PassManager(org.robovm.llvm.PassManager)

Example 2 with TargetMachine

use of org.robovm.llvm.TargetMachine in project robovm by robovm.

the class TypesTest method getAllocSize.

private int getAllocSize(StructureType type, String triple) {
    Context context = null;
    Module module = null;
    TargetMachine targetMachine = null;
    try {
        context = new Context();
        module = Module.parseIR(context, "%Object = type {i8*, i8*}\n%DataObject = type {%Object}\n%t = type " + type, null);
        Target target = Target.lookupTarget(triple);
        targetMachine = target.createTargetMachine(triple);
        return (int) targetMachine.getDataLayout().getTypeAllocSize(module.getTypeByName("t"));
    } finally {
        if (module != null) {
            module.dispose();
        }
        if (context != null) {
            context.dispose();
        }
        if (targetMachine != null) {
            targetMachine.dispose();
        }
    }
}
Also used : Context(org.robovm.llvm.Context) Target(org.robovm.llvm.Target) TargetMachine(org.robovm.llvm.TargetMachine) Module(org.robovm.llvm.Module)

Example 3 with TargetMachine

use of org.robovm.llvm.TargetMachine in project robovm by robovm.

the class ClassCompiler method generateMachineCode.

private static void generateMachineCode(Config config, Clazz clazz, byte[] llData, List<String> cCode) throws IOException {
    if (config.isDumpIntermediates()) {
        File llFile = config.getLlFile(clazz);
        llFile.getParentFile().mkdirs();
        FileUtils.writeByteArrayToFile(llFile, llData);
        File cFile = config.getCFile(clazz);
        if (cCode.isEmpty()) {
            cFile.delete();
        } else {
            FileUtils.writeLines(cFile, "ascii", cCode);
        }
    }
    File oFile = config.getOFile(clazz);
    try (Context context = new Context()) {
        try (Module module = Module.parseIR(context, llData, clazz.getClassName())) {
            if (!cCode.isEmpty()) {
                int size = 0;
                for (String s : cCode) {
                    size += s.length();
                }
                StringBuilder sb = new StringBuilder(size);
                for (String s : cCode) {
                    sb.append(s);
                }
                try (Module m2 = Module.parseClangString(context, sb.toString(), clazz.getClassName() + ".c", config.getClangTriple())) {
                    module.link(m2);
                    for (org.robovm.llvm.Function f1 : m2.getFunctions()) {
                        String name = f1.getName();
                        org.robovm.llvm.Function f2 = module.getFunctionByName(name);
                        if (Symbols.isBridgeCSymbol(name) || Symbols.isCallbackCSymbol(name) || Symbols.isCallbackInnerCSymbol(name)) {
                            f2.setLinkage(org.robovm.llvm.binding.Linkage.PrivateLinkage);
                            if (Symbols.isCallbackInnerCSymbol(name)) {
                                // TODO: We should also always inline the bridge functions but for some reason
                                // that makes the RoboVM tests hang indefinitely.
                                f2.removeAttribute(Attribute.NoInlineAttribute);
                                f2.addAttribute(Attribute.AlwaysInlineAttribute);
                            }
                        }
                    }
                }
            }
            try (PassManager passManager = createPassManager(config)) {
                passManager.run(module);
            }
            if (config.isDumpIntermediates()) {
                File bcFile = config.getBcFile(clazz);
                bcFile.getParentFile().mkdirs();
                module.writeBitcode(bcFile);
            }
            String triple = config.getTriple();
            Target target = Target.lookupTarget(triple);
            try (TargetMachine targetMachine = target.createTargetMachine(triple, config.getArch().getLlvmCpu(), null, config.isDebug() ? CodeGenOptLevel.CodeGenLevelNone : null, RelocMode.RelocPIC, null)) {
                targetMachine.setAsmVerbosityDefault(true);
                targetMachine.setFunctionSections(true);
                targetMachine.setDataSections(true);
                targetMachine.getOptions().setNoFramePointerElim(true);
                // NOTE: Doesn't have any effect on x86. See #503.
                targetMachine.getOptions().setPositionIndependentExecutable(!config.isDebug());
                ByteArrayOutputStream output = new ByteArrayOutputStream(256 * 1024);
                targetMachine.emit(module, output, CodeGenFileType.AssemblyFile);
                byte[] asm = output.toByteArray();
                output.reset();
                patchAsmWithFunctionSizes(config, clazz, new ByteArrayInputStream(asm), output);
                asm = output.toByteArray();
                if (config.isDumpIntermediates()) {
                    File sFile = config.getSFile(clazz);
                    sFile.getParentFile().mkdirs();
                    FileUtils.writeByteArrayToFile(sFile, asm);
                }
                oFile.getParentFile().mkdirs();
                ByteArrayOutputStream oFileBytes = new ByteArrayOutputStream();
                targetMachine.assemble(asm, clazz.getClassName(), oFileBytes);
                new HfsCompressor().compress(oFile, oFileBytes.toByteArray(), config);
                for (CompilerPlugin plugin : config.getCompilerPlugins()) {
                    plugin.afterObjectFile(config, clazz, oFile);
                }
                /*
                     * Read out line number info from the .o file if any and
                     * assemble into a separate .o file.
                     */
                String symbolPrefix = config.getOs().getFamily() == OS.Family.darwin ? "_" : "";
                symbolPrefix += Symbols.EXTERNAL_SYMBOL_PREFIX;
                ModuleBuilder linesMb = null;
                try (ObjectFile objectFile = ObjectFile.load(oFile)) {
                    for (Symbol symbol : objectFile.getSymbols()) {
                        if (symbol.getSize() > 0 && symbol.getName().startsWith(symbolPrefix)) {
                            List<LineInfo> lineInfos = objectFile.getLineInfos(symbol);
                            if (!lineInfos.isEmpty()) {
                                Collections.sort(lineInfos, new Comparator<LineInfo>() {

                                    public int compare(LineInfo o1, LineInfo o2) {
                                        return Long.compare(o1.getAddress(), o2.getAddress());
                                    }
                                });
                                // The base address of the method which will be used to calculate offsets into the method
                                long baseAddress = symbol.getAddress();
                                // The first line number in the method. All other line numbers in the table will be deltas against this.
                                int firstLineNumber = lineInfos.get(0).getLineNumber();
                                // Calculate the max address and line number offsets
                                long maxAddressOffset = 0;
                                long maxLineOffset = 0;
                                for (LineInfo lineInfo : lineInfos) {
                                    maxAddressOffset = Math.max(maxAddressOffset, lineInfo.getAddress() - baseAddress);
                                    maxLineOffset = Math.max(maxLineOffset, lineInfo.getLineNumber() - firstLineNumber);
                                }
                                // Calculate the number of bytes needed to represent the highest offsets.
                                // Either 1, 2 or 4 bytes will be used.
                                int addressOffsetSize = (maxAddressOffset & ~0xff) == 0 ? 1 : ((maxAddressOffset & ~0xffff) == 0 ? 2 : 4);
                                int lineOffsetSize = (maxLineOffset & ~0xff) == 0 ? 1 : ((maxLineOffset & ~0xffff) == 0 ? 2 : 4);
                                // The size of the address offsets table. We skip the first LineInfo as its offset is always 0.
                                int addressOffsetTableSize = addressOffsetSize * (lineInfos.size() - 1);
                                // Pad size of address offset table to make sure line offsets are aligned properly 
                                int addressOffsetPadding = (lineOffsetSize - (addressOffsetTableSize & (lineOffsetSize - 1))) & (lineOffsetSize - 1);
                                addressOffsetTableSize += addressOffsetPadding;
                                // The first 32 bits of the line number info contains the number of line numbers
                                // minus the first. The 4 most significant bits are used to store the number of
                                // bytes needed by each entry in each table.
                                int flags = 0;
                                flags = addressOffsetSize - 1;
                                flags <<= 2;
                                flags |= lineOffsetSize - 1;
                                flags <<= 28;
                                flags |= (lineInfos.size() - 1) & 0x0fffffff;
                                StructureConstantBuilder builder = new StructureConstantBuilder();
                                builder.add(new IntegerConstant(flags)).add(new IntegerConstant(firstLineNumber));
                                for (LineInfo lineInfo : lineInfos.subList(1, lineInfos.size())) {
                                    if (addressOffsetSize == 1) {
                                        builder.add(new IntegerConstant((byte) (lineInfo.getAddress() - baseAddress)));
                                    } else if (addressOffsetSize == 2) {
                                        builder.add(new IntegerConstant((short) (lineInfo.getAddress() - baseAddress)));
                                    } else {
                                        builder.add(new IntegerConstant((int) (lineInfo.getAddress() - baseAddress)));
                                    }
                                }
                                // Padding
                                for (int i = 0; i < addressOffsetPadding; i++) {
                                    builder.add(new IntegerConstant((byte) 0));
                                }
                                for (LineInfo lineInfo : lineInfos.subList(1, lineInfos.size())) {
                                    if (lineOffsetSize == 1) {
                                        builder.add(new IntegerConstant((byte) (lineInfo.getLineNumber() - firstLineNumber)));
                                    } else if (lineOffsetSize == 2) {
                                        builder.add(new IntegerConstant((short) (lineInfo.getLineNumber() - firstLineNumber)));
                                    } else {
                                        builder.add(new IntegerConstant((int) (lineInfo.getLineNumber() - firstLineNumber)));
                                    }
                                }
                                // Extract the method's name and descriptor from the symbol and
                                // build the linetable symbol name.
                                String methodName = symbol.getName().substring(symbol.getName().lastIndexOf('.') + 1);
                                methodName = methodName.substring(0, methodName.indexOf('('));
                                String methodDesc = symbol.getName().substring(symbol.getName().lastIndexOf('('));
                                String linetableSymbol = Symbols.linetableSymbol(clazz.getInternalName(), methodName, methodDesc);
                                if (linesMb == null) {
                                    linesMb = new ModuleBuilder();
                                }
                                linesMb.addGlobal(new Global(linetableSymbol, builder.build(), true));
                            }
                        }
                    }
                }
                if (linesMb != null) {
                    byte[] linesData = linesMb.build().toString().getBytes("UTF-8");
                    if (config.isDumpIntermediates()) {
                        File linesLlFile = config.getLinesLlFile(clazz);
                        linesLlFile.getParentFile().mkdirs();
                        FileUtils.writeByteArrayToFile(linesLlFile, linesData);
                    }
                    try (Module linesModule = Module.parseIR(context, linesData, clazz.getClassName() + ".lines")) {
                        File linesOFile = config.getLinesOFile(clazz);
                        ByteArrayOutputStream linesOBytes = new ByteArrayOutputStream();
                        targetMachine.emit(linesModule, linesOBytes, CodeGenFileType.ObjectFile);
                        new HfsCompressor().compress(linesOFile, linesOBytes.toByteArray(), config);
                    }
                } else {
                    // Make sure there's no stale lines.o file lingering
                    File linesOFile = config.getLinesOFile(clazz);
                    if (linesOFile.exists()) {
                        linesOFile.delete();
                    }
                }
            }
        }
    } catch (Throwable t) {
        if (oFile.exists()) {
            oFile.delete();
        }
        if (t instanceof IOException) {
            throw (IOException) t;
        }
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        }
        if (t instanceof Error) {
            throw (Error) t;
        }
        throw new CompilerException(t);
    }
}
Also used : CompilerPlugin(org.robovm.compiler.plugin.CompilerPlugin) Symbol(org.robovm.llvm.Symbol) LineInfo(org.robovm.llvm.LineInfo) PassManager(org.robovm.llvm.PassManager) Global(org.robovm.compiler.llvm.Global) HfsCompressor(org.robovm.compiler.util.io.HfsCompressor) Target(org.robovm.llvm.Target) ObjectFile(org.robovm.llvm.ObjectFile) Context(org.robovm.llvm.Context) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) StructureConstantBuilder(org.robovm.compiler.llvm.StructureConstantBuilder) PackedStructureConstantBuilder(org.robovm.compiler.llvm.PackedStructureConstantBuilder) IntegerConstant(org.robovm.compiler.llvm.IntegerConstant) TargetMachine(org.robovm.llvm.TargetMachine) ByteArrayInputStream(java.io.ByteArrayInputStream) Module(org.robovm.llvm.Module) ObjectFile(org.robovm.llvm.ObjectFile) File(java.io.File)

Example 4 with TargetMachine

use of org.robovm.llvm.TargetMachine in project robovm by robovm.

the class DataLayout method runTypeQuery.

private <T> T runTypeQuery(Type type, TypeCallback<T> cb) {
    Context context = null;
    Module module = null;
    TargetMachine targetMachine = null;
    try {
        String definition;
        if (type instanceof PrimitiveType) {
            definition = "{" + ((PrimitiveType) type).getName() + "}";
        } else if (type instanceof StructureType) {
            definition = ((StructureType) type).getDefinition();
        } else {
            definition = "{" + ((UserType) type).getDefinition() + "}";
        }
        context = new Context();
        module = Module.parseIR(context, "%t = type " + definition, null);
        targetMachine = target.createTargetMachine(triple);
        return cb.doWithType(targetMachine, module.getTypeByName("t"));
    } finally {
        if (targetMachine != null) {
            targetMachine.dispose();
        }
        if (module != null) {
            module.dispose();
        }
        if (context != null) {
            context.dispose();
        }
    }
}
Also used : Context(org.robovm.llvm.Context) TargetMachine(org.robovm.llvm.TargetMachine) Module(org.robovm.llvm.Module)

Aggregations

Context (org.robovm.llvm.Context)4 Module (org.robovm.llvm.Module)4 TargetMachine (org.robovm.llvm.TargetMachine)4 Target (org.robovm.llvm.Target)3 File (java.io.File)2 PassManager (org.robovm.llvm.PassManager)2 BufferedOutputStream (java.io.BufferedOutputStream)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileOutputStream (java.io.FileOutputStream)1 IOException (java.io.IOException)1 OutputStream (java.io.OutputStream)1 Global (org.robovm.compiler.llvm.Global)1 IntegerConstant (org.robovm.compiler.llvm.IntegerConstant)1 PackedStructureConstantBuilder (org.robovm.compiler.llvm.PackedStructureConstantBuilder)1 StructureConstantBuilder (org.robovm.compiler.llvm.StructureConstantBuilder)1 CompilerPlugin (org.robovm.compiler.plugin.CompilerPlugin)1 HfsCompressor (org.robovm.compiler.util.io.HfsCompressor)1 LineInfo (org.robovm.llvm.LineInfo)1 ObjectFile (org.robovm.llvm.ObjectFile)1