diff --git a/src/librustc_trans/trans/cabi.rs b/src/librustc_trans/trans/cabi.rs index 8a2a2534cabd2..f7ffbb95feb3b 100644 --- a/src/librustc_trans/trans/cabi.rs +++ b/src/librustc_trans/trans/cabi.rs @@ -115,8 +115,15 @@ pub fn compute_abi_info(ccx: &CrateContext, } else { cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def) }, - "arm" => cabi_arm::compute_abi_info(ccx, atys, rty, ret_def), "aarch64" => cabi_aarch64::compute_abi_info(ccx, atys, rty, ret_def), + "arm" => { + let flavor = if ccx.sess().target.target.target_os == "ios" { + cabi_arm::Flavor::Ios + } else { + cabi_arm::Flavor::General + }; + cabi_arm::compute_abi_info(ccx, atys, rty, ret_def, flavor) + }, "mips" => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a) []), diff --git a/src/librustc_trans/trans/cabi_arm.rs b/src/librustc_trans/trans/cabi_arm.rs index 46440fcf1a1b3..830771d7397e2 100644 --- a/src/librustc_trans/trans/cabi_arm.rs +++ b/src/librustc_trans/trans/cabi_arm.rs @@ -19,16 +19,23 @@ use trans::type_::Type; use std::cmp; +pub enum Flavor { + General, + Ios +} + +type TyAlignFn = fn(ty: Type) -> uint; + fn align_up_to(off: uint, a: uint) -> uint { return (off + a - 1u) / a * a; } -fn align(off: uint, ty: Type) -> uint { - let a = ty_align(ty); +fn align(off: uint, ty: Type, align_fn: TyAlignFn) -> uint { + let a = align_fn(ty); return align_up_to(off, a); } -fn ty_align(ty: Type) -> uint { +fn general_ty_align(ty: Type) -> uint { match ty.kind() { Integer => { unsafe { @@ -43,18 +50,51 @@ fn ty_align(ty: Type) -> uint { 1 } else { let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) + str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + general_ty_align(elt) + } + _ => panic!("ty_align: unhandled type") + } +} + +// For more information see: +// ARMv7 +// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual +// /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html +// ARMv6 +// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual +// /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html +fn ios_ty_align(ty: Type) -> uint { + match ty.kind() { + Integer => { + unsafe { + cmp::min(4, ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8) + } + } + Pointer => 4, + Float => 4, + Double => 4, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t))) } } Array => { let elt = ty.element_type(); - ty_align(elt) + ios_ty_align(elt) } _ => panic!("ty_align: unhandled type") } } -fn ty_size(ty: Type) -> uint { +fn ty_size(ty: Type, align_fn: TyAlignFn) -> uint { match ty.kind() { Integer => { unsafe { @@ -67,29 +107,32 @@ fn ty_size(ty: Type) -> uint { Struct => { if ty.is_packed() { let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn)) } else { let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) + let size = str_tys.iter() + .fold(0, |s, t| { + align(s, *t, align_fn) + ty_size(*t, align_fn) + }); + align(size, ty, align_fn) } } Array => { let len = ty.array_length(); let elt = ty.element_type(); - let eltsz = ty_size(elt); + let eltsz = ty_size(elt, align_fn); len * eltsz } _ => panic!("ty_size: unhandled type") } } -fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { +fn classify_ret_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { if is_reg_ty(ty) { let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; return ArgType::direct(ty, None, None, attr); } - let size = ty_size(ty); + let size = ty_size(ty, align_fn); if size <= 4 { let llty = if size <= 1 { Type::i8(ccx) @@ -103,13 +146,13 @@ fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { ArgType::indirect(ty, Some(StructRetAttribute)) } -fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType { +fn classify_arg_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { if is_reg_ty(ty) { let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; return ArgType::direct(ty, None, None, attr); } - let align = ty_align(ty); - let size = ty_size(ty); + let align = align_fn(ty); + let size = ty_size(ty, align_fn); let llty = if align <= 4 { Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64) } else { @@ -131,15 +174,21 @@ fn is_reg_ty(ty: Type) -> bool { pub fn compute_abi_info(ccx: &CrateContext, atys: &[Type], rty: Type, - ret_def: bool) -> FnType { + ret_def: bool, + flavor: Flavor) -> FnType { + let align_fn = match flavor { + Flavor::General => general_ty_align as TyAlignFn, + Flavor::Ios => ios_ty_align as TyAlignFn, + }; + let mut arg_tys = Vec::new(); for &aty in atys.iter() { - let ty = classify_arg_ty(ccx, aty); + let ty = classify_arg_ty(ccx, aty, align_fn); arg_tys.push(ty); } let ret_ty = if ret_def { - classify_ret_ty(ccx, rty) + classify_ret_ty(ccx, rty, align_fn) } else { ArgType::direct(Type::void(ccx), None, None, None) };