clang.py 3.34 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
"""Util to invoke clang in the system."""
# pylint: disable=invalid-name
from __future__ import absolute_import as _abs
import subprocess

from .._ffi.base import py_str
from .. import codegen
from . import util


def find_clang(required=True):
    """Find clang in system.

    Parameters
    ----------
    required : bool
        Whether it is required,
        runtime error will be raised if the compiler is required.

    Returns
    -------
    valid_list : list of str
        List of possible paths.

    Note
    ----
    This function will first search clang that
    matches the major llvm version that built with tvm
    """
    cc_list = []
    if hasattr(codegen, "llvm_version_major"):
        cc_list += ["clang-%d.0" % codegen.llvm_version_major()]
    cc_list += ["clang"]
50
    cc_list += ["clang.exe"]
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    valid_list = [util.which(x) for x in cc_list]
    valid_list = [x for x in valid_list if x]
    if not valid_list and required:
        raise RuntimeError(
            "cannot find clang, candidates are: " + str(cc_list))
    return valid_list


def create_llvm(inputs,
                output=None,
                options=None,
                cc=None):
    """Create llvm text ir.

    Parameters
    ----------
    inputs : list of str
        List of input files name or code source.

    output : str, optional
        Output file, if it is none
        a temporary file is created

    options : list
        The list of additional options string.

    cc : str, optional
        The clang compiler, if not specified,
        we will try to guess the matched clang version.

    Returns
    -------
    code : str
        The generated llvm text IR.
    """
    cc = cc if cc else find_clang()[0]
    cmd = [cc]
    cmd += ["-S", "-emit-llvm"]
    temp = util.tempdir()
    output = output if output else temp.relpath("output.ll")
    inputs = [inputs] if isinstance(inputs, str) else inputs
    input_files = []
    for i, code in enumerate(inputs):
        if util.is_source_path(code):
            input_files.append(code)
        else:
            temp_path = temp.relpath("input%d.cc" % i)
            with open(temp_path, "w") as output_file:
                output_file.write(code)
            input_files.append(temp_path)
    if options:
        cmd += options
    cmd += ["-o", output]
    cmd += input_files
    proc = subprocess.Popen(
        cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    (out, _) = proc.communicate()
    if proc.returncode != 0:
        msg = "Compilation error:\n"
        msg += py_str(out)
        raise RuntimeError(msg)

    return open(output).read()