packages feed

llvm-hs-5.0.0: src/LLVM/Internal/FFI/TargetC.cpp

#define __STDC_LIMIT_MACROS
#include "llvm-c/Target.h"
#include "LLVM/Internal/FFI/LibFunc.h"
#include "LLVM/Internal/FFI/Target.h"
#include "LLVM/Internal/FFI/Target.hpp"
#include "llvm-c/Core.h"
#include "llvm-c/TargetMachine.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

namespace llvm {
// Taken from llvm/lib/Target/TargetMachineC.cpp
// These functions need to be marked as static to avoid undefined behavior
// due to multiple definitions
static LLVMTargetRef wrap(const Target *P) {
  return reinterpret_cast<LLVMTargetRef>(const_cast<Target *>(P));
}

static inline TargetLibraryInfoImpl *unwrap(LLVMTargetLibraryInfoRef P) {
  return reinterpret_cast<TargetLibraryInfoImpl*>(P);
}

static inline LLVMTargetLibraryInfoRef wrap(const TargetLibraryInfoImpl *P) {
  TargetLibraryInfoImpl *X = const_cast<TargetLibraryInfoImpl*>(P);
  return reinterpret_cast<LLVMTargetLibraryInfoRef>(X);
}

static FloatABI::ABIType unwrap(LLVM_Hs_FloatABI x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case LLVM_Hs_FloatABI_##x:                                              \
    return FloatABI::x;
    LLVM_HS_FOR_EACH_FLOAT_ABI(ENUM_CASE)
#undef ENUM_CASE
  default:
    return FloatABI::ABIType(0);
  }
}

static LibFunc unwrap(LLVMLibFunc x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case LLVMLibFunc__##x:                                                       \
    return LibFunc_ ## x;
    LLVM_HS_FOR_EACH_LIB_FUNC(ENUM_CASE)
#undef ENUM_CASE
  default:
    return LibFunc(0);
  }
}

static LLVMLibFunc wrap(LibFunc x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case LibFunc_ ## x:                                                             \
    return LLVMLibFunc__##x;
    LLVM_HS_FOR_EACH_LIB_FUNC(ENUM_CASE)
#undef ENUM_CASE
  default:
    return LLVMLibFunc(0);
  }
}

static LLVM_Hs_FloatABI wrap(FloatABI::ABIType x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case FloatABI::x:                                                            \
    return LLVM_Hs_FloatABI_##x;
    LLVM_HS_FOR_EACH_FLOAT_ABI(ENUM_CASE)
#undef ENUM_CASE
  default:
    return LLVM_Hs_FloatABI(0);
  }
}

static FPOpFusion::FPOpFusionMode unwrap(LLVM_Hs_FPOpFusionMode x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case LLVM_Hs_FPOpFusionMode_##x:                                        \
    return FPOpFusion::x;
    LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(ENUM_CASE)
#undef ENUM_CASE
  default:
    return FPOpFusion::FPOpFusionMode(0);
  }
}

static LLVM_Hs_FPOpFusionMode wrap(FPOpFusion::FPOpFusionMode x) {
  switch (x) {
#define ENUM_CASE(x)                                                           \
  case FPOpFusion::x:                                                          \
    return LLVM_Hs_FPOpFusionMode_##x;
    LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(ENUM_CASE)
#undef ENUM_CASE
  default:
    return LLVM_Hs_FPOpFusionMode(0);
  }
}
}

