llvm_common.cc 4.93 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * 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.
 */

20 21 22 23 24 25
/*!
 * \file llvm_common.cc
 */
#ifdef TVM_LLVM_VERSION

#include <tvm/base.h>
26
#include <atomic>
27
#include <mutex>
28
#include <memory>
29
#include "llvm_common.h"
30 31 32 33 34 35

namespace tvm {
namespace codegen {

struct LLVMEnv {
  std::mutex mu;
36
  std::atomic<bool> all_initialized{false};
37 38 39 40 41 42 43 44 45

  static LLVMEnv* Global() {
    static LLVMEnv inst;
    return &inst;
  }
};

void InitializeLLVM() {
  LLVMEnv* e = LLVMEnv::Global();
46
  if (!e->all_initialized.load(std::memory_order::memory_order_acquire)) {
47
    std::lock_guard<std::mutex> lock(e->mu);
48
    if (!e->all_initialized.load(std::memory_order::memory_order_acquire)) {
49 50 51 52 53
      llvm::InitializeAllTargetInfos();
      llvm::InitializeAllTargets();
      llvm::InitializeAllTargetMCs();
      llvm::InitializeAllAsmParsers();
      llvm::InitializeAllAsmPrinters();
54
      e->all_initialized.store(true, std::memory_order::memory_order_release);
55 56 57 58
    }
  }
}

59 60 61 62 63
void ParseLLVMTargetOptions(const std::string& target_str,
                            std::string* triple,
                            std::string* mcpu,
                            std::string* mattr,
                            llvm::TargetOptions* options) {
64
  // setup target triple
65 66 67 68 69
  size_t start = 0;
  if (target_str.length() >= 4 &&
      target_str.substr(0, 4) == "llvm") {
    start = 4;
  }
70
  // simple parser
71 72 73 74
  triple->resize(0);
  mcpu->resize(0);
  mattr->resize(0);

75
  bool soft_float_abi = false;
76
  std::string key, value;
77 78 79 80 81 82 83 84 85
  std::istringstream is(target_str.substr(start, target_str.length() - start));

  while (is >> key) {
    if (key == "--system-lib" || key == "-system-lib") {
      continue;
    }
    size_t pos = key.find('=');
    if (pos != std::string::npos) {
      CHECK_GE(key.length(), pos + 1)
86
          << "invalid argument " << key;
87 88 89 90 91 92 93 94
      value = key.substr(pos + 1, key.length() - 1);
      key = key.substr(0, pos);
    } else {
      CHECK(is >> value)
          << "Unspecified value for option " << key;
    }
    if (key == "-target" ||
        key == "-mtriple") {
95
      *triple = value;
96
    } else if (key == "-mcpu") {
97
      *mcpu = value;
98
    } else if (key == "-mattr") {
99
      *mattr = value;
100 101
    } else if (key == "-mfloat-abi") {
      if (value == "hard") {
102 103 104
#if TVM_LLVM_VERSION < 60
        LOG(FATAL) << "-mfloat-abi hard is only supported for LLVM > 6.0";
#endif
105 106 107
        soft_float_abi = false;
      } else if (value == "soft") {
        soft_float_abi = true;
108
      } else {
109
        LOG(FATAL) << "invalid -mfloat-abi option " << value;
110
      }
111
    } else if (key == "-device" || key == "-libs" || key == "-model") {
112
      // pass
113 114
    } else {
      LOG(FATAL) << "unknown option " << key;
115
    }
116
  }
117

118 119 120
  if (triple->length() == 0 ||
      *triple == "default") {
    *triple = llvm::sys::getDefaultTargetTriple();
121
  }
122
  // set target option
123 124
  llvm::TargetOptions& opt = *options;
  opt = llvm::TargetOptions();
125
  #if TVM_LLVM_VERSION < 50
126
  opt.LessPreciseFPMADOption = true;
127
  #endif
128
  opt.AllowFPOpFusion = llvm::FPOpFusion::Fast;
129 130
  opt.UnsafeFPMath = false;
  opt.NoInfsFPMath = false;
131 132 133 134 135 136
  opt.NoNaNsFPMath = true;
  if (soft_float_abi) {
    opt.FloatABIType = llvm::FloatABI::Soft;
  } else {
    opt.FloatABIType = llvm::FloatABI::Hard;
  }
137 138 139
}


140
std::unique_ptr<llvm::TargetMachine>
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
GetLLVMTargetMachine(const std::string& target_str,
                     bool allow_null) {
  std::string target_triple, mcpu, mattr;
  llvm::TargetOptions opt;

  ParseLLVMTargetOptions(target_str,
                         &target_triple,
                         &mcpu,
                         &mattr,
                         &opt);

  if (target_triple.length() == 0 ||
      target_triple == "default") {
    target_triple = llvm::sys::getDefaultTargetTriple();
  }
  if (mcpu.length() == 0) {
    mcpu = "generic";
  }

  std::string err;
  const llvm::Target* target =
      llvm::TargetRegistry::lookupTarget(target_triple, err);
  if (target == nullptr) {
    CHECK(allow_null) << err << " target_triple=" << target_triple;
    return nullptr;
  }
167
  llvm::TargetMachine* tm = target->createTargetMachine(
168
      target_triple, mcpu, mattr, opt, llvm::Reloc::PIC_);
169
  return std::unique_ptr<llvm::TargetMachine>(tm);
170 171
}

172 173 174
}  // namespace codegen
}  // namespace tvm
#endif  // TVM_LLVM_VERSION