llvm_common.cc 4.05 KB
Newer Older
1 2 3 4 5 6 7
/*!
 *  Copyright (c) 2017 by Contributors
 * \file llvm_common.cc
 */
#ifdef TVM_LLVM_VERSION

#include <tvm/base.h>
8
#include <atomic>
9
#include <mutex>
10
#include "llvm_common.h"
11 12 13 14 15 16

namespace tvm {
namespace codegen {

struct LLVMEnv {
  std::mutex mu;
17
  std::atomic<bool> all_initialized{false};
18 19 20 21 22 23 24 25 26

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

void InitializeLLVM() {
  LLVMEnv* e = LLVMEnv::Global();
27
  if (!e->all_initialized.load(std::memory_order::memory_order_acquire)) {
28
    std::lock_guard<std::mutex> lock(e->mu);
29
    if (!e->all_initialized.load(std::memory_order::memory_order_acquire)) {
30 31 32 33 34
      llvm::InitializeAllTargetInfos();
      llvm::InitializeAllTargets();
      llvm::InitializeAllTargetMCs();
      llvm::InitializeAllAsmParsers();
      llvm::InitializeAllAsmPrinters();
35
      e->all_initialized.store(true, std::memory_order::memory_order_release);
36 37 38 39
    }
  }
}

40 41 42 43 44
void ParseLLVMTargetOptions(const std::string& target_str,
                            std::string* triple,
                            std::string* mcpu,
                            std::string* mattr,
                            llvm::TargetOptions* options) {
45
  // setup target triple
46 47 48 49 50
  size_t start = 0;
  if (target_str.length() >= 4 &&
      target_str.substr(0, 4) == "llvm") {
    start = 4;
  }
51
  // simple parser
52 53 54 55
  triple->resize(0);
  mcpu->resize(0);
  mattr->resize(0);

56
  bool soft_float_abi = false;
57
  std::string key, value;
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  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)
          << "inavlid argument " << key;
      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") {
76
      *triple = value;
77
    } else if (key == "-mcpu") {
78
      *mcpu = value;
79
    } else if (key == "-mattr") {
80
      *mattr = value;
81 82 83 84 85
    } else if (key == "-mfloat-abi") {
      if (value == "hard") {
        soft_float_abi = false;
      } else if (value == "soft") {
        soft_float_abi = true;
86
      } else {
87
        LOG(FATAL) << "invalid -mfloat-abi option " << value;
88
      }
89
    } else if (key == "-device" || key == "-libs" || key == "-model") {
90
      // pass
91 92
    } else {
      LOG(FATAL) << "unknown option " << key;
93
    }
94
  }
95

96 97 98
  if (triple->length() == 0 ||
      *triple == "default") {
    *triple = llvm::sys::getDefaultTargetTriple();
99
  }
100
  // set target option
101 102
  llvm::TargetOptions& opt = *options;
  opt = llvm::TargetOptions();
103
  #if TVM_LLVM_VERSION < 50
104
  opt.LessPreciseFPMADOption = true;
105
  #endif
106
  opt.AllowFPOpFusion = llvm::FPOpFusion::Fast;
107 108
  opt.UnsafeFPMath = false;
  opt.NoInfsFPMath = false;
109 110 111 112 113 114
  opt.NoNaNsFPMath = true;
  if (soft_float_abi) {
    opt.FloatABIType = llvm::FloatABI::Soft;
  } else {
    opt.FloatABIType = llvm::FloatABI::Hard;
  }
115 116 117
}


118
std::unique_ptr<llvm::TargetMachine>
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
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;
  }
145
  llvm::TargetMachine* tm = target->createTargetMachine(
146
      target_triple, mcpu, mattr, opt, llvm::Reloc::PIC_);
147
  return std::unique_ptr<llvm::TargetMachine>(tm);
148 149
}

150 151 152
}  // namespace codegen
}  // namespace tvm
#endif  // TVM_LLVM_VERSION