Use roc_target over target_lexicon

Tailors a target class for our needs.
Replaces tons of uses across the entire compiler.
This is a base for later adding new targets like thumb.
This commit is contained in:
Brendan Hansknecht 2024-03-21 21:54:58 -07:00
parent 185262510c
commit 6dc5bfb1b7
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
72 changed files with 1008 additions and 1371 deletions

View file

@ -52,10 +52,9 @@ use roc_mono::layout::{
RawFunctionLayout, STLayoutInterner, TagIdIntType, UnionLayout,
};
use roc_std::RocDec;
use roc_target::{PtrWidth, TargetInfo};
use roc_target::{PtrWidth, Target};
use std::convert::TryInto;
use std::path::Path;
use target_lexicon::{Aarch64Architecture, Architecture, OperatingSystem, Triple};
use super::convert::{struct_type_from_union_layout, RocUnion};
use super::intrinsics::{
@ -737,7 +736,7 @@ pub struct Env<'a, 'ctx, 'env> {
pub compile_unit: &'env DICompileUnit<'ctx>,
pub module: &'ctx Module<'ctx>,
pub interns: Interns,
pub target_info: TargetInfo,
pub target: Target,
pub mode: LlvmBackendMode,
pub exposed_to_host: MutSet<Symbol>,
}
@ -750,7 +749,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
pub fn ptr_int(&self) -> IntType<'ctx> {
let ctx = self.context;
match self.target_info.ptr_width() {
match self.target.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i32_type(),
roc_target::PtrWidth::Bytes8 => ctx.i64_type(),
}
@ -763,14 +762,14 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
pub fn twice_ptr_int(&self) -> IntType<'ctx> {
let ctx = self.context;
match self.target_info.ptr_width() {
match self.target.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i64_type(),
roc_target::PtrWidth::Bytes8 => ctx.i128_type(),
}
}
pub fn small_str_bytes(&self) -> u32 {
self.target_info.ptr_width() as u32 * 3
self.target.ptr_width() as u32 * 3
}
pub fn build_intrinsic_call(
@ -872,7 +871,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
) -> CallSiteValue<'ctx> {
let false_val = self.context.bool_type().const_int(0, false);
let intrinsic_name = match self.target_info.ptr_width() {
let intrinsic_name = match self.target.ptr_width() {
roc_target::PtrWidth::Bytes8 => LLVM_MEMSET_I64,
roc_target::PtrWidth::Bytes4 => LLVM_MEMSET_I32,
};
@ -932,7 +931,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
env: &Env<'a, 'ctx, 'env>,
string: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
match env.target_info.ptr_width() {
match env.target.ptr_width() {
PtrWidth::Bytes4 => {
// we need to pass the string by reference, but we currently hold the value.
let alloca = env
@ -1011,48 +1010,29 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
}
pub fn module_from_builtins<'ctx>(
target: &target_lexicon::Triple,
target: Target,
ctx: &'ctx Context,
module_name: &str,
) -> Module<'ctx> {
// In the build script for the builtins module, we compile the builtins into LLVM bitcode
let bitcode_bytes: &[u8] = if target == &target_lexicon::Triple::host() {
let bitcode_bytes: &[u8] = if target == target_lexicon::Triple::host().into() {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-host.bc")
} else {
match target {
Triple {
architecture: Architecture::Wasm32,
..
} => {
Target::Wasm32 => {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-wasm32.bc")
}
Triple {
architecture: Architecture::X86_32(_),
operating_system: OperatingSystem::Linux,
..
} => {
Target::LinuxX32 => {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-x86.bc")
}
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Linux,
..
} => {
Target::LinuxX64 => {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-x86_64.bc")
}
Triple {
architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64),
operating_system: OperatingSystem::Linux,
..
} => {
Target::LinuxArm64 => {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-aarch64.bc")
}
Triple {
architecture: Architecture::X86_64,
operating_system: OperatingSystem::Windows,
..
} => {
Target::WinX64 => {
include_bytes!("../../../builtins/bitcode/zig-out/builtins-windows-x86_64.bc")
}
_ => panic!("The zig builtins are not currently built for this target: {target:?}"),
@ -1416,7 +1396,7 @@ fn build_string_literal<'ctx>(
let alloca = const_str_alloca_ptr(env, parent, ptr, number_of_elements, number_of_elements);
match env.target_info.ptr_width() {
match env.target.ptr_width() {
PtrWidth::Bytes4 => {
env.builder
.new_build_load(zig_str_type(env), alloca, "load_const_str")
@ -1449,7 +1429,7 @@ fn small_str_ptr_width_8<'ctx>(
parent: FunctionValue<'ctx>,
str_literal: &str,
) -> PointerValue<'ctx> {
debug_assert_eq!(env.target_info.ptr_width() as u8, 8);
debug_assert_eq!(env.target.ptr_width() as u8, 8);
let mut array = [0u8; 24];
@ -1473,7 +1453,7 @@ fn small_str_ptr_width_8<'ctx>(
}
fn small_str_ptr_width_4<'ctx>(env: &Env<'_, 'ctx, '_>, str_literal: &str) -> StructValue<'ctx> {
debug_assert_eq!(env.target_info.ptr_width() as u8, 4);
debug_assert_eq!(env.target.ptr_width() as u8, 4);
let mut array = [0u8; 12];
@ -1779,7 +1759,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
let refcount_ptr = PointerToRefcount::from_ptr_to_data(
env,
if union_layout.stores_tag_id_in_pointer(env.target_info) {
if union_layout.stores_tag_id_in_pointer(env.target) {
tag_pointer_clear_tag_id(env, tag_ptr)
} else {
tag_ptr
@ -1876,7 +1856,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
let refcount_ptr = PointerToRefcount::from_ptr_to_data(
env,
if union_layout.stores_tag_id_in_pointer(env.target_info) {
if union_layout.stores_tag_id_in_pointer(env.target) {
tag_pointer_clear_tag_id(env, tag_ptr)
} else {
tag_ptr
@ -2261,7 +2241,7 @@ fn build_wrapped_tag<'a, 'ctx>(
);
let struct_type = env.context.struct_type(&field_types, false);
if union_layout.stores_tag_id_as_data(env.target_info) {
if union_layout.stores_tag_id_as_data(env.target) {
let tag_id_ptr = builder.new_build_struct_gep(
union_struct_type,
raw_data_ptr,
@ -2556,7 +2536,7 @@ fn tag_pointer_set_tag_id<'ctx>(
pointer: PointerValue<'ctx>,
) -> PointerValue<'ctx> {
// we only have 3 bits, so can encode only 0..7 (or on 32-bit targets, 2 bits to encode 0..3)
debug_assert!((tag_id as u32) < env.target_info.ptr_width() as u32);
debug_assert!((tag_id as u32) < env.target.ptr_width() as u32);
let tag_id_intval = env.ptr_int().const_int(tag_id as u64, false);
@ -2580,8 +2560,8 @@ fn tag_pointer_set_tag_id<'ctx>(
.new_build_pointer_cast(indexed_pointer, pointer.get_type(), "cast_from_i8_ptr")
}
pub fn tag_pointer_tag_id_bits_and_mask(target_info: TargetInfo) -> (u64, u64) {
match target_info.ptr_width() {
pub fn tag_pointer_tag_id_bits_and_mask(target: Target) -> (u64, u64) {
match target.ptr_width() {
roc_target::PtrWidth::Bytes8 => (3, 0b0000_0111),
roc_target::PtrWidth::Bytes4 => (2, 0b0000_0011),
}
@ -2591,7 +2571,7 @@ pub fn tag_pointer_read_tag_id<'ctx>(
env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>,
) -> IntValue<'ctx> {
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.target_info);
let (_, mask) = tag_pointer_tag_id_bits_and_mask(env.target);
let ptr_int = env.ptr_int();
let as_int = env.builder.new_build_ptr_to_int(pointer, ptr_int, "to_int");
@ -2607,7 +2587,7 @@ pub fn tag_pointer_clear_tag_id<'ctx>(
env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>,
) -> PointerValue<'ctx> {
let (_, tag_id_bits_mask) = tag_pointer_tag_id_bits_and_mask(env.target_info);
let (_, tag_id_bits_mask) = tag_pointer_tag_id_bits_and_mask(env.target);
let as_int = env
.builder
@ -2725,7 +2705,7 @@ pub fn get_tag_id<'a, 'ctx>(
UnionLayout::Recursive(_) => {
let argument_ptr = argument.into_pointer_value();
if union_layout.stores_tag_id_as_data(env.target_info) {
if union_layout.stores_tag_id_as_data(env.target) {
get_tag_id_wrapped(env, layout_interner, *union_layout, argument_ptr)
} else {
tag_pointer_read_tag_id(env, argument_ptr)
@ -2756,7 +2736,7 @@ pub fn get_tag_id<'a, 'ctx>(
{
env.builder.position_at_end(else_block);
let tag_id = if union_layout.stores_tag_id_as_data(env.target_info) {
let tag_id = if union_layout.stores_tag_id_as_data(env.target) {
get_tag_id_wrapped(env, layout_interner, *union_layout, argument_ptr)
} else {
tag_pointer_read_tag_id(env, argument_ptr)
@ -2894,7 +2874,7 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>(
union_layout: UnionLayout<'a>,
fields: &[&[InLayout<'a>]],
) -> PointerValue<'ctx> {
let ptr_bytes = env.target_info;
let ptr_bytes = env.target;
let roc_union = if union_layout.stores_tag_id_as_data(ptr_bytes) {
RocUnion::tagged_from_slices(layout_interner, env.context, fields)
@ -2988,11 +2968,11 @@ fn list_literal<'a, 'ctx>(
let size = list_length * element_width as usize;
let alignment = layout_interner
.alignment_bytes(element_layout)
.max(env.target_info.ptr_width() as u32);
.max(env.target.ptr_width() as u32);
let mut is_all_constant = true;
let zero_elements =
(env.target_info.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
(env.target.ptr_width() as u8 as f64 / element_width as f64).ceil() as usize;
// runtime-evaluated elements
let mut runtime_evaluated_elements = Vec::with_capacity_in(list_length, env.arena);
@ -3498,7 +3478,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
if value.is_pointer_value() {
let clear_tag_id = match other_layout {
LayoutRepr::Union(union_layout) => {
union_layout.stores_tag_id_in_pointer(env.target_info)
union_layout.stores_tag_id_in_pointer(env.target)
}
_ => false,
};
@ -3562,7 +3542,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
let value = value.into_pointer_value();
let clear_tag_id = match layout_interner.runtime_representation(layout) {
LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target_info),
LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target),
_ => false,
};
@ -3640,7 +3620,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
if env.mode.runs_expects() {
bd.position_at_end(throw_block);
match env.target_info.ptr_width() {
match env.target.ptr_width() {
roc_target::PtrWidth::Bytes8 => {
let shared_memory = SharedMemoryPointer::get(env);
@ -3712,7 +3692,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
if env.mode.runs_expects() {
bd.position_at_end(throw_block);
match env.target_info.ptr_width() {
match env.target.ptr_width() {
roc_target::PtrWidth::Bytes8 => {
let shared_memory = SharedMemoryPointer::get(env);
@ -4891,7 +4871,7 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx>(
// On x86_*, Modify the argument to specify it is passed by value and nonnull
// Aarch*, just passes in the pointer directly.
if matches!(
env.target_info.architecture,
env.target.architecture(),
roc_target::Architecture::X86_32 | roc_target::Architecture::X86_64
) {
let c_abi_type = match layout_interner.get_repr(*layout) {
@ -5072,7 +5052,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx>(
}
pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
let word_type = match env.target_info.ptr_width() {
let word_type = match env.target.ptr_width() {
PtrWidth::Bytes4 => env.context.i32_type(),
PtrWidth::Bytes8 => env.context.i64_type(),
};
@ -5088,7 +5068,7 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
// The following three words are available for use in a target-specific manner.
//
// So, let's create a 5-word buffer.
let size = if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
let size = if env.target.operating_system() == roc_target::OperatingSystem::Windows {
// Due to https://github.com/llvm/llvm-project/issues/72908
// on windows, we store the register contents into this buffer directly!
30
@ -5114,10 +5094,10 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
pub fn build_setjmp_call<'ctx>(env: &Env<'_, 'ctx, '_>) -> BasicValueEnum<'ctx> {
let jmp_buf = get_sjlj_buffer(env);
if env.target_info.architecture == roc_target::Architecture::Aarch64 {
if env.target.architecture() == roc_target::Architecture::Aarch64 {
// Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_SETJMP)
} else if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
} else if env.target.operating_system() == roc_target::OperatingSystem::Windows {
// Due to https://github.com/llvm/llvm-project/issues/72908, we use a setjmp defined as asm in Zig
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_WINDOWS_SETJMP)
} else {
@ -6770,10 +6750,14 @@ pub fn to_cc_return<'a>(
layout: InLayout<'a>,
) -> CCReturn {
let return_size = layout_interner.stack_size(layout);
let pass_result_by_pointer = match env.target_info.operating_system {
roc_target::OperatingSystem::Windows => return_size > env.target_info.ptr_width() as u32,
roc_target::OperatingSystem::Unix => return_size > 2 * env.target_info.ptr_width() as u32,
roc_target::OperatingSystem::Wasi => return_size > 2 * env.target_info.ptr_width() as u32,
// TODO: loop back and update this. It actually cares about the full abi (arch + os)
let pass_result_by_pointer = match env.target.operating_system() {
roc_target::OperatingSystem::Windows => return_size > env.target.ptr_width() as u32,
roc_target::OperatingSystem::Linux
| roc_target::OperatingSystem::Mac
| roc_target::OperatingSystem::Freestanding => {
return_size > 2 * env.target.ptr_width() as u32
}
};
if return_size == 0 {
@ -6996,7 +6980,7 @@ fn define_global_str_literal_ptr<'ctx>(
ptr,
&[env
.ptr_int()
.const_int(env.target_info.ptr_width() as u64, false)],
.const_int(env.target.ptr_width() as u64, false)],
"get_rc_ptr",
)
};
@ -7026,11 +7010,11 @@ fn define_global_str_literal<'ctx>(
Some(current) => current,
None => {
let size = message.bytes().len() + env.target_info.ptr_width() as usize;
let size = message.bytes().len() + env.target.ptr_width() as usize;
let mut bytes = Vec::with_capacity_in(size, env.arena);
// insert NULL bytes for the refcount
for _ in 0..env.target_info.ptr_width() as usize {
for _ in 0..env.target.ptr_width() as usize {
bytes.push(env.context.i8_type().const_zero());
}
@ -7049,7 +7033,7 @@ fn define_global_str_literal<'ctx>(
// strings are NULL-terminated, which means we can't store the refcount (which is 8
// NULL bytes)
global.set_constant(true);
global.set_alignment(env.target_info.ptr_width() as u32);
global.set_alignment(env.target.ptr_width() as u32);
global.set_unnamed_addr(true);
global.set_linkage(inkwell::module::Linkage::Private);