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

@ -17,7 +17,7 @@ use roc_reporting::{
cli::{report_problems, Problems},
report::{RenderTarget, DEFAULT_PALETTE},
};
use roc_target::{OperatingSystem, TargetInfo};
use roc_target::{Architecture, Target};
use std::ffi::OsStr;
use std::ops::Deref;
use std::{
@ -25,7 +25,6 @@ use std::{
thread::JoinHandle,
time::{Duration, Instant},
};
use target_lexicon::Triple;
#[cfg(feature = "target-wasm32")]
use roc_collections::all::MutSet;
@ -96,7 +95,7 @@ pub fn gen_from_mono_module<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
roc_file_path: &Path,
target: &target_lexicon::Triple,
target: Target,
code_gen_options: CodeGenOptions,
preprocessed_host_path: &Path,
wasm_dev_stack_bytes: Option<u32>,
@ -146,7 +145,7 @@ fn gen_from_mono_module_llvm<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
roc_file_path: &Path,
target: &target_lexicon::Triple,
target: Target,
opt_level: OptLevel,
backend_mode: LlvmBackendMode,
emit_debug_info: bool,
@ -162,7 +161,6 @@ fn gen_from_mono_module_llvm<'a>(
let all_code_gen_start = Instant::now();
// Generate the binary
let target_info = roc_target::TargetInfo::from(target);
let context = Context::create();
let module = arena.alloc(module_from_builtins(target, &context, "app"));
@ -210,7 +208,7 @@ fn gen_from_mono_module_llvm<'a>(
context: &context,
interns: loaded.interns,
module,
target_info,
target,
mode: backend_mode,
exposed_to_host: loaded
@ -387,9 +385,8 @@ fn gen_from_mono_module_llvm<'a>(
}
// Emit the .o file
use target_lexicon::Architecture;
match target.architecture {
Architecture::X86_64 | Architecture::X86_32(_) | Architecture::Aarch64(_) => {
match target.architecture() {
Architecture::X86_64 | Architecture::X86_32 | Architecture::Aarch64 => {
let reloc = RelocMode::PIC;
let target_machine =
target::target_machine(target, convert_opt_level(opt_level), reloc).unwrap();
@ -405,7 +402,7 @@ fn gen_from_mono_module_llvm<'a>(
}
_ => internal_error!(
"TODO gracefully handle unsupported architecture: {:?}",
target.architecture
target.architecture()
),
}
};
@ -432,21 +429,19 @@ fn gen_from_mono_module_llvm<'a>(
fn gen_from_mono_module_dev<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
target: &target_lexicon::Triple,
target: Target,
preprocessed_host_path: &Path,
wasm_dev_stack_bytes: Option<u32>,
backend_mode: AssemblyBackendMode,
) -> GenFromMono<'a> {
use target_lexicon::Architecture;
match target.architecture {
match target.architecture() {
Architecture::Wasm32 => gen_from_mono_module_dev_wasm32(
arena,
loaded,
preprocessed_host_path,
wasm_dev_stack_bytes,
),
Architecture::X86_64 | Architecture::Aarch64(_) => {
Architecture::X86_64 | Architecture::Aarch64 => {
gen_from_mono_module_dev_assembly(arena, loaded, target, backend_mode)
}
_ => todo!(),
@ -457,15 +452,13 @@ fn gen_from_mono_module_dev<'a>(
pub fn gen_from_mono_module_dev<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
target: &target_lexicon::Triple,
target: Target,
_host_input_path: &Path,
_wasm_dev_stack_bytes: Option<u32>,
backend_mode: AssemblyBackendMode,
) -> GenFromMono<'a> {
use target_lexicon::Architecture;
match target.architecture {
Architecture::X86_64 | Architecture::Aarch64(_) => {
match target.architecture() {
Architecture::X86_64 | Architecture::Aarch64 => {
gen_from_mono_module_dev_assembly(arena, loaded, target, backend_mode)
}
_ => todo!(),
@ -549,7 +542,7 @@ fn gen_from_mono_module_dev_wasm32<'a>(
fn gen_from_mono_module_dev_assembly<'a>(
arena: &'a bumpalo::Bump,
loaded: MonomorphizedModule<'a>,
target: &target_lexicon::Triple,
target: Target,
backend_mode: AssemblyBackendMode,
) -> GenFromMono<'a> {
let all_code_gen_start = Instant::now();
@ -694,12 +687,10 @@ pub fn handle_loading_problem(problem: LoadingProblem) -> std::io::Result<i32> {
}
pub fn standard_load_config(
target: &Triple,
target: Target,
order: BuildOrdering,
threading: Threading,
) -> LoadConfig {
let target_info = TargetInfo::from(target);
let exec_mode = match order {
BuildOrdering::BuildIfChecks => ExecutionMode::ExecutableIfCheck,
BuildOrdering::AlwaysBuild => ExecutionMode::Executable,
@ -717,7 +708,7 @@ pub fn standard_load_config(
};
LoadConfig {
target_info,
target,
function_kind,
render: RenderTarget::ColorTerminal,
palette: DEFAULT_PALETTE,
@ -729,7 +720,7 @@ pub fn standard_load_config(
#[allow(clippy::too_many_arguments)]
pub fn build_file<'a>(
arena: &'a Bump,
target: &Triple,
target: Target,
app_module_path: PathBuf,
code_gen_options: CodeGenOptions,
emit_timings: bool,
@ -767,7 +758,7 @@ pub fn build_file<'a>(
#[allow(clippy::too_many_arguments)]
fn build_loaded_file<'a>(
arena: &'a Bump,
target: &Triple,
target: Target,
app_module_path: PathBuf,
code_gen_options: CodeGenOptions,
emit_timings: bool,
@ -779,8 +770,6 @@ fn build_loaded_file<'a>(
compilation_start: Instant,
out_path: Option<&Path>,
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
let operating_system = roc_target::OperatingSystem::from(target.operating_system);
let platform_main_roc = match &loaded.entry_point {
EntryPoint::Executable { platform_path, .. } => platform_path.to_path_buf(),
_ => unreachable!(),
@ -792,9 +781,9 @@ fn build_loaded_file<'a>(
if is_platform_prebuilt && linking_strategy == LinkingStrategy::Surgical {
// Fallback to legacy linking if the preprocessed host file does not exist, but a legacy host does exist.
let preprocessed_host_path = platform_main_roc
.with_file_name(roc_linker::preprocessed_host_filename(target).unwrap());
let legacy_host_path = legacy_host_file(target, &platform_main_roc).unwrap();
let preprocessed_host_path =
platform_main_roc.with_file_name(roc_linker::preprocessed_host_filename(target));
let legacy_host_path = legacy_host_file(target, &platform_main_roc);
if !preprocessed_host_path.exists() && legacy_host_path.exists() {
linking_strategy = LinkingStrategy::Legacy;
}
@ -802,15 +791,15 @@ fn build_loaded_file<'a>(
// the preprocessed host is stored beside the platform's main.roc
let preprocessed_host_path = if linking_strategy == LinkingStrategy::Legacy {
if let roc_target::OperatingSystem::Wasi = operating_system {
if target == Target::Wasm32 {
// when compiling a wasm application, we implicitly assume here that the host is in zig
// and has a file called "host.zig"
platform_main_roc.with_file_name("host.zig")
} else {
legacy_host_file(target, &platform_main_roc).unwrap()
legacy_host_file(target, &platform_main_roc)
}
} else {
platform_main_roc.with_file_name(roc_linker::preprocessed_host_filename(target).unwrap())
platform_main_roc.with_file_name(roc_linker::preprocessed_host_filename(target))
};
let output_exe_path = match out_path {
@ -841,22 +830,12 @@ fn build_loaded_file<'a>(
if ends_with_sep {
let filename = app_module_path.file_name().unwrap_or_default();
with_output_extension(
&path.join(filename),
operating_system,
linking_strategy,
link_type,
)
with_output_extension(&path.join(filename), target, linking_strategy, link_type)
} else {
path.to_path_buf()
}
}
None => with_output_extension(
&app_module_path,
operating_system,
linking_strategy,
link_type,
),
None => with_output_extension(&app_module_path, target, linking_strategy, link_type),
};
// We don't need to spawn a rebuild thread when using a prebuilt host.
@ -1018,13 +997,13 @@ fn build_loaded_file<'a>(
std::fs::write(&output_exe_path, &*roc_app_bytes).unwrap();
}
(LinkingStrategy::Legacy, _) => {
let extension = if matches!(operating_system, roc_target::OperatingSystem::Wasi) {
let extension = if target == Target::Wasm32 {
// Legacy linker is only by used llvm wasm backend, not dev.
// llvm wasm backend directly emits a bitcode file when targeting wasi, not a `.o` or `.wasm` file.
// If we set the extension wrong, zig will print a ton of warnings when linking.
"bc"
} else {
operating_system.object_file_ext()
target.object_file_ext()
};
let app_o_file = tempfile::Builder::new()
.prefix("roc_app")
@ -1124,10 +1103,9 @@ fn spawn_rebuild_thread(
platform_main_roc: PathBuf,
preprocessed_host_path: PathBuf,
output_exe_path: PathBuf,
target: &Triple,
target: Target,
dll_stub_symbols: Vec<String>,
) -> std::thread::JoinHandle<u128> {
let thread_local_target = target.clone();
std::thread::spawn(move || {
// Printing to stderr because we want stdout to contain only the output of the roc program.
// We are aware of the trade-offs.
@ -1138,19 +1116,14 @@ fn spawn_rebuild_thread(
match linking_strategy {
LinkingStrategy::Additive => {
let host_dest = rebuild_host(
opt_level,
&thread_local_target,
platform_main_roc.as_path(),
None,
);
let host_dest = rebuild_host(opt_level, target, platform_main_roc.as_path(), None);
preprocess_host_wasm32(host_dest.as_path(), &preprocessed_host_path);
}
LinkingStrategy::Surgical => {
build_and_preprocess_host_lowlevel(
opt_level,
&thread_local_target,
target,
platform_main_roc.as_path(),
preprocessed_host_path.as_path(),
&dll_stub_symbols,
@ -1161,12 +1134,7 @@ fn spawn_rebuild_thread(
std::fs::copy(&preprocessed_host_path, output_exe_path.as_path()).unwrap();
}
LinkingStrategy::Legacy => {
rebuild_host(
opt_level,
&thread_local_target,
platform_main_roc.as_path(),
None,
);
rebuild_host(opt_level, target, platform_main_roc.as_path(), None);
}
}
@ -1176,7 +1144,7 @@ fn spawn_rebuild_thread(
pub fn build_and_preprocess_host(
opt_level: OptLevel,
target: &Triple,
target: Target,
platform_main_roc: &Path,
preprocessed_host_path: &Path,
exposed_symbols: roc_linker::ExposedSymbols,
@ -1194,7 +1162,7 @@ pub fn build_and_preprocess_host(
fn build_and_preprocess_host_lowlevel(
opt_level: OptLevel,
target: &Triple,
target: Target,
platform_main_roc: &Path,
preprocessed_host_path: &Path,
stub_dll_symbols: &[String],
@ -1227,12 +1195,12 @@ pub fn check_file<'a>(
// only used for generating errors. We don't do code generation, so hardcoding should be fine
// we need monomorphization for when exhaustiveness checking
let target_info = TargetInfo::default_x86_64();
let target = Target::LinuxX64;
// Step 1: compile the app and generate the .o file
let load_config = LoadConfig {
target_info,
target,
// TODO: we may not want this for just checking.
function_kind: FunctionKind::LambdaSet,
// TODO: expose this from CLI?
@ -1295,7 +1263,7 @@ pub fn build_str_test<'a>(
app_module_source: &'a str,
assume_prebuild: bool,
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
let triple = target_lexicon::Triple::host();
let target = target_lexicon::Triple::host().into();
let code_gen_options = CodeGenOptions {
backend: CodeGenBackend::Llvm(LlvmBackendMode::Binary),
@ -1314,7 +1282,7 @@ pub fn build_str_test<'a>(
let build_ordering = BuildOrdering::AlwaysBuild;
let threading = Threading::AtMost(2);
let load_config = standard_load_config(&triple, build_ordering, threading);
let load_config = standard_load_config(target, build_ordering, threading);
let compilation_start = std::time::Instant::now();
@ -1331,7 +1299,7 @@ pub fn build_str_test<'a>(
build_loaded_file(
arena,
&triple,
target,
app_module_path.to_path_buf(),
code_gen_options,
emit_timings,
@ -1347,15 +1315,15 @@ pub fn build_str_test<'a>(
fn with_output_extension(
path: &Path,
os: OperatingSystem,
target: Target,
linking_strategy: LinkingStrategy,
link_type: LinkType,
) -> PathBuf {
match (linking_strategy, link_type) {
(LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => {
// Additive linking and no linking both output the object file type.
path.with_extension(os.object_file_ext())
path.with_extension(target.object_file_ext())
}
_ => path.with_extension(os.executable_file_ext().unwrap_or_default()),
_ => path.with_extension(target.executable_file_ext().unwrap_or_default()),
}
}