compiler: Wire {TyAnd,}Layout into rustc_abi · rust-lang/rust@1072190 (original) (raw)

``

1

`+

mod abi {

`

``

2

`+

pub(crate) use crate::Primitive::*;

`

``

3

`+

pub(crate) use crate::Variants;

`

``

4

`+

}

`

``

5

+

``

6

`+

use rustc_macros::HashStable_Generic;

`

``

7

+

``

8

`+

use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};

`

``

9

+

``

10

`+

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]

`

``

11

`+

pub enum RegKind {

`

``

12

`+

Integer,

`

``

13

`+

Float,

`

``

14

`+

Vector,

`

``

15

`+

}

`

``

16

+

``

17

`+

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]

`

``

18

`+

pub struct Reg {

`

``

19

`+

pub kind: RegKind,

`

``

20

`+

pub size: Size,

`

``

21

`+

}

`

``

22

+

``

23

`+

macro_rules! reg_ctor {

`

``

24

`+

($name:ident, kind:ident,kind:ident, kind:ident,bits:expr) => {

`

``

25

`+

pub fn $name() -> Reg {

`

``

26

`+

Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }

`

``

27

`+

}

`

``

28

`+

};

`

``

29

`+

}

`

``

30

+

``

31

`+

impl Reg {

`

``

32

`+

reg_ctor!(i8, Integer, 8);

`

``

33

`+

reg_ctor!(i16, Integer, 16);

`

``

34

`+

reg_ctor!(i32, Integer, 32);

`

``

35

`+

reg_ctor!(i64, Integer, 64);

`

``

36

`+

reg_ctor!(i128, Integer, 128);

`

``

37

+

``

38

`+

reg_ctor!(f32, Float, 32);

`

``

39

`+

reg_ctor!(f64, Float, 64);

`

``

40

`+

}

`

``

41

+

``

42

`+

impl Reg {

`

``

43

`+

pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {

`

``

44

`+

let dl = cx.data_layout();

`

``

45

`+

match self.kind {

`

``

46

`+

RegKind::Integer => match self.size.bits() {

`

``

47

`+

1 => dl.i1_align.abi,

`

``

48

`+

2..=8 => dl.i8_align.abi,

`

``

49

`+

9..=16 => dl.i16_align.abi,

`

``

50

`+

17..=32 => dl.i32_align.abi,

`

``

51

`+

33..=64 => dl.i64_align.abi,

`

``

52

`+

65..=128 => dl.i128_align.abi,

`

``

53

`+

_ => panic!("unsupported integer: {self:?}"),

`

``

54

`+

},

`

``

55

`+

RegKind::Float => match self.size.bits() {

`

``

56

`+

16 => dl.f16_align.abi,

`

``

57

`+

32 => dl.f32_align.abi,

`

``

58

`+

64 => dl.f64_align.abi,

`

``

59

`+

128 => dl.f128_align.abi,

`

``

60

`+

_ => panic!("unsupported float: {self:?}"),

`

``

61

`+

},

`

``

62

`+

RegKind::Vector => dl.vector_align(self.size).abi,

`

``

63

`+

}

`

``

64

`+

}

`

``

65

`+

}

`

``

66

+

``

67

`` +

/// Return value from the homogeneous_aggregate test function.

``

``

68

`+

#[derive(Copy, Clone, Debug)]

`

``

69

`+

pub enum HomogeneousAggregate {

`

``

70

`+

/// Yes, all the "leaf fields" of this struct are passed in the

`

``

71

`` +

/// same way (specified in the Reg value).

``

``

72

`+

Homogeneous(Reg),

`

``

73

+

``

74

`+

/// There are no leaf fields at all.

`

``

75

`+

NoData,

`

``

76

`+

}

`

``

77

+

``

78

`` +

/// Error from the homogeneous_aggregate test function, indicating

``

``

79

`+

/// there are distinct leaf fields passed in different ways,

`

``

80

`+

/// or this is uninhabited.

`

``

81

`+

#[derive(Copy, Clone, Debug)]

`

``

82

`+

pub struct Heterogeneous;

`

``

83

