From dcd0c86cd47fe377c5c9f6caedf8dd7c48eb7f11 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sun, 3 Nov 2024 20:38:12 +0100 Subject: [PATCH] Use LLVM's UEFI targets The UEFI targets previously passed Windows targets to LLVM, because that's what they're the most similar to. That's not ideal though (part of this problem was analyzed in 21e062d), but it seems like LLVM has since the introduction of these targets gained support for UEFI in-tree, so we should just use that: https://discourse.llvm.org/t/rfc-uefi-driver-support-uefi-target/73261 --- .../src/spec/targets/aarch64_unknown_uefi.rs | 2 +- .../src/spec/targets/i686_unknown_uefi.rs | 58 +------------------ .../src/spec/targets/x86_64_unknown_uefi.rs | 5 +- 3 files changed, 5 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs index 9656024ddaa1f..d487b10bedf94 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { base.features = "+v8a".into(); Target { - llvm_target: "aarch64-unknown-windows".into(), + llvm_target: "aarch64-unknown-uefi".into(), metadata: crate::spec::TargetMetadata { description: Some("ARM64 UEFI".into()), tier: Some(2), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs index 39d3a5a46330f..4f3ddec34c9bf 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs @@ -3,7 +3,6 @@ // UEFI systems always run in protected-mode, have the interrupt-controller pre-configured and // force a single-CPU execution. // The cdecl ABI is used. It differs from the stdcall or fastcall ABI. -// "i686-unknown-windows" is used to get the minimal subset of windows-specific features. use crate::spec::{Target, base}; @@ -23,61 +22,8 @@ pub(crate) fn target() -> Target { // arguments, thus giving you access to full MMX/SSE acceleration. base.features = "-mmx,-sse,+soft-float".into(); - // Use -GNU here, because of the reason below: - // Background and Problem: - // If we use i686-unknown-windows, the LLVM IA32 MSVC generates compiler intrinsic - // _alldiv, _aulldiv, _allrem, _aullrem, _allmul, which will cause undefined symbol. - // A real issue is __aulldiv() is referred by __udivdi3() - udivmod_inner!(), from - // https://github.com/rust-lang-nursery/compiler-builtins. - // As result, rust-lld generates link error finally. - // Root-cause: - // In rust\src\llvm-project\llvm\lib\Target\X86\X86ISelLowering.cpp, - // we have below code to use MSVC intrinsics. It assumes MSVC target - // will link MSVC library. But that is NOT true in UEFI environment. - // UEFI does not link any MSVC or GCC standard library. - // if (Subtarget.isTargetKnownWindowsMSVC() || - // Subtarget.isTargetWindowsItanium()) { - // // Setup Windows compiler runtime calls. - // setLibcallName(RTLIB::SDIV_I64, "_alldiv"); - // setLibcallName(RTLIB::UDIV_I64, "_aulldiv"); - // setLibcallName(RTLIB::SREM_I64, "_allrem"); - // setLibcallName(RTLIB::UREM_I64, "_aullrem"); - // setLibcallName(RTLIB::MUL_I64, "_allmul"); - // setLibcallCallingConv(RTLIB::SDIV_I64, CallingConv::X86_StdCall); - // setLibcallCallingConv(RTLIB::UDIV_I64, CallingConv::X86_StdCall); - // setLibcallCallingConv(RTLIB::SREM_I64, CallingConv::X86_StdCall); - // setLibcallCallingConv(RTLIB::UREM_I64, CallingConv::X86_StdCall); - // setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::X86_StdCall); - // } - // The compiler intrinsics should be implemented by compiler-builtins. - // Unfortunately, compiler-builtins has not provided those intrinsics yet. Such as: - // i386/divdi3.S - // i386/lshrdi3.S - // i386/moddi3.S - // i386/muldi3.S - // i386/udivdi3.S - // i386/umoddi3.S - // Possible solution: - // 1. Eliminate Intrinsics generation. - // 1.1 Choose different target to bypass isTargetKnownWindowsMSVC(). - // 1.2 Remove the "Setup Windows compiler runtime calls" in LLVM - // 2. Implement Intrinsics. - // We evaluated all options. - // #2 is hard because we need implement the intrinsics (_aulldiv) generated - // from the other intrinsics (__udivdi3) implementation with the same - // functionality (udivmod_inner). If we let _aulldiv() call udivmod_inner!(), - // then we are in loop. We may have to find another way to implement udivmod_inner!(). - // #1.2 may break the existing usage. - // #1.1 seems the simplest solution today. - // The IA32 -gnu calling convention is same as the one defined in UEFI specification. - // It uses cdecl, EAX/ECX/EDX as volatile register, and EAX/EDX as return value. - // We also checked the LLVM X86TargetLowering, the differences between -gnu and -msvc - // is fmodf(f32), longjmp() and TLS. None of them impacts the UEFI code. - // As a result, we choose -gnu for i686 version before those intrinsics are implemented in - // compiler-builtins. After compiler-builtins implements all required intrinsics, we may - // remove -gnu and use the default one. Target { - llvm_target: "i686-unknown-windows-gnu".into(), + llvm_target: "i686-unknown-uefi".into(), metadata: crate::spec::TargetMetadata { description: Some("32-bit UEFI".into()), tier: Some(2), @@ -86,7 +32,7 @@ pub(crate) fn target() -> Target { }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" + i128:128-f64:32:64-f80:32-n8:16:32-S128" .into(), arch: "x86".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index a11a79ff41a8e..0d629a496b385 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -2,8 +2,7 @@ // uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec) // UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a // single-CPU execution. -// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with -// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features. +// The win64 ABI is used. It differs from the sysv64 ABI. use crate::abi::call::Conv; use crate::spec::{Target, base}; @@ -28,7 +27,7 @@ pub(crate) fn target() -> Target { base.features = "-mmx,-sse,+soft-float".into(); Target { - llvm_target: "x86_64-unknown-windows".into(), + llvm_target: "x86_64-unknown-uefi".into(), metadata: crate::spec::TargetMetadata { description: Some("64-bit UEFI".into()), tier: Some(2),