nativity/src/llvm/llvm.cpp
David Gonzalez Martin fff62dd396 Implement bitfield
2024-06-08 23:43:48 -06:00

1141 lines
46 KiB
C++

#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/FileSystem.h"
using namespace llvm;
using llvm::orc::ThreadSafeContext;
using llvm::orc::ThreadSafeModule;
extern "C" LLVMContext* NativityLLVMCreateContext()
{
auto* context = new LLVMContext();
return context;
}
extern "C" Module* NativityLLVMCreateModule(const char* name_ptr, size_t name_len, LLVMContext& context)
{
auto name = StringRef(name_ptr, name_len);
auto* module = new Module(name, context);
// module->addModuleFlag(Module::Max, "Dwarf Version", 5);
// module->addModuleFlag(Module::Warning, "Debug Info Version", 3);
// module->addModuleFlag(Module::Max, "frame-pointer", 2);
return module;
}
extern "C" IRBuilder<>* NativityLLVMCreateBuilder(LLVMContext& Context)
{
auto* builder = new IRBuilder<>(Context);
return builder;
}
extern "C" DIBuilder* NativityLLVMModuleCreateDebugInfoBuilder(Module& module)
{
DIBuilder* builder = new DIBuilder(module);
return builder;
}
extern "C" DIFile* NativityLLVMDebugInfoBuilderCreateFile(DIBuilder& builder, const char* filename_ptr, size_t filename_len, const char* directory_ptr, size_t directory_len)
{
auto filename = StringRef(filename_ptr, filename_len);
auto directory = StringRef(directory_ptr, directory_len);
auto* file = builder.createFile(filename, directory);
return file;
}
extern "C" DICompileUnit* NativityLLVMDebugInfoBuilderCreateCompileUnit(DIBuilder& builder, unsigned language, DIFile* file, const char* producer_ptr, size_t producer_len, bool is_optimized, const char* flags_ptr, size_t flags_len, unsigned runtime_version, const char* split_name_ptr, size_t split_name_len, DICompileUnit::DebugEmissionKind debug_emission_kind, uint64_t DWOId, bool split_debug_inlining, bool debug_info_for_profiling, DICompileUnit::DebugNameTableKind debug_name_table_kind, bool ranges_base_address, const char* sysroot_ptr, size_t sysroot_len, const char* sdk_ptr, size_t sdk_len)
{
auto producer = StringRef(producer_ptr, producer_len);
auto flags = StringRef(flags_ptr, flags_len);
auto split_name = StringRef(split_name_ptr, split_name_len);
auto sysroot = StringRef(sysroot_ptr, sysroot_len);
auto sdk = StringRef(sdk_ptr, sdk_len);
auto* compile_unit = builder.createCompileUnit(language, file, producer, is_optimized, flags, runtime_version, split_name, debug_emission_kind, DWOId, split_debug_inlining, debug_info_for_profiling, debug_name_table_kind, ranges_base_address, sysroot, sdk);
return compile_unit;
}
extern "C" DISubprogram* NativityLLVMDebugInfoBuilderCreateFunction(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, const char* linkage_name_ptr, size_t linkage_name_len, DIFile* file, unsigned line_number, DISubroutineType* type, unsigned scope_line, DINode::DIFlags flags, DISubprogram::DISPFlags subprogram_flags, DISubprogram* declaration)
{
auto name = StringRef(name_ptr, name_len);
auto linkage_name = StringRef(linkage_name_ptr, linkage_name_len);
DITemplateParameterArray template_parameters = nullptr;
DITypeArray thrown_types = nullptr;
DINodeArray annotations = nullptr;
StringRef target_function_name = "";
auto* function = builder.createFunction(scope, name, linkage_name, file, line_number, type, scope_line, flags, subprogram_flags, template_parameters, declaration, thrown_types, annotations, target_function_name);
return function;
}
extern "C" DISubroutineType* NativityLLVMDebugInfoBuilderCreateSubroutineType(DIBuilder& builder, DIType** parameter_types_ptr, size_t parameter_type_count, DINode::DIFlags flags, dwarf::CallingConvention calling_convention)
{
auto metadata_list = ArrayRef<Metadata*>(reinterpret_cast<Metadata**>( parameter_types_ptr), parameter_type_count);
auto parameter_types = builder.getOrCreateTypeArray(metadata_list);
auto* subroutine_type = builder.createSubroutineType(parameter_types, flags, calling_convention);
return subroutine_type;
}
extern "C" DILexicalBlock* NativityLLVMDebugInfoBuilderCreateLexicalBlock(DIBuilder& builder, DIScope* parent_scope, DIFile* parent_file, unsigned line, unsigned column)
{
assert(isa<DILocalScope>(parent_scope));
auto* block = builder.createLexicalBlock(parent_scope, parent_file, line, column);
return block;
}
extern "C" void NativityLLVMBuilderSetCurrentDebugLocation(IRBuilder<>& builder, LLVMContext& context, unsigned line, unsigned column, DIScope* scope, Function* function)
{
auto debug_location = DILocation::get(context, line, column, scope);
builder.SetCurrentDebugLocation(debug_location);
}
extern "C" void NativityLLVMBuilderClearCurrentDebugLocation(IRBuilder<>&builder)
{
builder.SetCurrentDebugLocation(DebugLoc());
}
extern "C" void NativityLLVMBuilderSetInstructionDebugLocation(IRBuilder<>& builder, Instruction* instruction)
{
builder.SetInstDebugLocation(instruction);
}
extern "C" DIExpression* NativityLLVMDebugInfoBuilderCreateExpression(DIBuilder& builder, uint64_t* address, size_t length)
{
auto expr = ArrayRef<uint64_t>(address, length);
auto* expression = builder.createExpression(expr);
return expression;
}
extern "C" DIGlobalVariableExpression* NativityLLVMDebugInfoBuilderCreateGlobalVariableExpression(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, const char* linkage_name_ptr, size_t linkage_name_len, DIFile* file, unsigned line_number, DIType* type, bool is_local_to_unit, bool is_defined, DIExpression* expression, MDNode* declaration, MDTuple* template_parameters, uint32_t alignment)
{
auto name = StringRef(name_ptr, name_len);
auto linkage_name = StringRef(linkage_name_ptr, linkage_name_len);
auto annotations = nullptr;
auto* global_variable = builder.createGlobalVariableExpression(scope, name, linkage_name, file, line_number, type, is_local_to_unit, is_defined, expression, declaration, template_parameters, alignment, annotations);
return global_variable;
}
extern "C" void NativityLLVMDebugInfoGlobalVariableAddDebugInfo(GlobalVariable& global_variable, DIGlobalVariableExpression* global_variable_expression)
{
global_variable.addDebugInfo(global_variable_expression);
}
extern "C" DILocalVariable* NativityLLVMDebugInfoBuilderCreateParameterVariable(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, unsigned argument_index, DIFile* file, unsigned line_number, DIType* type, bool always_preserve, DINode::DIFlags flags)
{
assert(isa<DILocalScope>(scope));
auto name = StringRef(name_ptr, name_len);
auto* parameter_variable = builder.createParameterVariable(scope, name, argument_index, file, line_number, type, always_preserve, flags);
return parameter_variable;
}
extern "C" DILocalVariable* NativityLLVMDebugInfoBuilderCreateAutoVariable(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, DIType* type, bool always_preserve, DINode::DIFlags flags, uint32_t alignment) // 0 means 1 << 0 (alignment of 1)
{
auto name = StringRef(name_ptr, name_len);
auto* auto_variable = builder.createAutoVariable(scope, name, file, line_number, type, always_preserve, flags, alignment);
return auto_variable;
}
extern "C" Instruction* NativityLLVMDebugInfoBuilderInsertDeclare(DIBuilder& builder, Value* pointer, DILocalVariable* local_variable, LLVMContext& context, unsigned line, unsigned column, DIScope* scope, BasicBlock* basic_block)
{
auto debug_location = DILocation::get(context, line, column, scope);
auto* expression = builder.createExpression();
auto* instruction = builder.insertDeclare(pointer, local_variable, expression, debug_location, basic_block);
return instruction;
}
extern "C" DIType* NativityLLVMDebugInfoBuilderCreateBasicType(DIBuilder& builder, const char* name_ptr, size_t name_len, uint64_t bit_count, unsigned dwarf_encoding, DINode::DIFlags flags)
{
auto name = StringRef(name_ptr, name_len);
auto* type = builder.createBasicType(name, bit_count, dwarf_encoding, flags);
return type;
}
extern "C" DIDerivedType* NativityLLVMDebugInfoBuilderCreatePointerType(DIBuilder& builder, DIType* element_type, uint64_t pointer_bit_count, uint32_t alignment, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
std::optional<unsigned> DWARFAddressSpace = std::nullopt;
DINodeArray annotations = nullptr;
auto* pointer_type = builder.createPointerType(element_type, pointer_bit_count, alignment, DWARFAddressSpace, name, annotations);
return pointer_type;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateStructType(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, uint64_t bit_count, uint32_t alignment, DINode::DIFlags flags, DIType* derived_from, DIType** element_type_ptr, size_t element_type_count)
{
auto name = StringRef(name_ptr, name_len);
auto type_array = ArrayRef<Metadata*>(reinterpret_cast<Metadata**>(element_type_ptr), element_type_count);
auto* struct_type = builder.createStructType(scope, name, file, line_number, bit_count, alignment, flags, derived_from, builder.getOrCreateArray(type_array));
return struct_type;
}
extern "C" void NativityLLVMDebugInfoBuilderCompositeTypeReplaceTypes(DIBuilder& builder, DICompositeType& type, DIType** element_type_ptr, size_t element_type_count)
{
auto type_array = ArrayRef<Metadata*>(reinterpret_cast<Metadata**>(element_type_ptr), element_type_count);
auto node_array = builder.getOrCreateArray(type_array);
type.replaceElements(node_array);
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateArrayType(DIBuilder& builder, uint64_t bit_size, uint32_t alignment, DIType* type, size_t element_count)
{
Metadata* subranges[1] = {
builder.getOrCreateSubrange(0, element_count),
};
DINodeArray subscripts = builder.getOrCreateArray(ArrayRef<Metadata*>(subranges, sizeof(subranges) / sizeof(subranges[0])));
auto* array_type = builder.createArrayType(bit_size, alignment, type, subscripts);
return array_type;
}
extern "C" DIEnumerator* NativityLLVMDebugInfoBuilderCreateEnumerator(DIBuilder& builder, const char* name_ptr, size_t name_len, uint64_t value, bool is_unsigned)
{
auto name = StringRef(name_ptr, name_len);
auto* enumerator = builder.createEnumerator(name, value, is_unsigned);
return enumerator;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateEnumerationType(DIBuilder& builder, DIScope* scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line, uint64_t bit_size, uint32_t alignment, DIEnumerator** enumerator_ptr, size_t enumerator_count, DIType* underlying_type)
{
auto name = StringRef(name_ptr, name_len);
DINodeArray enumerators = builder.getOrCreateArray(ArrayRef<Metadata*>(reinterpret_cast<Metadata**>(enumerator_ptr), enumerator_count));
auto* enumeration_type = builder.createEnumerationType(scope, name, file, line, bit_size, alignment, enumerators, underlying_type);
return enumeration_type;
}
extern "C" DICompositeType* NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType(DIBuilder& builder, unsigned tag, const char* name_ptr, size_t name_len, DIScope* scope, DIFile* file, unsigned line)
{
auto name = StringRef(name_ptr, name_len);
auto* composite_type = builder.createReplaceableCompositeType(tag, name, scope, file, line);
return composite_type;
}
extern "C" DIDerivedType* NativityLLVMDebugInfoBuilderCreateMemberType(DIBuilder& builder, DIScope *scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, uint64_t bit_size, uint32_t alignment, uint64_t bit_offset, DINode::DIFlags flags, DIType* type)
{
auto name = StringRef(name_ptr, name_len);
auto* member_type = builder.createMemberType(scope, name, file, line_number, bit_size, alignment, bit_offset, flags, type);
return member_type;
}
extern "C" DIDerivedType* NativityLLVMDebugInfoBuilderCreateBitfieldMemberType(DIBuilder& builder, DIScope *scope, const char* name_ptr, size_t name_len, DIFile* file, unsigned line_number, uint64_t bit_size, uint64_t bit_offset, uint64_t storage_bit_offset, DINode::DIFlags flags, DIType* type)
{
auto name = StringRef(name_ptr, name_len);
auto* member_type = builder.createBitFieldMemberType(scope, name, file, line_number, bit_size, bit_offset, storage_bit_offset, flags, type);
return member_type;
}
extern "C" bool NativityLLLVMDITypeIsResolved(DIType* type)
{
return type->isResolved();
}
extern "C" DISubprogram* NativityLLVMDebugInfoScopeToSubprogram(DIScope* scope)
{
auto* subprogram = dyn_cast<DISubprogram>(scope);
return subprogram;
}
extern "C" void NativityLLVMDebugInfoBuilderFinalizeSubprogram(DIBuilder& builder, DISubprogram* subprogram, const Function* function)
{
assert(subprogram->describes(function));
builder.finalizeSubprogram(subprogram);
}
extern "C" void NativityLLVMDebugInfoBuilderFinalize(DIBuilder& builder)
{
builder.finalize();
}
extern "C" DIFile* NativityLLVMDebugInfoSubprogramGetFile(DISubprogram& subprogram)
{
auto* file = subprogram.getFile();
return file;
}
extern "C" DIType* NativityLLVMDebugInfoSubprogramGetArgumentType(DISubprogram& subprogram, size_t argument_index)
{
auto* argument_type = subprogram.getType()->getTypeArray()[argument_index];
return argument_type;
}
extern "C" unsigned NativityLLVMArgumentGetIndex(Argument& argument)
{
unsigned argument_index = argument.getArgNo();
return argument_index;
}
extern "C" FunctionType* NativityLLVMGetFunctionType(Type* return_type, Type** type_ptr, size_t type_count, bool var_args)
{
auto types = ArrayRef<Type*>(type_ptr, type_count);
auto* function_type = FunctionType::get(return_type, types, var_args);
return function_type;
}
extern "C" IntegerType* NativityLLVMGetIntegerType(LLVMContext& context, unsigned bit_count)
{
auto integer_type = IntegerType::get(context, bit_count);
return integer_type;
}
extern "C" PointerType* NativityLLVMGetPointerType(LLVMContext& context, unsigned address_space)
{
auto pointer_type = PointerType::get(context, address_space);
return pointer_type;
}
extern "C" ArrayType* NativityLLVMGetArrayType(Type* element_type, uint64_t element_count)
{
auto* array_type = ArrayType::get(element_type, element_count);
return array_type;
}
extern "C" StructType* NativityLLVMGetStructType(LLVMContext& context, Type** type_ptr, size_t type_count, bool is_packed)
{
auto types = ArrayRef<Type*>(type_ptr, type_count);
auto* struct_type = StructType::get(context, types, is_packed);
return struct_type;
}
extern "C" StructType* NativityLLVMCreateStructType(LLVMContext& context, Type** type_ptr, size_t type_count, const char* name_pointer, size_t name_length, bool is_packed)
{
auto types = ArrayRef<Type*>(type_ptr, type_count);
auto name = StringRef(name_pointer, name_length);
auto* struct_type = StructType::create(context, types, name, is_packed);
return struct_type;
}
extern "C" LLVMContext* NativityLLVMTypeGetContext(Type& type)
{
auto& context = type.getContext();
return &context;
}
extern "C" Function* NativityLLVMModuleGetFunction(Module& module, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* function = module.getFunction(name);
return function;
}
extern "C" void NativityLLVMFunctionAddAttributeKey(Function& function, Attribute::AttrKind attribute)
{
static_assert(sizeof(Attribute) == sizeof(size_t));
function.addFnAttr(attribute);
}
extern "C" Function* NativityLLVModuleCreateFunction(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* function = Function::Create(function_type, linkage_type, address_space, name, module);
return function;
}
extern "C" BasicBlock* NativityLLVMCreateBasicBlock(LLVMContext& context, const char* name_ptr, size_t name_len, Function* parent, BasicBlock* insert_before)
{
auto name = StringRef(name_ptr, name_len);
auto* basic_block = BasicBlock::Create(context, name, parent, insert_before);
return basic_block;
}
extern "C" PHINode* NativityLLVMBuilderCreatePhi(IRBuilder<> builder, Type* type, unsigned reserved_value_count, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* phi = builder.CreatePHI(type, reserved_value_count, name);
return phi;
}
extern "C" void NativityLLVMPhiAddIncoming(PHINode& node, Value* value, BasicBlock* basic_block)
{
node.addIncoming(value, basic_block);
}
extern "C" void NativityLLVMBasicBlockRemoveFromParent(BasicBlock* basic_block)
{
basic_block->eraseFromParent();
}
extern "C" void NativityLLVMBuilderSetInsertPoint(IRBuilder<>& builder, BasicBlock* basic_block)
{
builder.SetInsertPoint(basic_block);
}
extern "C" void NativityLLVMValueSetName(Value* value, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
value->setName(name);
}
extern "C" Type* NativityLLVMValueGetType(Value* value)
{
auto* type = value->getType();
return type;
}
extern "C" LLVMContext* NativityLLVMValueGetContext(Value& value)
{
auto& context = value.getContext();
return &context;
}
extern "C" PoisonValue* NativityLLVMGetPoisonValue(Type* type)
{
auto* poison_value = PoisonValue::get(type);
return poison_value;
}
extern "C" void NativityLLVMFunctionGetArguments(Function& function, Argument** argument_ptr, size_t* argument_count)
{
auto actual_argument_count = function.arg_size();
assert(actual_argument_count <= *argument_count);
*argument_count = actual_argument_count;
size_t arg_i = 0;
for (auto& Arg : function.args()) {
argument_ptr[arg_i] = &Arg;
arg_i += 1;
}
}
extern "C" Argument* NativityLLVMFunctionGetArgument(Function& function, unsigned index)
{
auto* arg = function.getArg(index);
return arg;
}
extern "C" void NativityLLVMFunctionSetSubprogram(Function& function, DISubprogram* subprogram)
{
function.setSubprogram(subprogram);
}
extern "C" DISubprogram* NativityLLVMFunctionGetSubprogram(Function& function)
{
auto* subprogram = function.getSubprogram();
return subprogram;
}
extern "C" void NativityLLVMGlobalVariableSetInitializer(GlobalVariable& global_variable, Constant* constant_initializer)
{
global_variable.setInitializer(constant_initializer);
}
extern "C" Constant* NativityLLVMConstantStruct(StructType* struct_type, Constant** constant_ptr, size_t constant_count)
{
auto constants = ArrayRef<Constant*>(constant_ptr, constant_count);
auto* constant_struct = ConstantStruct::get(struct_type, constants);
return constant_struct;
}
extern "C" ConstantInt* NativityLLVMConstantToInt(Constant* constant)
{
auto* constant_int = dyn_cast<ConstantInt>(constant);
return constant_int;
}
extern "C" StoreInst* NativityLLVMBuilderCreateStore(IRBuilder<>& builder, Value* value, Value* pointer, bool is_volatile, uint32_t alignment)
{
auto align = Align{alignment};
auto* basic_block = builder.GetInsertBlock();
auto* store = new StoreInst(value, pointer, is_volatile, align,
AtomicOrdering::NotAtomic, SyncScope::System, basic_block);
return store;
}
extern "C" AllocaInst* NativityLLVMBuilderCreateAlloca(IRBuilder<>& builder, Type* type, unsigned address_space, Value* array_size, const char* name_ptr, size_t name_len, uint32_t alignment)
{
auto name = StringRef(name_ptr, name_len);
auto align = Align{ alignment };
BasicBlock* insert_block = builder.GetInsertBlock();
AllocaInst* alloca = new AllocaInst(type, address_space, array_size, align, name, insert_block);
return alloca;
}
extern "C" Type* NativityLLVMGetVoidType(LLVMContext& context)
{
auto* void_type = Type::getVoidTy(context);
return void_type;
}
extern "C" Value* NativityLLVMBuilderCreateICmp(IRBuilder<>& builder, CmpInst::Predicate comparation, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* icmp = builder.CreateICmp(comparation, left, right, name);
return icmp;
}
extern "C" Value* NativityLLVMBuilderCreateIsNotNull(IRBuilder<>& builder, Value* value, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* not_null = builder.CreateIsNotNull(value, name);
return not_null;
}
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* pointer, bool is_volatile, const char* name_ptr, size_t name_len, uint32_t alignment)
{
auto align = Align{alignment};
auto name = StringRef(name_ptr, name_len);
auto* basic_block = builder.GetInsertBlock();
auto* load = new LoadInst(type, pointer, name, is_volatile,
align, AtomicOrdering::NotAtomic, SyncScope::System, basic_block);
return load;
}
extern "C" ReturnInst* NativityLLVMBuilderCreateRet(IRBuilder<>& builder, Value* value)
{
auto* ret = builder.CreateRet(value);
return ret;
}
extern "C" InlineAsm* NativityLLVMGetInlineAssembly(FunctionType* function_type, const char* assembly_ptr, size_t assembly_len, const char* constraints_ptr, size_t constrains_len, bool has_side_effects, bool is_align_stack, InlineAsm::AsmDialect dialect, bool can_throw)
{
auto assembly = StringRef(assembly_ptr, assembly_len);
auto constraints = StringRef(constraints_ptr, constrains_len);
auto* inline_asm = InlineAsm::get(function_type, assembly, constraints, has_side_effects, is_align_stack, dialect, can_throw);
return inline_asm;
}
extern "C" Value* NativityLLVMBuilderCreateCast(IRBuilder<>& builder, Instruction::CastOps cast_type, Value* value, Type* type, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* cast = builder.CreateCast(cast_type, value, type, name);
return cast;
}
extern "C" CallInst* NativityLLVMBuilderCreateCall(IRBuilder<>& builder, FunctionType* function_type, Value* callee, Value** argument_ptr, size_t argument_count, const char* name_ptr, size_t name_len, MDNode* fp_math_tag)
{
auto arguments = ArrayRef<Value*>(argument_ptr, argument_count);
auto name = StringRef(name_ptr, name_len);
auto* call = builder.CreateCall(function_type, callee, arguments, name, fp_math_tag);
return call;
}
extern "C" UnreachableInst* NativityLLVMBuilderCreateUnreachable(IRBuilder<>& builder)
{
auto* unreachable = builder.CreateUnreachable();
return unreachable;
}
extern "C" GlobalVariable* NativityLLVMModuleAddGlobalVariable(Module& module, Type* type, bool is_constant, GlobalValue::LinkageTypes linkage_type, Constant* initializer, const char* name_ptr, size_t name_len, GlobalVariable* insert_before, GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized)
{
auto name = StringRef(name_ptr, name_len);
auto* global_variable = new GlobalVariable(module, type, is_constant, linkage_type, initializer, name, insert_before, thread_local_mode, address_space, externally_initialized);
return global_variable;
}
extern "C" Value* NativityLLVMBuilderCreateAdd(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* add = builder.CreateAdd(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return add;
}
extern "C" Value* NativityLLVMBuilderCreateSub(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* add = builder.CreateSub(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return add;
}
extern "C" Value* NativityLLVMBuilderCreateMultiply(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* multiply = builder.CreateMul(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return multiply;
}
extern "C" Value* NativityLLVMBuilderCreateUDiv(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateUDiv(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateSDiv(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateSDiv(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateURem(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateURem(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateSRem(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateSRem(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateXor(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateXor(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateAnd(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateAnd(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateOr(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateOr(left, right, name);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateShiftLeft(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool no_unsigned_wrapping, bool no_signed_wrapping)
{
auto name = StringRef(name_ptr, name_len);
auto* shl = builder.CreateShl(left, right, name, no_unsigned_wrapping, no_signed_wrapping);
return shl;
}
extern "C" Value* NativityLLVMBuilderCreateLogicalShiftRight(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateLShr(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateArithmeticShiftRight(IRBuilder<>& builder, Value* left, Value* right, const char* name_ptr, size_t name_len, bool is_exact)
{
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateAShr(left, right, name, is_exact);
return result;
}
extern "C" Value* NativityLLVMBuilderCreateGEP(IRBuilder<>& builder, Type* type, Value* pointer, Value** index_ptr, size_t index_count, const char* name_ptr, size_t name_len, bool in_bounds)
{
auto index_list = ArrayRef<Value*>(index_ptr, index_count);
auto name = StringRef(name_ptr, name_len);
auto* GEP = builder.CreateGEP(type, pointer, index_list, name, in_bounds);
return GEP;
}
extern "C" BranchInst* NativityLLVMBuilderCreateBranch(IRBuilder<>& builder, BasicBlock* basic_block)
{
auto* conditional_branch = builder.CreateBr(basic_block);
return conditional_branch;
}
extern "C" BranchInst* NativityLLVMBuilderCreateConditionalBranch(IRBuilder<>& builder, Value* condition, BasicBlock* true_block, BasicBlock* false_block, MDNode* branch_weights, MDNode* unpredictable)
{
auto* conditional_branch = builder.CreateCondBr(condition, true_block, false_block, branch_weights, unpredictable);
return conditional_branch;
}
extern "C" SwitchInst* NativityLLVMBuilderCreateSwitch(IRBuilder<> builder, Value* condition, BasicBlock* default_block, ConstantInt** case_ptr, BasicBlock** case_block_ptr, unsigned case_count, MDNode* branch_weights, MDNode* unpredictable)
{
auto switch_instruction = builder.CreateSwitch(condition, default_block, case_count, branch_weights, unpredictable);
for (unsigned i = 0; i < case_count; i += 1) {
ConstantInt* switch_case = case_ptr[i];
BasicBlock* case_block = case_block_ptr[i];
switch_instruction->addCase(switch_case, case_block);
}
return switch_instruction;
}
extern "C" Intrinsic::ID NativityLLVMLookupIntrinsic(const char* name_ptr, size_t name_len)
{
auto name = StringRef(name_ptr, name_len);
Intrinsic::ID id = Function::lookupIntrinsicID(name);
return id;
}
extern "C" Function* NativityLLVMModuleGetIntrinsicDeclaration(Module* module, Intrinsic::ID intrinsic_id, Type** parameter_types_ptr, size_t parameter_type_count)
{
auto parameter_types = ArrayRef<Type*>(parameter_types_ptr, parameter_type_count);
assert(intrinsic_id < Intrinsic::num_intrinsics);
Function* function = Intrinsic::getDeclaration(module, intrinsic_id, parameter_types);
return function;
}
extern "C" FunctionType* NativityLLVMFunctionGetType(Function& function)
{
auto* function_type = function.getFunctionType();
return function_type;
}
extern "C" Type* NativityLLVMFunctionTypeGetReturnType(FunctionType& function_type)
{
auto* return_type = function_type.getReturnType();
return return_type;
}
extern "C" bool NativityLLVMTypeIsVoid(Type& type)
{
bool is_void_type = type.isVoidTy();
return is_void_type;
}
extern "C" Value* NativityLLVMBuilderCreateExtractValue(IRBuilder<>& builder, Value* aggregate, unsigned* indices_ptr, size_t indices_len, const char* name_ptr, size_t name_len)
{
auto indices = ArrayRef<unsigned>(indices_ptr, indices_len);
auto name = StringRef(name_ptr, name_len);
auto* value = builder.CreateExtractValue(aggregate, indices, name);
return value;
}
extern "C" Value* NativityLLVMBuilderCreateInsertValue(IRBuilder<>& builder, Value* aggregate, Value* value, unsigned* indices_ptr, size_t indices_len, const char* name_ptr, size_t name_len)
{
auto indices = ArrayRef<unsigned>(indices_ptr, indices_len);
auto name = StringRef(name_ptr, name_len);
auto* result = builder.CreateInsertValue(aggregate, value, indices, name);
return result;
}
extern "C" ConstantInt* NativityLLVMContextGetConstantInt(LLVMContext& context, unsigned bit_count, uint64_t value, bool is_signed)
{
auto int_type = APInt(bit_count, value, is_signed);
auto constant_int = ConstantInt::get(context, int_type);
return constant_int;
}
extern "C" Constant* NativityLLVMContextGetConstantString(LLVMContext& context, const char* string_ptr, size_t string_len, bool null_terminate)
{
auto string = StringRef(string_ptr, string_len);
auto* constant = ConstantDataArray::getString(context, string, null_terminate);
return constant;
}
extern "C" Constant* NativityLLVMGetConstantArray(ArrayType* array_type, Constant** value_ptr, size_t value_count)
{
auto values = ArrayRef<Constant*>(value_ptr, value_count);
auto* constant_array = ConstantArray::get(array_type, values);
return constant_array;
}
extern "C" Constant* NativityLLVMGetConstantStruct(StructType* struct_type, Constant** constant_ptr, size_t constant_len)
{
auto values = ArrayRef<Constant*>(constant_ptr, constant_len);
auto* constant_struct = ConstantStruct::get(struct_type, values);
return constant_struct;
}
extern "C" GlobalVariable* NativityLLVMBuilderCreateGlobalString(IRBuilder<>& builder, const char* string_ptr, size_t string_len, const char* name_ptr, size_t name_len, unsigned address_space, Module* module)
{
auto string = StringRef(string_ptr, string_len);
auto name = StringRef(name_ptr, name_len);
auto* string_global_variable = builder.CreateGlobalString(string, name, address_space, module);
return string_global_variable;
}
extern "C" Constant* NativityLLVMBuilderCreateGlobalStringPointer(IRBuilder<>& builder, const char* string_ptr, size_t string_len, const char* name_ptr, size_t name_len, unsigned address_space, Module* module)
{
auto string = StringRef(string_ptr, string_len);
auto name = StringRef(name_ptr, name_len);
Constant* constant = builder.CreateGlobalStringPtr(string, name, address_space, module);
return constant;
}
extern "C" void stream_to_string(raw_string_ostream& stream, const char** message_ptr, size_t* message_len)
{
stream.flush();
auto string = stream.str();
char* result = new char[string.length()];
memcpy(result, string.c_str(), string.length());
*message_ptr = result;
*message_len = string.length();
}
extern "C" bool NativityLLVMVerifyFunction(Function& function, const char** message_ptr, size_t* message_len)
{
std::string message_buffer;
raw_string_ostream message_stream(message_buffer);
bool result = verifyFunction(function, &message_stream);
auto size = message_stream.str().size();
stream_to_string(message_stream, message_ptr, message_len);
// We invert the condition because LLVM conventions are just stupid
return !result;
}
extern "C" bool NativityLLVMVerifyModule(const Module& module, const char** message_ptr, size_t* message_len)
{
std::string message_buffer;
raw_string_ostream message_stream(message_buffer);
bool result = verifyModule(module, &message_stream);
stream_to_string(message_stream, message_ptr, message_len);
// We invert the condition because LLVM conventions are just stupid
return !result;
}
extern "C" void NativityLLVMFunctionToString(const Function& function, const char** ptr, size_t* len)
{
std::string buf;
raw_string_ostream os(buf);
function.print(os);
os.flush();
*len = buf.size();
*ptr = strdup(buf.c_str());
}
extern "C" Type* NativityLLVMAllocatGetAllocatedType(AllocaInst& alloca)
{
auto* type = alloca.getAllocatedType();
return type;
}
extern "C" AllocaInst* NativityLLVMValueToAlloca(Value* value)
{
assert(value);
auto* alloca = dyn_cast<AllocaInst>(value);
return alloca;
}
extern "C" Constant* NativityLLVMValueToConstant(Value* value)
{
assert(value);
auto* constant = dyn_cast<Constant>(value);
return constant;
}
extern "C" Function* NativityLLVMValueToFunction(Value* value)
{
assert(value);
auto* function = dyn_cast<Function>(value);
return function;
}
extern "C" BasicBlock* NativityLLVMValueToBasicBlock(Value* value)
{
auto* basic_block = dyn_cast<BasicBlock>(value);
return basic_block;
}
extern "C" bool NativityLLVMTypeIsPointer(Type* type)
{
bool is_pointer = type->isPointerTy();
return is_pointer;
}
extern "C" bool NativityLLVMTypeIsInteger(Type* type)
{
bool is_integer = type->isIntegerTy();
return is_integer;
}
extern "C" StructType* NativityLLVMTypeToStruct(Type* type)
{
auto* struct_type = dyn_cast<StructType>(type);
return struct_type;
}
extern "C" FunctionType* NativityLLVMTypeToFunction(Type* type)
{
auto* function_type = dyn_cast<FunctionType>(type);
return function_type;
}
extern "C" Type* NativityLLVMFunctionTypeGetArgumentType(FunctionType& function_type, unsigned argument_index)
{
auto* type = function_type.getParamType(argument_index);
return type;
}
extern "C" ArrayType* NativityLLVMTypeToArray(Type* type)
{
auto* array_type = dyn_cast<ArrayType>(type);
return array_type;
}
extern "C" PointerType* NativityLLVMTypeToPointer(Type* type)
{
auto* pointer_type = dyn_cast<PointerType>(type);
return pointer_type;
}
extern "C" ConstantPointerNull* NativityLLVMPointerTypeGetNull(PointerType* pointer_type)
{
auto* constant_pointer_null = ConstantPointerNull::get(pointer_type);
return constant_pointer_null;
}
extern "C" Type* NativityLLVMArrayTypeGetElementType(ArrayType* array_type)
{
auto* element_type = array_type->getElementType();
return element_type;
}
extern "C" void NativityLLVMModuleToString(const Module& module, const char** ptr, size_t* len)
{
std::string buf;
raw_string_ostream os(buf);
module.print(os, nullptr);
os.flush();
*len = buf.size();
*ptr = strdup(buf.c_str());
}
extern "C" void NativityLLVMValueToString(const Value& value, const char** ptr, size_t* len)
{
std::string buf;
raw_string_ostream os(buf);
value.print(os, true);
os.flush();
*len = buf.size();
*ptr = strdup(buf.c_str());
}
extern "C" BasicBlock* NativityLLVMBuilderGetInsertBlock(IRBuilder<>& builder)
{
return builder.GetInsertBlock();
}
extern "C" bool NativityLLVMBuilderIsCurrentBlockTerminated(IRBuilder<>& builder)
{
return builder.GetInsertBlock()->getTerminator() != nullptr;
}
extern "C" UndefValue* NativityLLVMGetUndefined(Type* type)
{
auto* undefined_value = UndefValue::get(type);
return undefined_value;
}
extern "C" void NativityLLVMFunctionSetCallingConvention(Function& function, CallingConv::ID calling_convention)
{
function.setCallingConv(calling_convention);
}
extern "C" CallingConv::ID NativityLLVMFunctionGetCallingConvention(Function& function)
{
auto calling_convention = function.getCallingConv();
return calling_convention;
}
extern "C" void NativityLLVMCallSetCallingConvention(CallBase& call_instruction, CallingConv::ID calling_convention)
{
call_instruction.setCallingConv(calling_convention);
}
extern "C" void NativityLLVMInitializeCodeGeneration()
{
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
InitializeAllAsmPrinters();
}
extern "C" const Target* NativityLLVMGetTarget(const char* target_triple_ptr, size_t target_triple_len, const char** message_ptr, size_t* message_len)
{
auto target_triple = StringRef(target_triple_ptr, target_triple_len);
std::string error_message;
const Target* target = TargetRegistry::lookupTarget(target_triple, error_message);
if (!target)
{
char* result = new char[error_message.length()];
memcpy(result, error_message.c_str(), error_message.length());
*message_ptr = result;
*message_len = error_message.length();
}
return target;
}
extern "C" TargetMachine* NativityLLVMTargetCreateTargetMachine(Target& target, const char* target_triple_ptr, size_t target_triple_len, const char* cpu_ptr, size_t cpu_len, const char* features_ptr, size_t features_len, Reloc::Model relocation_model, CodeModel::Model maybe_code_model, bool is_code_model_present, CodeGenOptLevel optimization_level, bool jit)
{
auto target_triple = StringRef(target_triple_ptr, target_triple_len);
auto cpu = StringRef(cpu_ptr, cpu_len);
auto features = StringRef(features_ptr, features_len);
TargetOptions target_options;
std::optional<CodeModel::Model> code_model = std::nullopt;
if (is_code_model_present) {
code_model = maybe_code_model;
}
TargetMachine* target_machine = target.createTargetMachine(target_triple, cpu, features, target_options, relocation_model, code_model, optimization_level, jit);
return target_machine;
}
extern "C" void NativityLLVMModuleSetTargetMachineDataLayout(Module& module, TargetMachine& target_machine)
{
module.setDataLayout(target_machine.createDataLayout());
}
extern "C" void NativityLLVMModuleSetTargetTriple(Module& module, const char* target_triple_ptr, size_t target_triple_len)
{
auto target_triple = StringRef(target_triple_ptr, target_triple_len);
module.setTargetTriple(target_triple);
}
extern "C" void NativityLLVMRunOptimizationPipeline(Module& module, TargetMachine& target_machine, OptimizationLevel optimization_level)
{
// TODO: PGO
// TODO: CS profile
bool loop_optimizations = !optimization_level.isOptimizingForSize() && optimization_level.getSpeedupLevel() >= 2;
llvm::PipelineTuningOptions pipeline_tuning_options;
pipeline_tuning_options.LoopUnrolling = loop_optimizations;
pipeline_tuning_options.LoopInterleaving = loop_optimizations;
pipeline_tuning_options.LoopVectorization = loop_optimizations;
pipeline_tuning_options.SLPVectorization = loop_optimizations;
pipeline_tuning_options.MergeFunctions = true;
pipeline_tuning_options.CallGraphProfile = false;
pipeline_tuning_options.UnifiedLTO = false;
// TODO: instrumentation
LoopAnalysisManager loop_analysis_manager;
FunctionAnalysisManager function_analysis_manager;
CGSCCAnalysisManager cgscc_analysis_manager;
ModuleAnalysisManager module_analysis_manager;
PassBuilder pass_builder(&target_machine, pipeline_tuning_options);
// TODO: assignment tracking
// TODO: debug info preserve
// TODO: plugins?
// TODO: target library analysis
pass_builder.registerModuleAnalyses(module_analysis_manager);
pass_builder.registerCGSCCAnalyses(cgscc_analysis_manager);
pass_builder.registerFunctionAnalyses(function_analysis_manager);
pass_builder.registerLoopAnalyses(loop_analysis_manager);
pass_builder.crossRegisterProxies(loop_analysis_manager, function_analysis_manager, cgscc_analysis_manager, module_analysis_manager);
ModulePassManager module_pass_manager;
bool thin_lto = false;
bool lto = false;
// TODO: thin lto post-link
// TODO: instrument
if (thin_lto) {
// TODO
} else if (lto) {
// TODO
} else {
module_pass_manager = pass_builder.buildPerModuleDefaultPipeline(optimization_level, lto);
}
// TODO: if emit bitcode/IR
module_pass_manager.run(module, module_analysis_manager);
}
extern "C" bool NativityLLVMModuleAddPassesToEmitFile(Module& module, TargetMachine& target_machine, const char* object_file_path_ptr, size_t object_file_path_len, CodeGenFileType codegen_file_type, bool disable_verify)
{
std::error_code error_code;
auto object_file_path = StringRef(object_file_path_ptr, object_file_path_len);
raw_fd_ostream stream(object_file_path, error_code, sys::fs::OF_None);
if (error_code) {
return false;
}
legacy::PassManager pass;
// We invert the condition because LLVM conventions are just stupid
if (target_machine.addPassesToEmitFile(pass, stream, nullptr, codegen_file_type, disable_verify)) {
return false;
}
pass.run(module);
stream.flush();
return true;
}
extern "C" Attribute NativityLLVMContextGetAttributeFromEnum(LLVMContext& context, Attribute::AttrKind kind, uint64_t value)
{
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
auto attribute = Attribute::get(context, kind, value);
return attribute;
}
extern "C" Attribute NativityLLVMContextGetAttributeFromType(LLVMContext& context, Attribute::AttrKind kind, Type* type)
{
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
auto attribute = Attribute::get(context, kind, type);
return attribute;
}
extern "C" Attribute NativityLLVMContextGetAttributeFromString(LLVMContext& context, const char* kind_ptr, size_t kind_len, const char* value_ptr, size_t value_len)
{
static_assert(sizeof(Attribute) == sizeof(uintptr_t));
auto kind = StringRef(kind_ptr, kind_len);
auto value = StringRef(value_ptr, value_len);
auto attribute = Attribute::get(context, kind, value);
return attribute;
}
extern "C" AttributeSet NativityLLVMContextGetAttributeSet(LLVMContext& context, const Attribute* attribute_ptr, size_t attribute_count)
{
static_assert(sizeof(AttributeSet) == sizeof(uintptr_t));
auto attributes = ArrayRef<Attribute>(attribute_ptr, attribute_count);
auto attribute_set = AttributeSet::get(context, attributes);
return attribute_set;
}
extern "C" void NativityLLVMFunctionSetAttributes(Function& function, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count)
{
auto parameter_attribute_sets = ArrayRef<AttributeSet>(parameter_attribute_set_ptr, parameter_attribute_set_count);
auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets);
function.setAttributes(attribute_list);
}
extern "C" void NativityLLVMCallSetAttributes(CallInst& call, LLVMContext& context, AttributeSet function_attributes, AttributeSet return_attributes, const AttributeSet* parameter_attribute_set_ptr, size_t parameter_attribute_set_count)
{
auto parameter_attribute_sets = ArrayRef<AttributeSet>(parameter_attribute_set_ptr, parameter_attribute_set_count);
auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, parameter_attribute_sets);
call.setAttributes(attribute_list);
}
extern "C" void NativityLLVMGlobalObjectSetAlignment(GlobalObject& global_object, uint32_t alignment)
{
Align align(alignment);
global_object.setAlignment(align);
}
extern "C" CallInst* NativityLLVMBuilderCreateMemcpy(IRBuilder<>& builder, Value* destination, uint32_t destination_alignment, Value* source, uint32_t source_alignment, uint64_t size, bool is_volatile)
{
auto dst_alignment = MaybeAlign(destination_alignment);
auto src_alignment = MaybeAlign(source_alignment);
auto memcpy = builder.CreateMemCpy(destination, dst_alignment, source, src_alignment, size, is_volatile);
return memcpy;
}
extern "C" bool NativityLLVMLinkModules(Module& destination, Module* source)
{
auto src = std::unique_ptr<Module>(source);
bool result = Linker::linkModules(destination, std::move(src));
// Invert the condition because LLVM boolean concept is lame
return !result;
}
extern "C" void NativityLLVMTypeAssertEqual(Type* a, Type* b)
{
assert(a == b);
}