aboutsummaryrefslogtreecommitdiffstats
path: root/include/llvm/IntrinsicsARM.td
blob: e16797ae70d599461f84539196c58fca0209a91b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
//===- IntrinsicsARM.td - Defines ARM intrinsics -----------*- tablegen -*-===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This file defines all of the ARM-specific intrinsics.
//
//===----------------------------------------------------------------------===//


//===----------------------------------------------------------------------===//
// TLS

let TargetPrefix = "arm" in {  // All intrinsics start with "llvm.arm.".
  def int_arm_thread_pointer : GCCBuiltin<"__builtin_thread_pointer">,
              Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
}

//===----------------------------------------------------------------------===//
// Advanced SIMD (NEON)

let TargetPrefix = "arm" in {  // All intrinsics start with "llvm.arm.".

  // The following classes do not correspond directly to GCC builtins.
  class Neon_1Arg_Intrinsic
    : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], [IntrNoMem]>;
  class Neon_1Arg_Float_Intrinsic
    : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
  class Neon_1Arg_Narrow_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMExtendedElementVectorType<0>], [IntrNoMem]>;
  class Neon_1Arg_Long_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMTruncatedElementVectorType<0>], [IntrNoMem]>;
  class Neon_2Arg_Intrinsic
    : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>],
                [IntrNoMem]>;
  class Neon_2Arg_Float_Intrinsic
    : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>],
                [IntrNoMem]>;
  class Neon_2Arg_Narrow_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMExtendedElementVectorType<0>,
                 LLVMExtendedElementVectorType<0>],
                [IntrNoMem]>;
  class Neon_2Arg_Long_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMTruncatedElementVectorType<0>,
                 LLVMTruncatedElementVectorType<0>],
                [IntrNoMem]>;
  class Neon_2Arg_Wide_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMMatchType<0>, LLVMTruncatedElementVectorType<0>],
                [IntrNoMem]>;
  class Neon_3Arg_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>],
                [IntrNoMem]>;
  class Neon_3Arg_Long_Intrinsic
    : Intrinsic<[llvm_anyint_ty],
                [LLVMMatchType<0>,
                 LLVMTruncatedElementVectorType<0>,
                 LLVMTruncatedElementVectorType<0>],
                [IntrNoMem]>;
  class Neon_CvtFxToFP_Intrinsic
    : Intrinsic<[llvm_anyfloat_ty], [llvm_anyint_ty, llvm_i32_ty], [IntrNoMem]>;
  class Neon_CvtFPToFx_Intrinsic
    : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem]>;
}

// Arithmetic ops

