Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spec/std/llvm/aarch64_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private def abi
triple = "aarch64-unknown-linux-gnu"
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
machine.enable_global_isel = false
LLVM::ABI::AArch64.new(machine)
end

Expand Down
1 change: 1 addition & 0 deletions spec/std/llvm/arm_abi_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private def abi
triple = "arm-unknown-linux-gnueabihf"
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
machine.enable_global_isel = false
LLVM::ABI::ARM.new(machine)
end

Expand Down
1 change: 1 addition & 0 deletions spec/std/llvm/x86_64_abi_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private def abi
triple = LLVM.default_target_triple.gsub(/^(.+?)-/, "x86_64-")
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
machine.enable_global_isel = false
LLVM::ABI::X86_64.new(machine)
end

Expand Down
1 change: 1 addition & 0 deletions spec/std/llvm/x86_abi_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ private def abi
{% end %}
target = LLVM::Target.from_triple(triple)
machine = target.create_target_machine(triple)
machine.enable_global_isel = false
LLVM::ABI::X86.new(machine)
end

Expand Down
9 changes: 8 additions & 1 deletion src/compiler/crystal/codegen/target.cr
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,14 @@ class Crystal::Codegen::Target
opt_level = release ? LLVM::CodeGenOptLevel::Aggressive : LLVM::CodeGenOptLevel::None

target = LLVM::Target.from_triple(self.to_s)
target.create_target_machine(self.to_s, cpu: cpu, features: features, opt_level: opt_level, code_model: code_model).not_nil!
machine = target.create_target_machine(self.to_s, cpu: cpu, features: features, opt_level: opt_level, code_model: code_model).not_nil!
# We need to disable global isel until https://reviews.llvm.org/D80898 is released,
# or we fixed generating values for 0 sized types.
# When removing this, also remove it from the ABI specs and jit compiler.
# See https://github.com/crystal-lang/crystal/issues/9297#issuecomment-636512270
# for background info
machine.enable_global_isel = false
machine
end

def to_s(io : IO) : Nil
Expand Down
84 changes: 82 additions & 2 deletions src/llvm/ext/llvm_ext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/ADT/Triple.h>
#include <llvm-c/TargetMachine.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
#include <llvm/Target/CodeGenCWrappers.h>

using namespace llvm;

Expand Down Expand Up @@ -475,10 +481,84 @@ char *LLVMExtBasicBlockName(LLVMBasicBlockRef BB) {
#endif
}

static TargetMachine *unwrap(LLVMTargetMachineRef P) {
return reinterpret_cast<TargetMachine *>(P);
}

void LLVMExtTargetMachineEnableGlobalIsel(LLVMTargetMachineRef T, LLVMBool Enable) {
unwrap(T)->setGlobalISel(Enable);
}

// Copy paste of https://github.com/llvm/llvm-project/blob/dace8224f38a31636a02fe9c2af742222831f70c/llvm/lib/ExecutionEngine/ExecutionEngineBindings.cpp#L160-L214
// but with a parameter to set global isel state
LLVMBool LLVMExtCreateMCJITCompilerForModule(
LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M,
LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions,
LLVMBool EnableGlobalISel,
char **OutError) {
LLVMMCJITCompilerOptions options;
// If the user passed a larger sized options struct, then they were compiled
// against a newer LLVM. Tell them that something is wrong.
if (SizeOfPassedOptions > sizeof(options)) {
*OutError = strdup(
"Refusing to use options struct that is larger than my own; assuming "
"LLVM library mismatch.");
return 1;
}


// Defend against the user having an old version of the API by ensuring that
// any fields they didn't see are cleared. We must defend against fields being
// set to the bitwise equivalent of zero, and assume that this means "do the
// default" as if that option hadn't been available.
LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
memcpy(&options, PassedOptions, SizeOfPassedOptions);


TargetOptions targetOptions;
targetOptions.EnableFastISel = options.EnableFastISel;
targetOptions.EnableGlobalISel = EnableGlobalISel;
std::unique_ptr<Module> Mod(unwrap(M));

if (Mod)
// Set function attribute "frame-pointer" based on
// NoFramePointerElim.
for (auto &F : *Mod) {
auto Attrs = F.getAttributes();
StringRef Value = options.NoFramePointerElim ? "all" : "none";
Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex,
"frame-pointer", Value);
F.setAttributes(Attrs);
}


std::string Error;
EngineBuilder builder(std::move(Mod));
builder.setEngineKind(EngineKind::JIT)
.setErrorStr(&Error)
.setOptLevel((CodeGenOpt::Level)options.OptLevel)
.setTargetOptions(targetOptions);
bool JIT;
if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT))
builder.setCodeModel(*CM);
if (options.MCJMM)
builder.setMCJITMemoryManager(
std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM)));

TargetMachine* tm = builder.selectTarget();
tm->setGlobalISel(EnableGlobalISel);

if (ExecutionEngine *JIT = builder.create(tm)) {
*OutJIT = wrap(JIT);
return 0;
}
*OutError = strdup(Error.c_str());
return 1;
}

LLVMMetadataRef LLVMExtDIBuilderGetOrCreateArraySubrange(
DIBuilderRef Dref, uint64_t Lo,
uint64_t Count) {
return wrap(Dref->getOrCreateSubrange(Lo, Count));
}

}
}
2 changes: 1 addition & 1 deletion src/llvm/jit_compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class LLVM::JITCompiler
mod.take_ownership { raise "Can't create two JIT compilers for the same module" }

# if LibLLVM.create_jit_compiler_for_module(out @unwrap, mod, 3, out error) != 0
if LibLLVM.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0, out error) != 0
if LibLLVMExt.create_mc_jit_compiler_for_module(out @unwrap, mod, nil, 0, false, out error) != 0
raise LLVM.string_and_dispose(error)
end

Expand Down
3 changes: 3 additions & 0 deletions src/llvm/lib_llvm_ext.cr
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,7 @@ lib LibLLVMExt
fun normalize_target_triple = LLVMExtNormalizeTargetTriple(triple : Char*) : Char*
fun basic_block_name = LLVMExtBasicBlockName(basic_block : LibLLVM::BasicBlockRef) : Char*
fun di_builder_get_or_create_array_subrange = LLVMExtDIBuilderGetOrCreateArraySubrange(builder : DIBuilder, lo : UInt64, count : UInt64) : Metadata

fun target_machine_enable_global_isel = LLVMExtTargetMachineEnableGlobalIsel(machine : LibLLVM::TargetMachineRef, enable : Bool)
fun create_mc_jit_compiler_for_module = LLVMExtCreateMCJITCompilerForModule(jit : LibLLVM::ExecutionEngineRef*, m : LibLLVM::ModuleRef, options : LibLLVM::JITCompilerOptions*, options_length : UInt32, enable_global_isel : Bool, error : UInt8**) : Int32
end
4 changes: 4 additions & 0 deletions src/llvm/target_machine.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class LLVM::TargetMachine
emit_to_file llvm_mod, filename, LLVM::CodeGenFileType::AssemblyFile
end

def enable_global_isel=(enable : Bool)
LibLLVMExt.target_machine_enable_global_isel(self, enable)
end

private def emit_to_file(llvm_mod, filename, type)
status = LibLLVM.target_machine_emit_to_file(self, llvm_mod, filename, type, out error_msg)
unless status == 0
Expand Down