rust-lang/rust · #162156
add IBM f128 type
compiler/rustc_abi/src/callconv.rs2 + / 5 −
@@ -1,5 +1,5 @@ #[cfg(feature = "nightly")]-use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants};+use crate::{BackendRepr, FieldsShape, Size, TyAbiInterface, TyAndLayout, Variants}; mod reg; @@ -73,10 +73,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { match self.backend_repr { // The primitive for this algorithm. BackendRepr::Scalar(scalar) => {- let kind = match scalar.primitive() {- Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,- Primitive::Float(_) => RegKind::Float,- };+ let kind = RegKind::from_primitive(scalar.primitive()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } compiler/rustc_abi/src/callconv/reg.rs13 + / 2 −
@@ -1,13 +1,19 @@ #[cfg(feature = "nightly")] use rustc_macros::StableHash; -use crate::{Align, HasDataLayout, Integer, Primitive, Size};+use crate::{Align, Float, HasDataLayout, Integer, Primitive, Size}; +/// The "kind" of backend type, which combined with a [`Size`] forms a [`Reg`]. #[cfg_attr(feature = "nightly", derive(StableHash))] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum RegKind { Integer, Float,+ /// The IBM extended-precision format: a pair of `f64`s, each passed in its own register.+ /// This variant is needed to distinguish IEEE f128 and IBM f128 in the backends.+ ///+ /// Only used on PowerPC targets.+ PpcF128, Vector { /// The `hint_vector_elem` is strictly for optimization purposes. E.g. it can be used by /// a codegen backend to prevent extra bitcasts that obscure a pattern. Alternatively,@@ -20,11 +26,15 @@ impl RegKind { pub fn from_primitive(primitive: Primitive) -> Self { match primitive { Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,- Primitive::Float(_) => RegKind::Float,+ Primitive::Float(Float::PpcF128) => RegKind::PpcF128,+ Primitive::Float(Float::F16 | Float::F16B | Float::F32 | Float::F64 | Float::F128) => {+ RegKind::Float+ } } } } +/// A combination of a [`RegKind`] and a [`Size`] that represents a builtin type in the backend. #[cfg_attr(feature = "nightly", derive(StableHash))] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Reg {@@ -79,6 +89,7 @@ impl Reg { 128 => dl.f128_align, _ => panic!("unsupported float: {self:?}"), },+ RegKind::PpcF128 => dl.f128_align, RegKind::Vector { .. } => dl.rust_vector_align(self.size), } }compiler/rustc_abi/src/layout/ty.rs3 + / 3 −
@@ -339,9 +339,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let primitive = scalar.primitive(); match primitive { Primitive::Int(integer, is_signed) => Some(Numeric::Int(integer, is_signed)),- Primitive::Float(float @ (Float::F16 | Float::F32 | Float::F64 | Float::F128)) => {- Some(Numeric::Float(float))- }+ Primitive::Float(+ float @ (Float::F16 | Float::F32 | Float::F64 | Float::F128 | Float::PpcF128),+ ) => Some(Numeric::Float(float)), Primitive::Pointer(..) | Primitive::Float(Float::F16B) => None, } }compiler/rustc_abi/src/lib.rs11 + / 1 −
@@ -1427,6 +1427,10 @@ pub enum Float { F32, F64, F128,+ /// `ppcf128`. This is not a builtin type in Rust (it is exposed as a lang item),+ /// but it is a builtin type in LLVM so needs to be explicitly represented+ /// in the backend.+ PpcF128, } impl Float {@@ -1439,6 +1443,7 @@ impl Float { F32 => Size::from_bits(32), F64 => Size::from_bits(64), F128 => Size::from_bits(128),+ PpcF128 => Size::from_bits(128), } } @@ -1451,6 +1456,7 @@ impl Float { F32 => dl.f32_align, F64 => dl.f64_align, F128 => dl.f128_align,+ PpcF128 => dl.f128_align, }) } @@ -1463,6 +1469,7 @@ impl Float { F32 => "f32", F64 => "f64", F128 => "f128",+ PpcF128 => "ppcf128", } } }@@ -1487,7 +1494,10 @@ impl Numeric { pub fn reg_kind(self) -> RegKind { match self { Numeric::Int(_, _) => RegKind::Integer,- Numeric::Float(_) => RegKind::Float,+ Numeric::Float(Float::PpcF128) => RegKind::PpcF128,+ Numeric::Float(Float::F16 | Float::F16B | Float::F32 | Float::F64 | Float::F128) => {+ RegKind::Float+ } } } }compiler/rustc_attr_ir/src/lang_items.rs1 + / 0 −
@@ -237,6 +237,7 @@ language_item_table! { VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; Complex, sym::complex, complex, Target::Struct, GenericRequirement::Exact(1);+ PpcF128, sym::ppcf128, ppcf128, Target::Struct, GenericRequirement::None; Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);compiler/rustc_codegen_cranelift/src/common.rs1 + / 0 −
@@ -39,6 +39,7 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { Float::F32 => types::F32, Float::F64 => types::F64, Float::F128 => types::F128,+ Float::PpcF128 => bug!("cranelift does not support powerpc"), }, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => pointer_ty(tcx),compiler/rustc_codegen_gcc/src/abi.rs1 + / 0 −
@@ -90,6 +90,7 @@ impl GccType for Reg { 64 => cx.type_f64(), _ => bug!("unsupported float: {:?}", self), },+ RegKind::PpcF128 => cx.type_ppcf128(), RegKind::Vector { hint_vector_elem: _ } => { cx.type_vector(cx.type_i8(), self.size.bytes()) }compiler/rustc_codegen_gcc/src/type_.rs6 + / 0 −
@@ -267,6 +267,12 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { bug!("unsupported float width 128") } + fn type_ppcf128(&self) -> Type<'gcc> {+ // FIXME(ppcf128): The GCC gcc_jit_types enum (which CType is based on) does not+ // have __ibm128. It does have long double but it may not correspond to ppc f128.+ bug!("unsupported ppcf128 type")+ }+ fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { self.context.new_function_pointer_type(None, return_type, params, false) }compiler/rustc_codegen_llvm/src/abi.rs2 + / 0 −
@@ -147,6 +147,7 @@ impl LlvmType for Reg { 128 => cx.type_f128(), _ => bug!("unsupported float: {:?}", self), },+ RegKind::PpcF128 => cx.type_ppcf128(), RegKind::Vector { hint_vector_elem } => { // NOTE: it is valid to ignore the element type hint (and always pick i8). // But providing a more accurate type means fewer casts in LLVM IR,@@ -165,6 +166,7 @@ impl LlvmType for Reg { Float::F32 => cx.type_f32(), Float::F64 => cx.type_f64(), Float::F128 => cx.type_f128(),+ Float::PpcF128 => bug!("ppcf128 is not a valid vector element type"), }, Primitive::Pointer(_) => cx.type_ptr(), };compiler/rustc_codegen_llvm/src/intrinsic.rs4 + / 0 −
@@ -350,6 +350,10 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { Primitive::Float(Float::F128) => { // Supported on some targets, especially where long double is IEEE f128. }+ Primitive::Float(Float::PpcF128) => {+ // FIXME(ppcf128) we should support this.+ bug!("the va_arg intrinsic does not currently support `ppcf128`")+ } } emit_va_arg(self, args[0], result_layout)compiler/rustc_codegen_llvm/src/llvm/ffi.rs1 + / 0 −
@@ -946,6 +946,7 @@ unsafe extern "C" { // Operations on non-IEEE real types pub(crate) fn LLVMBFloatTypeInContext(C: &Context) -> &Type;+ pub(crate) fn LLVMPPCFP128TypeInContext(C: &Context) -> &Type; // Operations on function types pub(crate) fn LLVMFunctionType<'a>(compiler/rustc_codegen_llvm/src/type_.rs4 + / 0 −
@@ -230,6 +230,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) } } + fn type_ppcf128(&self) -> &'ll Type {+ unsafe { llvm::LLVMPPCFP128TypeInContext(self.llcx()) }+ }+ fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, FALSE) } }compiler/rustc_codegen_llvm/src/va_arg.rs4 + / 2 −
@@ -96,8 +96,7 @@ fn get_param_type_alignment<'ll, 'tcx>( }, Primitive::Float(float) => match float { Float::F16 | Float::F16B | Float::F32 => unreachable!(),- Float::F64 => { /* fall through */ }- Float::F128 => return Align::from_bytes(16).unwrap(),+ Float::F64 | Float::F128 | Float::PpcF128 => { /* fall through */ } }, Primitive::Pointer(_) => { /* fall through */ } },@@ -471,6 +470,9 @@ fn emit_s390x_va_arg<'ll, 'tcx>( Primitive::Float(Float::F16B) => { bug!("`f16b` use in varadics unsupported on s390x") }+ Primitive::Float(Float::PpcF128) => {+ bug!("`ppcf128` use in varadics unsupported on s390x")+ } }, _ => false,compiler/rustc_codegen_ssa/src/mir/naked_asm.rs2 + / 0 −
@@ -490,6 +490,7 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t ..=8 => "f64", _ => ptr_type, },+ RegKind::PpcF128 => bug!("not a valid wasm type"), RegKind::Vector { .. } => "v128", }; @@ -513,6 +514,7 @@ fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str Float::F16 | Float::F32 => "f32", Float::F64 => "f64", Float::F128 => "i64, i64",+ Float::PpcF128 => bug!("`ppcf128` unsupported on wasm"), }, Primitive::Pointer(_) => ptr_type, }compiler/rustc_codegen_ssa/src/traits/type_.rs2 + / 0 −
@@ -22,6 +22,7 @@ pub trait BaseTypeCodegenMethods: BackendTypes { fn type_f32(&self) -> Self::Type; fn type_f64(&self) -> Self::Type; fn type_f128(&self) -> Self::Type;+ fn type_ppcf128(&self) -> Self::Type; fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::FunctionSignature;@@ -72,6 +73,7 @@ pub trait DerivedTypeCodegenMethods<'tcx>: F32 => self.type_f32(), F64 => self.type_f64(), F128 => self.type_f128(),+ PpcF128 => self.type_ppcf128(), } } compiler/rustc_middle/src/ty/layout.rs5 + / 0 −
@@ -146,6 +146,11 @@ impl abi::Float { F32 => tcx.types.f32, F64 => tcx.types.f64, F128 => tcx.types.f128,+ PpcF128 => Ty::new_adt(+ tcx,+ tcx.adt_def(tcx.require_lang_item(LangItem::PpcF128, DUMMY_SP)),+ ty::List::empty(),+ ), } } compiler/rustc_public/src/abi.rs2 + / 0 −
@@ -512,6 +512,7 @@ pub enum FloatLength { F32, F64, F128,+ PpcF128, } impl IntegerLength {@@ -533,6 +534,7 @@ impl FloatLength { FloatLength::F32 => 32, FloatLength::F64 => 64, FloatLength::F128 => 128,+ FloatLength::PpcF128 => 128, } } }compiler/rustc_public/src/unstable/convert/stable/abi.rs2 + / 0 −
@@ -244,6 +244,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Reg { kind: match self.kind { rustc_abi::RegKind::Integer => RegKind::Integer, rustc_abi::RegKind::Float => RegKind::Float,+ rustc_abi::RegKind::PpcF128 => RegKind::Float, rustc_abi::RegKind::Vector { .. } => RegKind::Vector, }, size: Size::from_bits(self.size.bits_usize()),@@ -486,6 +487,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Float { rustc_abi::Float::F32 => FloatLength::F32, rustc_abi::Float::F64 => FloatLength::F64, rustc_abi::Float::F128 => FloatLength::F128,+ rustc_abi::Float::PpcF128 => FloatLength::PpcF128, } } }compiler/rustc_span/src/symbol.rs1 + / 0 −
@@ -1633,6 +1633,7 @@ symbols! { powif32, powif64, powif128,+ ppcf128, pre_dash_lto: "pre-lto", precise_capturing, precise_capturing_in_traits,compiler/rustc_target/src/callconv/aarch64.rs1 + / 0 −
@@ -32,6 +32,7 @@ where let valid_unit = match unit.kind { RegKind::Integer => false,+ RegKind::PpcF128 => unreachable!(), // The softfloat ABI treats floats like integers, so they // do not get homogeneous aggregate treatment. RegKind::Float => cx.target_spec().rustc_abi != Some(RustcAbi::Softfloat),compiler/rustc_target/src/callconv/arm.rs1 + / 0 −
@@ -26,6 +26,7 @@ where let valid_unit = match unit.kind { RegKind::Integer => false, RegKind::Float => true,+ RegKind::PpcF128 => unreachable!(), RegKind::Vector { .. } => unit.size.bits() == 64 || unit.size.bits() == 128, }; compiler/rustc_target/src/callconv/mips64.rs4 + / 5 −
@@ -32,10 +32,11 @@ where match float { // C does not have the f16 type Float::F16 => None,- Float::F16B => unreachable!("`f16b` unsupported on mips64"), Float::F32 => Some(Reg::f32()), Float::F64 => Some(Reg::f64()), Float::F128 => Some(Reg::f128()),+ Float::F16B => unreachable!("`f16b` unsupported on mips64"),+ Float::PpcF128 => unreachable!("`ppcf128` unsupported on mips64"), } } _ => None,@@ -125,10 +126,7 @@ where // However, this implementation is consistent with GCC, which means we // are compatible with the de-facto ABI on the platform. if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {- let kind = match scalar.primitive() {- Primitive::Int(_, _) | Primitive::Pointer(_) => RegKind::Integer,- Primitive::Float(_) => RegKind::Float,- };+ let kind = RegKind::from_primitive(scalar.primitive()); arg.cast_to_and_pad_i32(CastTarget::from(Reg { kind, size }), pad_i32); } } else if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {@@ -144,6 +142,7 @@ where match component { Numeric::Float(Float::F16B) => unreachable!("Complex<f16b> is not C-compatible"), Numeric::Float(Float::F16) => unreachable!("not supported on mips64"),+ Numeric::Float(Float::PpcF128) => unreachable!("not supported on mips64"), Numeric::Float(Float::F32 | Float::F64) => { // Only pass a Complex<f32>/Complex<f64> in FPRs when two argument slots are free. if curr_offset.bytes() / slot.bytes() + 2 <= NUM_ARG_SLOTS {compiler/rustc_target/src/callconv/powerpc64.rs17 + / 8 −
@@ -60,18 +60,27 @@ where C: HasDataLayout, { arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {- // ELFv1 and AIX only passes one-member aggregates transparently.- // ELFv2 passes up to eight uniquely addressable members.- if ((abi == ELFv1 || abi == AIX)- && (arg.layout.size > unit.size || is_or_contains_union(cx, arg.layout)))- || arg.layout.size > unit.size.checked_mul(8, cx).unwrap()- {- return None;+ match abi {+ ELFv1 | AIX => {+ // Pass only one-member aggregates transparently.+ if arg.layout.size > unit.size || is_or_contains_union(cx, arg.layout) {+ return None;+ }+ }+ ELFv2 => {+ // A `ppcf128` occupies two floating-point registers, so only four of them fit.+ let max_members = if unit.kind == RegKind::PpcF128 { 4 } else { 8 };++ // Pass up to max_members uniquely addressable members.+ if arg.layout.size > unit.size.checked_mul(max_members, cx).unwrap() {+ return None;+ }+ } } let valid_unit = match unit.kind { RegKind::Integer => false,- RegKind::Float => true,+ RegKind::Float | RegKind::PpcF128 => true, RegKind::Vector { .. } => unit.size.bits() == 128, }; compiler/rustc_target/src/callconv/sparc64.rs1 + / 0 −
@@ -59,6 +59,7 @@ fn classify<'a, Ty, C>( // Match LLVM by passing `f16` in integer registers. } Float::F16B => unreachable!("`f16b` unsupported on sparc64"),+ Float::PpcF128 => unreachable!("`ppcf128` unsupported on sparc64"), } } else { /* pass unaligned floats in integer registers */compiler/rustc_ty_utils/src/layout.rs7 + / 0 −
@@ -826,6 +826,13 @@ fn layout_of_uncached<'tcx>( layout.backend_repr = BackendRepr::Scalar(bfloat); } + if tcx.is_lang_item(def.did(), LangItem::PpcF128) {+ let ppcf128 = scalar_unit(Primitive::Float(abi::Float::PpcF128));+ assert_eq!(layout.size, abi::Float::PpcF128.size());+ layout.align = abi::Float::PpcF128.align(cx);+ layout.backend_repr = BackendRepr::Scalar(ppcf128);+ }+ tcx.mk_layout(layout) } library/stdarch/crates/core_arch/src/lib.rs2 + / 1 −
@@ -39,7 +39,8 @@ maybe_uninit_as_bytes, movrs_target_feature, clflushopt_target_feature,- min_adt_const_params+ min_adt_const_params,+ lang_items, )] #![cfg_attr( test,library/stdarch/crates/core_arch/src/powerpc/mod.rs41 + / 0 −
@@ -2,6 +2,47 @@ pub(crate) mod macros; +/// The IBM extended-precision (double-double) floating-point type.+// FIXME(ppcf128) improve the docs.+#[lang = "ppcf128"]+#[doc(alias = "__ibm128")]+#[doc(alias = "doubledouble")]+#[doc(alias = "f64f64")]+#[unstable(feature = "powerpc_ppcf128", issue = "163323")]+#[allow(non_camel_case_types)]+#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]+#[derive(Clone, Copy)]+pub struct ppcf128(u128);++#[unstable(feature = "powerpc_ppcf128", issue = "163323")]+impl crate::fmt::Debug for ppcf128 {+ fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {+ let (hi, lo) = self.to_components();+ write!(f, "ppcf128({hi:?}, {lo:?})")+ }+}++impl ppcf128 {+ /// Returns the memory representation of this floating point number as a byte array in+ /// native byte order.+ #[unstable(feature = "powerpc_ppcf128", issue = "163323")]+ #[inline]+ pub const fn to_ne_bytes(self) -> [u8; 16] {+ // SAFETY: every bit pattern of a `ppcf128` is a valid `[u8; 16]`.+ unsafe { crate::mem::transmute::<ppcf128, [u8; 16]>(self) }+ }++ /// Returns the large and small component of this floating point number.+ #[unstable(feature = "powerpc_ppcf128", issue = "163323")]+ #[rustc_const_unstable(feature = "powerpc_ppcf128", issue = "163323")]+ #[inline]+ pub const fn to_components(self) -> (f64, f64) {+ // SAFETY: every bit pattern of a `ppcf128` is a valid `[f64; 2]`.+ let [large, small] = unsafe { crate::mem::transmute::<ppcf128, [f64; 2]>(self) };+ (large, small)+ }+}+ mod altivec; #[unstable(feature = "stdarch_powerpc", issue = "111145")] pub use self::altivec::*;tests/assembly-llvm/ppcf128.rsadded275 + / 0 −
@@ -0,0 +1,275 @@+//@ add-minicore+//@ assembly-output: emit-asm+//+//@ revisions: POWERPC POWERPC64LE POWERPC64 AIX+//@ [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu+//@ [POWERPC64LE] compile-flags: --target powerpc64le-unknown-linux-gnu+//@ [POWERPC64] compile-flags: --target powerpc64-unknown-linux-gnu+//@ [AIX] compile-flags: --target powerpc64-ibm-aix+//@ compile-flags: -Copt-level=3 --crate-type=lib+//@ needs-llvm-components: powerpc++#![feature(no_core)]+#![no_std]+#![no_core]++extern crate minicore;+#[cfg(target_arch = "powerpc")]+use minicore::arch::powerpc::ppcf128;+#[cfg(target_arch = "powerpc64")]+use minicore::arch::powerpc64::ppcf128;+use minicore::*;++// CHECK-LABEL: identity+//+// POWERPC: .Lfunc_begin{{[0-9]+}}:+// POWERPC-NEXT: .cfi_startproc+// POWERPC-NEXT: stwu 1, -48(1)+// POWERPC-NEXT: .cfi_def_cfa_offset 48+// POWERPC-NEXT: stfd 1, 24(1)+// POWERPC-NEXT: lwz 3, 28(1)+// POWERPC-NEXT: stfd 2, 16(1)+// POWERPC-NEXT: stw 3, 44(1)+// POWERPC-NEXT: lwz 3, 24(1)+// POWERPC-NEXT: stw 3, 40(1)+// POWERPC-NEXT: lwz 3, 20(1)+// POWERPC-NEXT: lfd 1, 40(1)+// POWERPC-NEXT: stw 3, 36(1)+// POWERPC-NEXT: lwz 3, 16(1)+// POWERPC-NEXT: stw 3, 32(1)+// POWERPC-NEXT: lfd 2, 32(1)+// POWERPC-NEXT: addi 1, 1, 48+// POWERPC-NEXT: blr+//+// POWERPC64: .Lfunc_begin{{[0-9]+}}:+// POWERPC64-NEXT: .cfi_startproc+// POWERPC64-NEXT: blr+//+// POWERPC64LE: .Lfunc_begin{{[0-9]+}}:+// POWERPC64LE-NEXT: .cfi_startproc+// POWERPC64LE-NEXT: blr+//+// AIX: .csect .identity[PR],5+// AIX-NEXT: blr+#[unsafe(no_mangle)]+pub extern "C" fn identity(x: ppcf128) -> ppcf128 {+ x+}++/// On elfv1 and aix single-float structs are passed as scalar arguments.+#[repr(C)]+struct Hfa1 {+ a: ppcf128,+}++/// On elfv2 homogenous aggregates of up to 4 elements are passed as scalars.+#[repr(C)]+struct Hfa2 {+ a: ppcf128,+ b: ppcf128,+}++#[repr(C)]+struct Hfa4 {+ a: ppcf128,+ b: ppcf128,+ c: ppcf128,+ d: ppcf128,+}++// CHECK-LABEL: hfa1+//+// POWERPC: .Lfunc_begin{{[0-9]+}}:+// POWERPC-NEXT: .cfi_startproc+// POWERPC-NEXT: stwu 1, -32(1)+// POWERPC-NEXT: .cfi_def_cfa_offset 32+// POWERPC-NEXT: lwz 4, 4(3)+// POWERPC-NEXT: stw 4, 20(1)+// POWERPC-NEXT: lwz 4, 0(3)+// POWERPC-NEXT: stw 4, 16(1)+// POWERPC-NEXT: lwz 4, 12(3)+// POWERPC-NEXT: lfd 1, 16(1)+// POWERPC-NEXT: stw 4, 28(1)+// POWERPC-NEXT: lwz 3, 8(3)+// POWERPC-NEXT: stw 3, 24(1)+// POWERPC-NEXT: lfd 2, 24(1)+// POWERPC-NEXT: addi 1, 1, 32+// POWERPC-NEXT: blr+//+// POWERPC64: .Lfunc_begin{{[0-9]+}}:+// POWERPC64-NEXT: .cfi_startproc+// POWERPC64-NEXT: blr+//+// POWERPC64LE: .Lfunc_begin{{[0-9]+}}:+// POWERPC64LE-NEXT: .cfi_startproc+// POWERPC64LE-NEXT: blr+//+// AIX: .csect .hfa1[PR],5+// AIX-NEXT: std 3, -16(1)+// AIX-NEXT: std 4, -8(1)+// AIX-NEXT: lfd 1, -16(1)+// AIX-NEXT: lfd 2, -8(1)+// AIX-NEXT: std 3, 48(1)+// AIX-NEXT: std 4, 56(1)+// AIX-NEXT: blr+#[unsafe(no_mangle)]+pub extern "C" fn hfa1(hfa: Hfa1) -> ppcf128 {+ hfa.a+}++// CHECK-LABEL: hfa2+//+// POWERPC: .Lfunc_begin{{[0-9]+}}:+// POWERPC-NEXT: .cfi_startproc+// POWERPC-NEXT: stwu 1, -32(1)+// POWERPC-NEXT: .cfi_def_cfa_offset 32+// POWERPC-NEXT: lwz 4, 20(3)+// POWERPC-NEXT: stw 4, 20(1)+// POWERPC-NEXT: lwz 4, 16(3)+// POWERPC-NEXT: stw 4, 16(1)+// POWERPC-NEXT: lwz 4, 28(3)+// POWERPC-NEXT: lfd 1, 16(1)+// POWERPC-NEXT: stw 4, 28(1)+// POWERPC-NEXT: lwz 3, 24(3)+// POWERPC-NEXT: stw 3, 24(1)+// POWERPC-NEXT: lfd 2, 24(1)+// POWERPC-NEXT: addi 1, 1, 32+// POWERPC-NEXT: blr+//+// POWERPC64: .Lfunc_begin{{[0-9]+}}:+// POWERPC64-NEXT: .cfi_startproc+// POWERPC64-NEXT: std 5, -16(1)+// POWERPC64-NEXT: std 6, -8(1)+// POWERPC64-NEXT: lfd 1, -16(1)+// POWERPC64-NEXT: lfd 2, -8(1)+// POWERPC64-NEXT: blr+//+// POWERPC64LE: .Lfunc_begin{{[0-9]+}}:+// POWERPC64LE-NEXT: .cfi_startproc+// POWERPC64LE-NEXT: fmr 2, 4+// POWERPC64LE-NEXT: fmr 1, 3+// POWERPC64LE-NEXT: blr+//+// AIX: .csect .hfa2[PR],5+// AIX-NEXT: std 5, -16(1)+// AIX-NEXT: std 6, -8(1)+// AIX-NEXT: lfd 1, -16(1)+// AIX-NEXT: lfd 2, -8(1)+// AIX-NEXT: std 6, 72(1)+// AIX-NEXT: std 5, 64(1)+// AIX-NEXT: std 3, 48(1)+// AIX-NEXT: std 4, 56(1)+// AIX-NEXT: blr+#[unsafe(no_mangle)]+pub extern "C" fn hfa2(value: Hfa2) -> ppcf128 {+ value.b+}++// CHECK-LABEL: hfa4+//+// POWERPC: .Lfunc_begin{{[0-9]+}}:+// POWERPC-NEXT: .cfi_startproc+// POWERPC-NEXT: stwu 1, -32(1)+// POWERPC-NEXT: .cfi_def_cfa_offset 32+// POWERPC-NEXT: lwz 4, 52(3)+// POWERPC-NEXT: stw 4, 20(1)+// POWERPC-NEXT: lwz 4, 48(3)+// POWERPC-NEXT: stw 4, 16(1)+// POWERPC-NEXT: lwz 4, 60(3)+// POWERPC-NEXT: lfd 1, 16(1)+// POWERPC-NEXT: stw 4, 28(1)+// POWERPC-NEXT: lwz 3, 56(3)+// POWERPC-NEXT: stw 3, 24(1)+// POWERPC-NEXT: lfd 2, 24(1)+// POWERPC-NEXT: addi 1, 1, 32+// POWERPC-NEXT: blr+//+// POWERPC64: .Lfunc_begin{{[0-9]+}}:+// POWERPC64-NEXT: .cfi_startproc+// POWERPC64-NEXT: std 9, -16(1)+// POWERPC64-NEXT: std 10, -8(1)+// POWERPC64-NEXT: lfd 1, -16(1)+// POWERPC64-NEXT: lfd 2, -8(1)+// POWERPC64-NEXT: blr+//+// POWERPC64LE: .Lfunc_begin{{[0-9]+}}:+// POWERPC64LE-NEXT: .cfi_startproc+// POWERPC64LE-NEXT: fmr 2, 8+// POWERPC64LE-NEXT: fmr 1, 7+// POWERPC64LE-NEXT: blr+//+// AIX: .csect .hfa4[PR],5+// AIX-NEXT: std 9, -16(1)+// AIX-NEXT: std 10, -8(1)+// AIX-NEXT: lfd 1, -16(1)+// AIX-NEXT: lfd 2, -8(1)+// AIX-NEXT: std 10, 104(1)+// AIX-NEXT: std 9, 96(1)+// AIX-NEXT: std 3, 48(1)+// AIX-NEXT: std 4, 56(1)+// AIX-NEXT: std 5, 64(1)+// AIX-NEXT: std 6, 72(1)+// AIX-NEXT: std 7, 80(1)+// AIX-NEXT: std 8, 88(1)+// AIX-NEXT: blr+#[unsafe(no_mangle)]+pub extern "C" fn hfa4(value: Hfa4) -> ppcf128 {+ value.d+}++#[repr(C)]+struct NonHfa5 {+ a: ppcf128,+ b: ppcf128,+ c: ppcf128,+ d: ppcf128,+ e: ppcf128,+}++// CHECK-LABEL: non_hfa5+//+// POWERPC: .Lfunc_begin{{[0-9]+}}:+// POWERPC-NEXT: .cfi_startproc+// POWERPC-NEXT: stwu 1, -32(1)+// POWERPC-NEXT: .cfi_def_cfa_offset 32+// POWERPC-NEXT: lwz 4, 68(3)+// POWERPC-NEXT: stw 4, 20(1)+// POWERPC-NEXT: lwz 4, 64(3)+// POWERPC-NEXT: stw 4, 16(1)+// POWERPC-NEXT: lwz 4, 76(3)+// POWERPC-NEXT: lfd 1, 16(1)+// POWERPC-NEXT: stw 4, 28(1)+// POWERPC-NEXT: lwz 3, 72(3)+// POWERPC-NEXT: stw 3, 24(1)+// POWERPC-NEXT: lfd 2, 24(1)+// POWERPC-NEXT: addi 1, 1, 32+// POWERPC-NEXT: blr+//+// POWERPC64: .Lfunc_begin{{[0-9]+}}:+// POWERPC64-NEXT: .cfi_startproc+// POWERPC64-NEXT: lfd 1, 112(1)+// POWERPC64-NEXT: lfd 2, 120(1)+// POWERPC64-NEXT: blr+//+// POWERPC64LE: .Lfunc_begin{{[0-9]+}}:+// POWERPC64LE-NEXT: .cfi_startproc+// POWERPC64LE-NEXT: lfd 1, 96(1)+// POWERPC64LE-NEXT: lfd 2, 104(1)+// POWERPC64LE-NEXT: blr+//+// AIX: .csect .non_hfa5[PR],5+// AIX-NEXT: lfd 1, 112(1)+// AIX-NEXT: lfd 2, 120(1)+// AIX-NEXT: std 3, 48(1)+// AIX-NEXT: std 4, 56(1)+// AIX-NEXT: std 5, 64(1)+// AIX-NEXT: std 6, 72(1)+// AIX-NEXT: std 7, 80(1)+// AIX-NEXT: std 8, 88(1)+// AIX-NEXT: std 9, 96(1)+// AIX-NEXT: std 10, 104(1)+// AIX-NEXT: blr+#[unsafe(no_mangle)]+pub extern "C" fn non_hfa5(value: NonHfa5) -> ppcf128 {+ value.e+}tests/auxiliary/minicore.rs18 + / 0 −
@@ -115,6 +115,24 @@ impl<T: PointeeSized> Copy for *const T {} impl<T: PointeeSized> Copy for *mut T {} impl<T: Copy, const N: usize> Copy for [T; N] {} +pub mod arch {+ #[cfg(target_arch = "powerpc")]+ pub mod powerpc {+ #[lang = "ppcf128"]+ pub struct ppcf128(u128);++ impl crate::Copy for ppcf128 {}+ }++ #[cfg(any(target_arch = "powerpc64"))]+ pub mod powerpc64 {+ #[lang = "ppcf128"]+ pub struct ppcf128(u128);++ impl crate::Copy for ppcf128 {}+ }+}+ #[lang = "phantom_data"] pub struct PhantomData<T: PointeeSized>; impl<T: PointeeSized> Copy for PhantomData<T> {}tests/codegen-llvm/powerpc-abi/ppcf128.rsadded92 + / 0 −
@@ -0,0 +1,92 @@+//@ add-minicore+//+//@ revisions: POWERPC POWERPC64LE POWERPC64 AIX+//@ [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu+//@ [POWERPC64LE] compile-flags: --target powerpc64le-unknown-linux-gnu+//@ [POWERPC64] compile-flags: --target powerpc64-unknown-linux-gnu+//@ [AIX] compile-flags: --target powerpc64-ibm-aix+//@ compile-flags: -Copt-level=3 --crate-type=lib+//@ needs-llvm-components: powerpc++#![feature(no_core)]+#![no_std]+#![no_core]++extern crate minicore;+#[cfg(target_arch = "powerpc")]+use minicore::arch::powerpc::ppcf128;+#[cfg(target_arch = "powerpc64")]+use minicore::arch::powerpc64::ppcf128;++/// On elfv1 and aix single-float structs are passed as scalar arguments.+#[repr(C)]+struct Hfa1 {+ a: ppcf128,+}++/// On elfv2 homogenous aggregates of up to 4 elements are passed as scalars.+#[repr(C)]+struct Hfa2 {+ a: ppcf128,+ b: ppcf128,+}++#[repr(C)]+struct Hfa4 {+ a: ppcf128,+ b: ppcf128,+ c: ppcf128,+ d: ppcf128,+}++#[repr(C)]+struct NonHfa5 {+ a: ppcf128,+ b: ppcf128,+ c: ppcf128,+ d: ppcf128,+ e: ppcf128,+}++// CHECK-LABEL: ppc_fp128 @scalar_second(ppc_fp128 noundef %_a, ppc_fp128 noundef returned %b)+#[unsafe(no_mangle)]+extern "C" fn scalar_second(_a: ppcf128, b: ppcf128) -> ppcf128 {+ // CHECK: ret ppc_fp128 %b+ b+}++// POWERPC64-LABEL: void @hfa1(ptr {{.*}}sret([16 x i8]) {{.*}}, ppc_fp128 %0)+// POWERPC64LE-LABEL: ppc_fp128 @hfa1(ppc_fp128 returned %0)+// AIX-LABEL: void @hfa1(ptr {{.*}}sret([16 x i8]) {{.*}}, ptr {{.*}}byval([16 x i8]) {{.*}})+// POWER-LABEL: void @hfa1(ptr {{.*}}sret([16 x i8]) {{.*}}, ptr {{.*}}byval([16 x i8]) {{.*}})+#[unsafe(no_mangle)]+extern "C" fn hfa1(x: Hfa1) -> Hfa1 {+ x+}++// POWERPC64-LABEL: ppc_fp128 @hfa2([2 x i128] %0)+// POWERPC64LE-LABEL: ppc_fp128 @hfa2([2 x ppc_fp128] %0)+// AIX-LABEL: ppc_fp128 @hfa2(ptr {{.*}}byval([32 x i8])+// POWER-LABEL: ppc_fp128 @hfa2(ptr {{.*}}byval([32 x i8])+#[unsafe(no_mangle)]+extern "C" fn hfa2(x: Hfa2) -> ppcf128 {+ x.b+}++// POWERPC64-LABEL: ppc_fp128 @hfa4([4 x i128] %0)+// POWERPC64LE-LABEL: ppc_fp128 @hfa4([4 x ppc_fp128] %0)+// AIX-LABEL: ppc_fp128 @hfa4(ptr {{.*}}byval([64 x i8])+// POWER-LABEL: ppc_fp128 @hfa4(ptr {{.*}}byval([64 x i8])+#[unsafe(no_mangle)]+extern "C" fn hfa4(x: Hfa4) -> ppcf128 {+ x.d+}++// POWERPC64-LABEL: ppc_fp128 @non_hfa5([5 x i128] %0)+// POWERPC64LE-LABEL: ppc_fp128 @non_hfa5([5 x i128] %0)+// AIX-LABEL: ppc_fp128 @non_hfa5(ptr {{.*}}byval([80 x i8])+// POWERPC-LABEL: ppc_fp128 @non_hfa5(ptr {{.*}}dereferenceable(80)+#[unsafe(no_mangle)]+extern "C" fn non_hfa5(x: NonHfa5) -> ppcf128 {+ x.c+}