+

``

84

`+

impl HomogeneousAggregate {

`

``

85

`+

/// If this is a homogeneous aggregate, returns the homogeneous

`

``

86

`` +

/// unit, else None.

``

``

87

`+

pub fn unit(self) -> Option {

`

``

88

`+

match self {

`

``

89

`+

HomogeneousAggregate::Homogeneous(reg) => Some(reg),

`

``

90

`+

HomogeneousAggregate::NoData => None,

`

``

91

`+

}

`

``

92

`+

}

`

``

93

+

``

94

`` +

/// Try to combine two HomogeneousAggregates, e.g. from two fields in

``

``

95

`` +

/// the same struct. Only succeeds if only one of them has any data,

``

``

96

`+

/// or both units are identical.

`

``

97

`+

fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {

`

``

98

`+

match (self, other) {

`

``

99

`+

(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),

`

``

100

+

``

101

`+

(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {

`

``

102

`+

if a != b {

`

``

103

`+

return Err(Heterogeneous);

`

``

104

`+

}

`

``

105

`+

Ok(self)

`

``

106

`+

}

`

``

107

`+

}

`

``

108

`+

}

`

``

109

`+

}

`

``

110

+

``

111

`+

impl<'a, Ty> TyAndLayout<'a, Ty> {

`

``

112

`` +

/// Returns true if this is an aggregate type (including a ScalarPair!)

``

``

113

`+

pub fn is_aggregate(&self) -> bool {

`

``

114

`+

match self.abi {

`

``

115

`+

Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,

`

``

116

`+

Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,

`

``

117

`+

}

`

``

118

`+

}

`

``

119

+

``

120

`` +

/// Returns Homogeneous if this layout is an aggregate containing fields of

``

``

121

`` +

/// only a single type (e.g., (u32, u32)). Such aggregates are often

``

``

122

`+

/// special-cased in ABIs.

`

``

123

`+

///

`

``

124

`+

/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).

`

``

125

`+

///

`

``

126

`+

/// This is public so that it can be used in unit tests, but

`

``

127

`+

/// should generally only be relevant to the ABI details of

`

``

128

`+

/// specific targets.

`

``

129

`+

pub fn homogeneous_aggregate(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>

`

``

130

`+

where

`

``

131

`+

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

`

``

132

`+

{

`

``

133

`+

match self.abi {

`

``

134

`+

Abi::Uninhabited => Err(Heterogeneous),

`

``

135

+

``

136

`+

// The primitive for this algorithm.

`

``

137

`+

Abi::Scalar(scalar) => {

`

``

138

`+

let kind = match scalar.primitive() {

`

``

139

`+

abi::Int(..) | abi::Pointer(_) => RegKind::Integer,

`

``

140

`+

abi::Float(_) => RegKind::Float,

`

``

141

`+

};

`

``

142

`+

Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))

`

``

143

`+

}

`

``

144

+

``

145

`+

Abi::Vector { .. } => {

`

``

146

`+

assert!(!self.is_zst());

`

``

147

`+

Ok(HomogeneousAggregate::Homogeneous(Reg {

`

``

148

`+

kind: RegKind::Vector,

`

``

149

`+

size: self.size,

`

``

150

`+

}))

`

``

151

`+

}

`

``

152

+

``

153

`+

Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => {

`

``

154

`` +

// Helper for computing homogeneous_aggregate, allowing a custom

``

``

155

`+

// starting offset (used below for handling variants).

`

``

156

`+

let from_fields_at =

`

``

157

`+

|layout: Self,

`

``

158

`+

start: Size|

`

``

159

`+

-> Result<(HomogeneousAggregate, Size), Heterogeneous> {

`

``

160

`+

let is_union = match layout.fields {

`

``

161

`+

FieldsShape::Primitive => {

`

``

162

`` +

unreachable!("aggregates can't have FieldsShape::Primitive")

``

``

163

`+

}

`

``

164

`+

FieldsShape::Array { count, .. } => {

`

``

165

`+

assert_eq!(start, Size::ZERO);

`

``

166

+

``

167

`+

let result = if count > 0 {

`

