]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/arm/neon-gen.ml
Update Copyright years for files modified in 2011 and/or 2012.
[thirdparty/gcc.git] / gcc / config / arm / neon-gen.ml
CommitLineData
d98a3884 1(* Auto-generate ARM Neon intrinsics header file.
71e45bc2 2 Copyright (C) 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
d98a3884 3 Contributed by CodeSourcery.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
038d1e19 9 Software Foundation; either version 3, or (at your option) any later
d98a3884 10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
038d1e19 18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>.
d98a3884 20
21 This is an O'Caml program. The O'Caml compiler is available from:
22
23 http://caml.inria.fr/
24
25 Or from your favourite OS's friendly packaging system. Tested with version
26 3.09.2, though other versions will probably work too.
27
28 Compile with:
29 ocamlc -c neon.ml
30 ocamlc -o neon-gen neon.cmo neon-gen.ml
31
32 Run with:
33 ./neon-gen > arm_neon.h
34*)
35
36open Neon
37
38(* The format codes used in the following functions are documented at:
39 http://caml.inria.fr/pub/docs/manual-ocaml/libref/Format.html\
40 #6_printflikefunctionsforprettyprinting
41 (one line, remove the backslash.)
42*)
43
44(* Following functions can be used to approximate GNU indentation style. *)
45let start_function () =
46 Format.printf "@[<v 0>";
47 ref 0
48
49let end_function nesting =
50 match !nesting with
51 0 -> Format.printf "@;@;@]"
52 | _ -> failwith ("Bad nesting (ending function at level "
53 ^ (string_of_int !nesting) ^ ")")
54
55let open_braceblock nesting =
56 begin match !nesting with
57 0 -> Format.printf "@,@<0>{@[<v 2>@,"
58 | _ -> Format.printf "@,@[<v 2> @<0>{@[<v 2>@,"
59 end;
60 incr nesting
61
62let close_braceblock nesting =
63 decr nesting;
64 match !nesting with
65 0 -> Format.printf "@]@,@<0>}"
66 | _ -> Format.printf "@]@,@<0>}@]"
67
68let print_function arity fnname body =
69 let ffmt = start_function () in
70 Format.printf "__extension__ static __inline ";
71 let inl = "__attribute__ ((__always_inline__))" in
72 begin match arity with
73 Arity0 ret ->
74 Format.printf "%s %s@,%s (void)" (string_of_vectype ret) inl fnname
75 | Arity1 (ret, arg0) ->
76 Format.printf "%s %s@,%s (%s __a)" (string_of_vectype ret) inl fnname
77 (string_of_vectype arg0)
78 | Arity2 (ret, arg0, arg1) ->
79 Format.printf "%s %s@,%s (%s __a, %s __b)"
80 (string_of_vectype ret) inl fnname (string_of_vectype arg0)
81 (string_of_vectype arg1)
82 | Arity3 (ret, arg0, arg1, arg2) ->
83 Format.printf "%s %s@,%s (%s __a, %s __b, %s __c)"
84 (string_of_vectype ret) inl fnname (string_of_vectype arg0)
85 (string_of_vectype arg1) (string_of_vectype arg2)
86 | Arity4 (ret, arg0, arg1, arg2, arg3) ->
87 Format.printf "%s %s@,%s (%s __a, %s __b, %s __c, %s __d)"
88 (string_of_vectype ret) inl fnname (string_of_vectype arg0)
89 (string_of_vectype arg1) (string_of_vectype arg2)
90 (string_of_vectype arg3)
91 end;
92 open_braceblock ffmt;
93 let rec print_lines = function
e71384dc 94 [] -> ()
95 | "" :: lines -> print_lines lines
d98a3884 96 | [line] -> Format.printf "%s" line
e71384dc 97 | line::lines -> Format.printf "%s@," line ; print_lines lines in
d98a3884 98 print_lines body;
99 close_braceblock ffmt;
100 end_function ffmt
101
d98a3884 102let union_string num elts base =
103 let itype = inttype_for_array num elts in
104 let iname = string_of_inttype itype
105 and sname = string_of_vectype (T_arrayof (num, elts)) in
106 Printf.sprintf "union { %s __i; %s __o; } %s" sname iname base
107
108let rec signed_ctype = function
109 T_uint8x8 | T_poly8x8 -> T_int8x8
110 | T_uint8x16 | T_poly8x16 -> T_int8x16
111 | T_uint16x4 | T_poly16x4 -> T_int16x4
112 | T_uint16x8 | T_poly16x8 -> T_int16x8
113 | T_uint32x2 -> T_int32x2
114 | T_uint32x4 -> T_int32x4
115 | T_uint64x1 -> T_int64x1
116 | T_uint64x2 -> T_int64x2
117 (* Cast to types defined by mode in arm.c, not random types pulled in from
118 the <stdint.h> header in use. This fixes incompatible pointer errors when
119 compiling with C++. *)
120 | T_uint8 | T_int8 -> T_intQI
121 | T_uint16 | T_int16 -> T_intHI
122 | T_uint32 | T_int32 -> T_intSI
123 | T_uint64 | T_int64 -> T_intDI
52a0d45c 124 | T_float32 -> T_floatSF
d98a3884 125 | T_poly8 -> T_intQI
126 | T_poly16 -> T_intHI
127 | T_arrayof (n, elt) -> T_arrayof (n, signed_ctype elt)
128 | T_ptrto elt -> T_ptrto (signed_ctype elt)
129 | T_const elt -> T_const (signed_ctype elt)
130 | x -> x
131
132let add_cast ctype cval =
133 let stype = signed_ctype ctype in
134 if ctype <> stype then
135 Printf.sprintf "(%s) %s" (string_of_vectype stype) cval
136 else
137 cval
138
139let cast_for_return to_ty = "(" ^ (string_of_vectype to_ty) ^ ")"
140
141(* Return a tuple of a list of declarations to go at the start of the function,
142 and a list of statements needed to return THING. *)
e71384dc 143let return arity thing =
d98a3884 144 match arity with
145 Arity0 (ret) | Arity1 (ret, _) | Arity2 (ret, _, _) | Arity3 (ret, _, _, _)
146 | Arity4 (ret, _, _, _, _) ->
e71384dc 147 begin match ret with
148 T_arrayof (num, vec) ->
d98a3884 149 let uname = union_string num vec "__rv" in
150 [uname ^ ";"], ["__rv.__o = " ^ thing ^ ";"; "return __rv.__i;"]
e71384dc 151 | T_void ->
152 [], [thing ^ ";"]
153 | _ ->
154 [], ["return " ^ (cast_for_return ret) ^ thing ^ ";"]
155 end
156
157let mask_shape_for_shuffle = function
158 All (num, reg) -> All (num, reg)
159 | Pair_result reg -> All (2, reg)
160 | _ -> failwith "mask_for_shuffle"
161
162let mask_elems shuffle shape elttype part =
163 let elem_size = elt_width elttype in
164 let num_elems =
165 match regmap shape 0 with
166 Dreg -> 64 / elem_size
167 | Qreg -> 128 / elem_size
168 | _ -> failwith "mask_elems" in
169 shuffle elem_size num_elems part
170
171(* Return a tuple of a list of declarations 0and a list of statements needed
172 to implement an intrinsic using __builtin_shuffle. SHUFFLE is a function
173 which returns a list of elements suitable for using as a mask. *)
174
175let shuffle_fn shuffle shape arity elttype =
176 let mshape = mask_shape_for_shuffle shape in
177 let masktype = type_for_elt mshape (unsigned_of_elt elttype) 0 in
178 let masktype_str = string_of_vectype masktype in
179 let shuffle_res = type_for_elt mshape elttype 0 in
180 let shuffle_res_str = string_of_vectype shuffle_res in
181 match arity with
182 Arity0 (ret) | Arity1 (ret, _) | Arity2 (ret, _, _) | Arity3 (ret, _, _, _)
183 | Arity4 (ret, _, _, _, _) ->
184 begin match ret with
185 T_arrayof (num, vec) ->
186 let elems1 = mask_elems shuffle mshape elttype `lo
187 and elems2 = mask_elems shuffle mshape elttype `hi in
188 let mask1 = (String.concat ", " (List.map string_of_int elems1))
189 and mask2 = (String.concat ", " (List.map string_of_int elems2)) in
190 let shuf1 = Printf.sprintf
191 "__rv.val[0] = (%s) __builtin_shuffle (__a, __b, (%s) { %s });"
192 shuffle_res_str masktype_str mask1
193 and shuf2 = Printf.sprintf
194 "__rv.val[1] = (%s) __builtin_shuffle (__a, __b, (%s) { %s });"
195 shuffle_res_str masktype_str mask2 in
196 [Printf.sprintf "%s __rv;" (string_of_vectype ret);],
197 [shuf1; shuf2; "return __rv;"]
198 | _ ->
199 let elems = mask_elems shuffle mshape elttype `lo in
200 let mask = (String.concat ", " (List.map string_of_int elems)) in
201 let shuf = Printf.sprintf
202 "return (%s) __builtin_shuffle (__a, (%s) { %s });" shuffle_res_str masktype_str mask in
203 [""],
204 [shuf]
205 end
d98a3884 206
207let rec element_type ctype =
208 match ctype with
209 T_arrayof (_, v) -> element_type v
210 | _ -> ctype
211
e71384dc 212let params ps =
d98a3884 213 let pdecls = ref [] in
214 let ptype t p =
215 match t with
216 T_arrayof (num, elts) ->
217 let uname = union_string num elts (p ^ "u") in
218 let decl = Printf.sprintf "%s = { %s };" uname p in
219 pdecls := decl :: !pdecls;
220 p ^ "u.__o"
221 | _ -> add_cast t p in
222 let plist = match ps with
223 Arity0 _ -> []
224 | Arity1 (_, t1) -> [ptype t1 "__a"]
225 | Arity2 (_, t1, t2) -> [ptype t1 "__a"; ptype t2 "__b"]
226 | Arity3 (_, t1, t2, t3) -> [ptype t1 "__a"; ptype t2 "__b"; ptype t3 "__c"]
227 | Arity4 (_, t1, t2, t3, t4) ->
228 [ptype t1 "__a"; ptype t2 "__b"; ptype t3 "__c"; ptype t4 "__d"] in
e71384dc 229 !pdecls, plist
d98a3884 230
231let modify_params features plist =
232 let is_flipped =
233 List.exists (function Flipped _ -> true | _ -> false) features in
234 if is_flipped then
235 match plist with
236 [ a; b ] -> [ b; a ]
237 | _ ->
238 failwith ("Don't know how to flip args " ^ (String.concat ", " plist))
239 else
240 plist
241
242(* !!! Decide whether to add an extra information word based on the shape
243 form. *)
244let extra_word shape features paramlist bits =
245 let use_word =
246 match shape with
247 All _ | Long | Long_noreg _ | Wide | Wide_noreg _ | Narrow
248 | By_scalar _ | Wide_scalar | Wide_lane | Binary_imm _ | Long_imm
249 | Narrow_imm -> true
250 | _ -> List.mem InfoWord features
251 in
252 if use_word then
253 paramlist @ [string_of_int bits]
254 else
255 paramlist
256
257(* Bit 0 represents signed (1) vs unsigned (0), or float (1) vs poly (0).
258 Bit 1 represents floats & polynomials (1), or ordinary integers (0).
259 Bit 2 represents rounding (1) vs none (0). *)
260let infoword_value elttype features =
261 let bits01 =
262 match elt_class elttype with
263 Signed | ConvClass (Signed, _) | ConvClass (_, Signed) -> 0b001
264 | Poly -> 0b010
265 | Float -> 0b011
266 | _ -> 0b000
267 and rounding_bit = if List.mem Rounding features then 0b100 else 0b000 in
268 bits01 lor rounding_bit
269
270(* "Cast" type operations will throw an exception in mode_of_elt (actually in
271 elt_width, called from there). Deal with that here, and generate a suffix
272 with multiple modes (<to><from>). *)
273let rec mode_suffix elttype shape =
274 try
275 let mode = mode_of_elt elttype shape in
276 string_of_mode mode
277 with MixedMode (dst, src) ->
278 let dstmode = mode_of_elt dst shape
279 and srcmode = mode_of_elt src shape in
280 string_of_mode dstmode ^ string_of_mode srcmode
281
e71384dc 282let get_shuffle features =
283 try
284 match List.find (function Use_shuffle _ -> true | _ -> false) features with
285 Use_shuffle fn -> Some fn
286 | _ -> None
287 with Not_found -> None
288
9abf7cc0 289let print_feature_test_start features =
290 try
291 match List.find (fun feature ->
292 match feature with Requires_feature _ -> true
614aede0 293 | Requires_arch _ -> true
9abf7cc0 294 | _ -> false)
295 features with
296 Requires_feature feature ->
297 Format.printf "#ifdef __ARM_FEATURE_%s@\n" feature
614aede0 298 | Requires_arch arch ->
299 Format.printf "#if __ARM_ARCH >= %d@\n" arch
9abf7cc0 300 | _ -> assert false
301 with Not_found -> assert true
302
303let print_feature_test_end features =
304 let feature =
305 List.exists (function Requires_feature x -> true
614aede0 306 | Requires_arch x -> true
307 | _ -> false) features in
9abf7cc0 308 if feature then Format.printf "#endif@\n"
309
310
d98a3884 311let print_variant opcode features shape name (ctype, asmtype, elttype) =
312 let bits = infoword_value elttype features in
313 let modesuf = mode_suffix elttype shape in
e71384dc 314 let pdecls, paramlist = params ctype in
315 let rdecls, stmts =
316 match get_shuffle features with
317 Some shuffle -> shuffle_fn shuffle shape ctype elttype
318 | None ->
319 let paramlist' = modify_params features paramlist in
320 let paramlist'' = extra_word shape features paramlist' bits in
321 let parstr = String.concat ", " paramlist'' in
322 let builtin = Printf.sprintf "__builtin_neon_%s%s (%s)"
323 (builtin_name features name) modesuf parstr in
324 return ctype builtin in
d98a3884 325 let body = pdecls @ rdecls @ stmts
326 and fnname = (intrinsic_name name) ^ "_" ^ (string_of_elt elttype) in
9abf7cc0 327 begin
328 print_feature_test_start features;
329 print_function ctype fnname body;
330 print_feature_test_end features;
331 end
d98a3884 332
333(* When this function processes the element types in the ops table, it rewrites
334 them in a list of tuples (a,b,c):
335 a : C type as an "arity", e.g. Arity1 (T_poly8x8, T_poly8x8)
336 b : Asm type : a single, processed element type, e.g. P16. This is the
337 type which should be attached to the asm opcode.
338 c : Variant type : the unprocessed type for this variant (e.g. in add
339 instructions which don't care about the sign, b might be i16 and c
340 might be s16.)
341*)
342
343let print_op (opcode, features, shape, name, munge, types) =
344 let sorted_types = List.sort compare types in
345 let munged_types = List.map
346 (fun elt -> let c, asm = munge shape elt in c, asm, elt) sorted_types in
347 List.iter
348 (fun variant -> print_variant opcode features shape name variant)
349 munged_types
350
351let print_ops ops =
352 List.iter print_op ops
353
354(* Output type definitions. Table entries are:
355 cbase : "C" name for the type.
356 abase : "ARM" base name for the type (i.e. int in int8x8_t).
357 esize : element size.
358 enum : element count.
359*)
360
361let deftypes () =
362 let typeinfo = [
363 (* Doubleword vector types. *)
364 "__builtin_neon_qi", "int", 8, 8;
365 "__builtin_neon_hi", "int", 16, 4;
366 "__builtin_neon_si", "int", 32, 2;
367 "__builtin_neon_di", "int", 64, 1;
368 "__builtin_neon_sf", "float", 32, 2;
369 "__builtin_neon_poly8", "poly", 8, 8;
370 "__builtin_neon_poly16", "poly", 16, 4;
371 "__builtin_neon_uqi", "uint", 8, 8;
372 "__builtin_neon_uhi", "uint", 16, 4;
373 "__builtin_neon_usi", "uint", 32, 2;
374 "__builtin_neon_udi", "uint", 64, 1;
375
376 (* Quadword vector types. *)
377 "__builtin_neon_qi", "int", 8, 16;
378 "__builtin_neon_hi", "int", 16, 8;
379 "__builtin_neon_si", "int", 32, 4;
380 "__builtin_neon_di", "int", 64, 2;
381 "__builtin_neon_sf", "float", 32, 4;
382 "__builtin_neon_poly8", "poly", 8, 16;
383 "__builtin_neon_poly16", "poly", 16, 8;
384 "__builtin_neon_uqi", "uint", 8, 16;
385 "__builtin_neon_uhi", "uint", 16, 8;
386 "__builtin_neon_usi", "uint", 32, 4;
387 "__builtin_neon_udi", "uint", 64, 2
388 ] in
389 List.iter
390 (fun (cbase, abase, esize, enum) ->
391 let attr =
392 match enum with
393 1 -> ""
394 | _ -> Printf.sprintf "\t__attribute__ ((__vector_size__ (%d)))"
395 (esize * enum / 8) in
396 Format.printf "typedef %s %s%dx%d_t%s;@\n" cbase abase esize enum attr)
397 typeinfo;
398 Format.print_newline ();
399 (* Extra types not in <stdint.h>. *)
52a0d45c 400 Format.printf "typedef float float32_t;\n";
d98a3884 401 Format.printf "typedef __builtin_neon_poly8 poly8_t;\n";
402 Format.printf "typedef __builtin_neon_poly16 poly16_t;\n"
403
404(* Output structs containing arrays, for load & store instructions etc. *)
405
406let arrtypes () =
407 let typeinfo = [
408 "int", 8; "int", 16;
409 "int", 32; "int", 64;
410 "uint", 8; "uint", 16;
411 "uint", 32; "uint", 64;
412 "float", 32; "poly", 8;
413 "poly", 16
414 ] in
415 let writestruct elname elsize regsize arrsize =
416 let elnum = regsize / elsize in
417 let structname =
418 Printf.sprintf "%s%dx%dx%d_t" elname elsize elnum arrsize in
419 let sfmt = start_function () in
420 Format.printf "typedef struct %s" structname;
421 open_braceblock sfmt;
422 Format.printf "%s%dx%d_t val[%d];" elname elsize elnum arrsize;
423 close_braceblock sfmt;
424 Format.printf " %s;" structname;
425 end_function sfmt;
426 in
427 for n = 2 to 4 do
428 List.iter
429 (fun (elname, elsize) ->
430 writestruct elname elsize 64 n;
431 writestruct elname elsize 128 n)
432 typeinfo
433 done
434
435let print_lines = List.iter (fun s -> Format.printf "%s@\n" s)
436
437(* Do it. *)
438
439let _ =
440 print_lines [
441"/* ARM NEON intrinsics include file. This file is generated automatically";
442" using neon-gen.ml. Please do not edit manually.";
443"";
614aede0 444" Copyright (C) 2006, 2007, 2009, 2012 Free Software Foundation, Inc.";
d98a3884 445" Contributed by CodeSourcery.";
446"";
447" This file is part of GCC.";
448"";
449" GCC is free software; you can redistribute it and/or modify it";
450" under the terms of the GNU General Public License as published";
6bc9506f 451" by the Free Software Foundation; either version 3, or (at your";
d98a3884 452" option) any later version.";
453"";
454" GCC is distributed in the hope that it will be useful, but WITHOUT";
455" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY";
456" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public";
457" License for more details.";
458"";
6bc9506f 459" Under Section 7 of GPL version 3, you are granted additional";
460" permissions described in the GCC Runtime Library Exception, version";
461" 3.1, as published by the Free Software Foundation.";
d98a3884 462"";
6bc9506f 463" You should have received a copy of the GNU General Public License and";
464" a copy of the GCC Runtime Library Exception along with this program;";
465" see the files COPYING3 and COPYING.RUNTIME respectively. If not, see";
466" <http://www.gnu.org/licenses/>. */";
d98a3884 467"";
468"#ifndef _GCC_ARM_NEON_H";
469"#define _GCC_ARM_NEON_H 1";
470"";
471"#ifndef __ARM_NEON__";
472"#error You must enable NEON instructions (e.g. -mfloat-abi=softfp -mfpu=neon) to use arm_neon.h";
473"#else";
474"";
475"#ifdef __cplusplus";
476"extern \"C\" {";
477"#endif";
478"";
479"#include <stdint.h>";
480""];
481 deftypes ();
482 arrtypes ();
483 Format.print_newline ();
484 print_ops ops;
485 Format.print_newline ();
486 print_ops reinterp;
487 print_lines [
488"#ifdef __cplusplus";
489"}";
490"#endif";
491"#endif";
492"#endif"]