mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Add new optimizer runner.
This commit is contained in:
@@ -1,14 +1,32 @@
|
||||
|
||||
// For hacking the C API
|
||||
#include <llvm/IR/PassManager.h>
|
||||
#include "c3_llvm.h"
|
||||
#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"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "lld/Common/CommonLinkerContext.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm-c/Transforms/PassBuilder.h"
|
||||
#include "llvm-c/TargetMachine.h"
|
||||
#include "llvm-c/Target.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/StandardInstrumentations.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
|
||||
#include "llvm/Transforms/Scalar/EarlyCSE.h"
|
||||
#include "llvm/Transforms/Scalar/GVN.h"
|
||||
#include "llvm/Transforms/Scalar/JumpThreading.h"
|
||||
#include "llvm/Transforms/InstCombine/InstCombine.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
|
||||
#define LINK_SIG \
|
||||
bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, \
|
||||
@@ -51,23 +69,6 @@ typedef enum
|
||||
MINGW
|
||||
} ObjFormat;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AR_GNU,
|
||||
AR_DARWIN,
|
||||
AR_DARWIN64,
|
||||
AR_BSD,
|
||||
AR_GNU64,
|
||||
AR_COFF,
|
||||
} ArFormat;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STRICT,
|
||||
RELAXED,
|
||||
FAST
|
||||
} FastMathOption;
|
||||
|
||||
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 *>();
|
||||
@@ -127,113 +128,216 @@ static bool llvm_link(ObjFormat format, const char **args, int arg_count, const
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool llvm_ar(const char *out_name, const char **args, size_t count, int ArFormat)
|
||||
|
||||
bool llvm_run_passes(LLVMModuleRef m, LLVMTargetMachineRef tm,
|
||||
LLVMPasses *passes)
|
||||
{
|
||||
llvm::TargetMachine *Machine = reinterpret_cast<llvm::TargetMachine *>(tm);
|
||||
llvm::Module *Mod = llvm::unwrap(m);
|
||||
llvm::PassInstrumentationCallbacks PIC;
|
||||
llvm::PipelineTuningOptions PTO{};
|
||||
PTO.LoopUnrolling = passes->opt.unroll_loops;
|
||||
PTO.LoopInterleaving = passes->opt.interleave_loops;
|
||||
PTO.LoopVectorization = passes->opt.vectorize_loops;
|
||||
PTO.SLPVectorization = passes->opt.slp_vectorize;
|
||||
PTO.MergeFunctions = passes->opt.merge_functions;
|
||||
PTO.CallGraphProfile = true; // We always use integrated ASM
|
||||
PTO.UnifiedLTO = false;
|
||||
|
||||
llvm::PassBuilder PB(Machine, PTO, std::nullopt, &PIC);
|
||||
|
||||
llvm::LoopAnalysisManager LAM;
|
||||
llvm::FunctionAnalysisManager FAM;
|
||||
llvm::CGSCCAnalysisManager CGAM;
|
||||
llvm::ModuleAnalysisManager MAM;
|
||||
PB.registerLoopAnalyses(LAM);
|
||||
PB.registerFunctionAnalyses(FAM);
|
||||
PB.registerCGSCCAnalyses(CGAM);
|
||||
PB.registerModuleAnalyses(MAM);
|
||||
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
|
||||
|
||||
llvm::StandardInstrumentations SI(Mod->getContext(), passes->should_debug, passes->should_verify);
|
||||
SI.registerCallbacks(PIC, &MAM);
|
||||
|
||||
// Assignment tracking pass is not enabled, but could be added
|
||||
// Skipping TargetLibraryAnalysis
|
||||
|
||||
llvm::OptimizationLevel level;
|
||||
switch (passes->opt_level)
|
||||
{
|
||||
llvm::object::Archive::Kind kind;
|
||||
switch (ArFormat)
|
||||
case LLVM_O0:
|
||||
level = llvm::OptimizationLevel::O0;
|
||||
break;
|
||||
case LLVM_O1:
|
||||
level = llvm::OptimizationLevel::O1;
|
||||
break;
|
||||
case LLVM_O2:
|
||||
level = llvm::OptimizationLevel::O2;
|
||||
break;
|
||||
case LLVM_O3:
|
||||
level = llvm::OptimizationLevel::O3;
|
||||
break;
|
||||
case LLVM_Os:
|
||||
level = llvm::OptimizationLevel::Os;
|
||||
break;
|
||||
case LLVM_Oz:
|
||||
level = llvm::OptimizationLevel::Oz;
|
||||
break;
|
||||
default:
|
||||
exit(-1);
|
||||
}
|
||||
llvm::ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(level, false);
|
||||
|
||||
if (passes->should_verify)
|
||||
{
|
||||
MPM.addPass(llvm::VerifierPass());
|
||||
}
|
||||
if (passes->sanitizer.mem_sanitize)
|
||||
{
|
||||
llvm::MemorySanitizerOptions options(passes->sanitizer.mem_track_origins,
|
||||
passes->sanitizer.recover,
|
||||
passes->is_kernel,
|
||||
passes->sanitizer.mem_retval);
|
||||
|
||||
MPM.addPass(llvm::MemorySanitizerPass(options));
|
||||
if (passes->opt_level != LLVM_O0)
|
||||
{
|
||||
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);
|
||||
// Add another function pass like Clang does.
|
||||
MPM.addPass(llvm::RequireAnalysisPass<llvm::GlobalsAA, llvm::Module>());
|
||||
llvm::FunctionPassManager FPM;
|
||||
FPM.addPass(llvm::EarlyCSEPass(true /* Enable mem-ssa. */));
|
||||
FPM.addPass(llvm::InstCombinePass());
|
||||
FPM.addPass(llvm::JumpThreadingPass());
|
||||
FPM.addPass(llvm::GVNPass());
|
||||
FPM.addPass(llvm::InstCombinePass());
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
|
||||
}
|
||||
bool is_win = ArFormat == AR_COFF;
|
||||
std::vector<llvm::NewArchiveMember> new_members {};
|
||||
for (size_t i = 0; i < count; i++)
|
||||
}
|
||||
if (passes->sanitizer.thread_sanitize)
|
||||
{
|
||||
MPM.addPass(llvm::ModuleThreadSanitizerPass());
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(llvm::ThreadSanitizerPass()));
|
||||
}
|
||||
|
||||
if (passes->sanitizer.address_sanitize)
|
||||
{
|
||||
llvm::AddressSanitizerOptions Opts;
|
||||
bool use_globals_gc = false; // No need to add this yet.
|
||||
Opts.CompileKernel = passes->is_kernel;
|
||||
Opts.Recover = passes->sanitizer.recover;
|
||||
Opts.UseAfterScope = passes->sanitizer.asan_use_after_scope;
|
||||
Opts.UseAfterReturn = passes->sanitizer.asan_use_after_return
|
||||
? llvm::AsanDetectStackUseAfterReturnMode::Always
|
||||
: llvm::AsanDetectStackUseAfterReturnMode::Never;
|
||||
bool is_windows = Machine->getTargetTriple().isOSWindows();
|
||||
MPM.addPass(llvm::AddressSanitizerPass(Opts,
|
||||
use_globals_gc,
|
||||
!is_windows,
|
||||
passes->sanitizer.asan_use_global_dstor
|
||||
? llvm::AsanDtorKind::Global
|
||||
: llvm::AsanDtorKind::None));
|
||||
}
|
||||
if (passes->sanitizer.hwaddress_sanitize)
|
||||
{
|
||||
MPM.addPass(llvm::HWAddressSanitizerPass({
|
||||
passes->is_kernel,
|
||||
passes->sanitizer.recover,
|
||||
passes->opt_level == LLVM_O0
|
||||
}));
|
||||
}
|
||||
// MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles));
|
||||
|
||||
MPM.run(*Mod, MAM);
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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));
|
||||
// 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));
|
||||
}
|
||||
#if LLVM_VERSION_MAJOR > 17
|
||||
return !llvm::writeArchive(std::string(out_name), std::move(new_members), llvm::SymtabWritingMode::NormalSymtab, kind, true, false, nullptr);
|
||||
return !llvm::writeArchive(std::string(out_name), std::move(new_members), llvm::SymtabWritingMode::NormalSymtab, kind, true, false, nullptr);
|
||||
#else
|
||||
return !llvm::writeArchive(std::string(out_name), std::move(new_members), true, kind, true, false, nullptr);
|
||||
return !llvm::writeArchive(std::string(out_name), std::move(new_members), true, kind, true, false, nullptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int llvm_version_major = LLVM_VERSION_MAJOR;
|
||||
int llvm_version_major = LLVM_VERSION_MAJOR;
|
||||
|
||||
void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array)
|
||||
void LLVMSetTargetMachineUseInitArray(LLVMTargetMachineRef ref, bool use_init_array)
|
||||
{
|
||||
auto machine = reinterpret_cast<llvm::TargetMachine *>(ref);
|
||||
machine->Options.UseInitArray = use_init_array;
|
||||
}
|
||||
void LLVMSetDSOLocal(LLVMValueRef Global, bool value)
|
||||
{
|
||||
llvm::unwrap<llvm::GlobalValue>(Global)->setDSOLocal(value);
|
||||
}
|
||||
|
||||
void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option)
|
||||
{
|
||||
llvm::FastMathFlags math_flags {};
|
||||
switch (option)
|
||||
{
|
||||
auto machine = reinterpret_cast<llvm::TargetMachine *>(ref);
|
||||
machine->Options.UseInitArray = use_init_array;
|
||||
}
|
||||
void LLVMSetDSOLocal(LLVMValueRef Global, bool value)
|
||||
{
|
||||
llvm::unwrap<llvm::GlobalValue>(Global)->setDSOLocal(value);
|
||||
case RELAXED:
|
||||
math_flags.setAllowReassoc(true);
|
||||
math_flags.setAllowReciprocal(true);
|
||||
math_flags.setAllowContract(true);
|
||||
break;
|
||||
case FAST:
|
||||
math_flags.setFast(true);
|
||||
break;
|
||||
case STRICT:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
llvm::unwrap(Builder)->setFastMathFlags(math_flags);
|
||||
}
|
||||
|
||||
void LLVMBuilderSetFastMathFlags(LLVMBuilderRef Builder, FastMathOption option)
|
||||
{
|
||||
llvm::FastMathFlags math_flags {};
|
||||
switch (option)
|
||||
{
|
||||
case RELAXED:
|
||||
math_flags.setAllowReassoc(true);
|
||||
math_flags.setAllowReciprocal(true);
|
||||
math_flags.setAllowContract(true);
|
||||
break;
|
||||
case FAST:
|
||||
math_flags.setFast(true);
|
||||
break;
|
||||
case STRICT:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
llvm::unwrap(Builder)->setFastMathFlags(math_flags);
|
||||
}
|
||||
|
||||
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
|
||||
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()));
|
||||
}
|
||||
|
||||
bool llvm_link_elf(const char **args, int arg_count, const char** error_string)
|
||||
{
|
||||
@@ -261,5 +365,4 @@ bool llvm_link_mingw(const char **args, int arg_count, const char** error_string
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user