extern "C" {

LLVMBool LLVM_Hs_InitializeNativeTarget() {
  return LLVMInitializeNativeTarget() || InitializeNativeTargetAsmPrinter() ||
         InitializeNativeTargetAsmParser();
}

LLVMTargetRef LLVM_Hs_LookupTarget(const char *arch, const char *ctriple,
                                        const char **tripleOut,
                                        const char **cerror) {
  std::string error;
  Triple triple(ctriple);
  if (const Target *result =
          TargetRegistry::lookupTarget(arch, triple, error)) {
    *tripleOut = strdup(triple.getTriple().c_str());
    return wrap(result);
  }
  *cerror = strdup(error.c_str());
  return 0;
}

TargetOptions *LLVM_Hs_CreateTargetOptions() {
  TargetOptions *to = new TargetOptions();
  return to;
}

void LLVM_Hs_SetTargetOptionFlag(TargetOptions *to,
                                      LLVM_Hs_TargetOptionFlag f,
                                      unsigned v) {
  switch (f) {
#define ENUM_CASE(op)                                                          \
  case LLVM_Hs_TargetOptionFlag_##op:                                     \
    to->op = v ? 1 : 0;                                                        \
    break;
    LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(ENUM_CASE)
#undef ENUM_CASE
  }
}

static llvm::DebugCompressionType unwrap(LLVM_Hs_DebugCompressionType compressionType) {
    switch(compressionType) {
#define ENUM_CASE(op)                                \
        case LLVM_Hs_DebugCompressionType_ ## op:    \
            return llvm::DebugCompressionType::op;
        LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(ENUM_CASE)
#undef ENUM_CASE
    default:
            assert(false && "Unknown debug compression type");
        return llvm::DebugCompressionType::None;
    }
}

static LLVM_Hs_DebugCompressionType wrap(llvm::DebugCompressionType compressionType) {
    switch(compressionType) {
#define ENUM_CASE(op)                                   \
        case llvm::DebugCompressionType::op:            \
            return LLVM_Hs_DebugCompressionType_ ## op;
        LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(ENUM_CASE)
#undef ENUM_CASE
    default: {
            assert(false && "Unknown debug compression type");
            return LLVM_Hs_DebugCompressionType_None;
        }
    }
}

void LLVM_Hs_SetCompressDebugSections(TargetOptions *to,
                                      LLVM_Hs_DebugCompressionType compress) {
    to->CompressDebugSections = unwrap(compress);
}

LLVM_Hs_DebugCompressionType LLVM_Hs_GetCompressDebugSections(TargetOptions* to) {
    return wrap(to->CompressDebugSections);
}

unsigned LLVM_Hs_GetTargetOptionFlag(TargetOptions *to,
                                          LLVM_Hs_TargetOptionFlag f) {
  switch (f) {
#define ENUM_CASE(op)                                                          \
  case LLVM_Hs_TargetOptionFlag_##op:                                     \
    return to->op;
    LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(ENUM_CASE)
#undef ENUM_CASE
  default:
    assert(false && "Unknown target option flag");
    return 0;
  }
}

void LLVM_Hs_SetStackAlignmentOverride(TargetOptions *to, unsigned v) {
  to->StackAlignmentOverride = v;
}

unsigned LLVM_Hs_GetStackAlignmentOverride(TargetOptions *to) {
  return to->StackAlignmentOverride;
}

void LLVM_Hs_SetFloatABIType(TargetOptions *to, LLVM_Hs_FloatABI v) {
  to->FloatABIType = unwrap(v);
}

LLVM_Hs_FloatABI LLVM_Hs_GetFloatABIType(TargetOptions *to) {
  return wrap(to->FloatABIType);
}

void LLVM_Hs_SetAllowFPOpFusion(TargetOptions *to,
                                     LLVM_Hs_FPOpFusionMode v) {
  to->AllowFPOpFusion = unwrap(v);
}

LLVM_Hs_FPOpFusionMode LLVM_Hs_GetAllowFPOpFusion(TargetOptions *to) {
  return wrap(to->AllowFPOpFusion);
}

void LLVM_Hs_DisposeTargetOptions(TargetOptions *t) { delete t; }

// const TargetLowering *LLVM_Hs_GetTargetLowering(LLVMTargetMachineRef t)
// {
// 	return unwrap(t)->getTargetLowering();
// }

char *LLVM_Hs_GetDefaultTargetTriple() {
  return strdup(sys::getDefaultTargetTriple().c_str());
}

char *LLVM_Hs_GetProcessTargetTriple() {
  return strdup(sys::getProcessTriple().c_str());
}

const char *LLVM_Hs_GetHostCPUName(size_t &len) {
  StringRef r = sys::getHostCPUName();
  len = r.size();
  return r.data();
}

char *LLVM_Hs_GetHostCPUFeatures() {
  StringMap<bool> featureMap;
  std::string features;
  if (sys::getHostCPUFeatures(featureMap)) {
    bool first = true;
    for (llvm::StringMap<bool>::const_iterator it = featureMap.begin();
         it != featureMap.end(); ++it) {
      if (!first) {
        features += ",";
      }
      first = false;
      features += (it->second ? "+" : "-") + it->first().str();
    }
  }
  return strdup(features.c_str());
}

char *LLVM_Hs_GetTargetMachineDataLayout(LLVMTargetMachineRef t) {
  return strdup(
      unwrap(t)->createDataLayout().getStringRepresentation().c_str());
}

LLVMTargetLibraryInfoRef
LLVM_Hs_CreateTargetLibraryInfo(const char *triple) {
    const TargetLibraryInfoImpl* p = new TargetLibraryInfoImpl(Triple(triple));
    return wrap(p);
}

LLVMBool LLVM_Hs_GetLibFunc(
	LLVMTargetLibraryInfoRef l,
	const char *funcName,
	LLVMLibFunc *f
) {
	LibFunc func;
	LLVMBool result = unwrap(l)->getLibFunc(funcName, func);
	*f = wrap(func);
	return result;
}

const char *LLVM_Hs_LibFuncGetName(
	LLVMTargetLibraryInfoRef l,
	LLVMLibFunc f,
	size_t *nameSize
) {
	TargetLibraryInfo impl(*unwrap(l));
    StringRef s = impl.getName(unwrap(f));
	*nameSize = s.size();
	return s.data();
}

void LLVM_Hs_LibFuncSetAvailableWithName(
	LLVMTargetLibraryInfoRef l,
	LLVMLibFunc f,
	const char *name
) {
	unwrap(l)->setAvailableWithName(unwrap(f), name);
}

void LLVM_Hs_DisposeTargetLibraryInfo(LLVMTargetLibraryInfoRef l) {
	delete unwrap(l);
}

void LLVM_Hs_InitializeAllTargets() {
  InitializeAllTargetInfos();
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  // None of the other components are bound yet
}

// This is identical to LLVMTargetMachineEmit but LLVM doesn’t expose this function so we copy it here.
LLVMBool LLVM_Hs_TargetMachineEmit(
    LLVMTargetMachineRef T,
    LLVMModuleRef M,
    raw_pwrite_stream *OS,
    LLVMCodeGenFileType codegen,
    char **ErrorMessage
) {
  TargetMachine* TM = unwrap(T);
  Module* Mod = unwrap(M);

  legacy::PassManager pass;

  std::string error;

  Mod->setDataLayout(TM->createDataLayout());

  TargetMachine::CodeGenFileType ft;
  switch (codegen) {
    case LLVMAssemblyFile:
      ft = TargetMachine::CGFT_AssemblyFile;
      break;
    default:
      ft = TargetMachine::CGFT_ObjectFile;
      break;
  }
  if (TM->addPassesToEmitFile(pass, *OS, ft)) {
    error = "TargetMachine can't emit a file of this type";
    *ErrorMessage = strdup(error.c_str());
    return true;
  }

  pass.run(*Mod);

  OS->flush();
  return false;
}

}