let Properties = [IntrNoMem, Commutative] in {

  // Vector Add.
  def int_arm_neon_vhadds : Neon_2Arg_Intrinsic;
  def int_arm_neon_vhaddu : Neon_2Arg_Intrinsic;
  def int_arm_neon_vrhadds : Neon_2Arg_Intrinsic;
  def int_arm_neon_vrhaddu : Neon_2Arg_Intrinsic;
  def int_arm_neon_vqadds : Neon_2Arg_Intrinsic;
  def int_arm_neon_vqaddu : Neon_2Arg_Intrinsic;
  def int_arm_neon_vaddhn : Neon_2Arg_Narrow_Intrinsic;
  def int_arm_neon_vraddhn : Neon_2Arg_Narrow_Intrinsic;
  def int_arm_neon_vaddls : Neon_2Arg_Long_Intrinsic;
  def int_arm_neon_vaddlu : Neon_2Arg_Long_Intrinsic;
  def int_arm_neon_vaddws : Neon_2Arg_Wide_Intrinsic;
  def int_arm_neon_vaddwu : Neon_2Arg_Wide_Intrinsic;

  // Vector Multiply.
  def int_arm_neon_vmulp : Neon_2Arg_Intrinsic;
  def int_arm_neon_vqdmulh : Neon_2Arg_Intrinsic;
  def int_arm_neon_vqrdmulh : Neon_2Arg_Intrinsic;
  def int_arm_neon_vmulls : Neon_2Arg_Long_Intrinsic;
  def int_arm_neon_vmullu : Neon_2Arg_Long_Intrinsic;
  def int_arm_neon_vmullp : Neon_2Arg_Long_Intrinsic;
  def int_arm_neon_vqdmull : Neon_2Arg_Long_Intrinsic;

  // Vector Multiply and Accumulate/Subtract.
  def int_arm_neon_vmlals : Neon_3Arg_Long_Intrinsic;
  def int_arm_neon_vmlalu : Neon_3Arg_Long_Intrinsic;
  def int_arm_neon_vmlsls : Neon_3Arg_Long_Intrinsic;
  def int_arm_neon_vmlslu : Neon_3Arg_Long_Intrinsic;
  def int_arm_neon_vqdmlal : Neon_3Arg_Long_Intrinsic;
  def int_arm_neon_vqdmlsl : Neon_3Arg_Long_Intrinsic;

  // Vector Maximum.
  def int_arm_neon_vmaxs : Neon_2Arg_Intrinsic;
  def int_arm_neon_vmaxu : Neon_2Arg_Intrinsic;
  def int_arm_neon_vmaxf : Neon_2Arg_Float_Intrinsic;

  // Vector Minimum.
  def int_arm_neon_vmins : Neon_2Arg_Intrinsic;
  def int_arm_neon_vminu : Neon_2Arg_Intrinsic;
  def int_arm_neon_vminf : Neon_2Arg_Float_Intrinsic;

  // Vector Reciprocal Step.
  def int_arm_neon_vrecps : Neon_2Arg_Float_Intrinsic;

  // Vector Reciprocal Square Root Step.
  def int_arm_neon_vrsqrts : Neon_2Arg_Float_Intrinsic;
}

// Vector Subtract.
def int_arm_neon_vhsubs : Neon_2Arg_Intrinsic;
def int_arm_neon_vhsubu : Neon_2Arg_Intrinsic;
def int_arm_neon_vqsubs : Neon_2Arg_Intrinsic;
def int_arm_neon_vqsubu : Neon_2Arg_Intrinsic;
def int_arm_neon_vsubhn : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vrsubhn : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vsubls : Neon_2Arg_Long_Intrinsic;
def int_arm_neon_vsublu : Neon_2Arg_Long_Intrinsic;
def int_arm_neon_vsubws : Neon_2Arg_Wide_Intrinsic;
def int_arm_neon_vsubwu : Neon_2Arg_Wide_Intrinsic;

// Vector Absolute Compare.
let TargetPrefix = "arm" in {
  def int_arm_neon_vacged : Intrinsic<[llvm_v2i32_ty],
                                      [llvm_v2f32_ty, llvm_v2f32_ty],
                                      [IntrNoMem]>;
  def int_arm_neon_vacgeq : Intrinsic<[llvm_v4i32_ty],
                                      [llvm_v4f32_ty, llvm_v4f32_ty],
                                      [IntrNoMem]>;
  def int_arm_neon_vacgtd : Intrinsic<[llvm_v2i32_ty],
                                      [llvm_v2f32_ty, llvm_v2f32_ty],
                                      [IntrNoMem]>;
  def int_arm_neon_vacgtq : Intrinsic<[llvm_v4i32_ty],
                                      [llvm_v4f32_ty, llvm_v4f32_ty],
                                      [IntrNoMem]>;
}

// Vector Absolute Differences.
def int_arm_neon_vabds : Neon_2Arg_Intrinsic;
def int_arm_neon_vabdu : Neon_2Arg_Intrinsic;
def int_arm_neon_vabdf : Neon_2Arg_Float_Intrinsic;
def int_arm_neon_vabdls : Neon_2Arg_Long_Intrinsic;
def int_arm_neon_vabdlu : Neon_2Arg_Long_Intrinsic;

// Vector Absolute Difference and Accumulate.
def int_arm_neon_vabas : Neon_3Arg_Intrinsic;
def int_arm_neon_vabau : Neon_3Arg_Intrinsic;
def int_arm_neon_vabals : Neon_3Arg_Long_Intrinsic;
def int_arm_neon_vabalu : Neon_3Arg_Long_Intrinsic;