``

168

`+

layout.field(cx, 0).homogeneous_aggregate(cx)?

`

``

169

`+

} else {

`

``

170

`+

HomogeneousAggregate::NoData

`

``

171

`+

};

`

``

172

`+

return Ok((result, layout.size));

`

``

173

`+

}

`

``

174

`+

FieldsShape::Union(_) => true,

`

``

175

`+

FieldsShape::Arbitrary { .. } => false,

`

``

176

`+

};

`

``

177

+

``

178

`+

let mut result = HomogeneousAggregate::NoData;

`

``

179

`+

let mut total = start;

`

``

180

+

``

181

`+

for i in 0..layout.fields.count() {

`

``

182

`+

let field = layout.field(cx, i);

`

``

183

`+

if field.is_1zst() {

`

``

184

`+

// No data here and no impact on layout, can be ignored.

`

``

185

`+

// (We might be able to also ignore all aligned ZST but that's less clear.)

`

``

186

`+

continue;

`

``

187

`+

}

`

``

188

+

``

189

`+

if !is_union && total != layout.fields.offset(i) {

`

``

190

`+

// This field isn't just after the previous one we considered, abort.

`

``

191

`+

return Err(Heterogeneous);

`

``

192

`+

}

`

``

193

+

``

194

`+

result = result.merge(field.homogeneous_aggregate(cx)?)?;

`

``

195

+

``

196

`+

// Keep track of the offset (without padding).

`

``

197

`+

let size = field.size;

`

``

198

`+

if is_union {

`

``

199

`+

total = total.max(size);

`

``

200

`+

} else {

`

``

201

`+

total += size;

`

``

202

`+

}

`

``

203

`+

}

`

``

204

+

``

205

`+

Ok((result, total))

`

``

206

`+

};

`

``

207

+

``

208

`+

let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;

`

``

209

+

``

210

`+

match &self.variants {

`

``

211

`+

abi::Variants::Single { .. } => {}

`

``

212

`+

abi::Variants::Multiple { variants, .. } => {

`

``

213

`+

// Treat enum variants like union members.

`

``

214

`` +

// HACK(eddyb) pretend the enum field (discriminant)

``

``

215

`+

// is at the start of every variant (otherwise the gap

`

``

216

`+

// at the start of all variants would disqualify them).

`

``

217

`+

//

`

``

218

`` +

// NB: for all tagged enums (which include all non-C-like

``

``

219

`` +

// enums with defined FFI representation), this will

``

``

220

`+

// match the homogeneous computation on the equivalent

`

``

221

`` +

// struct { tag; union { variant1; ... } } and/or

``

``

222

`` +

// union { struct { tag; variant1; } ... }

``

``

223

`+

// (the offsets of variant fields should be identical

`

``

224

`+

// between the two for either to be a homogeneous aggregate).

`

``

225

`+

let variant_start = total;

`

``

226

`+

for variant_idx in variants.indices() {

`

``

227

`+

let (variant_result, variant_total) =

`

``

228

`+

from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;

`

``

229

+

``

230

`+

result = result.merge(variant_result)?;

`

``

231

`+

total = total.max(variant_total);

`

``

232

`+

}

`

``

233

`+

}

`

``

234

`+

}

`

``

235

+

``

236

`+

// There needs to be no padding.

`

``

237

`+

if total != self.size {

`

``

238

`+

Err(Heterogeneous)

`

``

239

`+

} else {

`

``

240

`+

match result {

`

``

241

`+

HomogeneousAggregate::Homogeneous(_) => {

`

``

242

`+

assert_ne!(total, Size::ZERO);

`

``

243

`+

}

`

``

244

`+

HomogeneousAggregate::NoData => {

`

``

245

`+

assert_eq!(total, Size::ZERO);

`

``

246

`+

}

`

``

247

`+

}

`

``

248

`+

Ok(result)

`

``

249

`+

}

`

``

250

`+

}

`

``

251

`+

Abi::Aggregate { sized: false } => Err(Heterogeneous),

`

``

252

`+

}

`

``

253

`+

}

`

``

254

`+

}

`