aarch64 softfloat target: always pass floats in int registers · rust-lang/rust@666bcbd (original) (raw)

``

1

`+

use std::iter;

`

``

2

+

``

3

`+

use rustc_abi::{BackendRepr, Primitive};

`

``

4

+

1

5

`use crate::abi:🤙:{ArgAbi, FnAbi, Reg, RegKind, Uniform};

`

2

6

`use crate::abi::{HasDataLayout, TyAbiInterface};

`

``

7

`+

use crate::spec::{HasTargetSpec, Target};

`

3

8

``

4

9

`/// Indicates the variant of the AArch64 ABI we are compiling for.

`

5

10

`/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.

`

`@@ -15,7 +20,7 @@ pub(crate) enum AbiKind {

`

15

20

`fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option

`

16

21

`where

`

17

22

`Ty: TyAbiInterface<'a, C> + Copy,

`

18

``

`-

C: HasDataLayout,

`

``

23

`+

C: HasDataLayout + HasTargetSpec,

`

19

24

`{

`

20

25

` arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {

`

21

26

`let size = arg.layout.size;

`

`@@ -27,18 +32,52 @@ where

`

27

32

``

28

33

`let valid_unit = match unit.kind {

`

29

34

`RegKind::Integer => false,

`

30

``

`-

RegKind::Float => true,

`

``

35

`+

// The softfloat ABI treats floats like integers, so they

`

``

36

`+

// do not get homogeneous aggregate treatment.

`

``

37

`+

RegKind::Float => cx.target_spec().abi != "softfloat",

`

31

38

`RegKind::Vector => size.bits() == 64 || size.bits() == 128,

`

32

39

`};

`

33

40

``

34

41

` valid_unit.then_some(Uniform::consecutive(unit, size))

`

35

42

`})

`

36

43

`}

`

37

44

``

``

45

`+

fn softfloat_float_abi(target: &Target, arg: &mut ArgAbi<'_, Ty>) {

`

``

46

`+

if target.abi != "softfloat" {

`

``

47

`+

return;

`

``

48

`+

}

`

``

49

`+

// Do not use the float registers for passing arguments, as that would make LLVM pick the ABI

`

``

50

`` +

// and its choice depends on whether neon instructions are enabled. Instead, we follow the

``

``

51

`+

// AAPCS "softfloat" ABI, which specifies that floats should be passed as equivalently-sized

`

``

52

`+

// integers. Nominally this only exists for "R" profile chips, but sometimes people don't want

`

``

53

`+

// to use hardfloats even if the hardware supports them, so we do this for all softfloat

`

``

54

`+

// targets.

`

``

55

`+

if let BackendRepr::Scalar(s) = arg.layout.backend_repr

`

``

56

`+

&& let Primitive::Float(f) = s.primitive()

`

``

57

`+

{

`

``

58

`+

arg.cast_to(Reg { kind: RegKind::Integer, size: f.size() });

`

``

59

`+

} else if let BackendRepr::ScalarPair(s1, s2) = arg.layout.backend_repr

`

``

60

`+

&& (matches!(s1.primitive(), Primitive::Float(_))

`

``

61

`+

|| matches!(s2.primitive(), Primitive::Float(_)))

`

``

62

`+

{

`

``

63

`+

// This case can only be reached for the Rust ABI, so we can do whatever we want here as

`

``

64

`+

// long as it does not depend on target features (i.e., as long as we do not use float

`

``

65

`+

// registers). So we pass small things in integer registers and large things via pointer

`

``

66

`+

// indirection. This means we lose the nice "pass it as two arguments" optimization, but we

`

``

67

`` +

// currently just have to way to combine a PassMode::Cast with that optimization (and we

``

``

68

`+

// need a cast since we want to pass the float as an int).

`

``

69

`+

if arg.layout.size.bits() <= target.pointer_width.into() {

`

``

70

`+

arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size });

`

``

71

`+

} else {

`

``

72

`+

arg.make_indirect();

`

``

73

`+

}

`

``

74

`+

}

`

``

75

`+

}

`

``

76

+

38

77

`fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)

`

39

78

`where

`

40

79

`Ty: TyAbiInterface<'a, C> + Copy,

`

41

``

`-

C: HasDataLayout,

`

``

80

`+

C: HasDataLayout + HasTargetSpec,

`

42

81

`{

`

43

82

`if !ret.layout.is_sized() {

`

44

83

`// Not touching this...

`

`@@ -51,6 +90,7 @@ where

`

51

90

`// See also: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly

`

52

91

` ret.extend_integer_width_to(32)

`

53

92

`}

`

``

93

`+

softfloat_float_abi(cx.target_spec(), ret);

`

54

94

`return;

`

55

95

`}

`

56

96

`if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {

`

`@@ -69,7 +109,7 @@ where

`

69

109

`fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)

`

70

110

`where

`

71

111

`Ty: TyAbiInterface<'a, C> + Copy,

`

72

``

`-

C: HasDataLayout,

`

``

112

`+

C: HasDataLayout + HasTargetSpec,

`

73

113

`{

`

74

114

`if !arg.layout.is_sized() {

`

75

115

`// Not touching this...

`

`@@ -82,6 +122,8 @@ where

`

82

122

`// See also: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly

`

83

123

` arg.extend_integer_width_to(32);

`

84

124

`}

`

``

125

`+

softfloat_float_abi(cx.target_spec(), arg);

`

``

126

+

85

127

`return;

`

86

128

`}

`

87

129

`if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {

`

`@@ -112,7 +154,7 @@ where

`

112

154

`pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind)

`

113

155

`where

`

114

156

`Ty: TyAbiInterface<'a, C> + Copy,

`

115

``

`-

C: HasDataLayout,

`

``

157

`+

C: HasDataLayout + HasTargetSpec,

`

116

158

`{

`

117

159

`if !fn_abi.ret.is_ignore() {

`

118

160

`classify_ret(cx, &mut fn_abi.ret, kind);

`

`@@ -125,3 +167,13 @@ where

`

125

167

`classify_arg(cx, arg, kind);

`

126

168

`}

`

127

169

`}

`

``

170

+

``

171

`+

pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)

`

``

172

`+

where

`

``

173

`+

Ty: TyAbiInterface<'a, C> + Copy,

`

``

174

`+

C: HasDataLayout + HasTargetSpec,

`

``

175

`+

{

`

``

176

`+

for arg in fn_abi.args.iter_mut().chain(iter::once(&mut fn_abi.ret)) {

`

``

177

`+

softfloat_float_abi(cx.target_spec(), arg);

`

``

178

`+

}

`

``

179

`+

}

`