From efc67646fabbba0d79b386fb9fec2f89c20314bc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 27 Jul 2017 20:40:24 -0700 Subject: [PATCH] Support homogeneous aggregates for hard-float ARM Hard-float ARM targets use the AACPS-VFP ABI, which passes and returns homogeneous float/vector aggregates in the VFP registers. Fixes #43329. --- src/librustc_trans/cabi_arm.rs | 60 +++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs index 7a91cad511d..635741b4d1a 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_trans/cabi_arm.rs @@ -8,14 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Reg, Uniform}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; +use llvm::CallConv; -fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn is_homogeneous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogeneous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); + + // Ensure we have at most four uniquely addressable members. + if size > unit.size.checked_mul(4, ccx).unwrap() { + return None; + } + + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 64 || size.bits() == 128 + }; + + if valid_unit { + Some(Uniform { + unit, + total: size + }) + } else { + None + } + }) +} + +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>, vfp: bool) { if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; } + + if vfp { + if let Some(uniform) = is_homogeneous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); + return; + } + } + let size = ret.layout.size(ccx); let bits = size.bits(); if bits <= 32 { @@ -35,11 +71,19 @@ fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tc ret.make_indirect(ccx); } -fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>, vfp: bool) { if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; } + + if vfp { + if let Some(uniform) = is_homogeneous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); + return; + } + } + let align = arg.layout.align(ccx).abi(); let total = arg.layout.size(ccx); arg.cast_to(ccx, Uniform { @@ -49,12 +93,18 @@ fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tc } pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + // If this is a target with a hard-float ABI, and the function is not explicitly + // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates. + let vfp = ccx.sess().target.target.llvm_target.ends_with("hf") + && fty.cconv != CallConv::ArmAapcsCallConv + && !fty.variadic; + if !fty.ret.is_ignore() { - classify_ret_ty(ccx, &mut fty.ret); + classify_ret_ty(ccx, &mut fty.ret, vfp); } for arg in &mut fty.args { if arg.is_ignore() { continue; } - classify_arg_ty(ccx, arg); + classify_arg_ty(ccx, arg, vfp); } } -- GitLab