// Vector Pairwise Add.
def int_arm_neon_vpaddi : Neon_2Arg_Intrinsic;
def int_arm_neon_vpaddf : Neon_2Arg_Float_Intrinsic;

// Vector Pairwise Add Long.
// Note: This is different than the other "long" NEON intrinsics because
// the result vector has half as many elements as the source vector.
// The source and destination vector types must be specified separately.
let TargetPrefix = "arm" in {
  def int_arm_neon_vpaddls : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty],
                                       [IntrNoMem]>;
  def int_arm_neon_vpaddlu : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty],
                                       [IntrNoMem]>;
}

// Vector Pairwise Add and Accumulate Long.
// Note: This is similar to vpaddl but the destination vector also appears
// as the first argument.
let TargetPrefix = "arm" in {
  def int_arm_neon_vpadals : Intrinsic<[llvm_anyint_ty],
                                       [LLVMMatchType<0>, llvm_anyint_ty],
                                       [IntrNoMem]>;
  def int_arm_neon_vpadalu : Intrinsic<[llvm_anyint_ty],
                                       [LLVMMatchType<0>, llvm_anyint_ty],
                                       [IntrNoMem]>;
}

// Vector Pairwise Maximum and Minimum.
def int_arm_neon_vpmaxs : Neon_2Arg_Intrinsic;
def int_arm_neon_vpmaxu : Neon_2Arg_Intrinsic;
def int_arm_neon_vpmaxf : Neon_2Arg_Float_Intrinsic;
def int_arm_neon_vpmins : Neon_2Arg_Intrinsic;
def int_arm_neon_vpminu : Neon_2Arg_Intrinsic;
def int_arm_neon_vpminf : Neon_2Arg_Float_Intrinsic;

// Vector Shifts:
//
// The various saturating and rounding vector shift operations need to be
// represented by intrinsics in LLVM, and even the basic VSHL variable shift
// operation cannot be safely translated to LLVM's shift operators.  VSHL can
// be used for both left and right shifts, or even combinations of the two,
// depending on the signs of the shift amounts.  It also has well-defined
// behavior for shift amounts that LLVM leaves undefined.  Only basic shifts
// by constants can be represented with LLVM's shift operators.
//
// The shift counts for these intrinsics are always vectors, even for constant
// shifts, where the constant is replicated.  For consistency with VSHL (and
// other variable shift instructions), left shifts have positive shift counts
// and right shifts have negative shift counts.  This convention is also used
// for constant right shift intrinsics, and to help preserve sanity, the
// intrinsic names use "shift" instead of either "shl" or "shr".  Where
// applicable, signed and unsigned versions of the intrinsics are
// distinguished with "s" and "u" suffixes.  A few NEON shift instructions,
// such as VQSHLU, take signed operands but produce unsigned results; these
// use a "su" suffix.

// Vector Shift.
def int_arm_neon_vshifts : Neon_2Arg_Intrinsic;
def int_arm_neon_vshiftu : Neon_2Arg_Intrinsic;
def int_arm_neon_vshiftls : Neon_2Arg_Long_Intrinsic;
def int_arm_neon_vshiftlu : Neon_2Arg_Long_Intrinsic;
def int_arm_neon_vshiftn : Neon_2Arg_Narrow_Intrinsic;

// Vector Rounding Shift.
def int_arm_neon_vrshifts : Neon_2Arg_Intrinsic;
def int_arm_neon_vrshiftu : Neon_2Arg_Intrinsic;
def int_arm_neon_vrshiftn : Neon_2Arg_Narrow_Intrinsic;

// Vector Saturating Shift.
def int_arm_neon_vqshifts : Neon_2Arg_Intrinsic;
def int_arm_neon_vqshiftu : Neon_2Arg_Intrinsic;
def int_arm_neon_vqshiftsu : Neon_2Arg_Intrinsic;
def int_arm_neon_vqshiftns : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vqshiftnu : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vqshiftnsu : Neon_2Arg_Narrow_Intrinsic;

