@@ -7,6 +7,7 @@ import cllvm
7
7
/// sizes and offsets of types with respect to this target.
8
8
public class TargetData {
9
9
internal let llvm : LLVMTargetDataRef
10
+ private var structLayoutCache = [ LLVMTypeRef: StructLayout] ( )
10
11
11
12
/// Creates a Target Data object from an `LLVMTargetDataRef` object.
12
13
public init ( llvm: LLVMTargetDataRef ) {
@@ -46,16 +47,6 @@ public class TargetData {
46
47
return Int ( LLVMSizeOfTypeInBits ( llvm, type. asLLVM ( ) ) )
47
48
}
48
49
49
- /// Computes the minimum ABI-required number of bits necessary to hold a value
50
- /// of the given type for this target environment.
51
- ///
52
- /// - parameter type: The type to compute the size of.
53
- ///
54
- /// - returns: The minimum ABI-required size of the type in bytes.
55
- public func abiSizeOfType( _ type: IRType ) -> Int {
56
- return Int ( LLVMABISizeOfType ( llvm, type. asLLVM ( ) ) )
57
- }
58
-
59
50
/// The current platform byte order, either big or little endian.
60
51
public var byteOrder : ByteOrder {
61
52
return ByteOrder ( llvm: LLVMByteOrder ( llvm) )
@@ -94,6 +85,124 @@ public class TargetData {
94
85
///
95
86
/// - parameter global: The global variable
96
87
/// - returns: The variable's preferred alignment in this target
88
+ public func preferredAlignment( of global: Global ) -> Alignment {
89
+ return Alignment ( LLVMPreferredAlignmentOfGlobal ( llvm, global. asLLVM ( ) ) )
90
+ }
91
+
92
+ /// Computes the preferred alignment of the given type for this target
93
+ ///
94
+ /// - parameter type: The type for which you're computing the alignment
95
+ /// - returns: The type's preferred alignment in this target
96
+ public func preferredAlignment( of type: IRType ) -> Alignment {
97
+ return Alignment ( LLVMPreferredAlignmentOfType ( llvm, type. asLLVM ( ) ) )
98
+ }
99
+
100
+ /// Computes the minimum ABI-required alignment for the specified type.
101
+ ///
102
+ /// - parameter type: The type to whose ABI alignment you wish to compute.
103
+ /// - returns: The minimum ABI-required alignment for the specified type.
104
+ public func abiAlignment( of type: IRType ) -> Alignment {
105
+ return Alignment ( LLVMABIAlignmentOfType ( llvm, type. asLLVM ( ) ) )
106
+ }
107
+
108
+ /// Computes the minimum ABI-required alignment for the specified type.
109
+ ///
110
+ /// This function is equivalent to `TargetData.abiAlignment(of:)`.
111
+ ///
112
+ /// - parameter type: The type to whose ABI alignment you wish to compute.
113
+ /// - returns: The minimum ABI-required alignment for the specified type.
114
+ public func callFrameAlignment( of type: IRType ) -> Alignment {
115
+ return Alignment ( LLVMCallFrameAlignmentOfType ( llvm, type. asLLVM ( ) ) )
116
+ }
117
+
118
+ /// Computes the ABI size of a type in bytes for a target.
119
+ ///
120
+ /// - parameter type: The type to whose ABI size you wish to compute.
121
+ /// - returns: The ABI size for the specified type.
122
+ public func abiSize( of type: IRType ) -> Size {
123
+ return Size ( LLVMABISizeOfType ( llvm, type. asLLVM ( ) ) )
124
+ }
125
+ /// Computes the maximum number of bytes that may be overwritten by
126
+ /// storing the specified type.
127
+ ///
128
+ /// - parameter type: The type to whose store size you wish to compute.
129
+ /// - returns: The store size of the type in the given target.
130
+ public func storeSize( of type: IRType ) -> Size {
131
+ return Size ( LLVMStoreSizeOfType ( llvm, type. asLLVM ( ) ) )
132
+ }
133
+
134
+ /// Computes the pointer size for the platform, optionally in a given
135
+ /// address space.
136
+ ///
137
+ /// - parameter addressSpace: The address space in which to compute
138
+ /// pointer size.
139
+ /// - returns: The size of a pointer in the target address space.
140
+ public func pointerSize( addressSpace: Int ? = nil ) -> Size {
141
+ if let addressSpace = addressSpace {
142
+ return Size ( UInt64 ( LLVMPointerSizeForAS ( llvm, UInt32 ( addressSpace) ) ) )
143
+ } else {
144
+ return Size ( UInt64 ( LLVMPointerSize ( llvm) ) )
145
+ }
146
+ }
147
+
148
+ /// Returns the offset in bytes between successive objects of the
149
+ /// specified type, including alignment padding.
150
+ ///
151
+ /// This is the amount that alloca reserves for this type. For example,
152
+ /// returns 12 or 16 for x86_fp80, depending on alignment.
153
+ ///
154
+ /// - parameter type: The type whose allocation size you wish to compute.
155
+ /// - returns: The size an alloca would reserve for the given type.
156
+ public func allocationSize( of type: IRType ) -> Size {
157
+ // Round up to the next alignment boundary.
158
+ return TargetData . align ( self . storeSize ( of: type) , to: self . abiAlignment ( of: type) )
159
+ }
160
+
161
+ /// Returns a `StructLayout` object containing the alignment of the
162
+ /// struct, its size, and the offsets of its fields with respect to this
163
+ /// data layout.
164
+ ///
165
+ /// - parameter struct: The struct type whose layout you wish to retrieve.
166
+ /// - returns: A `StructLayout` describing the layout of the given type.
167
+ public func layout( of struct: StructType ) -> StructLayout {
168
+ guard let cachedLayout = self . structLayoutCache [ `struct`. asLLVM ( ) ] else {
169
+ let layout = StructLayout ( `struct`, self )
170
+ self . structLayoutCache [ `struct`. asLLVM ( ) ] = layout
171
+ return layout
172
+ }
173
+ return cachedLayout
174
+ }
175
+
176
+ /// Returns the next integer (mod 2**64) that is greater than or equal to
177
+ /// \p Value and is a multiple of \p Align. \p Align must be non-zero.
178
+ ///
179
+ /// If non-zero \p Skew is specified, the return value will be a minimal
180
+ /// integer that is greater than or equal to \p Value and equal to
181
+ /// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
182
+ /// \p Align, its value is adjusted to '\p Skew mod \p Align'.
183
+ ///
184
+ /// Computes the next size value that is greater than or equal to the given
185
+ /// value and is a multiple of the given alignment.
186
+ ///
187
+ /// If the skew value is non-zero, the return value will be the next size
188
+ /// value that is greater than or equal to the given value multipled by the
189
+ /// provided alignment with a skew value added
190
+ public static func align( _ value: Size , to align: Alignment , skew: Size = Size . zero) -> Size {
191
+ precondition ( !align. isZero, " Align can't be 0. " )
192
+
193
+ let skewValue = skew. rawValue % UInt64( align. rawValue)
194
+ let alignValue = UInt64 ( align. rawValue)
195
+ let retVal = ( value. rawValue + alignValue - 1 - skewValue) / alignValue * alignValue + skewValue
196
+ return Size ( retVal)
197
+ }
198
+ }
199
+
200
+ extension TargetData {
201
+ /// Computes the preferred alignment of the given global for this target
202
+ ///
203
+ /// - parameter global: The global variable
204
+ /// - returns: The variable's preferred alignment in this target
205
+ @available ( * , message: " Prefer the overload of prefferedAlignment(of:) that returns an Alignment " )
97
206
public func preferredAlignment( of global: Global ) -> Int {
98
207
return Int ( LLVMPreferredAlignmentOfGlobal ( llvm, global. asLLVM ( ) ) )
99
208
}
@@ -102,6 +211,7 @@ public class TargetData {
102
211
///
103
212
/// - parameter type: The type for which you're computing the alignment
104
213
/// - returns: The type's preferred alignment in this target
214
+ @available ( * , message: " Prefer the overload of prefferedAlignment(of:) that returns an Alignment " )
105
215
public func preferredAlignment( of type: IRType ) -> Int {
106
216
return Int ( LLVMPreferredAlignmentOfType ( llvm, type. asLLVM ( ) ) )
107
217
}
@@ -110,6 +220,7 @@ public class TargetData {
110
220
///
111
221
/// - parameter type: The type to whose ABI alignment you wish to compute.
112
222
/// - returns: The minimum ABI-required alignment for the specified type.
223
+ @available ( * , message: " Prefer the overload of abiAlignment(of:) that returns an Alignment " )
113
224
public func abiAlignment( of type: IRType ) -> Int {
114
225
return Int ( LLVMABIAlignmentOfType ( llvm, type. asLLVM ( ) ) )
115
226
}
@@ -120,6 +231,7 @@ public class TargetData {
120
231
///
121
232
/// - parameter type: The type to whose ABI alignment you wish to compute.
122
233
/// - returns: The minimum ABI-required alignment for the specified type.
234
+ @available ( * , message: " Prefer the overload of callFrameAlignment(of:) that returns an Alignment " )
123
235
public func callFrameAlignment( of type: IRType ) -> Int {
124
236
return Int ( LLVMCallFrameAlignmentOfType ( llvm, type. asLLVM ( ) ) )
125
237
}
@@ -128,6 +240,7 @@ public class TargetData {
128
240
///
129
241
/// - parameter type: The type to whose ABI size you wish to compute.
130
242
/// - returns: The ABI size for the specified type.
243
+ @available ( * , message: " Prefer the overload of abiSize(of:) that returns a Size " )
131
244
public func abiSize( of type: IRType ) -> Int {
132
245
return Int ( LLVMABISizeOfType ( llvm, type. asLLVM ( ) ) )
133
246
}
@@ -136,6 +249,7 @@ public class TargetData {
136
249
///
137
250
/// - parameter type: The type to whose store size you wish to compute.
138
251
/// - returns: The store size of the type in the given target.
252
+ @available ( * , message: " Prefer the overload of storeSize(of:) that returns a Size " )
139
253
public func storeSize( of type: IRType ) -> Int {
140
254
return Int ( LLVMStoreSizeOfType ( llvm, type. asLLVM ( ) ) )
141
255
}
@@ -146,6 +260,7 @@ public class TargetData {
146
260
/// - parameter addressSpace: The address space in which to compute
147
261
/// pointer size.
148
262
/// - returns: The size of a pointer in the target address space.
263
+ @available ( * , message: " Prefer the overload of pointerSize(addressSpace:) that returns a Size " )
149
264
public func pointerSize( addressSpace: Int ? = nil ) -> Int {
150
265
if let addressSpace = addressSpace {
151
266
return Int ( LLVMPointerSizeForAS ( llvm, UInt32 ( addressSpace) ) )
@@ -155,6 +270,87 @@ public class TargetData {
155
270
}
156
271
}
157
272
273
+ /// A `StructLayout` encapsulates information about the layout of a `StructType`.
274
+ public struct StructLayout {
275
+ /// Returns the total size of the struct in bytes.
276
+ ///
277
+ /// If the structure is packed, this returns a value that is effectively
278
+ /// the sum of the sizes of its fields. If the structure is not packed, this
279
+ /// returns the value of the sum of the sizes of its fields plus any
280
+ /// platform-dictated padding.
281
+ public let size : Size
282
+ /// Returns the alignment of the struct in bytes.
283
+ ///
284
+ /// The alignment value is effectively the maximum of the alignment of each of
285
+ /// its member values. This value will never be zero, as even an empty
286
+ /// structure has an alignment of one byte.
287
+ public let alignment : Alignment
288
+ /// Returns true if the structure type includes padding between elements.
289
+ public let isPadded : Bool
290
+ /// Returns the number of elements of this structure type.
291
+ public let elementCount : Int
292
+ /// Returns the offsets of each member from the start of the of the struct in
293
+ /// bytes.
294
+ public let memberOffsets : [ Size ]
295
+
296
+ fileprivate init ( _ st: StructType , _ dl: TargetData ) {
297
+ assert ( !st. isOpaque, " Cannot get layout of opaque structs " )
298
+ var structAlignment = Alignment . zero
299
+ var structSize = Size . zero
300
+ var structIsPadded = false
301
+ var structMemberOffsets = [ Size] ( )
302
+ structMemberOffsets. reserveCapacity ( st. elementTypes. count)
303
+ self . elementCount = st. elementTypes. count
304
+
305
+ // Loop over each of the elements, placing them in memory.
306
+ for ty in st. elementTypes {
307
+ let tyAlign = Alignment ( UInt32 ( st. isPacked ? 1 : dl. abiAlignment ( of: ty) ) )
308
+
309
+ // Add padding if necessary to align the data element properly.
310
+ if ( structSize. rawValue & UInt64 ( tyAlign. rawValue- 1 ) ) != 0 {
311
+ structIsPadded = true
312
+ structSize = TargetData . align ( structSize, to: tyAlign)
313
+ }
314
+
315
+ // Keep track of maximum alignment constraint.
316
+ structAlignment = max ( tyAlign, structAlignment)
317
+
318
+ structMemberOffsets. append ( structSize)
319
+ // Consume space for this data item
320
+ structSize = structSize + dl. allocationSize ( of: ty)
321
+ }
322
+
323
+ // Empty structures have alignment of 1 byte.
324
+ if structAlignment == Alignment . zero {
325
+ structAlignment = Alignment . one
326
+ }
327
+
328
+ // Add padding to the end of the struct so that it could be put in an array
329
+ // and all array elements would be aligned correctly.
330
+ if ( structSize. rawValue & UInt64 ( structAlignment. rawValue- 1 ) ) != 0 {
331
+ structIsPadded = true
332
+ structSize = TargetData . align ( structSize, to: structAlignment)
333
+ }
334
+ self . size = structSize
335
+ self . alignment = structAlignment
336
+ self . isPadded = structIsPadded
337
+ self . memberOffsets = structMemberOffsets
338
+ }
339
+
340
+ /// Given a valid byte offset into the structure, returns the structure
341
+ /// index that contains it.
342
+ public func index( of offset: Size ) -> Int {
343
+ precondition ( !self . memberOffsets. isEmpty,
344
+ " Cannot compute index member offset of an empty struct type! " )
345
+ // Multiple fields can have the same offset if any of them are zero sized.
346
+ // For example, in { i32, [0 x i32], i32 }, searching for offset 4 will stop
347
+ // at the i32 element, because it is the last element at that offset. This is
348
+ // the right one to return, because anything after it will have a higher
349
+ // offset, implying that this element is non-empty.
350
+ return self . memberOffsets. firstIndex ( where: { $0 > offset } ) ?? self . memberOffsets. endIndex
351
+ }
352
+ }
353
+
158
354
/// `ByteOrder` enumerates the ordering semantics of sequences of bytes on a
159
355
/// particular target architecture.
160
356
public enum ByteOrder {
0 commit comments