wip
This commit is contained in:
parent
c07849aa79
commit
9dec8231c6
268
src/compiler.h
268
src/compiler.h
@ -1,6 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <lib.h>
|
||||
namespace llvm
|
||||
{
|
||||
class Type;
|
||||
class Value;
|
||||
class Module;
|
||||
class Builder;
|
||||
class LLVMContext;
|
||||
class Function;
|
||||
class FunctionType;
|
||||
|
||||
class DIBuilder;
|
||||
class DICompileUnit;
|
||||
class DIFile;
|
||||
class DIScope;
|
||||
class DIType;
|
||||
class DISubroutineType;
|
||||
}
|
||||
|
||||
#define report_error() trap_raw()
|
||||
|
||||
@ -38,6 +55,23 @@ fn String build_mode_to_string(BuildMode build_mode)
|
||||
}
|
||||
}
|
||||
|
||||
fn bool build_mode_is_optimized(BuildMode build_mode)
|
||||
{
|
||||
switch (build_mode)
|
||||
{
|
||||
case BuildMode::debug_none:
|
||||
case BuildMode::debug:
|
||||
return false;
|
||||
case BuildMode::soft_optimize:
|
||||
case BuildMode::optimize_for_speed:
|
||||
case BuildMode::optimize_for_size:
|
||||
case BuildMode::aggressively_optimize_for_speed:
|
||||
case BuildMode::aggressively_optimize_for_size:
|
||||
return true;
|
||||
case BuildMode::count: unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
enum class ValueKind
|
||||
{
|
||||
right,
|
||||
@ -65,6 +99,165 @@ struct Argument;
|
||||
struct Scope;
|
||||
struct MacroDeclaration;
|
||||
|
||||
struct DirectAttributes
|
||||
{
|
||||
u32 offset;
|
||||
u32 alignment;
|
||||
};
|
||||
|
||||
struct IndirectAttributes
|
||||
{
|
||||
u32 alignment;
|
||||
u32 address_space;
|
||||
};
|
||||
|
||||
enum class AbiKind : u8
|
||||
{
|
||||
ignore,
|
||||
direct,
|
||||
extend,
|
||||
indirect,
|
||||
indirect_aliased,
|
||||
expand,
|
||||
coerce_and_expand,
|
||||
in_alloca,
|
||||
};
|
||||
|
||||
struct AbiFlags
|
||||
{
|
||||
AbiKind kind;
|
||||
bool padding_in_reg;
|
||||
bool in_alloca_sret;
|
||||
bool in_alloca_indirect;
|
||||
bool indirect_by_value;
|
||||
bool indirect_realign;
|
||||
bool sret_after_this;
|
||||
bool in_reg;
|
||||
bool can_be_flattened;
|
||||
bool sign_extension;
|
||||
};
|
||||
|
||||
struct AbiInformation
|
||||
{
|
||||
Type* semantic_type;
|
||||
Type* coerce_to_type;
|
||||
union
|
||||
{
|
||||
Type* type;
|
||||
Type* unpadded_coerce_and_expand_type;
|
||||
} padding;
|
||||
u16 padding_argument_index;
|
||||
union
|
||||
{
|
||||
DirectAttributes direct;
|
||||
IndirectAttributes indirect;
|
||||
u32 alloca_field_index;
|
||||
} attributes;
|
||||
AbiFlags flags;
|
||||
u16 abi_start;
|
||||
u16 abi_count;
|
||||
|
||||
inline void set_sret_after_this(bool sret_after_this)
|
||||
{
|
||||
assert(flags.kind == AbiKind::indirect);
|
||||
flags.sret_after_this = sret_after_this;
|
||||
}
|
||||
|
||||
inline void set_indirect_realign(bool realign)
|
||||
{
|
||||
assert(flags.kind == AbiKind::indirect);
|
||||
flags.indirect_realign = realign;
|
||||
}
|
||||
|
||||
inline void set_indirect_by_value(bool by_value)
|
||||
{
|
||||
assert(flags.kind == AbiKind::indirect);
|
||||
flags.indirect_by_value = by_value;
|
||||
}
|
||||
|
||||
inline void set_indirect_align(u32 alignment)
|
||||
{
|
||||
assert(flags.kind == AbiKind::indirect || flags.kind == AbiKind::indirect_aliased);
|
||||
attributes.indirect.alignment = alignment;
|
||||
}
|
||||
|
||||
inline bool can_have_coerce_to_type()
|
||||
{
|
||||
switch (flags.kind)
|
||||
{
|
||||
case AbiKind::direct:
|
||||
case AbiKind::extend:
|
||||
case AbiKind::coerce_and_expand:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_coerce_to_type(Type* coerce_to_type)
|
||||
{
|
||||
assert(can_have_coerce_to_type());
|
||||
this->coerce_to_type = coerce_to_type;
|
||||
}
|
||||
|
||||
inline Type* get_coerce_to_type()
|
||||
{
|
||||
assert(can_have_coerce_to_type());
|
||||
return coerce_to_type;
|
||||
}
|
||||
|
||||
inline void set_padding_type(Type* padding_type)
|
||||
{
|
||||
assert(can_have_coerce_to_type());
|
||||
padding = {
|
||||
.type = padding_type,
|
||||
};
|
||||
}
|
||||
|
||||
inline bool can_have_padding_type()
|
||||
{
|
||||
switch (flags.kind)
|
||||
{
|
||||
case AbiKind::direct:
|
||||
case AbiKind::extend:
|
||||
case AbiKind::indirect:
|
||||
case AbiKind::indirect_aliased:
|
||||
case AbiKind::expand:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline Type* get_padding_type()
|
||||
{
|
||||
return can_have_padding_type() ? padding.type : 0;
|
||||
}
|
||||
|
||||
inline void set_direct_offset(u32 offset)
|
||||
{
|
||||
assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
|
||||
attributes.direct.offset = offset;
|
||||
}
|
||||
|
||||
inline void set_direct_alignment(u32 alignment)
|
||||
{
|
||||
assert(flags.kind == AbiKind::direct || flags.kind == AbiKind::extend);
|
||||
attributes.direct.alignment = alignment;
|
||||
}
|
||||
|
||||
inline void set_can_be_flattened(bool can_be_flattened)
|
||||
{
|
||||
assert(flags.kind == AbiKind::direct);
|
||||
flags.can_be_flattened = can_be_flattened;
|
||||
}
|
||||
|
||||
inline bool get_can_be_flattened()
|
||||
{
|
||||
return flags.can_be_flattened;
|
||||
}
|
||||
};
|
||||
|
||||
struct Target
|
||||
{
|
||||
CPUArchitecture cpu;
|
||||
@ -87,6 +280,24 @@ enum class CallingConvention
|
||||
count,
|
||||
};
|
||||
|
||||
enum class ResolvedCallingConvention
|
||||
{
|
||||
system_v,
|
||||
win64,
|
||||
count,
|
||||
};
|
||||
|
||||
fn ResolvedCallingConvention resolve_calling_convention(CallingConvention cc)
|
||||
{
|
||||
switch (cc)
|
||||
{
|
||||
case CallingConvention::c:
|
||||
// TODO:
|
||||
return ResolvedCallingConvention::system_v;
|
||||
case CallingConvention::count: unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
enum class InlineBehavior
|
||||
{
|
||||
normal,
|
||||
@ -124,12 +335,29 @@ struct TypeInteger
|
||||
bool is_signed;
|
||||
};
|
||||
|
||||
struct AbiRegisterCountSystemV
|
||||
{
|
||||
u32 gpr;
|
||||
u32 sse;
|
||||
};
|
||||
|
||||
union AbiRegisterCount
|
||||
{
|
||||
AbiRegisterCountSystemV system_v;
|
||||
};
|
||||
|
||||
struct TypeFunction
|
||||
{
|
||||
Type* semantic_return_type;
|
||||
Slice<Type*> semantic_argument_types;
|
||||
CallingConvention calling_convention;
|
||||
bool is_variable_arguments;
|
||||
// ABI
|
||||
Slice<Type*> abi_argument_types;
|
||||
Type* abi_return_type;
|
||||
AbiRegisterCount available_registers;
|
||||
Slice<AbiInformation> argument_abis;
|
||||
AbiInformation return_abi;
|
||||
};
|
||||
|
||||
struct TypePointer
|
||||
@ -221,6 +449,13 @@ struct TypeUnion
|
||||
u32 biggest_field;
|
||||
};
|
||||
|
||||
struct LLVMType
|
||||
{
|
||||
llvm::Type* abi;
|
||||
llvm::Type* memory;
|
||||
llvm::DIType* debug;
|
||||
};
|
||||
|
||||
struct Type
|
||||
{
|
||||
union
|
||||
@ -238,6 +473,7 @@ struct Type
|
||||
TypeId id;
|
||||
String name;
|
||||
Type* next;
|
||||
LLVMType llvm;
|
||||
};
|
||||
|
||||
fn u32 align_bit_count(u32 bit_count)
|
||||
@ -340,6 +576,7 @@ struct Scope
|
||||
u32 line;
|
||||
u32 column;
|
||||
ScopeKind kind;
|
||||
llvm::DIScope* llvm;
|
||||
};
|
||||
|
||||
enum class StatementId
|
||||
@ -694,6 +931,7 @@ struct Value
|
||||
Type* type;
|
||||
ValueId id;
|
||||
ValueKind kind;
|
||||
llvm::Value* llvm;
|
||||
|
||||
bool is_constant()
|
||||
{
|
||||
@ -742,6 +980,35 @@ struct Argument
|
||||
u32 index;
|
||||
};
|
||||
|
||||
struct LLVMIntrinsicId
|
||||
{
|
||||
u32 n;
|
||||
};
|
||||
|
||||
struct LLVMIntrinsicTable
|
||||
{
|
||||
LLVMIntrinsicId
|
||||
trap,
|
||||
va_start,
|
||||
va_end,
|
||||
va_copy;
|
||||
};
|
||||
|
||||
struct ModuleLLVM
|
||||
{
|
||||
llvm::LLVMContext* context;
|
||||
llvm::Module* module;
|
||||
llvm::Builder* builder;
|
||||
llvm::DIBuilder* di_builder;
|
||||
llvm::DIFile* file;
|
||||
llvm::DICompileUnit* compile_unit;
|
||||
llvm::Type* pointer_type;
|
||||
llvm::Type* void_type;
|
||||
LLVMIntrinsicTable intrinsic_table;
|
||||
llvm::Function* memcmp;
|
||||
u32 debug_tag;
|
||||
};
|
||||
|
||||
struct Module
|
||||
{
|
||||
Arena* arena;
|
||||
@ -768,6 +1035,7 @@ struct Module
|
||||
MacroDeclaration* current_macro_declaration;
|
||||
MacroInstantiation* current_macro_instantiation;
|
||||
|
||||
ModuleLLVM llvm;
|
||||
Scope scope;
|
||||
|
||||
String name;
|
||||
|
540
src/emitter.cpp
540
src/emitter.cpp
@ -1,5 +1,545 @@
|
||||
#include <compiler.h>
|
||||
#include <llvm.h>
|
||||
|
||||
fn void llvm_initialize(Module* module)
|
||||
{
|
||||
llvm_initialize_all();
|
||||
|
||||
auto context = LLVMContextCreate();
|
||||
auto m = llvm_context_create_module(context, module->name);
|
||||
auto builder = LLVMCreateBuilderInContext(context);
|
||||
llvm::DIBuilder* di_builder = 0;
|
||||
llvm::DICompileUnit* di_compile_unit = 0;
|
||||
llvm::DIFile* di_file = 0;
|
||||
|
||||
if (module->has_debug_info)
|
||||
{
|
||||
di_builder = LLVMCreateDIBuilder(m);
|
||||
auto last_slash = string_last_character(module->path, '/');
|
||||
if (last_slash == string_no_match)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
auto directory = module->path(0, last_slash);
|
||||
auto file_name = module->path(last_slash + 1);
|
||||
auto file = LLVMDIBuilderCreateFile(di_builder, file_name.pointer, file_name.length, directory.pointer, directory.length);
|
||||
auto producer_name = string_literal("bloat buster");
|
||||
auto is_optimized = build_mode_is_optimized(module->build_mode);
|
||||
auto flags = string_literal("");
|
||||
u32 runtime_version = 0;
|
||||
auto split_name = string_literal("");
|
||||
auto sysroot = string_literal("");
|
||||
auto sdk = string_literal("");
|
||||
di_compile_unit = LLVMDIBuilderCreateCompileUnit(di_builder, DwarfSourceLanguage::C17, file, producer_name.pointer, producer_name.length, is_optimized, flags.pointer, flags.length, runtime_version, split_name.pointer, split_name.length, DwarfEmissionKind::full, 0, 0, is_optimized, sysroot.pointer, sysroot.length, sdk.pointer, sdk.length);
|
||||
module->scope.llvm = (llvm::DIScope*)di_compile_unit;
|
||||
}
|
||||
|
||||
module->llvm = {
|
||||
.context = context,
|
||||
.module = m,
|
||||
.builder = builder,
|
||||
.di_builder = di_builder,
|
||||
.file = di_file,
|
||||
.compile_unit = di_compile_unit,
|
||||
.pointer_type = LLVMPointerTypeInContext(context),
|
||||
.void_type = LLVMVoidTypeInContext(context),
|
||||
.intrinsic_table = {
|
||||
.trap = LLVMLookupIntrinsicID(split_string_literal("llvm.trap")),
|
||||
.va_start = LLVMLookupIntrinsicID(split_string_literal("llvm.va_start")),
|
||||
.va_end = LLVMLookupIntrinsicID(split_string_literal("llvm.va_end")),
|
||||
.va_copy = LLVMLookupIntrinsicID(split_string_literal("llvm.va_copy")),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
enum class AbiSystemVClass
|
||||
{
|
||||
none,
|
||||
integer,
|
||||
sse,
|
||||
sse_up,
|
||||
x87,
|
||||
x87_up,
|
||||
complex_x87,
|
||||
memory,
|
||||
};
|
||||
|
||||
fn bool contains_no_user_data(Type* type, u64 start, u64 end)
|
||||
{
|
||||
if (get_byte_size(type) <= start)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::structure:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
case TypeId::array:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn Type* get_integer_type_at_offset(Module* module, Type* type, u32 offset, Type* source_type, u32 source_offset)
|
||||
{
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::integer:
|
||||
{
|
||||
auto bit_count = type->integer.bit_count;
|
||||
switch (bit_count)
|
||||
{
|
||||
case 64: return type;
|
||||
case 32: case 16: case 8:
|
||||
{
|
||||
assert(offset == 0);
|
||||
auto start = source_offset + get_byte_size(type);
|
||||
auto end = source_offset + 8;
|
||||
|
||||
if (contains_no_user_data(source_type, start, end))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
auto source_size = get_byte_size(source_type);
|
||||
auto byte_count = source_size - source_offset;
|
||||
auto bit_count = byte_count > 8 ? 64 : byte_count * 8;
|
||||
auto result = integer_type(module, { .bit_count = 64, .is_signed = false });
|
||||
return result;
|
||||
}
|
||||
|
||||
struct AbiSystemVClassify
|
||||
{
|
||||
u64 base_offset;
|
||||
bool is_variable_argument;
|
||||
bool is_register_call;
|
||||
};
|
||||
|
||||
struct AbiSystemVClassifyResult
|
||||
{
|
||||
AbiSystemVClass r[2];
|
||||
};
|
||||
|
||||
fn AbiSystemVClassifyResult abi_system_v_classify_type(Type* type, AbiSystemVClassify options)
|
||||
{
|
||||
AbiSystemVClassifyResult result = {};
|
||||
auto is_memory = options.base_offset >= 8;
|
||||
auto current_index = is_memory;
|
||||
auto not_current_index = !is_memory;
|
||||
assert(current_index != not_current_index);
|
||||
result.r[current_index] = AbiSystemVClass::memory;
|
||||
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::void_type:
|
||||
case TypeId::noreturn:
|
||||
result.r[current_index] = AbiSystemVClass::none;
|
||||
break;
|
||||
case TypeId::bits:
|
||||
return abi_system_v_classify_type(type->bits.backing_type, options);
|
||||
case TypeId::enumerator:
|
||||
return abi_system_v_classify_type(type->enumerator.backing_type, options);
|
||||
case TypeId::pointer:
|
||||
result.r[current_index] = AbiSystemVClass::integer;
|
||||
break;
|
||||
case TypeId::integer:
|
||||
{
|
||||
if (type->integer.bit_count <= 64)
|
||||
{
|
||||
result.r[current_index] = AbiSystemVClass::integer;
|
||||
}
|
||||
else if (type->integer.bit_count == 128)
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
else
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
} break;
|
||||
case TypeId::array:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
case TypeId::structure:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
case TypeId::alias:
|
||||
return abi_system_v_classify_type(type->alias.type, options);
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn bool is_integral_or_enumeration_type(Type* type)
|
||||
{
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::alias: return is_integral_or_enumeration_type(type->alias.type);
|
||||
case TypeId::integer:
|
||||
case TypeId::bits:
|
||||
return true;
|
||||
case TypeId::structure:
|
||||
return false;
|
||||
default: unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
fn bool is_promotable_integer_type_for_abi(Type* type)
|
||||
{
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::integer: return type->integer.bit_count < 32;
|
||||
case TypeId::bits: return is_promotable_integer_type_for_abi(type->bits.backing_type);
|
||||
case TypeId::alias: return is_promotable_integer_type_for_abi(type->alias.type);
|
||||
default: unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
struct DirectOptions
|
||||
{
|
||||
Type* semantic_type;
|
||||
Type* type;
|
||||
Type* padding;
|
||||
u32 offset;
|
||||
u32 alignment;
|
||||
bool cannot_be_flattened;
|
||||
};
|
||||
|
||||
fn void resolve_type_in_place_abi(Module* module, Type* type)
|
||||
{
|
||||
if (!type->llvm.abi)
|
||||
{
|
||||
llvm::Type* result;
|
||||
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::void_type:
|
||||
case TypeId::noreturn:
|
||||
result = module->llvm.void_type;
|
||||
break;
|
||||
case TypeId::integer:
|
||||
result = LLVMIntTypeInContext(module->llvm.context, type->integer.bit_count);
|
||||
break;
|
||||
case TypeId::pointer:
|
||||
result = module->llvm.pointer_type;
|
||||
break;
|
||||
case TypeId::array:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
type->llvm.abi = result;
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_type_in_place_memory(Module* module, Type* type)
|
||||
{
|
||||
if (!type->llvm.memory)
|
||||
{
|
||||
resolve_type_in_place_abi(module, type);
|
||||
|
||||
llvm::Type* result;
|
||||
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::void_type:
|
||||
case TypeId::noreturn:
|
||||
case TypeId::pointer:
|
||||
result = type->llvm.abi;
|
||||
break;
|
||||
case TypeId::integer:
|
||||
{
|
||||
auto byte_size = get_byte_size(type);
|
||||
auto bit_count = byte_size * 8;
|
||||
result = LLVMIntTypeInContext(module->llvm.context, bit_count);
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
type->llvm.memory = result;
|
||||
|
||||
if (type->id == TypeId::bits)
|
||||
{
|
||||
assert(type->llvm.memory == type->llvm.abi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_type_in_place_debug(Module* module, Type* type)
|
||||
{
|
||||
if (module->has_debug_info)
|
||||
{
|
||||
if (!type->llvm.debug)
|
||||
{
|
||||
llvm::DIType* result;
|
||||
|
||||
switch (type->id)
|
||||
{
|
||||
case TypeId::integer:
|
||||
{
|
||||
DwarfType dwarf_type = type->integer.bit_count == 1 ? DwarfType::boolean : (type->integer.is_signed ? DwarfType::signed_type : DwarfType::unsigned_type);
|
||||
DIFlags flags = {};
|
||||
result = LLVMDIBuilderCreateBasicType(module->llvm.di_builder, type->name.pointer, type->name.length, type->integer.bit_count, dwarf_type, flags);
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
type->llvm.debug = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_type_in_place(Module* module, Type* type)
|
||||
{
|
||||
resolve_type_in_place_abi(module, type);
|
||||
resolve_type_in_place_memory(module, type);
|
||||
resolve_type_in_place_debug(module, type);
|
||||
}
|
||||
|
||||
fn AbiInformation abi_system_v_get_direct(Module* module, DirectOptions direct)
|
||||
{
|
||||
AbiInformation result = {
|
||||
.semantic_type = direct.semantic_type,
|
||||
.flags = {
|
||||
.kind = AbiKind::direct,
|
||||
},
|
||||
};
|
||||
resolve_type_in_place(module, direct.semantic_type);
|
||||
resolve_type_in_place(module, direct.type);
|
||||
if (unlikely(direct.padding))
|
||||
{
|
||||
resolve_type_in_place(module, direct.padding);
|
||||
}
|
||||
|
||||
result.set_coerce_to_type(direct.type);
|
||||
result.set_padding_type(direct.type);
|
||||
result.set_direct_offset(direct.offset);
|
||||
result.set_direct_alignment(direct.alignment);
|
||||
result.set_can_be_flattened(!direct.cannot_be_flattened);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn AbiInformation abi_system_classify_return_type(Module* module, Type* semantic_return_type)
|
||||
{
|
||||
auto type_classes = abi_system_v_classify_type(semantic_return_type, {});
|
||||
auto low_class = type_classes.r[0];
|
||||
auto high_class = type_classes.r[1];
|
||||
assert(high_class != AbiSystemVClass::memory || low_class == AbiSystemVClass::memory);
|
||||
assert(high_class != AbiSystemVClass::sse_up || low_class == AbiSystemVClass::sse);
|
||||
|
||||
Type* low_type = 0;
|
||||
|
||||
switch (low_class)
|
||||
{
|
||||
case AbiSystemVClass::none:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
case AbiSystemVClass::integer:
|
||||
{
|
||||
low_type = get_integer_type_at_offset(module, semantic_return_type, 0, semantic_return_type, 0);
|
||||
|
||||
if (high_class == AbiSystemVClass::none && low_type->id == TypeId::integer)
|
||||
{
|
||||
if (semantic_return_type->id == TypeId::enumerator)
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
|
||||
if (is_integral_or_enumeration_type(semantic_return_type) && is_promotable_integer_type_for_abi(semantic_return_type))
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
Type* high_type = 0;
|
||||
|
||||
switch (high_class)
|
||||
{
|
||||
case AbiSystemVClass::none:
|
||||
break;
|
||||
case AbiSystemVClass::integer:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
|
||||
default: unreachable();
|
||||
}
|
||||
|
||||
if (high_type)
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
|
||||
auto result = abi_system_v_get_direct(module, {
|
||||
.semantic_type = semantic_return_type,
|
||||
.type = low_type,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void emit(Module* module)
|
||||
{
|
||||
llvm_initialize(module);
|
||||
|
||||
for (auto* global = module->first_global; global; global = global->next)
|
||||
{
|
||||
switch (global->variable.storage->id)
|
||||
{
|
||||
case ValueId::function:
|
||||
case ValueId::external_function:
|
||||
{
|
||||
auto function_type = &global->variable.storage->type->pointer.element_type->function;
|
||||
function_type->argument_abis = arena_allocate<AbiInformation>(module->arena, function_type->semantic_argument_types.length);
|
||||
auto resolved_calling_convention = resolve_calling_convention(function_type->calling_convention);
|
||||
auto is_reg_call = resolved_calling_convention == ResolvedCallingConvention::system_v && false; // TODO: regcall calling convention
|
||||
|
||||
llvm::Type* llvm_abi_argument_type_buffer[64];
|
||||
|
||||
switch (resolved_calling_convention)
|
||||
{
|
||||
case ResolvedCallingConvention::system_v:
|
||||
{
|
||||
function_type->available_registers = {
|
||||
.system_v = {
|
||||
.gpr = (u32)(is_reg_call ? 11 : 6),
|
||||
.sse = (u32)(is_reg_call ? 16 : 8),
|
||||
},
|
||||
};
|
||||
function_type->return_abi = abi_system_classify_return_type(module, function_type->semantic_return_type);
|
||||
auto return_abi_kind = function_type->return_abi.flags.kind;
|
||||
|
||||
Type* abi_argument_type_buffer[64];
|
||||
u16 abi_argument_type_count = 0;
|
||||
|
||||
Type* abi_return_type;
|
||||
switch (return_abi_kind)
|
||||
{
|
||||
case AbiKind::direct:
|
||||
case AbiKind::extend:
|
||||
{
|
||||
abi_return_type = function_type->return_abi.coerce_to_type;
|
||||
} break;
|
||||
case AbiKind::ignore:
|
||||
case AbiKind::indirect:
|
||||
{
|
||||
abi_return_type = void_type(module);
|
||||
} break;
|
||||
default: unreachable(); // TODO
|
||||
}
|
||||
assert(abi_return_type);
|
||||
function_type->abi_return_type = abi_return_type;
|
||||
resolve_type_in_place(module, abi_return_type);
|
||||
|
||||
if (function_type->return_abi.flags.kind == AbiKind::indirect)
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
|
||||
auto required_argument_count = function_type->semantic_argument_types.length;
|
||||
|
||||
for (auto abi: function_type->argument_abis)
|
||||
{
|
||||
trap_raw();
|
||||
}
|
||||
|
||||
auto abi_argument_types = new_type_array(module, abi_argument_type_count);
|
||||
memcpy(abi_argument_types.pointer, abi_argument_type_buffer, sizeof(abi_argument_type_buffer[0]) * abi_argument_type_count);
|
||||
function_type->abi_argument_types = abi_argument_types;
|
||||
} break;
|
||||
case ResolvedCallingConvention::win64:
|
||||
{
|
||||
report_error();
|
||||
} break;
|
||||
case ResolvedCallingConvention::count: unreachable();
|
||||
}
|
||||
|
||||
auto llvm_function_type = LLVMFunctionType(function_type->abi_return_type->llvm.abi, llvm_abi_argument_type_buffer, (u32)function_type->abi_argument_types.length, function_type->is_variable_arguments);
|
||||
|
||||
llvm::DISubroutineType* subroutine_type = 0;
|
||||
if (module->has_debug_info)
|
||||
{
|
||||
llvm::DIType* debug_argument_type_buffer[64];
|
||||
Slice<llvm::DIType*> debug_argument_types = { .pointer = debug_argument_type_buffer, .length = function_type->argument_abis.length + 1 + function_type->is_variable_arguments };
|
||||
debug_argument_types[0] = function_type->return_abi.semantic_type->llvm.debug;
|
||||
assert(debug_argument_types[0]);
|
||||
|
||||
auto debug_argument_type_slice = debug_argument_types(1)(0, function_type->argument_abis.length);
|
||||
|
||||
for (u64 i = 0; i < function_type->argument_abis.length; i += 1)
|
||||
{
|
||||
auto& argument_abi = function_type->argument_abis[i];
|
||||
auto* debug_argument_type = &debug_argument_type_slice[i];
|
||||
*debug_argument_type = argument_abi.semantic_type->llvm.debug;
|
||||
assert(*debug_argument_type);
|
||||
}
|
||||
|
||||
if (function_type->is_variable_arguments)
|
||||
{
|
||||
auto void_ty = void_type(module);
|
||||
assert(void_ty->llvm.debug);
|
||||
debug_argument_types[function_type->argument_abis.length + 1] = void_ty->llvm.debug;
|
||||
}
|
||||
|
||||
DIFlags flags = {};
|
||||
subroutine_type = LLVMDIBuilderCreateSubroutineType(module->llvm.di_builder, module->llvm.file, debug_argument_types.pointer, (u32)debug_argument_types.length, flags);
|
||||
}
|
||||
|
||||
global->variable.storage->type->pointer.element_type->llvm.abi = (llvm::Type*)llvm_function_type;
|
||||
global->variable.storage->type->pointer.element_type->llvm.debug = (llvm::DIType*)subroutine_type;
|
||||
|
||||
LinkageType llvm_linkage_type;
|
||||
switch (global->linkage)
|
||||
{
|
||||
case Linkage::internal: llvm_linkage_type = LinkageType::internal; break;
|
||||
case Linkage::external: llvm_linkage_type = LinkageType::external; break;
|
||||
}
|
||||
unsigned address_space = 0;
|
||||
auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, llvm_linkage_type, address_space, global->variable.name);
|
||||
global->variable.storage->llvm = (llvm::Value*)llvm_function;
|
||||
|
||||
LLVMCallingConvention cc;
|
||||
switch (function_type->calling_convention)
|
||||
{
|
||||
case CallingConvention::c: cc = LLVMCallingConvention::c; break;
|
||||
case CallingConvention::count: unreachable();
|
||||
}
|
||||
LLVMSetFunctionCallConv(llvm_function, cc);
|
||||
|
||||
trap_raw();
|
||||
} break;
|
||||
case ValueId::global:
|
||||
{
|
||||
trap_raw();
|
||||
} break;
|
||||
default: report_error();
|
||||
}
|
||||
}
|
||||
|
||||
trap_raw();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define breakpoint() __builtin_debugtrap()
|
||||
#define string_literal_length(s) (sizeof(s) - 1)
|
||||
#define string_literal(s) ((String){ .pointer = (u8*)(s), .length = string_literal_length(s), })
|
||||
#define split_string_literal(s) (u8*)s, string_literal_length(s)
|
||||
#define offsetof(S, f) __builtin_offsetof(S, f)
|
||||
|
||||
#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
|
||||
|
433
src/llvm.cpp
433
src/llvm.cpp
@ -26,97 +26,110 @@
|
||||
|
||||
#include "lld/Common/CommonLinkerContext.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
fn StringRef string_ref(String string)
|
||||
fn llvm::StringRef string_ref(String string)
|
||||
{
|
||||
return StringRef((char*)string.pointer, string.length);
|
||||
return llvm::StringRef((char*)string.pointer, string.length);
|
||||
}
|
||||
|
||||
EXPORT Module* llvm_context_create_module(LLVMContext& context, String name)
|
||||
EXPORT llvm::Module* llvm_context_create_module(llvm::LLVMContext* context, String name)
|
||||
{
|
||||
return new Module(string_ref(name), context);
|
||||
return new llvm::Module(string_ref(name), *context);
|
||||
}
|
||||
|
||||
EXPORT unsigned llvm_integer_type_get_bit_count(const IntegerType& integer_type)
|
||||
EXPORT unsigned llvm_integer_type_get_bit_count(const llvm::IntegerType& integer_type)
|
||||
{
|
||||
auto result = integer_type.getBitWidth();
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT GlobalVariable* llvm_module_create_global_variable(Module& module, Type* type, bool is_constant, GlobalValue::LinkageTypes linkage_type, Constant* initial_value, String name, GlobalVariable* before, GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized)
|
||||
EXPORT llvm::GlobalVariable* llvm_module_create_global_variable(llvm::Module& module, llvm::Type* type, bool is_constant, llvm::GlobalValue::LinkageTypes linkage_type, llvm::Constant* initial_value, String name, llvm::GlobalVariable* before, llvm::GlobalValue::ThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized)
|
||||
{
|
||||
auto* global = new GlobalVariable(module, type, is_constant, linkage_type, initial_value, string_ref(name), before, thread_local_mode, address_space, externally_initialized);
|
||||
auto* global = new llvm::GlobalVariable(module, type, is_constant, linkage_type, initial_value, string_ref(name), before, thread_local_mode, address_space, externally_initialized);
|
||||
return global;
|
||||
}
|
||||
|
||||
EXPORT void llvm_global_variable_add_debug_info(GlobalVariable& global, DIGlobalVariableExpression* debug_global_variable)
|
||||
EXPORT void llvm_global_variable_add_debug_info(llvm::GlobalVariable& global, llvm::DIGlobalVariableExpression* debug_global_variable)
|
||||
{
|
||||
global.addDebugInfo(debug_global_variable);
|
||||
}
|
||||
|
||||
EXPORT void llvm_global_variable_delete(GlobalVariable* global)
|
||||
EXPORT void llvm_global_variable_delete(llvm::GlobalVariable* global)
|
||||
{
|
||||
delete global;
|
||||
}
|
||||
|
||||
EXPORT void llvm_subprogram_replace_type(DISubprogram& subprogram, DISubroutineType* subroutine_type)
|
||||
EXPORT void llvm_subprogram_replace_type(llvm::DISubprogram& subprogram, llvm::DISubroutineType* subroutine_type)
|
||||
{
|
||||
subprogram.replaceType(subroutine_type);
|
||||
}
|
||||
|
||||
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, String name)
|
||||
EXPORT llvm::Function* llvm_module_create_function(llvm::Module* module, llvm::FunctionType* function_type, LinkageType linkage_type, unsigned address_space, String name)
|
||||
{
|
||||
auto* function = Function::Create(function_type, linkage_type, address_space, string_ref(name), module);
|
||||
llvm::GlobalValue::LinkageTypes llvm_linkage_type;
|
||||
switch (linkage_type)
|
||||
{
|
||||
case LinkageType::external: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break;
|
||||
case LinkageType::available_externally: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage; break;
|
||||
case LinkageType::link_once_any: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage; break;
|
||||
case LinkageType::link_once_odr: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage; break;
|
||||
case LinkageType::weak_any: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakAnyLinkage; break;
|
||||
case LinkageType::weak_odr: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakODRLinkage; break;
|
||||
case LinkageType::appending: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AppendingLinkage; break;
|
||||
case LinkageType::internal: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::InternalLinkage; break;
|
||||
case LinkageType::private_: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::PrivateLinkage; break;
|
||||
case LinkageType::external_weak: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break;
|
||||
case LinkageType::common: llvm_linkage_type = llvm::GlobalValue::LinkageTypes::CommonLinkage; break;
|
||||
}
|
||||
auto* function = llvm::Function::Create(function_type, llvm_linkage_type, address_space, string_ref(name), module);
|
||||
return function;
|
||||
}
|
||||
|
||||
EXPORT StructType* llvm_context_create_forward_declared_struct_type(LLVMContext& context, String name)
|
||||
EXPORT llvm::StructType* llvm_context_create_forward_declared_struct_type(llvm::LLVMContext& context, String name)
|
||||
{
|
||||
auto* struct_type = StructType::create(context, string_ref(name));
|
||||
auto* struct_type = llvm::StructType::create(context, string_ref(name));
|
||||
return struct_type;
|
||||
}
|
||||
|
||||
EXPORT StructType* llvm_context_create_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, String name, bool is_packed)
|
||||
EXPORT llvm::StructType* llvm_context_create_struct_type(llvm::LLVMContext& context, llvm::Type** type_pointer, size_t type_count, String name, bool is_packed)
|
||||
{
|
||||
auto types = ArrayRef<Type*>(type_pointer, type_count);
|
||||
auto* struct_type = StructType::create(context, types, string_ref(name), is_packed);
|
||||
auto types = llvm::ArrayRef<llvm::Type*>(type_pointer, type_count);
|
||||
auto* struct_type = llvm::StructType::create(context, types, string_ref(name), is_packed);
|
||||
return struct_type;
|
||||
}
|
||||
|
||||
EXPORT StructType* llvm_context_get_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, bool is_packed)
|
||||
EXPORT llvm::StructType* llvm_context_get_struct_type(llvm::LLVMContext& context, llvm::Type** type_pointer, size_t type_count, bool is_packed)
|
||||
{
|
||||
auto types = ArrayRef<Type*>(type_pointer, type_count);
|
||||
auto* struct_type = StructType::get(context, types, is_packed);
|
||||
auto types = llvm::ArrayRef<llvm::Type*>(type_pointer, type_count);
|
||||
auto* struct_type = llvm::StructType::get(context, types, is_packed);
|
||||
return struct_type;
|
||||
}
|
||||
|
||||
EXPORT BasicBlock* llvm_context_create_basic_block(LLVMContext& context, String name, Function* parent)
|
||||
EXPORT llvm::BasicBlock* llvm_context_create_basic_block(llvm::LLVMContext& context, String name, llvm::Function* parent)
|
||||
{
|
||||
auto* basic_block = BasicBlock::Create(context, string_ref(name), parent);
|
||||
auto* basic_block = llvm::BasicBlock::Create(context, string_ref(name), parent);
|
||||
return basic_block;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_value_has_one_use(Value& value)
|
||||
EXPORT bool llvm_value_has_one_use(llvm::Value& value)
|
||||
{
|
||||
auto result = value.hasOneUse();
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT Value* llvm_basic_block_user_begin(BasicBlock* basic_block)
|
||||
EXPORT llvm::Value* llvm_basic_block_user_begin(llvm::BasicBlock* basic_block)
|
||||
{
|
||||
Value* value = *basic_block->user_begin();
|
||||
llvm::Value* value = *basic_block->user_begin();
|
||||
return value;
|
||||
}
|
||||
|
||||
EXPORT void llvm_basic_block_delete(BasicBlock* basic_block)
|
||||
EXPORT void llvm_basic_block_delete(llvm::BasicBlock* basic_block)
|
||||
{
|
||||
delete basic_block;
|
||||
}
|
||||
|
||||
EXPORT BranchInst* llvm_value_to_branch(Value* value)
|
||||
EXPORT llvm::BranchInst* llvm_value_to_branch(llvm::Value* value)
|
||||
{
|
||||
auto* result = dyn_cast<BranchInst>(value);
|
||||
auto* result = dyn_cast<llvm::BranchInst>(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -124,7 +137,7 @@ EXPORT BranchInst* llvm_value_to_branch(Value* value)
|
||||
// for something immediately preceding the IP. Sometimes this can
|
||||
// happen with how we generate implicit-returns; it can also happen
|
||||
// with noreturn cleanups.
|
||||
fn StoreInst* get_store_if_valid(User* user, Value* return_alloca, Type* element_type)
|
||||
fn llvm::StoreInst* get_store_if_valid(llvm::User* user, llvm::Value* return_alloca, llvm::Type* element_type)
|
||||
{
|
||||
auto *SI = dyn_cast<llvm::StoreInst>(user);
|
||||
if (!SI || SI->getPointerOperand() != return_alloca ||
|
||||
@ -142,7 +155,7 @@ fn StoreInst* get_store_if_valid(User* user, Value* return_alloca, Type* element
|
||||
|
||||
// copy of static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
||||
// in clang/lib/CodeGen/CGCall.cpp:3526 in LLVM 19
|
||||
EXPORT StoreInst* llvm_find_return_value_dominating_store(IRBuilder<>& builder, Value* return_alloca, Type* element_type)
|
||||
EXPORT llvm::StoreInst* llvm_find_return_value_dominating_store(llvm::IRBuilder<>& builder, llvm::Value* return_alloca, llvm::Type* element_type)
|
||||
{
|
||||
// Check if a User is a store which pointerOperand is the ReturnValue.
|
||||
// We are looking for stores to the ReturnValue, not for stores of the
|
||||
@ -183,21 +196,21 @@ EXPORT StoreInst* llvm_find_return_value_dominating_store(IRBuilder<>& builder,
|
||||
return store;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_value_use_empty(Value& value)
|
||||
EXPORT bool llvm_value_use_empty(llvm::Value& value)
|
||||
{
|
||||
return value.use_empty();
|
||||
}
|
||||
|
||||
EXPORT bool llvm_basic_block_is_empty(BasicBlock& basic_block)
|
||||
EXPORT bool llvm_basic_block_is_empty(llvm::BasicBlock& basic_block)
|
||||
{
|
||||
return basic_block.empty();
|
||||
}
|
||||
|
||||
EXPORT AllocaInst* llvm_builder_create_alloca(IRBuilder<>& builder, Type* type, unsigned address_space, String name)
|
||||
EXPORT llvm::AllocaInst* llvm_builder_create_alloca(llvm::IRBuilder<>& builder, llvm::Type* type, unsigned address_space, String name)
|
||||
{
|
||||
const DataLayout &data_layout = builder.GetInsertBlock()->getDataLayout();
|
||||
Align alignment = data_layout.getABITypeAlign(type);
|
||||
return builder.Insert(new AllocaInst(type, address_space, 0, alignment), string_ref(name));
|
||||
const llvm::DataLayout &data_layout = builder.GetInsertBlock()->getDataLayout();
|
||||
llvm::Align alignment = data_layout.getABITypeAlign(type);
|
||||
return builder.Insert(new llvm::AllocaInst(type, address_space, 0, alignment), string_ref(name));
|
||||
}
|
||||
|
||||
enum class BBLLVMAttributeFramePointerKind : u8
|
||||
@ -273,8 +286,8 @@ enum class BBLLVMUWTableKind
|
||||
|
||||
struct BBLLVMArgumentAttributes
|
||||
{
|
||||
Type* semantic_type;
|
||||
Type* abi_type;
|
||||
llvm::Type* semantic_type;
|
||||
llvm::Type* abi_type;
|
||||
u64 dereferenceable_bytes;
|
||||
u32 alignment;
|
||||
u32 no_alias:1;
|
||||
@ -299,9 +312,9 @@ struct BBLLVMArgumentAttributes
|
||||
|
||||
static_assert(sizeof(BBLLVMArgumentAttributes) == 2 * sizeof(Type*) + 2 * sizeof(u64));
|
||||
|
||||
fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgumentAttributes& attributes)
|
||||
fn llvm::AttributeSet build_argument_attributes(llvm::LLVMContext& context, const BBLLVMArgumentAttributes& attributes)
|
||||
{
|
||||
AttrBuilder builder(context);
|
||||
llvm::AttrBuilder builder(context);
|
||||
|
||||
if (attributes.alignment)
|
||||
{
|
||||
@ -310,32 +323,32 @@ fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgu
|
||||
|
||||
if (attributes.no_alias)
|
||||
{
|
||||
builder.addAttribute(Attribute::NoAlias);
|
||||
builder.addAttribute(llvm::Attribute::NoAlias);
|
||||
}
|
||||
|
||||
if (attributes.non_null)
|
||||
{
|
||||
builder.addAttribute(Attribute::NonNull);
|
||||
builder.addAttribute(llvm::Attribute::NonNull);
|
||||
}
|
||||
|
||||
if (attributes.no_undef)
|
||||
{
|
||||
builder.addAttribute(Attribute::NoUndef);
|
||||
builder.addAttribute(llvm::Attribute::NoUndef);
|
||||
}
|
||||
|
||||
if (attributes.sign_extend)
|
||||
{
|
||||
builder.addAttribute(Attribute::SExt);
|
||||
builder.addAttribute(llvm::Attribute::SExt);
|
||||
}
|
||||
|
||||
if (attributes.zero_extend)
|
||||
{
|
||||
builder.addAttribute(Attribute::ZExt);
|
||||
builder.addAttribute(llvm::Attribute::ZExt);
|
||||
}
|
||||
|
||||
if (attributes.in_reg)
|
||||
{
|
||||
builder.addAttribute(Attribute::InReg);
|
||||
builder.addAttribute(llvm::Attribute::InReg);
|
||||
}
|
||||
|
||||
if (attributes.no_fp_class)
|
||||
@ -350,12 +363,12 @@ fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgu
|
||||
|
||||
if (attributes.writable)
|
||||
{
|
||||
builder.addAttribute(Attribute::Writable);
|
||||
builder.addAttribute(llvm::Attribute::Writable);
|
||||
}
|
||||
|
||||
if (attributes.dead_on_unwind)
|
||||
{
|
||||
builder.addAttribute(Attribute::DeadOnUnwind);
|
||||
builder.addAttribute(llvm::Attribute::DeadOnUnwind);
|
||||
}
|
||||
|
||||
if (attributes.in_alloca)
|
||||
@ -375,7 +388,7 @@ fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgu
|
||||
|
||||
if (attributes.nest)
|
||||
{
|
||||
builder.addAttribute(Attribute::Nest);
|
||||
builder.addAttribute(llvm::Attribute::Nest);
|
||||
}
|
||||
|
||||
if (attributes.by_value)
|
||||
@ -390,10 +403,10 @@ fn AttributeSet build_argument_attributes(LLVMContext& context, const BBLLVMArgu
|
||||
|
||||
if (attributes.no_capture)
|
||||
{
|
||||
builder.addAttribute(Attribute::NoCapture);
|
||||
builder.addAttribute(llvm::Attribute::NoCapture);
|
||||
}
|
||||
|
||||
auto attribute_set = AttributeSet::get(context, builder);
|
||||
auto attribute_set = llvm::AttributeSet::get(context, builder);
|
||||
return attribute_set;
|
||||
}
|
||||
|
||||
@ -510,9 +523,9 @@ static_assert(sizeof(BBLLVMAttributeList) == sizeof(BBLLVMFunctionAttributes) +
|
||||
|
||||
typedef void* BBLLVMAttributeListHandle;
|
||||
|
||||
EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context, const BBLLVMAttributeList& attributes, bool call_site)
|
||||
EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(llvm::LLVMContext& context, const BBLLVMAttributeList& attributes, bool call_site)
|
||||
{
|
||||
AttrBuilder function_attribute_builder(context);
|
||||
llvm::AttrBuilder function_attribute_builder(context);
|
||||
|
||||
if (attributes.function.prefer_vector_width.length)
|
||||
{
|
||||
@ -526,7 +539,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.noreturn)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoReturn);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoReturn);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.cmse_ns_call)
|
||||
@ -536,42 +549,42 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.nounwind)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoUnwind);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoUnwind);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.returns_twice)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::ReturnsTwice);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::ReturnsTwice);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.cold)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::Cold);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::Cold);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.hot)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::Hot);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::Hot);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.no_duplicate)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoDuplicate);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoDuplicate);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.convergent)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::Convergent);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::Convergent);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.no_merge)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoMerge);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoMerge);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.will_return)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::WillReturn);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::WillReturn);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.no_caller_saved_registers)
|
||||
@ -581,12 +594,12 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.no_cf_check)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoCfCheck);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoCfCheck);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.no_callback)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoCallback);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoCallback);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.alloc_size)
|
||||
@ -656,17 +669,17 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.optimize_for_size)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::OptimizeForSize);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::OptimizeForSize);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.min_size)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::MinSize);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::MinSize);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.no_red_zone)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoRedZone);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoRedZone);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.indirect_tls_seg_refs)
|
||||
@ -676,7 +689,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.no_implicit_floats)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoImplicitFloat);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoImplicitFloat);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.sample_profile_suffix_elision_policy)
|
||||
@ -701,7 +714,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.memory_arg_memory_only)
|
||||
{
|
||||
Attribute attribute = function_attribute_builder.getAttribute(Attribute::Memory);
|
||||
llvm::Attribute attribute = function_attribute_builder.getAttribute(llvm::Attribute::Memory);
|
||||
function_attribute_builder.addMemoryAttr(attribute.getMemoryEffects() | llvm::MemoryEffects::argMemOnly());
|
||||
}
|
||||
|
||||
@ -713,7 +726,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
{
|
||||
if (attributes.function.flags0.call_no_builtins)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NoBuiltin);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NoBuiltin);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -728,7 +741,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
function_attribute_builder.addAttribute("stack-probe-size", string_ref(attributes.function.definition_stack_probe_size));
|
||||
}
|
||||
|
||||
StringRef frame_pointer_kind_name;
|
||||
llvm::StringRef frame_pointer_kind_name;
|
||||
switch ((BBLLVMAttributeFramePointerKind) attributes.function.flags0.definition_frame_pointer_kind)
|
||||
{
|
||||
case BBLLVMAttributeFramePointerKind::None: frame_pointer_kind_name = "none"; break;
|
||||
@ -745,7 +758,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.definition_null_pointer_is_valid)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NullPointerIsValid);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NullPointerIsValid);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.definition_no_trapping_fp_math)
|
||||
@ -812,7 +825,7 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags0.definition_non_lazy_bind)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::NonLazyBind);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::NonLazyBind);
|
||||
}
|
||||
|
||||
if (attributes.function.flags0.definition_cmse_nonsecure_entry)
|
||||
@ -820,12 +833,12 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
function_attribute_builder.addAttribute("cmse_nonsecure_entry");
|
||||
}
|
||||
|
||||
UWTableKind unwind_table_kind;
|
||||
llvm::UWTableKind unwind_table_kind;
|
||||
switch ((BBLLVMUWTableKind)attributes.function.flags0.definition_unwind_table_kind)
|
||||
{
|
||||
case BBLLVMUWTableKind::None: unwind_table_kind = UWTableKind::None; break;
|
||||
case BBLLVMUWTableKind::Sync: unwind_table_kind = UWTableKind::Sync; break;
|
||||
case BBLLVMUWTableKind::Async: unwind_table_kind = UWTableKind::Async; break;
|
||||
case BBLLVMUWTableKind::None: unwind_table_kind = llvm::UWTableKind::None; break;
|
||||
case BBLLVMUWTableKind::Sync: unwind_table_kind = llvm::UWTableKind::Sync; break;
|
||||
case BBLLVMUWTableKind::Async: unwind_table_kind = llvm::UWTableKind::Async; break;
|
||||
}
|
||||
|
||||
function_attribute_builder.addUWTableAttr(unwind_table_kind);
|
||||
@ -837,17 +850,17 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags1.definition_stack_protect_strong)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::StackProtectStrong);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::StackProtectStrong);
|
||||
}
|
||||
|
||||
if (attributes.function.flags1.definition_stack_protect)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::StackProtect);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::StackProtect);
|
||||
}
|
||||
|
||||
if (attributes.function.flags1.definition_stack_protect_req)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::StackProtectReq);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::StackProtectReq);
|
||||
}
|
||||
|
||||
if (attributes.function.flags1.definition_aarch64_new_za)
|
||||
@ -862,25 +875,25 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
|
||||
if (attributes.function.flags1.definition_optimize_none)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::OptimizeNone);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::OptimizeNone);
|
||||
}
|
||||
|
||||
if (attributes.function.flags1.definition_naked)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::Naked);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::Naked);
|
||||
}
|
||||
|
||||
if (attributes.function.flags1.definition_inline_hint)
|
||||
{
|
||||
function_attribute_builder.addAttribute(Attribute::InlineHint);
|
||||
function_attribute_builder.addAttribute(llvm::Attribute::InlineHint);
|
||||
}
|
||||
}
|
||||
|
||||
auto function_attributes = AttributeSet::get(context, function_attribute_builder);
|
||||
auto function_attributes = llvm::AttributeSet::get(context, function_attribute_builder);
|
||||
|
||||
auto return_attributes = build_argument_attributes(context, attributes.return_);
|
||||
|
||||
AttributeSet argument_attribute_buffer[128];
|
||||
llvm::AttributeSet argument_attribute_buffer[128];
|
||||
assert(attributes.argument_count < array_length(argument_attribute_buffer));
|
||||
|
||||
for (u64 i = 0; i < attributes.argument_count; i += 1)
|
||||
@ -889,33 +902,33 @@ EXPORT BBLLVMAttributeListHandle llvm_attribute_list_build(LLVMContext& context,
|
||||
argument_attribute_buffer[i] = attribute_set;
|
||||
}
|
||||
|
||||
ArrayRef<AttributeSet> argument_attributes = ArrayRef(argument_attribute_buffer, attributes.argument_count);
|
||||
llvm::ArrayRef<llvm::AttributeSet> argument_attributes = llvm::ArrayRef(argument_attribute_buffer, attributes.argument_count);
|
||||
|
||||
auto attribute_list = AttributeList::get(context, function_attributes, return_attributes, argument_attributes);
|
||||
auto attribute_list = llvm::AttributeList::get(context, function_attributes, return_attributes, argument_attributes);
|
||||
|
||||
static_assert(sizeof(AttributeList) == sizeof(uintptr_t));
|
||||
static_assert(sizeof(llvm::AttributeList) == sizeof(uintptr_t));
|
||||
|
||||
return *(BBLLVMAttributeListHandle*)&attribute_list;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_instruction_is_call_base(Instruction* instruction)
|
||||
EXPORT bool llvm_instruction_is_call_base(llvm::Instruction* instruction)
|
||||
{
|
||||
return isa<CallBase>(instruction);
|
||||
return isa<llvm::CallBase>(instruction);
|
||||
}
|
||||
|
||||
EXPORT void llvm_function_set_attributes(Function& function, BBLLVMAttributeListHandle attribute_list_handle)
|
||||
EXPORT void llvm_function_set_attributes(llvm::Function& function, BBLLVMAttributeListHandle attribute_list_handle)
|
||||
{
|
||||
auto attribute_list = *(AttributeList*)&attribute_list_handle;
|
||||
auto attribute_list = *(llvm::AttributeList*)&attribute_list_handle;
|
||||
function.setAttributes(attribute_list);
|
||||
}
|
||||
|
||||
EXPORT void llvm_call_base_set_attributes(CallBase& call, BBLLVMAttributeListHandle attribute_list_handle)
|
||||
EXPORT void llvm_call_base_set_attributes(llvm::CallBase& call, BBLLVMAttributeListHandle attribute_list_handle)
|
||||
{
|
||||
auto attribute_list = *(AttributeList*)&attribute_list_handle;
|
||||
auto attribute_list = *(llvm::AttributeList*)&attribute_list_handle;
|
||||
call.setAttributes(attribute_list);
|
||||
}
|
||||
|
||||
fn String stream_to_string(raw_string_ostream& stream)
|
||||
fn String stream_to_string(llvm::raw_string_ostream& stream)
|
||||
{
|
||||
// No need to call stream.flush(); because it's string-based
|
||||
stream.flush();
|
||||
@ -933,20 +946,20 @@ fn String stream_to_string(raw_string_ostream& stream)
|
||||
return String{ result, length };
|
||||
}
|
||||
|
||||
EXPORT String llvm_function_to_string(Function& function)
|
||||
EXPORT String llvm_function_to_string(llvm::Function& function)
|
||||
{
|
||||
std::string buffer;
|
||||
raw_string_ostream os(buffer);
|
||||
llvm::raw_string_ostream os(buffer);
|
||||
function.print(os);
|
||||
os.flush();
|
||||
auto result = stream_to_string(os);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_function_verify(Function& function, String* error_message)
|
||||
EXPORT bool llvm_function_verify(llvm::Function& function, String* error_message)
|
||||
{
|
||||
std::string message_buffer;
|
||||
raw_string_ostream message_stream(message_buffer);
|
||||
llvm::raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
bool result = verifyFunction(function, &message_stream);
|
||||
auto size = message_stream.str().size();
|
||||
@ -956,22 +969,22 @@ EXPORT bool llvm_function_verify(Function& function, String* error_message)
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_module_verify(const Module& module, String* error_message)
|
||||
EXPORT bool llvm_module_verify(const llvm::Module& module, String* error_message)
|
||||
{
|
||||
std::string message_buffer;
|
||||
raw_string_ostream message_stream(message_buffer);
|
||||
llvm::raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
bool result = verifyModule(module, &message_stream);
|
||||
bool result = llvm::verifyModule(module, &message_stream);
|
||||
*error_message = stream_to_string(message_stream);
|
||||
|
||||
// We invert the condition because LLVM conventions are just stupid
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT String llvm_module_to_string(Module* module)
|
||||
EXPORT String llvm_module_to_string(llvm::Module* module)
|
||||
{
|
||||
std::string buffer;
|
||||
raw_string_ostream stream(buffer);
|
||||
llvm::raw_string_ostream stream(buffer);
|
||||
module->print(stream, 0);
|
||||
|
||||
return stream_to_string(stream);
|
||||
@ -1000,9 +1013,9 @@ EXPORT String llvm_host_cpu_name()
|
||||
|
||||
EXPORT String llvm_host_cpu_features()
|
||||
{
|
||||
SubtargetFeatures Features;
|
||||
llvm::SubtargetFeatures Features;
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
auto host_cpu_features = sys::getHostCPUFeatures();
|
||||
auto host_cpu_features = llvm::sys::getHostCPUFeatures();
|
||||
#else
|
||||
StringMap<bool> host_cpu_features;
|
||||
if (!sys::getHostCPUFeatures(host_cpu_features)) {
|
||||
@ -1279,50 +1292,50 @@ struct BBLLVMTargetMachineCreate
|
||||
static_assert(sizeof(BBLLVMTargetMachineCreate) == 192);
|
||||
static_assert(BB_LLVM_TARGET_MACHINE_CREATE_PADDING_BYTE_COUNT == 4);
|
||||
|
||||
EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate& create, String* error_message)
|
||||
EXPORT llvm::TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate& create, String* error_message)
|
||||
{
|
||||
std::string error_message_string;
|
||||
const Target* target = TargetRegistry::lookupTarget(string_ref(create.target_triple), error_message_string);
|
||||
const llvm::Target* target = llvm::TargetRegistry::lookupTarget(string_ref(create.target_triple), error_message_string);
|
||||
|
||||
TargetMachine* target_machine;
|
||||
llvm::TargetMachine* target_machine;
|
||||
|
||||
if (target)
|
||||
{
|
||||
std::optional<CodeModel::Model> code_model;
|
||||
std::optional<llvm::CodeModel::Model> code_model;
|
||||
switch (create.code_model)
|
||||
{
|
||||
case BBLLVMCodeModel::none: code_model = std::nullopt; break;
|
||||
case BBLLVMCodeModel::tiny: code_model = CodeModel::Tiny; break;
|
||||
case BBLLVMCodeModel::small: code_model = CodeModel::Small; break;
|
||||
case BBLLVMCodeModel::kernel: code_model = CodeModel::Kernel; break;
|
||||
case BBLLVMCodeModel::medium: code_model = CodeModel::Medium; break;
|
||||
case BBLLVMCodeModel::large: code_model = CodeModel::Large; break;
|
||||
case BBLLVMCodeModel::tiny: code_model = llvm::CodeModel::Tiny; break;
|
||||
case BBLLVMCodeModel::small: code_model = llvm::CodeModel::Small; break;
|
||||
case BBLLVMCodeModel::kernel: code_model = llvm::CodeModel::Kernel; break;
|
||||
case BBLLVMCodeModel::medium: code_model = llvm::CodeModel::Medium; break;
|
||||
case BBLLVMCodeModel::large: code_model = llvm::CodeModel::Large; break;
|
||||
}
|
||||
|
||||
std::optional<Reloc::Model> relocation_model;
|
||||
std::optional<llvm::Reloc::Model> relocation_model;
|
||||
|
||||
switch (create.relocation_model)
|
||||
{
|
||||
case BBLLVMRelocationModel::default_relocation: relocation_model = std::nullopt; break;
|
||||
case BBLLVMRelocationModel::static_relocation: relocation_model = Reloc::Static; break;
|
||||
case BBLLVMRelocationModel::pic: relocation_model = Reloc::PIC_; break;
|
||||
case BBLLVMRelocationModel::dynamic_no_pic: relocation_model = Reloc::DynamicNoPIC; break;
|
||||
case BBLLVMRelocationModel::ropi: relocation_model = Reloc::ROPI; break;
|
||||
case BBLLVMRelocationModel::rwpi: relocation_model = Reloc::RWPI; break;
|
||||
case BBLLVMRelocationModel::ropi_rwpi: relocation_model = Reloc::ROPI_RWPI; break;
|
||||
case BBLLVMRelocationModel::static_relocation: relocation_model = llvm::Reloc::Static; break;
|
||||
case BBLLVMRelocationModel::pic: relocation_model = llvm::Reloc::PIC_; break;
|
||||
case BBLLVMRelocationModel::dynamic_no_pic: relocation_model = llvm::Reloc::DynamicNoPIC; break;
|
||||
case BBLLVMRelocationModel::ropi: relocation_model = llvm::Reloc::ROPI; break;
|
||||
case BBLLVMRelocationModel::rwpi: relocation_model = llvm::Reloc::RWPI; break;
|
||||
case BBLLVMRelocationModel::ropi_rwpi: relocation_model = llvm::Reloc::ROPI_RWPI; break;
|
||||
}
|
||||
|
||||
CodeGenOptLevel optimization_level;
|
||||
llvm::CodeGenOptLevel optimization_level;
|
||||
switch (create.optimization_level)
|
||||
{
|
||||
case BBLLVMCodeGenerationOptimizationLevel::none: optimization_level = CodeGenOptLevel::None; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::less: optimization_level = CodeGenOptLevel::Less; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::normal: optimization_level = CodeGenOptLevel::Default; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::aggressive: optimization_level = CodeGenOptLevel::Aggressive; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::none: optimization_level = llvm::CodeGenOptLevel::None; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::less: optimization_level = llvm::CodeGenOptLevel::Less; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::normal: optimization_level = llvm::CodeGenOptLevel::Default; break;
|
||||
case BBLLVMCodeGenerationOptimizationLevel::aggressive: optimization_level = llvm::CodeGenOptLevel::Aggressive; break;
|
||||
}
|
||||
|
||||
// INFO: This calls the default constructor, so all LLVM defaults are set and we only override what we control
|
||||
TargetOptions target_options;
|
||||
llvm::TargetOptions target_options;
|
||||
|
||||
target_options.UnsafeFPMath = create.target_options.unsafe_fp_math;
|
||||
target_options.NoInfsFPMath = create.target_options.no_infs_fp_math;
|
||||
@ -1341,16 +1354,16 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate
|
||||
auto global_isel_abort_mode = (BBLLVMGlobalISelAbortMode)create.target_options.global_isel_abort_mode;
|
||||
switch (global_isel_abort_mode)
|
||||
{
|
||||
case BBLLVMGlobalISelAbortMode::disable: target_options.GlobalISelAbort = GlobalISelAbortMode::Disable; break;
|
||||
case BBLLVMGlobalISelAbortMode::enable: target_options.GlobalISelAbort = GlobalISelAbortMode::Enable; break;
|
||||
case BBLLVMGlobalISelAbortMode::disable_with_diag: target_options.GlobalISelAbort = GlobalISelAbortMode::DisableWithDiag; break;
|
||||
case BBLLVMGlobalISelAbortMode::disable: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::Disable; break;
|
||||
case BBLLVMGlobalISelAbortMode::enable: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::Enable; break;
|
||||
case BBLLVMGlobalISelAbortMode::disable_with_diag: target_options.GlobalISelAbort = llvm::GlobalISelAbortMode::DisableWithDiag; break;
|
||||
}
|
||||
auto swift_async_frame_pointer = (BBLLVMSwiftAsyncFramePointerMode)create.target_options.swift_async_frame_pointer;
|
||||
switch (swift_async_frame_pointer)
|
||||
{
|
||||
case BBLLVMSwiftAsyncFramePointerMode::deployment_based: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::DeploymentBased; break;
|
||||
case BBLLVMSwiftAsyncFramePointerMode::always: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Always; break;
|
||||
case BBLLVMSwiftAsyncFramePointerMode::never: target_options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Never; break;
|
||||
case BBLLVMSwiftAsyncFramePointerMode::deployment_based: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::DeploymentBased; break;
|
||||
case BBLLVMSwiftAsyncFramePointerMode::always: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::Always; break;
|
||||
case BBLLVMSwiftAsyncFramePointerMode::never: target_options.SwiftAsyncFramePointer = llvm::SwiftAsyncFramePointerMode::Never; break;
|
||||
}
|
||||
|
||||
target_options.UseInitArray = create.target_options.use_init_array;
|
||||
@ -1382,10 +1395,10 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate
|
||||
auto bb_sections = (BBLLVMBasicBlockSection) create.target_options.bb_sections;
|
||||
switch (bb_sections)
|
||||
{
|
||||
case BBLLVMBasicBlockSection::all: target_options.BBSections = BasicBlockSection::All; break;
|
||||
case BBLLVMBasicBlockSection::list: target_options.BBSections = BasicBlockSection::List; break;
|
||||
case BBLLVMBasicBlockSection::preset: target_options.BBSections = BasicBlockSection::Preset; break;
|
||||
case BBLLVMBasicBlockSection::none: target_options.BBSections = BasicBlockSection::None; break;
|
||||
case BBLLVMBasicBlockSection::all: target_options.BBSections = llvm::BasicBlockSection::All; break;
|
||||
case BBLLVMBasicBlockSection::list: target_options.BBSections = llvm::BasicBlockSection::List; break;
|
||||
case BBLLVMBasicBlockSection::preset: target_options.BBSections = llvm::BasicBlockSection::Preset; break;
|
||||
case BBLLVMBasicBlockSection::none: target_options.BBSections = llvm::BasicBlockSection::None; break;
|
||||
}
|
||||
|
||||
target_options.EmitCallSiteInfo = create.target_options.emit_call_site_information;
|
||||
@ -1405,57 +1418,57 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate
|
||||
auto float_abi = (BBLLVMFloatAbi) create.target_options.float_abi;
|
||||
switch (float_abi)
|
||||
{
|
||||
case BBLLVMFloatAbi::normal: target_options.FloatABIType = FloatABI::Default; break;
|
||||
case BBLLVMFloatAbi::soft: target_options.FloatABIType = FloatABI::Soft; break;
|
||||
case BBLLVMFloatAbi::hard: target_options.FloatABIType = FloatABI::Hard; break;
|
||||
case BBLLVMFloatAbi::normal: target_options.FloatABIType = llvm::FloatABI::Default; break;
|
||||
case BBLLVMFloatAbi::soft: target_options.FloatABIType = llvm::FloatABI::Soft; break;
|
||||
case BBLLVMFloatAbi::hard: target_options.FloatABIType = llvm::FloatABI::Hard; break;
|
||||
}
|
||||
|
||||
auto thread_model = (BBLLVMThreadModel) create.target_options.thread_model;
|
||||
switch (thread_model)
|
||||
{
|
||||
case BBLLVMThreadModel::posix: target_options.ThreadModel = ThreadModel::POSIX; break;
|
||||
case BBLLVMThreadModel::single: target_options.ThreadModel = ThreadModel::Single; break;
|
||||
case BBLLVMThreadModel::posix: target_options.ThreadModel = llvm::ThreadModel::POSIX; break;
|
||||
case BBLLVMThreadModel::single: target_options.ThreadModel = llvm::ThreadModel::Single; break;
|
||||
}
|
||||
|
||||
auto fp_op_fusion_mode = (BBLLVMFPOpFusion) create.target_options.fp_op_fusion_mode;
|
||||
switch (fp_op_fusion_mode)
|
||||
{
|
||||
case BBLLVMFPOpFusion::fast: target_options.AllowFPOpFusion = FPOpFusion::Fast; break;
|
||||
case BBLLVMFPOpFusion::standard: target_options.AllowFPOpFusion = FPOpFusion::Standard; break;
|
||||
case BBLLVMFPOpFusion::strict: target_options.AllowFPOpFusion = FPOpFusion::Strict; break;
|
||||
case BBLLVMFPOpFusion::fast: target_options.AllowFPOpFusion = llvm::FPOpFusion::Fast; break;
|
||||
case BBLLVMFPOpFusion::standard: target_options.AllowFPOpFusion = llvm::FPOpFusion::Standard; break;
|
||||
case BBLLVMFPOpFusion::strict: target_options.AllowFPOpFusion = llvm::FPOpFusion::Strict; break;
|
||||
}
|
||||
|
||||
auto eabi_version = (BBLLVMEAbi) create.target_options.eabi_version;
|
||||
switch (eabi_version)
|
||||
{
|
||||
case BBLLVMEAbi::unknown: target_options.EABIVersion = EABI::Unknown; break;
|
||||
case BBLLVMEAbi::normal: target_options.EABIVersion = EABI::Default; break;
|
||||
case BBLLVMEAbi::eabi4: target_options.EABIVersion = EABI::EABI4; break;
|
||||
case BBLLVMEAbi::eabi5: target_options.EABIVersion = EABI::EABI5; break;
|
||||
case BBLLVMEAbi::gnu: target_options.EABIVersion = EABI::GNU; break;
|
||||
case BBLLVMEAbi::unknown: target_options.EABIVersion = llvm::EABI::Unknown; break;
|
||||
case BBLLVMEAbi::normal: target_options.EABIVersion = llvm::EABI::Default; break;
|
||||
case BBLLVMEAbi::eabi4: target_options.EABIVersion = llvm::EABI::EABI4; break;
|
||||
case BBLLVMEAbi::eabi5: target_options.EABIVersion = llvm::EABI::EABI5; break;
|
||||
case BBLLVMEAbi::gnu: target_options.EABIVersion = llvm::EABI::GNU; break;
|
||||
}
|
||||
|
||||
auto debugger_kind = (BBLLVMDebuggerKind) create.target_options.debugger_kind;
|
||||
switch (debugger_kind)
|
||||
{
|
||||
case BBLLVMDebuggerKind::normal: target_options.DebuggerTuning = DebuggerKind::Default; break;
|
||||
case BBLLVMDebuggerKind::gdb: target_options.DebuggerTuning = DebuggerKind::GDB; break;
|
||||
case BBLLVMDebuggerKind::lldb: target_options.DebuggerTuning = DebuggerKind::LLDB; break;
|
||||
case BBLLVMDebuggerKind::sce: target_options.DebuggerTuning = DebuggerKind::SCE; break;
|
||||
case BBLLVMDebuggerKind::dbx: target_options.DebuggerTuning = DebuggerKind::DBX; break;
|
||||
case BBLLVMDebuggerKind::normal: target_options.DebuggerTuning = llvm::DebuggerKind::Default; break;
|
||||
case BBLLVMDebuggerKind::gdb: target_options.DebuggerTuning = llvm::DebuggerKind::GDB; break;
|
||||
case BBLLVMDebuggerKind::lldb: target_options.DebuggerTuning = llvm::DebuggerKind::LLDB; break;
|
||||
case BBLLVMDebuggerKind::sce: target_options.DebuggerTuning = llvm::DebuggerKind::SCE; break;
|
||||
case BBLLVMDebuggerKind::dbx: target_options.DebuggerTuning = llvm::DebuggerKind::DBX; break;
|
||||
}
|
||||
|
||||
auto exception_handling = (BBLLVMExceptionHandling) create.target_options.exception_handling;
|
||||
switch (exception_handling)
|
||||
{
|
||||
case BBLLVMExceptionHandling::none: target_options.ExceptionModel = ExceptionHandling::None; break;
|
||||
case BBLLVMExceptionHandling::dwarf_cfi: target_options.ExceptionModel = ExceptionHandling::DwarfCFI; break;
|
||||
case BBLLVMExceptionHandling::setjmp_longjmp: target_options.ExceptionModel = ExceptionHandling::SjLj; break;
|
||||
case BBLLVMExceptionHandling::arm: target_options.ExceptionModel = ExceptionHandling::ARM; break;
|
||||
case BBLLVMExceptionHandling::win_eh: target_options.ExceptionModel = ExceptionHandling::WinEH; break;
|
||||
case BBLLVMExceptionHandling::wasm: target_options.ExceptionModel = ExceptionHandling::Wasm; break;
|
||||
case BBLLVMExceptionHandling::aix: target_options.ExceptionModel = ExceptionHandling::AIX; break;
|
||||
case BBLLVMExceptionHandling::zos: target_options.ExceptionModel = ExceptionHandling::ZOS; break;
|
||||
case BBLLVMExceptionHandling::none: target_options.ExceptionModel = llvm::ExceptionHandling::None; break;
|
||||
case BBLLVMExceptionHandling::dwarf_cfi: target_options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI; break;
|
||||
case BBLLVMExceptionHandling::setjmp_longjmp: target_options.ExceptionModel = llvm::ExceptionHandling::SjLj; break;
|
||||
case BBLLVMExceptionHandling::arm: target_options.ExceptionModel = llvm::ExceptionHandling::ARM; break;
|
||||
case BBLLVMExceptionHandling::win_eh: target_options.ExceptionModel = llvm::ExceptionHandling::WinEH; break;
|
||||
case BBLLVMExceptionHandling::wasm: target_options.ExceptionModel = llvm::ExceptionHandling::Wasm; break;
|
||||
case BBLLVMExceptionHandling::aix: target_options.ExceptionModel = llvm::ExceptionHandling::AIX; break;
|
||||
case BBLLVMExceptionHandling::zos: target_options.ExceptionModel = llvm::ExceptionHandling::ZOS; break;
|
||||
}
|
||||
|
||||
target_options.LoopAlignment = create.target_options.loop_alignment;
|
||||
@ -1520,26 +1533,26 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate
|
||||
auto emit_dwarf_unwind = (BBLLVMEmitDwarfUnwindType) create.target_options.mc.emit_dwarf_unwind;
|
||||
switch (emit_dwarf_unwind)
|
||||
{
|
||||
case BBLLVMEmitDwarfUnwindType::always: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always; break;
|
||||
case BBLLVMEmitDwarfUnwindType::no_compact_unwind: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::NoCompactUnwind; break;
|
||||
case BBLLVMEmitDwarfUnwindType::normal: target_options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Default; break;
|
||||
case BBLLVMEmitDwarfUnwindType::always: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::Always; break;
|
||||
case BBLLVMEmitDwarfUnwindType::no_compact_unwind: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::NoCompactUnwind; break;
|
||||
case BBLLVMEmitDwarfUnwindType::normal: target_options.MCOptions.EmitDwarfUnwind = llvm::EmitDwarfUnwindType::Default; break;
|
||||
}
|
||||
|
||||
auto use_dwarf_directory = (BBLLVMDwarfDirectory) create.target_options.mc.use_dwarf_directory;
|
||||
switch (use_dwarf_directory)
|
||||
{
|
||||
case BBLLVMDwarfDirectory::disable: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::DisableDwarfDirectory; break;
|
||||
case BBLLVMDwarfDirectory::enable: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::EnableDwarfDirectory; break;
|
||||
case BBLLVMDwarfDirectory::normal: target_options.MCOptions.MCUseDwarfDirectory = MCTargetOptions::DwarfDirectory::DefaultDwarfDirectory; break;
|
||||
case BBLLVMDwarfDirectory::disable: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::DisableDwarfDirectory; break;
|
||||
case BBLLVMDwarfDirectory::enable: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::EnableDwarfDirectory; break;
|
||||
case BBLLVMDwarfDirectory::normal: target_options.MCOptions.MCUseDwarfDirectory = llvm::MCTargetOptions::DwarfDirectory::DefaultDwarfDirectory; break;
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
auto debug_compression_type = (BBLLVMDebugCompressionType) create.target_options.mc.debug_compression_type;
|
||||
switch (debug_compression_type)
|
||||
{
|
||||
case BBLLVMDebugCompressionType::none: target_options.MCOptions.CompressDebugSections = DebugCompressionType::None; break;
|
||||
case BBLLVMDebugCompressionType::zlib: target_options.MCOptions.CompressDebugSections = DebugCompressionType::Zlib; break;
|
||||
case BBLLVMDebugCompressionType::zstd: target_options.MCOptions.CompressDebugSections = DebugCompressionType::Zstd; break;
|
||||
case BBLLVMDebugCompressionType::none: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::None; break;
|
||||
case BBLLVMDebugCompressionType::zlib: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::Zlib; break;
|
||||
case BBLLVMDebugCompressionType::zstd: target_options.MCOptions.CompressDebugSections = llvm::DebugCompressionType::Zstd; break;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1562,11 +1575,11 @@ EXPORT TargetMachine* llvm_create_target_machine(const BBLLVMTargetMachineCreate
|
||||
return target_machine;
|
||||
}
|
||||
|
||||
EXPORT void llvm_module_set_target(Module& module, TargetMachine& target_machine)
|
||||
EXPORT void llvm_module_set_target(llvm::Module& module, llvm::TargetMachine& target_machine)
|
||||
{
|
||||
module.setDataLayout(target_machine.createDataLayout());
|
||||
auto& triple_string = target_machine.getTargetTriple().getTriple();
|
||||
module.setTargetTriple(StringRef(triple_string));
|
||||
module.setTargetTriple(llvm::StringRef(triple_string));
|
||||
}
|
||||
|
||||
enum class BBLLVMOptimizationLevel : u8
|
||||
@ -1599,12 +1612,12 @@ struct BBLLVMOptimizationPipelineOptions
|
||||
static_assert(sizeof(BBLLVMOptimizationPipelineOptions) == sizeof(u64));
|
||||
static_assert(BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT == 51);
|
||||
|
||||
EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine& target_machine, BBLLVMOptimizationPipelineOptions options)
|
||||
EXPORT void llvm_module_run_optimization_pipeline(llvm::Module& module, llvm::TargetMachine& target_machine, BBLLVMOptimizationPipelineOptions options)
|
||||
{
|
||||
// TODO: PGO
|
||||
// TODO: CS profile
|
||||
|
||||
PipelineTuningOptions pipeline_tuning_options;
|
||||
llvm::PipelineTuningOptions pipeline_tuning_options;
|
||||
pipeline_tuning_options.LoopUnrolling = options.loop_unrolling;
|
||||
pipeline_tuning_options.LoopInterleaving = options.loop_interleaving;
|
||||
pipeline_tuning_options.LoopVectorization = options.loop_vectorization;
|
||||
@ -1615,24 +1628,24 @@ EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine&
|
||||
|
||||
// TODO: instrumentation
|
||||
|
||||
LoopAnalysisManager loop_analysis_manager;
|
||||
FunctionAnalysisManager function_analysis_manager;
|
||||
CGSCCAnalysisManager cgscc_analysis_manager;
|
||||
ModuleAnalysisManager module_analysis_manager;
|
||||
llvm::LoopAnalysisManager loop_analysis_manager;
|
||||
llvm::FunctionAnalysisManager function_analysis_manager;
|
||||
llvm::CGSCCAnalysisManager cgscc_analysis_manager;
|
||||
llvm::ModuleAnalysisManager module_analysis_manager;
|
||||
|
||||
PassBuilder pass_builder(&target_machine, pipeline_tuning_options);
|
||||
llvm::PassBuilder pass_builder(&target_machine, pipeline_tuning_options);
|
||||
|
||||
if (options.assignment_tracking && options.debug_info != 0)
|
||||
{
|
||||
pass_builder.registerPipelineStartEPCallback([&](ModulePassManager& MPM, OptimizationLevel Level) {
|
||||
MPM.addPass(AssignmentTrackingPass());
|
||||
pass_builder.registerPipelineStartEPCallback([&](llvm::ModulePassManager& MPM, llvm::OptimizationLevel Level) {
|
||||
MPM.addPass(llvm::AssignmentTrackingPass());
|
||||
});
|
||||
}
|
||||
|
||||
Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718
|
||||
llvm::Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718
|
||||
// TODO: add library (?)
|
||||
std::unique_ptr<TargetLibraryInfoImpl> TLII(llvm::driver::createTLII(target_triple, driver::VectorLibrary::NoLibrary));
|
||||
function_analysis_manager.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
|
||||
std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII(llvm::driver::createTLII(target_triple, llvm::driver::VectorLibrary::NoLibrary));
|
||||
function_analysis_manager.registerPass([&] { return llvm::TargetLibraryAnalysis(*TLII); });
|
||||
|
||||
pass_builder.registerModuleAnalyses(module_analysis_manager);
|
||||
pass_builder.registerCGSCCAnalyses(cgscc_analysis_manager);
|
||||
@ -1640,25 +1653,25 @@ EXPORT void llvm_module_run_optimization_pipeline(Module& module, TargetMachine&
|
||||
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;
|
||||
llvm::ModulePassManager module_pass_manager;
|
||||
|
||||
if (options.verify_module)
|
||||
{
|
||||
module_pass_manager.addPass(VerifierPass());
|
||||
module_pass_manager.addPass(llvm::VerifierPass());
|
||||
}
|
||||
|
||||
bool thin_lto = false;
|
||||
bool lto = false;
|
||||
|
||||
OptimizationLevel optimization_level;
|
||||
llvm::OptimizationLevel optimization_level;
|
||||
switch ((BBLLVMOptimizationLevel)options.optimization_level)
|
||||
{
|
||||
case BBLLVMOptimizationLevel::O0: optimization_level = OptimizationLevel::O0; break;
|
||||
case BBLLVMOptimizationLevel::O1: optimization_level = OptimizationLevel::O1; break;
|
||||
case BBLLVMOptimizationLevel::O2: optimization_level = OptimizationLevel::O2; break;
|
||||
case BBLLVMOptimizationLevel::O3: optimization_level = OptimizationLevel::O3; break;
|
||||
case BBLLVMOptimizationLevel::Os: optimization_level = OptimizationLevel::Os; break;
|
||||
case BBLLVMOptimizationLevel::Oz: optimization_level = OptimizationLevel::Oz; break;
|
||||
case BBLLVMOptimizationLevel::O0: optimization_level = llvm::OptimizationLevel::O0; break;
|
||||
case BBLLVMOptimizationLevel::O1: optimization_level = llvm::OptimizationLevel::O1; break;
|
||||
case BBLLVMOptimizationLevel::O2: optimization_level = llvm::OptimizationLevel::O2; break;
|
||||
case BBLLVMOptimizationLevel::O3: optimization_level = llvm::OptimizationLevel::O3; break;
|
||||
case BBLLVMOptimizationLevel::Os: optimization_level = llvm::OptimizationLevel::Os; break;
|
||||
case BBLLVMOptimizationLevel::Oz: optimization_level = llvm::OptimizationLevel::Oz; break;
|
||||
}
|
||||
|
||||
// TODO: thin lto post-link
|
||||
@ -1707,12 +1720,12 @@ enum class BBLLVMCodeGenerationPipelineResult : u8
|
||||
failed_to_add_emit_passes = 2,
|
||||
};
|
||||
|
||||
EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(Module& module, TargetMachine& target_machine, BBLLVMCodeGenerationPipelineOptions options)
|
||||
EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(llvm::Module& module, llvm::TargetMachine& target_machine, BBLLVMCodeGenerationPipelineOptions options)
|
||||
{
|
||||
// We still use the legacy PM to run the codegen pipeline since the new PM
|
||||
// does not work with the codegen pipeline.
|
||||
// FIXME: make the new PM work with the codegen pipeline.
|
||||
legacy::PassManager CodeGenPasses;
|
||||
llvm::legacy::PassManager CodeGenPasses;
|
||||
#if LLVM_VERSION_MAJOR >= 19
|
||||
if (options.optimize_when_possible)
|
||||
{
|
||||
@ -1720,7 +1733,7 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli
|
||||
}
|
||||
#endif
|
||||
|
||||
raw_pwrite_stream* dwarf_object_file = 0;
|
||||
llvm::raw_pwrite_stream* dwarf_object_file = 0;
|
||||
if (options.output_dwarf_file_path.length)
|
||||
{
|
||||
__builtin_trap();
|
||||
@ -1728,19 +1741,19 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli
|
||||
|
||||
if (options.optimize_when_possible)
|
||||
{
|
||||
Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718
|
||||
llvm::Triple target_triple = target_machine.getTargetTriple(); // Need to make a copy, incoming bugfix: https://github.com/llvm/llvm-project/pull/127718
|
||||
// TODO: add library (?)
|
||||
std::unique_ptr<TargetLibraryInfoImpl> TLII(llvm::driver::createTLII(target_triple, driver::VectorLibrary::NoLibrary));
|
||||
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(*TLII));
|
||||
std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII(llvm::driver::createTLII(target_triple, llvm::driver::VectorLibrary::NoLibrary));
|
||||
CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII));
|
||||
}
|
||||
|
||||
std::unique_ptr<raw_pwrite_stream> stream;
|
||||
std::unique_ptr<llvm::raw_pwrite_stream> stream;
|
||||
|
||||
if (options.output_file_path.length)
|
||||
{
|
||||
std::error_code error_code;
|
||||
|
||||
stream = std::make_unique<llvm::raw_fd_ostream>(string_ref(options.output_file_path), error_code, sys::fs::OF_None);
|
||||
stream = std::make_unique<llvm::raw_fd_ostream>(string_ref(options.output_file_path), error_code, llvm::sys::fs::OF_None);
|
||||
|
||||
if (error_code)
|
||||
{
|
||||
@ -1752,12 +1765,12 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli
|
||||
stream = std::make_unique<llvm::raw_null_ostream>();
|
||||
}
|
||||
|
||||
CodeGenFileType file_type;
|
||||
llvm::CodeGenFileType file_type;
|
||||
switch ((BBLLVMCodeGenerationFileType)options.code_generation_file_type)
|
||||
{
|
||||
case BBLLVMCodeGenerationFileType::assembly_file: file_type = CodeGenFileType::AssemblyFile; break;
|
||||
case BBLLVMCodeGenerationFileType::object_file: file_type = CodeGenFileType::ObjectFile; break;
|
||||
case BBLLVMCodeGenerationFileType::null: file_type = CodeGenFileType::Null; break;
|
||||
case BBLLVMCodeGenerationFileType::assembly_file: file_type = llvm::CodeGenFileType::AssemblyFile; break;
|
||||
case BBLLVMCodeGenerationFileType::object_file: file_type = llvm::CodeGenFileType::ObjectFile; break;
|
||||
case BBLLVMCodeGenerationFileType::null: file_type = llvm::CodeGenFileType::Null; break;
|
||||
}
|
||||
|
||||
auto disable_verify = !options.verify_module;
|
||||
|
270
src/llvm.h
270
src/llvm.h
@ -1,10 +1,241 @@
|
||||
#include <lib.h>
|
||||
#pragma once
|
||||
|
||||
namespace llvm
|
||||
#include <compiler.h>
|
||||
|
||||
enum class DwarfEmissionKind
|
||||
{
|
||||
class Type;
|
||||
class Value;
|
||||
}
|
||||
none,
|
||||
full,
|
||||
line_tables_only,
|
||||
};
|
||||
|
||||
enum class DwarfSourceLanguage
|
||||
{
|
||||
C89,
|
||||
C,
|
||||
Ada83,
|
||||
C_plus_plus,
|
||||
Cobol74,
|
||||
Cobol85,
|
||||
Fortran77,
|
||||
Fortran90,
|
||||
Pascal83,
|
||||
Modula2,
|
||||
// New in DWARF v3:
|
||||
Java,
|
||||
C99,
|
||||
Ada95,
|
||||
Fortran95,
|
||||
PLI,
|
||||
ObjC,
|
||||
ObjC_plus_plus,
|
||||
UPC,
|
||||
D,
|
||||
// New in DWARF v4:
|
||||
Python,
|
||||
// New in DWARF v5:
|
||||
OpenCL,
|
||||
Go,
|
||||
Modula3,
|
||||
Haskell,
|
||||
C_plus_plus_03,
|
||||
C_plus_plus_11,
|
||||
OCaml,
|
||||
Rust,
|
||||
C11,
|
||||
Swift,
|
||||
Julia,
|
||||
Dylan,
|
||||
C_plus_plus_14,
|
||||
Fortran03,
|
||||
Fortran08,
|
||||
RenderScript,
|
||||
BLISS,
|
||||
Kotlin,
|
||||
Zig,
|
||||
Crystal,
|
||||
C_plus_plus_17,
|
||||
C_plus_plus_20,
|
||||
C17,
|
||||
Fortran18,
|
||||
Ada2005,
|
||||
Ada2012,
|
||||
HIP,
|
||||
Assembly,
|
||||
C_sharp,
|
||||
Mojo,
|
||||
GLSL,
|
||||
GLSL_ES,
|
||||
HLSL,
|
||||
OpenCL_CPP,
|
||||
CPP_for_OpenCL,
|
||||
SYCL,
|
||||
Ruby,
|
||||
Move,
|
||||
Hylo,
|
||||
|
||||
// Vendor extensions:
|
||||
Mips_Assembler,
|
||||
GOOGLE_RenderScript,
|
||||
BORLAND_Delphi,
|
||||
};
|
||||
|
||||
enum class DwarfType
|
||||
{
|
||||
void_type = 0x0,
|
||||
address = 0x1,
|
||||
boolean = 0x2,
|
||||
complex_float = 0x3,
|
||||
float_type = 0x4,
|
||||
signed_type = 0x5,
|
||||
signed_char = 0x6,
|
||||
unsigned_type = 0x7,
|
||||
unsigned_char = 0x8,
|
||||
|
||||
// DWARF 3.
|
||||
imaginary_float = 0x9,
|
||||
packed_decimal = 0xa,
|
||||
numeric_string = 0xb,
|
||||
edited = 0xc,
|
||||
signed_fixed = 0xd,
|
||||
unsigned_fixed = 0xe,
|
||||
decimal_float = 0xf,
|
||||
|
||||
// DWARF 4.
|
||||
UTF = 0x10,
|
||||
|
||||
// DWARF 5.
|
||||
UCS = 0x11,
|
||||
ASCII = 0x12,
|
||||
|
||||
// HP extensions.
|
||||
HP_float80 = 0x80, // Floating-point (80 bit).
|
||||
HP_complex_float80 = 0x81, // Complex floating-point (80 bit).
|
||||
HP_float128 = 0x82, // Floating-point (128 bit).
|
||||
HP_complex_float128 = 0x83, // Complex fp (128 bit).
|
||||
HP_floathpintel = 0x84, // Floating-point (82 bit IA64).
|
||||
HP_imaginary_float80 = 0x85,
|
||||
HP_imaginary_float128 = 0x86,
|
||||
HP_VAX_float = 0x88, // F or G floating.
|
||||
HP_VAX_float_d = 0x89, // D floating.
|
||||
HP_packed_decimal = 0x8a, // Cobol.
|
||||
HP_zoned_decimal = 0x8b, // Cobol.
|
||||
HP_edited = 0x8c, // Cobol.
|
||||
HP_signed_fixed = 0x8d, // Cobol.
|
||||
HP_unsigned_fixed = 0x8e, // Cobol.
|
||||
HP_VAX_complex_float = 0x8f, // F or G floating complex.
|
||||
HP_VAX_complex_float_d = 0x90, // D floating complex.
|
||||
};
|
||||
|
||||
enum class DIFlagsVisibility : u32
|
||||
{
|
||||
none = 0,
|
||||
private_ = 1,
|
||||
protected_ = 2,
|
||||
public_ = 3,
|
||||
};
|
||||
|
||||
enum class DIFlagsInheritance : u32
|
||||
{
|
||||
none = 0,
|
||||
single_ = 1,
|
||||
multiple_ = 2,
|
||||
virtual_ = 3,
|
||||
};
|
||||
|
||||
struct DIFlags
|
||||
{
|
||||
DIFlagsVisibility visibility:2;
|
||||
u32 forward_declaration:1;
|
||||
u32 apple_block:1;
|
||||
u32 block_by_ref_struct:1;
|
||||
u32 virtual_:1;
|
||||
u32 artificial:1;
|
||||
u32 explicit_:1;
|
||||
u32 prototyped:1;
|
||||
u32 objective_c_class_complete:1;
|
||||
u32 object_pointer:1;
|
||||
u32 vector:1;
|
||||
u32 static_member:1;
|
||||
u32 lvalue_reference:1;
|
||||
u32 rvalue_reference:1;
|
||||
u32 reserved:1;
|
||||
DIFlagsInheritance inheritance:2;
|
||||
u32 introduced_virtual:1;
|
||||
u32 bit_field:1;
|
||||
u32 no_return:1;
|
||||
u32 type_pass_by_value:1;
|
||||
u32 type_pass_by_reference:1;
|
||||
u32 enum_class:1;
|
||||
u32 thunk:1;
|
||||
u32 non_trivial:1;
|
||||
u32 big_endian:1;
|
||||
u32 little_endian:1;
|
||||
u32 all_calls_described:1;
|
||||
u32 _:3;
|
||||
};
|
||||
|
||||
static_assert(sizeof(DIFlags) == sizeof(u32));
|
||||
|
||||
enum class LinkageType : u32
|
||||
{
|
||||
external,
|
||||
available_externally,
|
||||
link_once_any,
|
||||
link_once_odr,
|
||||
weak_any,
|
||||
weak_odr,
|
||||
appending,
|
||||
internal,
|
||||
private_,
|
||||
external_weak,
|
||||
common,
|
||||
};
|
||||
|
||||
enum class LLVMCallingConvention : u32
|
||||
{
|
||||
c = 0,
|
||||
fast = 8,
|
||||
cold = 9,
|
||||
ghc = 10,
|
||||
hipe = 11,
|
||||
anyreg = 13,
|
||||
preserve_most = 14,
|
||||
preserve_all = 15,
|
||||
swift = 16,
|
||||
cxx_fast_tls = 17,
|
||||
x86_stdcall = 64,
|
||||
x86_fastcall = 65,
|
||||
arm_apcs = 66,
|
||||
arm_aapcs = 67,
|
||||
arm_aapcsvfp = 68,
|
||||
msp430_interrupt = 69,
|
||||
x86_thiscall = 70,
|
||||
ptx_kernel = 71,
|
||||
ptx_device = 72,
|
||||
spir_func = 75,
|
||||
spir_kernel = 76,
|
||||
intel_oclbi = 77,
|
||||
x86_64_system_v = 78,
|
||||
win64 = 79,
|
||||
x86_vector = 80,
|
||||
hhvm = 81,
|
||||
hhvmc = 82,
|
||||
x86_interrupt = 83,
|
||||
avr_interrupt = 84,
|
||||
avr_signal = 85,
|
||||
avr_builtin = 86,
|
||||
amdgpu_vs = 87,
|
||||
amdgpu_gs = 88,
|
||||
amdgpu_ps = 89,
|
||||
amdgpu_cs = 90,
|
||||
amdgpu_kernel = 91,
|
||||
x86_regcall = 92,
|
||||
amdgpu_hs = 93,
|
||||
msp430_builtin = 94,
|
||||
amgpu_ls = 95,
|
||||
amdgpu_es = 96,
|
||||
};
|
||||
|
||||
fn bool llvm_initialized = false;
|
||||
|
||||
@ -19,6 +250,24 @@ extern "C" String llvm_default_target_triple();
|
||||
extern "C" String llvm_host_cpu_name();
|
||||
extern "C" String llvm_host_cpu_features();
|
||||
|
||||
extern "C" llvm::LLVMContext* LLVMContextCreate();
|
||||
extern "C" llvm::Module* llvm_context_create_module(llvm::LLVMContext* context, String name);
|
||||
extern "C" llvm::Builder* LLVMCreateBuilderInContext(llvm::LLVMContext* context);
|
||||
extern "C" llvm::Type* LLVMVoidTypeInContext(llvm::LLVMContext* context);
|
||||
extern "C" llvm::Type* LLVMIntTypeInContext(llvm::LLVMContext* context, u32 bit_count);
|
||||
extern "C" llvm::Type* LLVMPointerTypeInContext(llvm::LLVMContext* context);
|
||||
extern "C" llvm::FunctionType* LLVMFunctionType(llvm::Type* return_type, llvm::Type** parameter_type_pointer, u32 parameter_type_count, int is_var_args);
|
||||
extern "C" LLVMIntrinsicId LLVMLookupIntrinsicID(const u8* name_pointer, u64 name_length);
|
||||
|
||||
extern "C" llvm::Function* llvm_module_create_function(llvm::Module* module, llvm::FunctionType* function_type, LinkageType linkage_type, unsigned address_space, String name);
|
||||
extern "C" void LLVMSetFunctionCallConv(llvm::Function* function, LLVMCallingConvention calling_convention);
|
||||
|
||||
extern "C" llvm::DIBuilder* LLVMCreateDIBuilder(llvm::Module* module);
|
||||
extern "C" llvm::DIFile* LLVMDIBuilderCreateFile(llvm::DIBuilder* builder, const u8* file_name_pointer, u64 file_name_length, const u8* directory_name_pointer, u64 directory_name_length);
|
||||
extern "C" llvm::DICompileUnit* LLVMDIBuilderCreateCompileUnit(llvm::DIBuilder* builder, DwarfSourceLanguage dwarf_source_language, llvm::DIFile* file, const u8* producer_name_pointer, u64 producer_name_length, int is_optimized, const u8* flag_pointer, u64 flag_length, unsigned runtime_version, const u8* split_name_pointer, u64 split_name_length, DwarfEmissionKind emission_kind, unsigned debug_with_offset_id, int split_debug_inlining, int debug_info_for_profiling, const u8* sysroot_name_pointer, u64 sysroot_name_length, const u8* sdk_name_pointer, u64 sdk_name_length);
|
||||
extern "C" llvm::DIType* LLVMDIBuilderCreateBasicType(llvm::DIBuilder* builder, const u8* name_pointer, u64 name_length, u64 bit_count, DwarfType dwarf_type, DIFlags flags);
|
||||
extern "C" llvm::DISubroutineType* LLVMDIBuilderCreateSubroutineType(llvm::DIBuilder* builder, llvm::DIFile* file, llvm::DIType** parameter_type_pointer, u32 parameter_type_count, DIFlags flags);
|
||||
|
||||
struct LLVMGlobal
|
||||
{
|
||||
String host_triple;
|
||||
@ -28,9 +277,10 @@ struct LLVMGlobal
|
||||
|
||||
global_variable LLVMGlobal llvm_global;
|
||||
|
||||
fn void initialize_all()
|
||||
fn void llvm_initialize_all_raw()
|
||||
{
|
||||
assert(!llvm_initialized);
|
||||
|
||||
LLVMInitializeX86TargetInfo();
|
||||
LLVMInitializeX86Target();
|
||||
LLVMInitializeX86TargetMC();
|
||||
@ -44,3 +294,11 @@ fn void initialize_all()
|
||||
.host_cpu_features = llvm_host_cpu_features(),
|
||||
};
|
||||
}
|
||||
|
||||
fn void llvm_initialize_all()
|
||||
{
|
||||
if (!llvm_initialized)
|
||||
{
|
||||
llvm_initialize_all_raw();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user