// Vector Saturating Rounding Shift.
def int_arm_neon_vqrshifts : Neon_2Arg_Intrinsic;
def int_arm_neon_vqrshiftu : Neon_2Arg_Intrinsic;
def int_arm_neon_vqrshiftns : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vqrshiftnu : Neon_2Arg_Narrow_Intrinsic;
def int_arm_neon_vqrshiftnsu : Neon_2Arg_Narrow_Intrinsic;

// Vector Shift and Insert.
def int_arm_neon_vshiftins : Neon_3Arg_Intrinsic;

// Vector Absolute Value and Saturating Absolute Value.
def int_arm_neon_vabs : Neon_1Arg_Intrinsic;
def int_arm_neon_vabsf : Neon_1Arg_Float_Intrinsic;
def int_arm_neon_vqabs : Neon_1Arg_Intrinsic;

// Vector Saturating Negate.
def int_arm_neon_vqneg : Neon_1Arg_Intrinsic;

// Vector Count Leading Sign/Zero Bits.
def int_arm_neon_vcls : Neon_1Arg_Intrinsic;
def int_arm_neon_vclz : Neon_1Arg_Intrinsic;

// Vector Count One Bits.
def int_arm_neon_vcnt : Neon_1Arg_Intrinsic;

// Vector Reciprocal Estimate.
def int_arm_neon_vrecpe : Neon_1Arg_Intrinsic;
def int_arm_neon_vrecpef : Neon_1Arg_Float_Intrinsic;

// Vector Reciprocal Square Root Estimate.
def int_arm_neon_vrsqrte : Neon_1Arg_Intrinsic;
def int_arm_neon_vrsqrtef : Neon_1Arg_Float_Intrinsic;

// Vector Conversions Between Floating-point and Fixed-point.
def int_arm_neon_vcvtfp2fxs : Neon_CvtFPToFx_Intrinsic;
def int_arm_neon_vcvtfp2fxu : Neon_CvtFPToFx_Intrinsic;
def int_arm_neon_vcvtfxs2fp : Neon_CvtFxToFP_Intrinsic;
def int_arm_neon_vcvtfxu2fp : Neon_CvtFxToFP_Intrinsic;

// Narrowing and Lengthening Vector Moves.
def int_arm_neon_vmovn : Neon_1Arg_Narrow_Intrinsic;
def int_arm_neon_vqmovns : Neon_1Arg_Narrow_Intrinsic;
def int_arm_neon_vqmovnu : Neon_1Arg_Narrow_Intrinsic;
def int_arm_neon_vqmovnsu : Neon_1Arg_Narrow_Intrinsic;
def int_arm_neon_vmovls : Neon_1Arg_Long_Intrinsic;
def int_arm_neon_vmovlu : Neon_1Arg_Long_Intrinsic;

let TargetPrefix = "arm" in {

  // De-interleaving vector loads from N-element structures.
  def int_arm_neon_vldi : Intrinsic<[llvm_anyint_ty],
                                    [llvm_ptr_ty, llvm_i32_ty],
                                    [IntrReadArgMem]>;
  def int_arm_neon_vldf : Intrinsic<[llvm_anyfloat_ty],
                                    [llvm_ptr_ty, llvm_i32_ty],
                                    [IntrReadArgMem]>;

  // Interleaving vector stores from N-element structures.
  def int_arm_neon_vsti : Intrinsic<[llvm_void_ty],
                                    [llvm_ptr_ty, llvm_anyint_ty, llvm_i32_ty],
                                    [IntrWriteArgMem]>;
  def int_arm_neon_vstf : Intrinsic<[llvm_void_ty],
                                    [llvm_ptr_ty, llvm_anyfloat_ty,llvm_i32_ty],
                                    [IntrWriteArgMem]>;

  // Vector Table Lookup
  def int_arm_neon_vtbl : Intrinsic<[llvm_v8i8_ty],
                                    [llvm_anyint_ty, llvm_v8i8_ty],
                                    [IntrNoMem]>;
  // Vector Table Extension
  def int_arm_neon_vtbx : Intrinsic<[llvm_v8i8_ty],
                                    [llvm_v8i8_ty, llvm_anyint_ty,
                                     llvm_v8i8_ty], [IntrNoMem]>;
}