1
+ // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2
+ // file at the top-level directory of this distribution and at
3
+ // http://rust-lang.org/COPYRIGHT.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6
+ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7
+ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8
+ // option. This file may not be copied, modified, or distributed
9
+ // except according to those terms.
10
+
11
+ use abi:: { Align , HasDataLayout , Size } ;
12
+
13
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
14
+ pub enum PassMode {
15
+ /// Ignore the argument (useful for empty struct).
16
+ Ignore ,
17
+ /// Pass the argument directly.
18
+ Direct ( ArgAttributes ) ,
19
+ /// Pass a pair's elements directly in two arguments.
20
+ Pair ( ArgAttributes , ArgAttributes ) ,
21
+ /// Pass the argument after casting it, to either
22
+ /// a single uniform or a pair of registers.
23
+ Cast ( CastTarget ) ,
24
+ /// Pass the argument indirectly via a hidden pointer.
25
+ Indirect ( ArgAttributes ) ,
26
+ }
27
+
28
+ // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
29
+ // of this module
30
+ pub use self :: attr_impl:: ArgAttribute ;
31
+
32
+ #[ allow( non_upper_case_globals) ]
33
+ #[ allow( unused) ]
34
+ mod attr_impl {
35
+ // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
36
+ bitflags ! {
37
+ #[ derive( Default ) ]
38
+ pub struct ArgAttribute : u16 {
39
+ const ByVal = 1 << 0 ;
40
+ const NoAlias = 1 << 1 ;
41
+ const NoCapture = 1 << 2 ;
42
+ const NonNull = 1 << 3 ;
43
+ const ReadOnly = 1 << 4 ;
44
+ const SExt = 1 << 5 ;
45
+ const StructRet = 1 << 6 ;
46
+ const ZExt = 1 << 7 ;
47
+ const InReg = 1 << 8 ;
48
+ }
49
+ }
50
+ }
51
+
52
+ /// A compact representation of LLVM attributes (at least those relevant for this module)
53
+ /// that can be manipulated without interacting with LLVM's Attribute machinery.
54
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
55
+ pub struct ArgAttributes {
56
+ pub regular : ArgAttribute ,
57
+ pub pointee_size : Size ,
58
+ pub pointee_align : Option < Align >
59
+ }
60
+
61
+ impl ArgAttributes {
62
+ pub fn new ( ) -> Self {
63
+ ArgAttributes {
64
+ regular : ArgAttribute :: default ( ) ,
65
+ pointee_size : Size :: from_bytes ( 0 ) ,
66
+ pointee_align : None ,
67
+ }
68
+ }
69
+
70
+ pub fn set ( & mut self , attr : ArgAttribute ) -> & mut Self {
71
+ self . regular = self . regular | attr;
72
+ self
73
+ }
74
+
75
+ pub fn contains ( & self , attr : ArgAttribute ) -> bool {
76
+ self . regular . contains ( attr)
77
+ }
78
+ }
79
+
80
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
81
+ pub enum RegKind {
82
+ Integer ,
83
+ Float ,
84
+ Vector
85
+ }
86
+
87
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
88
+ pub struct Reg {
89
+ pub kind : RegKind ,
90
+ pub size : Size ,
91
+ }
92
+
93
+ macro_rules! reg_ctor {
94
+ ( $name: ident, $kind: ident, $bits: expr) => {
95
+ pub fn $name( ) -> Reg {
96
+ Reg {
97
+ kind: RegKind :: $kind,
98
+ size: Size :: from_bits( $bits)
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ impl Reg {
105
+ reg_ctor ! ( i8 , Integer , 8 ) ;
106
+ reg_ctor ! ( i16 , Integer , 16 ) ;
107
+ reg_ctor ! ( i32 , Integer , 32 ) ;
108
+ reg_ctor ! ( i64 , Integer , 64 ) ;
109
+
110
+ reg_ctor ! ( f32 , Float , 32 ) ;
111
+ reg_ctor ! ( f64 , Float , 64 ) ;
112
+ }
113
+
114
+ impl Reg {
115
+ pub fn align < C : HasDataLayout > ( & self , cx : C ) -> Align {
116
+ let dl = cx. data_layout ( ) ;
117
+ match self . kind {
118
+ RegKind :: Integer => {
119
+ match self . size . bits ( ) {
120
+ 1 => dl. i1_align ,
121
+ 2 ...8 => dl. i8_align ,
122
+ 9 ...16 => dl. i16_align ,
123
+ 17 ...32 => dl. i32_align ,
124
+ 33 ...64 => dl. i64_align ,
125
+ 65 ...128 => dl. i128_align ,
126
+ _ => panic ! ( "unsupported integer: {:?}" , self )
127
+ }
128
+ }
129
+ RegKind :: Float => {
130
+ match self . size . bits ( ) {
131
+ 32 => dl. f32_align ,
132
+ 64 => dl. f64_align ,
133
+ _ => panic ! ( "unsupported float: {:?}" , self )
134
+ }
135
+ }
136
+ RegKind :: Vector => dl. vector_align ( self . size )
137
+ }
138
+ }
139
+ }
140
+
141
+ /// An argument passed entirely registers with the
142
+ /// same kind (e.g. HFA / HVA on PPC64 and AArch64).
143
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
144
+ pub struct Uniform {
145
+ pub unit : Reg ,
146
+
147
+ /// The total size of the argument, which can be:
148
+ /// * equal to `unit.size` (one scalar/vector)
149
+ /// * a multiple of `unit.size` (an array of scalar/vectors)
150
+ /// * if `unit.kind` is `Integer`, the last element
151
+ /// can be shorter, i.e. `{ i64, i64, i32 }` for
152
+ /// 64-bit integers with a total size of 20 bytes
153
+ pub total : Size ,
154
+ }
155
+
156
+ impl From < Reg > for Uniform {
157
+ fn from ( unit : Reg ) -> Uniform {
158
+ Uniform {
159
+ unit,
160
+ total : unit. size
161
+ }
162
+ }
163
+ }
164
+
165
+ impl Uniform {
166
+ pub fn align < C : HasDataLayout > ( & self , cx : C ) -> Align {
167
+ self . unit . align ( cx)
168
+ }
169
+ }
170
+
171
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
172
+ pub struct CastTarget {
173
+ pub prefix : [ Option < RegKind > ; 8 ] ,
174
+ pub prefix_chunk : Size ,
175
+ pub rest : Uniform ,
176
+ }
177
+
178
+ impl From < Reg > for CastTarget {
179
+ fn from ( unit : Reg ) -> CastTarget {
180
+ CastTarget :: from ( Uniform :: from ( unit) )
181
+ }
182
+ }
183
+
184
+ impl From < Uniform > for CastTarget {
185
+ fn from ( uniform : Uniform ) -> CastTarget {
186
+ CastTarget {
187
+ prefix : [ None ; 8 ] ,
188
+ prefix_chunk : Size :: from_bytes ( 0 ) ,
189
+ rest : uniform
190
+ }
191
+ }
192
+ }
193
+
194
+ impl CastTarget {
195
+ pub fn pair ( a : Reg , b : Reg ) -> CastTarget {
196
+ CastTarget {
197
+ prefix : [ Some ( a. kind ) , None , None , None , None , None , None , None ] ,
198
+ prefix_chunk : a. size ,
199
+ rest : Uniform :: from ( b)
200
+ }
201
+ }
202
+
203
+ pub fn size < C : HasDataLayout > ( & self , cx : C ) -> Size {
204
+ ( self . prefix_chunk * self . prefix . iter ( ) . filter ( |x| x. is_some ( ) ) . count ( ) as u64 )
205
+ . abi_align ( self . rest . align ( cx) ) + self . rest . total
206
+ }
207
+
208
+ pub fn align < C : HasDataLayout > ( & self , cx : C ) -> Align {
209
+ self . prefix . iter ( )
210
+ . filter_map ( |x| x. map ( |kind| Reg { kind : kind, size : self . prefix_chunk } . align ( cx) ) )
211
+ . fold ( cx. data_layout ( ) . aggregate_align . max ( self . rest . align ( cx) ) ,
212
+ |acc, align| acc. max ( align) )
213
+ }
214
+ }
0 commit comments