mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
237 lines
5.7 KiB
C++
237 lines
5.7 KiB
C++
|
|
// For hacking the C API
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/Object/Archive.h"
|
|
#include "llvm/Object/ArchiveWriter.h"
|
|
#include "llvm/Object/IRObjectFile.h"
|
|
#include "llvm/Object/SymbolicFile.h"
|
|
|
|
#if LLVM_VERSION_MAJOR > 13
|
|
#define LINK_SIG \
|
|
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, \
|
|
llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
|
|
#define CALL_ARGS arg_vector, output, output_err, false, false
|
|
#else
|
|
#define LINK_SIG \
|
|
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly, \
|
|
llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS);
|
|
#define CALL_ARGS arg_vector, false, output, output_err
|
|
#endif
|
|
|
|
namespace lld {
|
|
namespace coff {
|
|
LINK_SIG
|
|
}
|
|
|
|
namespace mingw {
|
|
LINK_SIG
|
|
}
|
|
|
|
namespace elf {
|
|
LINK_SIG
|
|
}
|
|
|
|
namespace mach_o {
|
|
LINK_SIG
|
|
}
|
|
|
|
namespace macho {
|
|
LINK_SIG
|
|
}
|
|
|
|
namespace wasm {
|
|
LINK_SIG
|
|
}
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
ELF,
|
|
WASM,
|
|
MACHO,
|
|
COFF,
|
|
MINGW
|
|
} ObjFormat;
|
|
|
|
typedef enum
|
|
{
|
|
AR_GNU,
|
|
AR_DARWIN,
|
|
AR_DARWIN64,
|
|
AR_BSD,
|
|
AR_GNU64,
|
|
AR_COFF,
|
|
} ArFormat;
|
|
|
|
|
|
|
|
static bool llvm_link(ObjFormat format, const char **args, int arg_count, const char** error_string)
|
|
{
|
|
std::vector<const char*> arg_vector = std::vector<const char *>();
|
|
switch (format)
|
|
{
|
|
case ELF:
|
|
arg_vector.push_back("ld.lld");
|
|
break;
|
|
case WASM:
|
|
arg_vector.push_back("wasm-ld");
|
|
break;
|
|
case MACHO:
|
|
arg_vector.push_back("ld64.lld");
|
|
break;
|
|
case COFF:
|
|
arg_vector.push_back("lld-link");
|
|
break;
|
|
case MINGW:
|
|
arg_vector.push_back("ld");
|
|
break;
|
|
}
|
|
for (int i = 0; i < arg_count; i++) arg_vector.push_back(strdup(args[i]));
|
|
std::string output_string {};
|
|
std::string output_err_string {};
|
|
/*
|
|
llvm::raw_string_ostream output { output_string };
|
|
llvm::raw_string_ostream output_err { output_err_string };*/
|
|
llvm::raw_ostream &output = llvm::outs();
|
|
llvm::raw_ostream &output_err = llvm::errs();
|
|
switch (format)
|
|
{
|
|
case ELF:
|
|
if (lld::elf::link(CALL_ARGS)) return true;
|
|
break;
|
|
case MACHO:
|
|
if (lld::macho::link(CALL_ARGS)) return true;
|
|
break;
|
|
case WASM:
|
|
if (lld::wasm::link(CALL_ARGS)) return true;
|
|
break;
|
|
case COFF:
|
|
if (lld::coff::link(CALL_ARGS)) return true;
|
|
break;
|
|
case MINGW:
|
|
exit(-1);
|
|
if (lld::mingw::link(CALL_ARGS)) return true;
|
|
break;
|
|
default:
|
|
exit(-1);
|
|
}
|
|
//*error_string = strdup(output_err_string.c_str());
|
|
return false;
|
|
}
|
|
|
|
|
|
extern "C" {
|
|
|
|
bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat)
|
|
{
|
|
llvm::object::Archive::Kind kind;
|
|
switch (ArFormat)
|
|
{
|
|
case AR_BSD:
|
|
kind = llvm::object::Archive::K_BSD;
|
|
break;
|
|
case AR_DARWIN:
|
|
kind = llvm::object::Archive::K_DARWIN;
|
|
break;
|
|
case AR_DARWIN64:
|
|
kind = llvm::object::Archive::K_DARWIN64;
|
|
break;
|
|
case AR_GNU:
|
|
kind = llvm::object::Archive::K_GNU;
|
|
break;
|
|
case AR_GNU64:
|
|
kind = llvm::object::Archive::K_GNU64;
|
|
break;
|
|
case AR_COFF:
|
|
kind = llvm::object::Archive::K_GNU;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
bool is_win = ArFormat == AR_COFF;
|
|
std::vector<llvm::NewArchiveMember> new_members {};
|
|
for (size_t i = 0; i < count; i++)
|
|
{
|
|
auto member = llvm::NewArchiveMember::getFile(std::string(args[i]), false);
|
|
if (!member) return false;
|
|
if (is_win)
|
|
{
|
|
// Needs relative paths.
|
|
const char *rel_name = strrchr(args[i], '/');
|
|
if (rel_name) member->MemberName = rel_name + 1;
|
|
}
|
|
new_members.push_back(std::move(*member));
|
|
}
|
|
return !llvm::writeArchive(std::string(out_name), std::move(new_members), true, kind, true, false, nullptr);
|
|
}
|
|
|
|
int llvm_version_major = LLVM_VERSION_MAJOR;
|
|
#if LLVM_VERSION_MAJOR < 13
|
|
#if _MSC_VER
|
|
__declspec(selectany)
|
|
#else
|
|
__attribute__((weak))
|
|
#endif
|
|
LLVMAttributeRef LLVMCreateTypeAttribute(LLVMContextRef C, unsigned KindID,
|
|
LLVMTypeRef type_ref)
|
|
{
|
|
auto &Ctx = *llvm::unwrap(C);
|
|
auto AttrKind = (llvm::Attribute::AttrKind)KindID;
|
|
return wrap(llvm::Attribute::get(Ctx, AttrKind, llvm::unwrap(type_ref)));
|
|
}
|
|
#endif
|
|
LLVMValueRef LLVMConstBswap(LLVMValueRef ConstantVal)
|
|
{
|
|
llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal);
|
|
const llvm::APInt& i = Val->getUniqueInteger();
|
|
return llvm::wrap(llvm::Constant::getIntegerValue(Val->getType(), i.byteSwap()));
|
|
}
|
|
#if LLVM_VERSION_MAJOR < 14
|
|
LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
|
|
LLVMValueRef *ConstantIndices, unsigned NumIndices) {
|
|
llvm::ArrayRef<llvm::Constant *> IdxList(llvm::unwrap<llvm::Constant>(ConstantIndices, NumIndices),
|
|
NumIndices);
|
|
llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal);
|
|
return wrap(llvm::ConstantExpr::getGetElementPtr(llvm::unwrap(Ty), Val, IdxList));
|
|
}
|
|
|
|
LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty,
|
|
LLVMValueRef ConstantVal,
|
|
LLVMValueRef *ConstantIndices,
|
|
unsigned NumIndices) {
|
|
llvm::ArrayRef<llvm::Constant *> IdxList(llvm::unwrap<llvm::Constant>(ConstantIndices, NumIndices),
|
|
NumIndices);
|
|
llvm::Constant *Val = llvm::unwrap<llvm::Constant>(ConstantVal);
|
|
return wrap(llvm::ConstantExpr::getInBoundsGetElementPtr(llvm::unwrap(Ty), Val, IdxList));
|
|
}
|
|
#endif
|
|
|
|
bool llvm_link_elf(const char **args, int arg_count, const char** error_string)
|
|
{
|
|
return llvm_link(ELF, args, arg_count, error_string);
|
|
}
|
|
|
|
bool llvm_link_macho(const char **args, int arg_count, const char** error_string)
|
|
{
|
|
return llvm_link(MACHO, args, arg_count, error_string);
|
|
}
|
|
|
|
bool llvm_link_coff(const char **args, int arg_count, const char** error_string)
|
|
{
|
|
return llvm_link(COFF, args, arg_count, error_string);
|
|
}
|
|
|
|
bool llvm_link_wasm(const char **args, int arg_count, const char** error_string)
|
|
{
|
|
return llvm_link(WASM, args, arg_count, error_string);
|
|
}
|
|
|
|
bool llvm_link_mingw(const char **args, int arg_count, const char** error_string)
|
|
{
|
|
return llvm_link(MINGW, args, arg_count, error_string);
|
|
}
|
|
|
|
|
|
|
|
}
|