2
2
import cllvm
3
3
#endif
4
4
5
+ /// The `LLVMIntrinsic` protocol represents types that act as selectors for
6
+ /// intrinsic functions.
7
+ ///
8
+ /// LLVM supports the notion of an “intrinsic function”. These functions have
9
+ /// well known names and semantics and are required to follow certain
10
+ /// restrictions. Overall, these intrinsics represent an extension mechanism for
11
+ /// the LLVM language that does not require changing all of the transformations
12
+ /// in LLVM when adding to the language.
13
+ ///
14
+ /// Intrinsic function names all start with an "llvm." prefix. This prefix is
15
+ /// reserved in LLVM for intrinsic names; thus, function names may not begin
16
+ /// with this prefix. Intrinsic functions must always be external functions:
17
+ /// you cannot define the body of intrinsic functions. Intrinsic functions may
18
+ /// only be used in call or invoke instructions: it is illegal to take the
19
+ /// address of an intrinsic function.
5
20
public protocol LLVMIntrinsic {
6
21
var signature : FunctionType { get }
7
22
var llvmSelector : String { get }
8
23
}
9
24
25
+ /// The `LLVMOverloadedIntrinsic` protocol represents types that act as
26
+ /// selectors for a family of overloaded intrinsic functions.
27
+ ///
28
+ /// Some intrinsic functions can be overloaded, i.e., the intrinsic represents a
29
+ /// family of functions that perform the same operation but on different data
30
+ /// types. Because LLVM can represent over 8 million different integer types,
31
+ /// overloading is used commonly to allow an intrinsic function to operate on
32
+ /// any integer type. One or more of the argument types or the result type can
33
+ /// be overloaded to accept any integer type. Argument types may also be defined
34
+ /// as exactly matching a previous argument’s type or the result type. This
35
+ /// allows an intrinsic function which accepts multiple arguments, but needs all
36
+ /// of them to be of the same type, to only be overloaded with respect to a
37
+ /// single argument or the result.
38
+ ///
39
+ /// Overloaded intrinsics will have the names of its overloaded argument types
40
+ /// encoded into its function name, each preceded by a period. Only those types
41
+ /// which are overloaded result in a name suffix. Arguments whose type is
42
+ /// matched against another type do not. For example, the llvm.ctpop function
43
+ /// can take an integer of any width and returns an integer of exactly the same
44
+ /// integer width. This leads to a family of functions such as
45
+ /// `i8 @llvm.ctpop.i8(i8 %val) and i29 @llvm.ctpop.i29(i29 %val)`. Only one
46
+ /// type, the return type, is overloaded, and only one type suffix is required.
47
+ /// Because the argument’s type is matched against the return type, it does not
48
+ /// require its own name suffix.
10
49
public protocol LLVMOverloadedIntrinsic : LLVMIntrinsic {
11
50
static var overloadSet : [ LLVMIntrinsic ] { get }
12
51
}
13
52
14
- internal struct IntrinsicSubstitutionMarker : IRType {
15
- func asLLVM( ) -> LLVMTypeRef {
16
- fatalError ( " Unhandled substitution marker in type " )
17
- }
18
- }
53
+ extension IRBuilder {
54
+ /// Builds a call to an intrinsic function.
55
+ ///
56
+ /// - note: In debug builds this function type checks its arguments to ensure
57
+ /// calls are well-formed. In release builds no such checking will
58
+ /// occur and all calls to intrinsics with mismatched arguments will
59
+ /// result in undefined behavior.
60
+ ///
61
+ /// - Parameters:
62
+ /// - intr: The selector for the intrinsic to be invoked.
63
+ /// - returnType: A suggested return type for overloaded intrinsics. By
64
+ /// default, the framework will infer a type and attempt to match the
65
+ /// right intrinsic function.
66
+ /// - args: The arguments to the intrinsic function.
67
+ /// - Returns: A value representing the result of calling the intrinsic
68
+ /// function.
69
+ public func buildIntrinsicCall< I: LLVMIntrinsic > ( to intr: I , returnType: IRType ? = nil , args: IRValue ... ) -> IRValue {
70
+ assert ( typeCheckArguments ( to: intr, args: args) )
19
71
20
- internal struct ResolvedIntrinsic : LLVMIntrinsic {
21
- let signature : FunctionType
22
- let llvmSelector : String
23
- }
72
+ return self . buildCall ( self . buildIntrinsic ( self . resolveIntrinsic ( intr, args, returnType) ) , args: args)
73
+ }
24
74
25
- extension IRBuilder {
75
+
26
76
/// Builds a call to one of a family of overloaded intrinsic functions.
27
77
///
28
- /// The type of the arguments ultimately determines the selector for the
29
- /// intrinsic that is called. Failure of the arguments to correspond to any
30
- /// of the overloads is a fatal condition.
31
- public func buildIntrinsicCall< I: LLVMOverloadedIntrinsic > ( family i: I . Type , returnType: IRType ? = nil , args: IRValue ... ) -> IRValue {
32
- guard let intr = resolveOverloadedArguments ( to: i, args: args) else {
78
+ /// - note: The type of the arguments ultimately determines the selector for
79
+ /// the intrinsic that is called. Failure of the arguments to
80
+ /// correspond to any of the overloads is a fatal condition.
81
+ ///
82
+ /// - Parameters:
83
+ /// - intr: The selector for the overloaded intrinsic to be resolved and
84
+ /// invoked.
85
+ /// - returnType: A suggested return type for overloaded intrinsics. By
86
+ /// default, the framework will infer a type and attempt to match the
87
+ /// right intrinsic function.
88
+ /// - args: The arguments to the intrinsic function.
89
+ /// - Returns: A value representing the result of calling the intrinsic
90
+ /// function.
91
+ public func buildIntrinsicCall< I: LLVMOverloadedIntrinsic > ( to intr: I . Type , returnType: IRType ? = nil , args: IRValue ... ) -> IRValue {
92
+ guard let intr = resolveOverloadedArguments ( to: intr, args: args) else {
33
93
fatalError ( " Unable to resolve overload among \( I . overloadSet. map { $0. llvmSelector} ) " )
34
94
}
35
95
return self . buildCall ( self . buildIntrinsic ( self . resolveIntrinsic ( intr, args, returnType) ) , args: args)
36
96
}
37
97
38
- public func buildIntrinsicCall< I: LLVMIntrinsic > ( to intr: I , returnType: IRType ? = nil , args: IRValue ... ) -> IRValue {
39
- assert ( typeCheckArguments ( to: intr, args: args) )
40
-
41
- return self . buildCall ( self . buildIntrinsic ( self . resolveIntrinsic ( intr, args, returnType) ) , args: args)
42
- }
43
-
44
98
private func resolveIntrinsic( _ i: LLVMIntrinsic , _ args: [ IRValue ] , _ returnTy: IRType ? ) -> LLVMIntrinsic {
45
99
let fnArgTypes = i. signature. argTypes
46
100
47
- func markerForType ( _ type: IRType ) -> String {
101
+ func typeNameForType ( _ type: IRType ) -> String {
48
102
if let iTy = type as? IntType {
49
103
return " i \( iTy. width) "
50
104
} else if let fTy = type as? FloatType {
@@ -63,9 +117,9 @@ extension IRBuilder {
63
117
return " ppcf128 "
64
118
}
65
119
} else if let pTy = type as? PointerType {
66
- return " p0 " + markerForType ( pTy. pointee)
120
+ return " p0 " + typeNameForType ( pTy. pointee)
67
121
} else if let vTy = type as? VectorType {
68
- return " v \( vTy. count) " + markerForType ( vTy. elementType)
122
+ return " v \( vTy. count) " + typeNameForType ( vTy. elementType)
69
123
}
70
124
fatalError ( )
71
125
}
@@ -78,7 +132,7 @@ extension IRBuilder {
78
132
continue
79
133
}
80
134
argTypes. append ( t. 1 . type)
81
- sigName += " . " + markerForType ( t. 1 . type)
135
+ sigName += " . " + typeNameForType ( t. 1 . type)
82
136
}
83
137
84
138
let retTy : IRType
@@ -114,11 +168,17 @@ extension IRBuilder {
114
168
if t. 0 is IntrinsicSubstitutionMarker {
115
169
continue
116
170
} else if let vecTy = t. 0 as? VectorType , vecTy. elementType is IntrinsicSubstitutionMarker {
117
- // Vector<<SUB>> => Vector<T>
171
+ // Vector<n, <SUB>> => Vector<n, T>
118
172
guard t. 1 is VectorType else {
119
173
return false
120
174
}
121
175
continue
176
+ } else if let vecTy = t. 0 as? VectorType , vecTy. count == - 1 {
177
+ // Vector<-1, T> => Vector<n, T>
178
+ guard let vecTy2 = t. 1 as? VectorType , vecTy. elementType. asLLVM ( ) == vecTy2. elementType. asLLVM ( ) else {
179
+ return false
180
+ }
181
+ continue
122
182
}
123
183
124
184
// Fall back to pointer equality
@@ -138,3 +198,18 @@ extension IRBuilder {
138
198
} ) . first
139
199
}
140
200
}
201
+
202
+ // A marker type generated by the 'intrinsics-gen' tool to indicate that a
203
+ // substitution should be performed on an argument. They cannot be reified into
204
+ // an LLVM Type and will trap if an attempt is made to do so.
205
+ internal struct IntrinsicSubstitutionMarker : IRType {
206
+ func asLLVM( ) -> LLVMTypeRef {
207
+ fatalError ( " Unhandled substitution marker in type " )
208
+ }
209
+ }
210
+
211
+ /// A marker intrinsic for the candidate selected during overload resolution.
212
+ internal struct ResolvedIntrinsic : LLVMIntrinsic {
213
+ let signature : FunctionType
214
+ let llvmSelector : String
215
+ }
0 commit comments