You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
1
(5) |
2
(11) |
3
|
4
(9) |
5
(10) |
6
(4) |
7
(14) |
|
8
(15) |
9
(15) |
10
(14) |
11
(13) |
12
(16) |
13
(12) |
14
(9) |
|
15
(21) |
16
(13) |
17
(11) |
18
(13) |
19
(5) |
20
(29) |
21
(20) |
|
22
(13) |
23
(18) |
24
(21) |
25
(17) |
26
(26) |
27
(13) |
28
(17) |
|
29
(10) |
30
(5) |
|
|
|
|
|
|
From: <sv...@va...> - 2014-06-30 21:04:26
|
Author: florian
Date: Mon Jun 30 21:04:16 2014
New Revision: 14124
Log:
Update the C++ demangler by importing files from GCC trunk @ 212125.
Add a smoke test for the demangler and update the helper script.
Added:
trunk/memcheck/tests/demangle.cpp
trunk/memcheck/tests/demangle.vgtest
Modified:
trunk/NEWS
trunk/auxprogs/update-demangler
trunk/coregrind/m_demangle/ansidecl.h
trunk/coregrind/m_demangle/cp-demangle.c
trunk/coregrind/m_demangle/cp-demangle.h
trunk/coregrind/m_demangle/cplus-dem.c
trunk/coregrind/m_demangle/demangle.h
trunk/memcheck/tests/ (props changed)
trunk/memcheck/tests/Makefile.am
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Mon Jun 30 21:04:16 2014
@@ -69,6 +69,8 @@
- Code compiled with -ffunction-sections -fdata-sections -Wl,--gc-sections
does not cause assert errors anymore.
+* The C++ demangler has been updated for better C++11 support.
+
* ==================== FIXED BUGS ====================
The following bugs have been fixed or resolved. Note that "n-i-bz"
Modified: trunk/auxprogs/update-demangler
==============================================================================
--- trunk/auxprogs/update-demangler (original)
+++ trunk/auxprogs/update-demangler Mon Jun 30 21:04:16 2014
@@ -6,19 +6,19 @@
# This quick and dirty script assists in updating the C++ demangler
# machinery in coregrind/m_demangle.
# The script will check out
-# - old and new revisions of the C++ demangler related files from GCC
+# - old and new revisions of the C++ demangler related files from GCC's trunk
# - m_demangle from valgrind's trunk.
# It will assemble
# - a patch file with local changes that were applied to the C++
# demangler to make it work within valgrind
# - a directory new_m_demangle whose contents should be copied to
# m_demangle in valgrind trunk
-# The patch will *not* be applied automacially.
+# The patch will *not* be applied automatically.
#---------------------------------------------------------------------
# You need to modify these revision numbers for your update.
-old_gcc_revision=r141363 # the revision of the previous update
-new_gcc_revision=r181975 # the revision for this update
+old_gcc_revision=r181975 # the revision of the previous update
+new_gcc_revision=r212125 # the revision for this update
# Unless the organization of demangler related files has changed, no
# changes below this line should be necessary.
Modified: trunk/coregrind/m_demangle/ansidecl.h
==============================================================================
--- trunk/coregrind/m_demangle/ansidecl.h (original)
+++ trunk/coregrind/m_demangle/ansidecl.h Mon Jun 30 21:04:16 2014
@@ -1,6 +1,6 @@
/* ANSI and traditional C compatability macros
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
+ 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2013
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -24,93 +24,16 @@
Macro ANSI C definition Traditional C definition
----- ---- - ---------- ----------- - ----------
- ANSI_PROTOTYPES 1 not defined
PTR `void *' `char *'
- PTRCONST `void *const' `char *'
- LONG_DOUBLE `long double' `double'
const not defined `'
volatile not defined `'
signed not defined `'
- VA_START(ap, var) va_start(ap, var) va_start(ap)
-
- Note that it is safe to write "void foo();" indicating a function
- with no return value, in all K+R compilers we have been able to test.
-
- For declaring functions with prototypes, we also provide these:
-
- PARAMS ((prototype))
- -- for functions which take a fixed number of arguments. Use this
- when declaring the function. When defining the function, write a
- K+R style argument list. For example:
-
- char *strcpy PARAMS ((char *dest, char *source));
- ...
- char *
- strcpy (dest, source)
- char *dest;
- char *source;
- { ... }
-
-
- VPARAMS ((prototype, ...))
- -- for functions which take a variable number of arguments. Use
- PARAMS to declare the function, VPARAMS to define it. For example:
-
- int printf PARAMS ((const char *format, ...));
- ...
- int
- printf VPARAMS ((const char *format, ...))
- {
- ...
- }
-
- For writing functions which take variable numbers of arguments, we
- also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These
- hide the differences between K+R <varargs.h> and C89 <stdarg.h> more
- thoroughly than the simple VA_START() macro mentioned above.
-
- VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end.
- Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls
- corresponding to the list of fixed arguments. Then use va_arg
- normally to get the variable arguments, or pass your va_list object
- around. You do not declare the va_list yourself; VA_OPEN does it
- for you.
-
- Here is a complete example:
-
- int
- printf VPARAMS ((const char *format, ...))
- {
- int result;
-
- VA_OPEN (ap, format);
- VA_FIXEDARG (ap, const char *, format);
-
- result = vfprintf (stdout, format, ap);
- VA_CLOSE (ap);
-
- return result;
- }
-
-
- You can declare variables either before or after the VA_OPEN,
- VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning
- and end of a block. They must appear at the same nesting level,
- and any variables declared after VA_OPEN go out of scope at
- VA_CLOSE. Unfortunately, with a K+R compiler, that includes the
- argument list. You can have multiple instances of VA_OPEN/VA_CLOSE
- pairs in a single function in case you need to traverse the
- argument list more than once.
For ease of writing code which uses GCC extensions but needs to be
portable to other compilers, we provide the GCC_VERSION macro that
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
wrappers around __attribute__. Also, __extension__ will be #defined
- to nothing if it doesn't work. See below.
-
- This header also defines a lot of obsolete macros:
- CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID,
- AND, DOTS, NOARGS. Don't use them. */
+ to nothing if it doesn't work. See below. */
#ifndef _ANSIDECL_H
#define _ANSIDECL_H 1
@@ -149,28 +72,8 @@
C++ compilers, does not define __STDC__, though it acts as if this
was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
-#define ANSI_PROTOTYPES 1
#define PTR void *
-#define PTRCONST void *const
-#define LONG_DOUBLE long double
-
-/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in
- a #ifndef. */
-#ifndef PARAMS
-#define PARAMS(ARGS) ARGS
-#endif
-
-#define VPARAMS(ARGS) ARGS
-#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR)
-/* variadic function helper macros */
-/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's
- use without inhibiting further decls and without declaring an
- actual variable. */
-#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy
-#define VA_CLOSE(AP) } va_end(AP); }
-#define VA_FIXEDARG(AP, T, N) struct Qdmy
-
#undef const
#undef volatile
#undef signed
@@ -188,35 +91,9 @@
# endif
#endif
-/* These are obsolete. Do not use. */
-#ifndef IN_GCC
-#define CONST const
-#define VOLATILE volatile
-#define SIGNED signed
-
-#define PROTO(type, name, arglist) type name arglist
-#define EXFUN(name, proto) name proto
-#define DEFUN(name, arglist, args) name(args)
-#define DEFUN_VOID(name) name(void)
-#define AND ,
-#define DOTS , ...
-#define NOARGS void
-#endif /* ! IN_GCC */
-
#else /* Not ANSI C. */
-#undef ANSI_PROTOTYPES
#define PTR char *
-#define PTRCONST PTR
-#define LONG_DOUBLE double
-
-#define PARAMS(args) ()
-#define VPARAMS(args) (va_alist) va_dcl
-#define VA_START(va_list, var) va_start(va_list)
-
-#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy
-#define VA_CLOSE(AP) } va_end(AP); }
-#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE)
/* some systems define these in header files for non-ansi mode */
#undef const
@@ -228,20 +105,6 @@
#define signed
#define inline
-#ifndef IN_GCC
-#define CONST
-#define VOLATILE
-#define SIGNED
-
-#define PROTO(type, name, arglist) type name ()
-#define EXFUN(name, proto) name()
-#define DEFUN(name, arglist, args) name arglist args;
-#define DEFUN_VOID(name) name()
-#define AND ;
-#define DOTS
-#define NOARGS
-#endif /* ! IN_GCC */
-
#endif /* ANSI C. */
/* Define macros for some gcc attributes. This permits us to use the
@@ -279,8 +142,15 @@
# endif
#endif
+/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
+ couldn't parse attributes placed after the identifier name, and now
+ the entire compiler is built with C++. */
#ifndef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#if GCC_VERSION >= 3004
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#else
+#define ATTRIBUTE_UNUSED
+#endif
#endif /* ATTRIBUTE_UNUSED */
/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
@@ -304,6 +174,15 @@
# endif /* GNUC >= 3.3 */
#endif /* ATTRIBUTE_NONNULL */
+/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
+#ifndef ATTRIBUTE_RETURNS_NONNULL
+# if (GCC_VERSION >= 4009)
+# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
+# else
+# define ATTRIBUTE_RETURNS_NONNULL
+# endif /* GNUC >= 4.9 */
+#endif /* ATTRIBUTE_RETURNS_NONNULL */
+
/* Attribute `pure' was valid as of gcc 3.0. */
#ifndef ATTRIBUTE_PURE
# if (GCC_VERSION >= 3000)
Modified: trunk/coregrind/m_demangle/cp-demangle.c
==============================================================================
--- trunk/coregrind/m_demangle/cp-demangle.c (original)
+++ trunk/coregrind/m_demangle/cp-demangle.c Mon Jun 30 21:04:16 2014
@@ -1,5 +1,5 @@
/* Demangler for g++ V3 ABI.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014
Free Software Foundation, Inc.
Written by Ian Lance Taylor <ia...@wa...>.
@@ -290,6 +290,41 @@
int allocation_failure;
};
+/* Stack of components, innermost first, used to avoid loops. */
+
+struct d_component_stack
+{
+ /* This component. */
+ const struct demangle_component *dc;
+ /* This component's parent. */
+ const struct d_component_stack *parent;
+};
+
+/* A demangle component and some scope captured when it was first
+ traversed. */
+
+struct d_saved_scope
+{
+ /* The component whose scope this is. */
+ const struct demangle_component *container;
+ /* The list of templates, if any, that was current when this
+ scope was captured. */
+ struct d_print_template *templates;
+};
+
+/* Checkpoint structure to allow backtracking. This holds copies
+ of the fields of struct d_info that need to be restored
+ if a trial parse needs to be backtracked over. */
+
+struct d_info_checkpoint
+{
+ const char *n;
+ int next_comp;
+ int next_sub;
+ int did_subs;
+ int expansion;
+};
+
enum { D_PRINT_BUFFER_LENGTH = 256 };
struct d_print_info
{
@@ -317,6 +352,22 @@
int pack_index;
/* Number of d_print_flush calls so far. */
unsigned long int flush_count;
+ /* Stack of components, innermost first, used to avoid loops. */
+ const struct d_component_stack *component_stack;
+ /* Array of saved scopes for evaluating substitutions. */
+ struct d_saved_scope *saved_scopes;
+ /* Index of the next unused saved scope in the above array. */
+ int next_saved_scope;
+ /* Number of saved scopes in the above array. */
+ int num_saved_scopes;
+ /* Array of templates for saving into scopes. */
+ struct d_print_template *copy_templates;
+ /* Index of the next unused copy template in the above array. */
+ int next_copy_template;
+ /* Number of copy templates in the above array. */
+ int num_copy_templates;
+ /* The nearest enclosing template, if any. */
+ const struct demangle_component *current_template;
};
#ifdef CP_DEMANGLE_DEBUG
@@ -397,6 +448,9 @@
d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
static struct demangle_component *
+d_ref_qualifier (struct d_info *, struct demangle_component *);
+
+static struct demangle_component *
d_function_type (struct d_info *);
static struct demangle_component *
@@ -440,6 +494,10 @@
static struct demangle_component *d_substitution (struct d_info *, int);
+static void d_checkpoint (struct d_info *, struct d_info_checkpoint *);
+
+static void d_backtrack (struct d_info *, struct d_info_checkpoint *);
+
static void d_growable_string_init (struct d_growable_string *, size_t);
static inline void
@@ -452,7 +510,8 @@
d_growable_string_callback_adapter (const char *, size_t, void *);
static void
-d_print_init (struct d_print_info *, demangle_callbackref, void *);
+d_print_init (struct d_print_info *, demangle_callbackref, void *,
+ const struct demangle_component *);
static inline void d_print_error (struct d_print_info *);
@@ -523,9 +582,17 @@
case DEMANGLE_COMPONENT_NAME:
printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
return;
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ printf ("tagged name\n");
+ d_dump (dc->u.s_binary.left, indent + 2);
+ d_dump (dc->u.s_binary.right, indent + 2);
+ return;
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
printf ("template parameter %ld\n", dc->u.s_number.number);
return;
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ printf ("function parameter %ld\n", dc->u.s_number.number);
+ return;
case DEMANGLE_COMPONENT_CTOR:
printf ("constructor %d\n", (int) dc->u.s_ctor.kind);
d_dump (dc->u.s_ctor.name, indent + 2);
@@ -624,6 +691,12 @@
case DEMANGLE_COMPONENT_CONST_THIS:
printf ("const this\n");
break;
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ printf ("reference this\n");
+ break;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ printf ("rvalue reference this\n");
+ break;
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
printf ("vendor type qualifier\n");
break;
@@ -663,9 +736,15 @@
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
printf ("template argument list\n");
break;
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ printf ("initializer list\n");
+ break;
case DEMANGLE_COMPONENT_CAST:
printf ("cast\n");
break;
+ case DEMANGLE_COMPONENT_NULLARY:
+ printf ("nullary operator\n");
+ break;
case DEMANGLE_COMPONENT_UNARY:
printf ("unary operator\n");
break;
@@ -699,12 +778,29 @@
case DEMANGLE_COMPONENT_CHARACTER:
printf ("character '%c'\n", dc->u.s_character.character);
return;
+ case DEMANGLE_COMPONENT_NUMBER:
+ printf ("number %ld\n", dc->u.s_number.number);
+ return;
case DEMANGLE_COMPONENT_DECLTYPE:
printf ("decltype\n");
break;
case DEMANGLE_COMPONENT_PACK_EXPANSION:
printf ("pack expansion\n");
break;
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ printf ("tls init function\n");
+ break;
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ printf ("tls wrapper function\n");
+ break;
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ printf ("default argument %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
+ case DEMANGLE_COMPONENT_LAMBDA:
+ printf ("lambda %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
}
d_dump (d_left (dc), indent + 2);
@@ -812,6 +908,7 @@
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE:
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
@@ -821,7 +918,6 @@
case DEMANGLE_COMPONENT_BINARY_ARGS:
case DEMANGLE_COMPONENT_TRINARY:
case DEMANGLE_COMPONENT_TRINARY_ARG1:
- case DEMANGLE_COMPONENT_TRINARY_ARG2:
case DEMANGLE_COMPONENT_LITERAL:
case DEMANGLE_COMPONENT_LITERAL_NEG:
case DEMANGLE_COMPONENT_COMPOUND_NAME:
@@ -842,6 +938,8 @@
case DEMANGLE_COMPONENT_COVARIANT_THUNK:
case DEMANGLE_COMPONENT_JAVA_CLASS:
case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
case DEMANGLE_COMPONENT_REFTEMP:
case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
@@ -858,6 +956,8 @@
case DEMANGLE_COMPONENT_PACK_EXPANSION:
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ case DEMANGLE_COMPONENT_NULLARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
if (left == NULL)
return NULL;
break;
@@ -865,6 +965,7 @@
/* This needs a right parameter, but the left parameter can be
empty. */
case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
if (right == NULL)
return NULL;
break;
@@ -878,6 +979,8 @@
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
break;
@@ -1116,6 +1219,8 @@
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
return has_return_type (d_left (dc));
}
}
@@ -1171,7 +1276,9 @@
v2 demangler without DMGL_PARAMS. */
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
@@ -1185,7 +1292,9 @@
dcr = d_right (dc);
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dcr->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || dcr->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dcr = d_left (dcr);
dc->u.s_binary.right = dcr;
}
@@ -1201,6 +1310,23 @@
}
}
+/* <tagged-name> ::= <name> B <source-name> */
+
+static struct demangle_component *
+d_abi_tags (struct d_info *di, struct demangle_component *dc)
+{
+ char peek;
+ while (peek = d_peek_char (di),
+ peek == 'B')
+ {
+ struct demangle_component *tag;
+ d_advance (di, 1);
+ tag = d_source_name (di);
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
+ }
+ return dc;
+}
+
/* <name> ::= <nested-name>
::= <unscoped-name>
::= <unscoped-template-name> <template-args>
@@ -1227,7 +1353,6 @@
case 'Z':
return d_local_name (di);
- case 'L':
case 'U':
return d_unqualified_name (di);
@@ -1274,6 +1399,7 @@
return dc;
}
+ case 'L':
default:
dc = d_unqualified_name (di);
if (d_peek_char (di) == 'I')
@@ -1290,8 +1416,8 @@
}
}
-/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
- ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
*/
static struct demangle_component *
@@ -1299,6 +1425,7 @@
{
struct demangle_component *ret;
struct demangle_component **pret;
+ struct demangle_component *rqual;
if (! d_check_char (di, 'N'))
return NULL;
@@ -1307,10 +1434,20 @@
if (pret == NULL)
return NULL;
+ /* Parse the ref-qualifier now and then attach it
+ once we have something to attach it to. */
+ rqual = d_ref_qualifier (di, NULL);
+
*pret = d_prefix (di);
if (*pret == NULL)
return NULL;
+ if (rqual)
+ {
+ d_left (rqual) = ret;
+ ret = rqual;
+ }
+
if (! d_check_char (di, 'E'))
return NULL;
@@ -1415,26 +1552,27 @@
static struct demangle_component *
d_unqualified_name (struct d_info *di)
{
+ struct demangle_component *ret;
char peek;
peek = d_peek_char (di);
if (IS_DIGIT (peek))
- return d_source_name (di);
+ ret = d_source_name (di);
else if (IS_LOWER (peek))
{
- struct demangle_component *ret;
-
ret = d_operator_name (di);
if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
- di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
- return ret;
+ {
+ di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
+ if (!strcmp (ret->u.s_operator.op->code, "li"))
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret,
+ d_source_name (di));
+ }
}
else if (peek == 'C' || peek == 'D')
- return d_ctor_dtor_name (di);
+ ret = d_ctor_dtor_name (di);
else if (peek == 'L')
{
- struct demangle_component * ret;
-
d_advance (di, 1);
ret = d_source_name (di);
@@ -1442,22 +1580,27 @@
return NULL;
if (! d_discriminator (di))
return NULL;
- return ret;
}
else if (peek == 'U')
{
switch (d_peek_next_char (di))
{
case 'l':
- return d_lambda (di);
+ ret = d_lambda (di);
+ break;
case 't':
- return d_unnamed_type (di);
+ ret = d_unnamed_type (di);
+ break;
default:
return NULL;
}
}
else
return NULL;
+
+ if (d_peek_char (di) == 'B')
+ ret = d_abi_tags (di, ret);
+ return ret;
}
/* <source-name> ::= <(positive length) number> <identifier> */
@@ -1569,7 +1712,8 @@
/* operator_name ::= many different two character encodings.
::= cv <type>
::= v <digit> <source-name>
-*/
+
+ This list is sorted for binary search. */
#define NL(s) s, (sizeof s) - 1
@@ -1581,23 +1725,30 @@
{ "aa", NL ("&&"), 2 },
{ "ad", NL ("&"), 1 },
{ "an", NL ("&"), 2 },
+ { "at", NL ("alignof "), 1 },
+ { "az", NL ("alignof "), 1 },
+ { "cc", NL ("const_cast"), 2 },
{ "cl", NL ("()"), 2 },
{ "cm", NL (","), 2 },
{ "co", NL ("~"), 1 },
{ "dV", NL ("/="), 2 },
- { "da", NL ("delete[]"), 1 },
+ { "da", NL ("delete[] "), 1 },
+ { "dc", NL ("dynamic_cast"), 2 },
{ "de", NL ("*"), 1 },
- { "dl", NL ("delete"), 1 },
+ { "dl", NL ("delete "), 1 },
+ { "ds", NL (".*"), 2 },
{ "dt", NL ("."), 2 },
{ "dv", NL ("/"), 2 },
{ "eO", NL ("^="), 2 },
{ "eo", NL ("^"), 2 },
{ "eq", NL ("=="), 2 },
{ "ge", NL (">="), 2 },
+ { "gs", NL ("::"), 1 },
{ "gt", NL (">"), 2 },
{ "ix", NL ("[]"), 2 },
{ "lS", NL ("<<="), 2 },
{ "le", NL ("<="), 2 },
+ { "li", NL ("operator\"\" "), 1 },
{ "ls", NL ("<<"), 2 },
{ "lt", NL ("<"), 2 },
{ "mI", NL ("-="), 2 },
@@ -1605,11 +1756,11 @@
{ "mi", NL ("-"), 2 },
{ "ml", NL ("*"), 2 },
{ "mm", NL ("--"), 1 },
- { "na", NL ("new[]"), 1 },
+ { "na", NL ("new[]"), 3 },
{ "ne", NL ("!="), 2 },
{ "ng", NL ("-"), 1 },
{ "nt", NL ("!"), 1 },
- { "nw", NL ("new"), 1 },
+ { "nw", NL ("new"), 3 },
{ "oR", NL ("|="), 2 },
{ "oo", NL ("||"), 2 },
{ "or", NL ("|"), 2 },
@@ -1622,12 +1773,14 @@
{ "qu", NL ("?"), 3 },
{ "rM", NL ("%="), 2 },
{ "rS", NL (">>="), 2 },
+ { "rc", NL ("reinterpret_cast"), 2 },
{ "rm", NL ("%"), 2 },
{ "rs", NL (">>"), 2 },
+ { "sc", NL ("static_cast"), 2 },
{ "st", NL ("sizeof "), 1 },
{ "sz", NL ("sizeof "), 1 },
- { "at", NL ("alignof "), 1 },
- { "az", NL ("alignof "), 1 },
+ { "tr", NL ("throw"), 0 },
+ { "tw", NL ("throw "), 1 },
{ NULL, NULL, 0, 0 }
};
@@ -1642,8 +1795,15 @@
if (c1 == 'v' && IS_DIGIT (c2))
return d_make_extended_operator (di, c2 - '0', d_source_name (di));
else if (c1 == 'c' && c2 == 'v')
- return d_make_comp (di, DEMANGLE_COMPONENT_CAST,
- cplus_demangle_type (di), NULL);
+ {
+ struct demangle_component *type;
+ int was_conversion = di->is_conversion;
+
+ di->is_conversion = ! di->is_expression;
+ type = cplus_demangle_type (di);
+ di->is_conversion = was_conversion;
+ return d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL);
+ }
else
{
/* LOW is the inclusive lower bound. */
@@ -1859,6 +2019,14 @@
return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
cplus_demangle_type (di), NULL);
+ case 'H':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
+ d_name (di), NULL);
+
+ case 'W':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
+ d_name (di), NULL);
+
default:
return NULL;
}
@@ -1981,6 +2149,9 @@
case '3':
kind = gnu_v3_complete_object_allocating_ctor;
break;
+ case '4':
+ kind = gnu_v3_unified_ctor;
+ break;
case '5':
kind = gnu_v3_object_ctor_group;
break;
@@ -2006,6 +2177,10 @@
case '2':
kind = gnu_v3_base_object_dtor;
break;
+ /* digit '3' is not used */
+ case '4':
+ kind = gnu_v3_unified_dtor;
+ break;
case '5':
kind = gnu_v3_object_dtor_group;
break;
@@ -2114,8 +2289,28 @@
pret = d_cv_qualifiers (di, &ret, 0);
if (pret == NULL)
return NULL;
- *pret = cplus_demangle_type (di);
- if (! *pret || ! d_add_substitution (di, ret))
+ if (d_peek_char (di) == 'F')
+ {
+ /* cv-qualifiers before a function type apply to 'this',
+ so avoid adding the unqualified function type to
+ the substitution list. */
+ *pret = d_function_type (di);
+ }
+ else
+ *pret = cplus_demangle_type (di);
+ if (!*pret)
+ return NULL;
+ if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ || (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS)
+ {
+ /* Move the ref-qualifier outside the cv-qualifiers so that
+ they are printed in the right order. */
+ struct demangle_component *fn = d_left (*pret);
+ d_left (*pret) = ret;
+ ret = *pret;
+ *pret = fn;
+ }
+ if (! d_add_substitution (di, ret))
return NULL;
return ret;
}
@@ -2164,13 +2359,61 @@
ret = d_template_param (di);
if (d_peek_char (di) == 'I')
{
- /* This is <template-template-param> <template-args>. The
- <template-template-param> part is a substitution
+ /* This may be <template-template-param> <template-args>.
+ If this is the type for a conversion operator, we can
+ have a <template-template-param> here only by following
+ a derivation like this:
+
+ <nested-name>
+ -> <template-prefix> <template-args>
+ -> <prefix> <template-unqualified-name> <template-args>
+ -> <unqualified-name> <template-unqualified-name> <template-args>
+ -> <source-name> <template-unqualified-name> <template-args>
+ -> <source-name> <operator-name> <template-args>
+ -> <source-name> cv <type> <template-args>
+ -> <source-name> cv <template-template-param> <template-args> <template-args>
+
+ where the <template-args> is followed by another.
+ Otherwise, we must have a derivation like this:
+
+ <nested-name>
+ -> <template-prefix> <template-args>
+ -> <prefix> <template-unqualified-name> <template-args>
+ -> <unqualified-name> <template-unqualified-name> <template-args>
+ -> <source-name> <template-unqualified-name> <template-args>
+ -> <source-name> <operator-name> <template-args>
+ -> <source-name> cv <type> <template-args>
+ -> <source-name> cv <template-param> <template-args>
+
+ where we need to leave the <template-args> to be processed
+ by d_prefix (following the <template-prefix>).
+
+ The <template-template-param> part is a substitution
candidate. */
- if (! d_add_substitution (di, ret))
- return NULL;
- ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
- d_template_args (di));
+ if (! di->is_conversion)
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ }
+ else
+ {
+ struct demangle_component *args;
+ struct d_info_checkpoint checkpoint;
+
+ d_checkpoint (di, &checkpoint);
+ args = d_template_args (di);
+ if (d_peek_char (di) == 'I')
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ args);
+ }
+ else
+ d_backtrack (di, &checkpoint);
+ }
}
break;
@@ -2257,12 +2500,19 @@
d_expression (di), NULL);
if (ret && d_next_char (di) != 'E')
ret = NULL;
+ can_subst = 1;
break;
case 'p':
/* Pack expansion. */
ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
cplus_demangle_type (di), NULL);
+ can_subst = 1;
+ break;
+
+ case 'a':
+ /* auto */
+ ret = d_make_name (di, "auto", 4);
break;
case 'f':
@@ -2313,6 +2563,7 @@
case 'v':
ret = d_vector_type (di);
+ can_subst = 1;
break;
case 'n':
@@ -2410,7 +2661,38 @@
return pret;
}
-/* <function-type> ::= F [Y] <bare-function-type> E */
+/* <ref-qualifier> ::= R
+ ::= O */
+
+static struct demangle_component *
+d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
+{
+ struct demangle_component *ret = sub;
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'R' || peek == 'O')
+ {
+ enum demangle_component_type t;
+ if (peek == 'R')
+ {
+ t = DEMANGLE_COMPONENT_REFERENCE_THIS;
+ di->expansion += sizeof "&";
+ }
+ else
+ {
+ t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS;
+ di->expansion += sizeof "&&";
+ }
+ d_advance (di, 1);
+
+ ret = d_make_comp (di, t, ret, NULL);
+ }
+
+ return ret;
+}
+
+/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
static struct demangle_component *
d_function_type (struct d_info *di)
@@ -2426,6 +2708,8 @@
d_advance (di, 1);
}
ret = d_bare_function_type (di, 1);
+ ret = d_ref_qualifier (di, ret);
+
if (! d_check_char (di, 'E'))
return NULL;
return ret;
@@ -2448,6 +2732,10 @@
char peek = d_peek_char (di);
if (peek == '\0' || peek == 'E' || peek == '.')
break;
+ if ((peek == 'R' || peek == 'O')
+ && d_peek_next_char (di) == 'E')
+ /* Function ref-qualifier, not a ref prefix for a parameter type. */
+ break;
type = cplus_demangle_type (di);
if (type == NULL)
return NULL;
@@ -2598,41 +2886,32 @@
{
struct demangle_component *cl;
struct demangle_component *mem;
- struct demangle_component **pmem;
if (! d_check_char (di, 'M'))
return NULL;
cl = cplus_demangle_type (di);
-
- /* The ABI specifies that any type can be a substitution source, and
- that M is followed by two types, and that when a CV-qualified
- type is seen both the base type and the CV-qualified types are
- substitution sources. The ABI also specifies that for a pointer
- to a CV-qualified member function, the qualifiers are attached to
- the second type. Given the grammar, a plain reading of the ABI
- suggests that both the CV-qualified member function and the
- non-qualified member function are substitution sources. However,
- g++ does not work that way. g++ treats only the CV-qualified
- member function as a substitution source. FIXME. So to work
- with g++, we need to pull off the CV-qualifiers here, in order to
- avoid calling add_substitution() in cplus_demangle_type(). But
- for a CV-qualified member which is not a function, g++ does
- follow the ABI, so we need to handle that case here by calling
- d_add_substitution ourselves. */
-
- pmem = d_cv_qualifiers (di, &mem, 1);
- if (pmem == NULL)
- return NULL;
- *pmem = cplus_demangle_type (di);
- if (*pmem == NULL)
+ if (cl == NULL)
return NULL;
- if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
- {
- if (! d_add_substitution (di, mem))
- return NULL;
- }
+ /* The ABI says, "The type of a non-static member function is considered
+ to be different, for the purposes of substitution, from the type of a
+ namespace-scope or static member function whose type appears
+ similar. The types of two non-static member functions are considered
+ to be different, for the purposes of substitution, if the functions
+ are members of different classes. In other words, for the purposes of
+ substitution, the class of which the function is a member is
+ considered part of the type of function."
+
+ For a pointer to member function, this call to cplus_demangle_type
+ will end up adding a (possibly qualified) non-member function type to
+ the substitution table, which is not correct; however, the member
+ function type will never be used in a substitution, so putting the
+ wrong type in the substitution table is harmless. */
+
+ mem = cplus_demangle_type (di);
+ if (mem == NULL)
+ return NULL;
return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
}
@@ -2690,8 +2969,10 @@
constructor or destructor. */
hold_last_name = di->last_name;
- if (! d_check_char (di, 'I'))
+ if (d_peek_char (di) != 'I'
+ && d_peek_char (di) != 'J')
return NULL;
+ d_advance (di, 1);
if (d_peek_char (di) == 'E')
{
@@ -2750,6 +3031,7 @@
return d_expr_primary (di);
case 'I':
+ case 'J':
/* An argument pack. */
return d_template_args (di);
@@ -2758,15 +3040,16 @@
}
}
-/* Subroutine of <expression> ::= cl <expression>+ E */
+/* Parse a sequence of expressions until we hit the terminator
+ character. */
static struct demangle_component *
-d_exprlist (struct d_info *di)
+d_exprlist (struct d_info *di, char terminator)
{
struct demangle_component *list = NULL;
struct demangle_component **p = &list;
- if (d_peek_char (di) == 'E')
+ if (d_peek_char (di) == terminator)
{
d_advance (di, 1);
return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
@@ -2783,7 +3066,7 @@
return NULL;
p = &d_right (*p);
- if (d_peek_char (di) == 'E')
+ if (d_peek_char (di) == terminator)
{
d_advance (di, 1);
break;
@@ -2793,6 +3076,18 @@
return list;
}
+/* Returns nonzero iff OP is an operator for a C++ cast: const_cast,
+ dynamic_cast, static_cast or reinterpret_cast. */
+
+static int
+op_is_new_cast (struct demangle_component *op)
+{
+ const char *code = op->u.s_operator.op->code;
+ return (code[1] == 'c'
+ && (code[0] == 's' || code[0] == 'd'
+ || code[0] == 'c' || code[0] == 'r'));
+}
+
/* <expression> ::= <(unary) operator-name> <expression>
::= <(binary) operator-name> <expression> <expression>
::= <(trinary) operator-name> <expression> <expression> <expression>
@@ -2804,8 +3099,8 @@
::= <expr-primary>
*/
-static struct demangle_component *
-d_expression (struct d_info *di)
+static inline struct demangle_component *
+d_expression_1 (struct d_info *di)
{
char peek;
@@ -2833,7 +3128,7 @@
{
d_advance (di, 2);
return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
- d_expression (di), NULL);
+ d_expression_1 (di), NULL);
}
else if (peek == 'f' && d_peek_next_char (di) == 'p')
{
@@ -2874,9 +3169,21 @@
else
return name;
}
+ else if ((peek == 'i' || peek == 't')
+ && d_peek_next_char (di) == 'l')
+ {
+ /* Brace-enclosed initializer list, untyped or typed. */
+ struct demangle_component *type = NULL;
+ if (peek == 't')
+ type = cplus_demangle_type (di);
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
+ type, d_exprlist (di, 'E'));
+ }
else
{
struct demangle_component *op;
+ const char *code = NULL;
int args;
op = d_operator_name (di);
@@ -2884,12 +3191,13 @@
return NULL;
if (op->type == DEMANGLE_COMPONENT_OPERATOR)
- di->expansion += op->u.s_operator.op->len - 2;
-
- if (op->type == DEMANGLE_COMPONENT_OPERATOR
- && strcmp (op->u.s_operator.op->code, "st") == 0)
- return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
- cplus_demangle_type (di));
+ {
+ code = op->u.s_operator.op->code;
+ di->expansion += op->u.s_operator.op->len - 2;
+ if (strcmp (code, "st") == 0)
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ cplus_demangle_type (di));
+ }
switch (op->type)
{
@@ -2908,26 +3216,46 @@
switch (args)
{
+ case 0:
+ return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL);
+
case 1:
{
struct demangle_component *operand;
+ int suffix = 0;
+
+ if (code && (code[0] == 'p' || code[0] == 'm')
+ && code[1] == code[0])
+ /* pp_ and mm_ are the prefix variants. */
+ suffix = !d_check_char (di, '_');
+
if (op->type == DEMANGLE_COMPONENT_CAST
&& d_check_char (di, '_'))
- operand = d_exprlist (di);
+ operand = d_exprlist (di, 'E');
else
- operand = d_expression (di);
- return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
- operand);
+ operand = d_expression_1 (di);
+
+ if (suffix)
+ /* Indicate the suffix variant for d_print_comp. */
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ operand, operand));
+ else
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ operand);
}
case 2:
{
struct demangle_component *left;
struct demangle_component *right;
- const char *code = op->u.s_operator.op->code;
- left = d_expression (di);
+ if (op_is_new_cast (op))
+ left = cplus_demangle_type (di);
+ else
+ left = d_expression_1 (di);
if (!strcmp (code, "cl"))
- right = d_exprlist (di);
+ right = d_exprlist (di, 'E');
else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
{
right = d_unqualified_name (di);
@@ -2936,7 +3264,7 @@
right, d_template_args (di));
}
else
- right = d_expression (di);
+ right = d_expression_1 (di);
return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
d_make_comp (di,
@@ -2947,17 +3275,50 @@
{
struct demangle_component *first;
struct demangle_component *second;
+ struct demangle_component *third;
- first = d_expression (di);
- second = d_expression (di);
+ if (!strcmp (code, "qu"))
+ {
+ /* ?: expression. */
+ first = d_expression_1 (di);
+ second = d_expression_1 (di);
+ third = d_expression_1 (di);
+ }
+ else if (code[0] == 'n')
+ {
+ /* new-expression. */
+ if (code[1] != 'w' && code[1] != 'a')
+ return NULL;
+ first = d_exprlist (di, '_');
+ second = cplus_demangle_type (di);
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ third = NULL;
+ }
+ else if (d_peek_char (di) == 'p'
+ && d_peek_next_char (di) == 'i')
+ {
+ /* Parenthesized initializer. */
+ d_advance (di, 2);
+ third = d_exprlist (di, 'E');
+ }
+ else if (d_peek_char (di) == 'i'
+ && d_peek_next_char (di) == 'l')
+ /* initializer-list. */
+ third = d_expression_1 (di);
+ else
+ return NULL;
+ }
+ else
+ return NULL;
return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
d_make_comp (di,
DEMANGLE_COMPONENT_TRINARY_ARG1,
first,
d_make_comp (di,
DEMANGLE_COMPONENT_TRINARY_ARG2,
- second,
- d_expression (di))));
+ second, third)));
}
default:
return NULL;
@@ -2965,6 +3326,18 @@
}
}
+static struct demangle_component *
+d_expression (struct d_info *di)
+{
+ struct demangle_component *ret;
+ int was_expression = di->is_expression;
+
+ di->is_expression = 1;
+ ret = d_expression_1 (di);
+ di->is_expression = was_expression;
+ return ret;
+}
+
/* <expr-primary> ::= L <type> <(value) number> E
::= L <type> <(value) float> E
::= L <mangled-name> E
@@ -3030,6 +3403,7 @@
/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
::= Z <(function) encoding> E s [<discriminator>]
+ ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
*/
static struct demangle_component *
@@ -3349,6 +3723,26 @@
}
}
+static void
+d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint)
+{
+ checkpoint->n = di->n;
+ checkpoint->next_comp = di->next_comp;
+ checkpoint->next_sub = di->next_sub;
+ checkpoint->did_subs = di->did_subs;
+ checkpoint->expansion = di->expansion;
+}
+
+static void
+d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint)
+{
+ di->n = checkpoint->n;
+ di->next_comp = checkpoint->next_comp;
+ di->next_sub = checkpoint->next_sub;
+ di->did_subs = checkpoint->did_subs;
+ di->expansion = checkpoint->expansion;
+}
+
/* Initialize a growable string. */
static void
@@ -3425,11 +3819,141 @@
d_growable_string_append_buffer (dgs, s, l);
}
+/* Walk the tree, counting the number of templates encountered, and
+ the number of times a scope might be saved. These counts will be
+ used to allocate data structures for d_print_comp, so the logic
+ here must mirror the logic d_print_comp will use. It is not
+ important that the resulting numbers are exact, so long as they
+ are larger than the actual numbers encountered. */
+
+static void
+d_count_templates_scopes (int *num_templates, int *num_scopes,
+ const struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ case DEMANGLE_COMPONENT_SUB_STD:
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ case DEMANGLE_COMPONENT_OPERATOR:
+ case DEMANGLE_COMPONENT_CHARACTER:
+ case DEMANGLE_COMPONENT_NUMBER:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ break;
+
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ (*num_templates)++;
+ goto recurse_left_right;
+
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
+ (*num_scopes)++;
+ goto recurse_left_right;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_VTABLE:
+ case DEMANGLE_COMPONENT_VTT:
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ case DEMANGLE_COMPONENT_THUNK:
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ case DEMANGLE_COMPONENT_REFTEMP:
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ case DEMANGLE_COMPONENT_VECTOR_TYPE:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_NULLARY:
+ case DEMANGLE_COMPONENT_UNARY:
+ case DEMANGLE_COMPONENT_BINARY:
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ case DEMANGLE_COMPONENT_TRINARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ case DEMANGLE_COMPONENT_CLONE:
+ recurse_left_right:
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_left (dc));
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_right (dc));
+ break;
+
+ case DEMANGLE_COMPONENT_CTOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_ctor.name);
+ break;
+
+ case DEMANGLE_COMPONENT_DTOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_dtor.name);
+ break;
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_extended_operator.name);
+ break;
+
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_left (dc));
+ break;
+
+ case DEMANGLE_COMPONENT_LAMBDA:
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_unary_num.sub);
+ break;
+ }
+}
+
/* Initialize a print information structure. */
static void
d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
- void *opaque)
+ void *opaque, const struct demangle_component *dc)
{
dpi->len = 0;
dpi->last_char = '\0';
@@ -3442,6 +3966,22 @@
dpi->opaque = opaque;
dpi->demangle_failure = 0;
+
+ dpi->component_stack = NULL;
+
+ dpi->saved_scopes = NULL;
+ dpi->next_saved_scope = 0;
+ dpi->num_saved_scopes = 0;
+
+ dpi->copy_templates = NULL;
+ dpi->next_copy_template = 0;
+ dpi->num_copy_templates = 0;
+
+ d_count_templates_scopes (&dpi->num_copy_templates,
+ &dpi->num_saved_scopes, dc);
+ dpi->num_copy_templates *= dpi->num_saved_scopes;
+
+ dpi->current_template = NULL;
}
/* Indicate that an error occurred during printing, and test for error. */
@@ -3527,9 +4067,24 @@
{
struct d_print_info dpi;
- d_print_init (&dpi, callback, opaque);
+ d_print_init (&dpi, callback, opaque, dc);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes];
+ __extension__ struct d_print_template temps[dpi.num_copy_templates];
+
+ dpi.saved_scopes = scopes;
+ dpi.copy_templates = temps;
+#else
+ dpi.saved_scopes = alloca (dpi.num_saved_scopes
+ * sizeof (*dpi.saved_scopes));
+ dpi.copy_templates = alloca (dpi.num_copy_templates
+ * sizeof (*dpi.copy_templates));
+#endif
- d_print_comp (&dpi, options, dc);
+ d_print_comp (&dpi, options, dc);
+ }
d_print_flush (&dpi);
@@ -3631,11 +4186,13 @@
case DEMANGLE_COMPONENT_LAMBDA:
case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_OPERATOR:
case DEMANGLE_COMPONENT_BUILTIN_TYPE:
case DEMANGLE_COMPONENT_SUB_STD:
case DEMANGLE_COMPONENT_CHARACTER:
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
return NULL;
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
@@ -3677,6 +4234,8 @@
{
int simple = 0;
if (dc->type == DEMANGLE_COMPONENT_NAME
+ || dc->type == DEMANGLE_COMPONENT_QUAL_NAME
+ || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST
|| dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
simple = 1;
if (!simple)
@@ -3686,16 +4245,79 @@
d_append_char (dpi, ')');
}
+/* Save the current scope. */
+
+static void
+d_save_scope (struct d_print_info *dpi,
+ const struct demangle_component *container)
+{
+ struct d_saved_scope *scope;
+ struct d_print_template *src, **link;
+
+ if (dpi->next_saved_scope >= dpi->num_saved_scopes)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ scope = &dpi->saved_scopes[dpi->next_saved_scope];
+ dpi->next_saved_scope++;
+
+ scope->container = container;
+ link = &scope->templates;
+
+ for (src = dpi->templates; src != NULL; src = src->next)
+ {
+ struct d_print_template *dst;
+
+ if (dpi->next_copy_template >= dpi->num_copy_templates)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ dst = &dpi->copy_templates[dpi->next_copy_template];
+ dpi->next_copy_template++;
+
+ dst->template_decl = src->template_decl;
+ *link = dst;
+ link = &dst->next;
+ }
+
+ *link = NULL;
+}
+
+/* Attempt to locate a previously saved scope. Returns NULL if no
+ corresponding saved scope was found. */
+
+static struct d_saved_scope *
+d_get_saved_scope (struct d_print_info *dpi,
+ const struct demangle_component *container)
+{
+ int i;
+
+ for (i = 0; i < dpi->next_saved_scope; i++)
+ if (dpi->saved_scopes[i].container == container)
+ return &dpi->saved_scopes[i];
+
+ return NULL;
+}
+
/* Subroutine to handle components. */
static void
-d_print_comp (struct d_print_info *dpi, int options,
- const struct demangle_component *dc)
+d_print_comp_inner (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
{
/* Magic variable to let reference smashing skip over the next modifier
without needing to modify *dc. */
const struct demangle_component *mod_inner = NULL;
+ /* Variable used to store the current templates while a previously
+ captured scope is used. */
+ struct d_print_template *saved_templates;
+
+ /* Nonzero if templates have been stored in the above variable. */
+ int need_template_restore = 0;
+
if (dc == NULL)
{
d_print_error (dpi);
@@ -3713,6 +4335,13 @@
d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
return;
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, "[abi:");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_char (dpi, ']');
+ return;
+
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
d_print_comp (dpi, options, d_left (dc));
@@ -3720,7 +4349,17 @@
d_append_string (dpi, "::");
else
d_append_char (dpi, '.');
- d_print_comp (dpi, options, d_right (dc));
+ {
+ struct demangle_component *local_name = d_right (dc);
+ if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ {
+ d_append_string (dpi, "{default arg#");
+ d_append_num (dpi, local_name->u.s_unary_num.num + 1);
+ d_append_string (dpi, "}::");
+ local_name = local_name->u.s_unary_num.sub;
+ }
+ d_print_comp (dpi, options, local_name);
+ }
return;
case DEMANGLE_COMPONENT_TYPED_NAME:
@@ -3755,7 +4394,9 @@
if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
- && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS)
+ && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
break;
typed_name = d_left (typed_name);
@@ -3789,7 +4430,10 @@
local_name = local_name->u.s_unary_num.sub;
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || local_name->type == DEMANGLE_COMPONENT_CONST_THIS
+ || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || (local_name->type
+ == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
{
if (i >= sizeof adpm / sizeof adpm[0])
{
@@ -3836,6 +4480,12 @@
{
struct d_print_mod *hold_dpm;
struct demangle_component *dcl;
+ const struct demangle_component *hold_current;
+
+ /* This template may need to be referenced by a cast operator
+ contained in its subtree. */
+ hold_current = dpi->current_template;
+ dpi->current_template = dc;
/* Don't push modifiers into a template definition. Doing so
could give the wrong definition for a template argument.
@@ -3872,6 +4522,7 @@
}
dpi->modifiers = hold_dpm;
+ dpi->current_template = hold_current;
return;
}
@@ -3971,6 +4622,16 @@
d_print_comp (dpi, options, d_left (dc));
return;
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ d_append_string (dpi, "TLS init function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ d_append_string (dpi, "TLS wrapper function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
case DEMANGLE_COMPONENT_REFTEMP:
d_append_string (dpi, "reference temporary #");
d_print_comp (dpi, options, d_right (dc));
@@ -4032,12 +4693,56 @@
const struct demangle_component *sub = d_left (dc);
if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
{
- struct demangle_component *a = d_lookup_template_argument (dpi, sub);
+ struct d_saved_scope *scope = d_get_saved_scope (dpi, sub);
+ struct demangle_component *a;
+
+ if (scope == NULL)
+ {
+ /* This is the first time SUB has been traversed.
+ We need to capture the current templates so
+ they can be restored if SUB is reentered as a
+ substitution. */
+ d_save_scope (dpi, sub);
+ if (d_print_saw_error (dpi))
+ return;
+ }
+ else
+ {
+ const struct d_component_stack *dcse;
+ int found_self_or_parent = 0;
+
+ /* This traversal is reentering SUB as a substition.
+ If we are not beneath SUB or DC in the tree then we
+ need to restore SUB's template stack temporarily. */
+ for (dcse = dpi->component_stack; dcse != NULL;
+ dcse = dcse->parent)
+ {
+ if (dcse->dc == sub
+ || (dcse->dc == dc
+ && dcse != dpi->component_stack))
+ {
+ found_self_or_parent = 1;
+ break;
+ }
+ }
+
+ if (!found_self_or_parent)
+ {
+ saved_templates = dpi->templates;
+ dpi->templates = scope->templates;
+ need_template_restore = 1;
+ }
+ }
+
+ a = d_lookup_template_argument (dpi, sub);
if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
a = d_index_template_argument (a, dpi->pack_index);
if (a == NULL)
{
+ if (need_template_restore)
+ dpi->templates = saved_templates;
+
d_print_error (dpi);
return;
}
@@ -4056,6 +4761,8 @@
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
@@ -4083,6 +4790,9 @@
dpi->modifiers = dpm.next;
+ if (need_template_restore)
+ dpi->templates = saved_templates;
+
return;
}
@@ -4272,16 +4982,32 @@
}
return;
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ {
+ struct demangle_component *type = d_left (dc);
+ struct demangle_component *list = d_right (dc);
+
+ if (type)
+ d_print_comp (dpi, options, type);
+ d_append_char (dpi, '{');
+ d_print_comp (dpi, options, list);
+ d_append_char (dpi, '}');
+ }
+ return;
+
case DEMANGLE_COMPONENT_OPERATOR:
{
- char c;
+ const struct demangle_operator_info *op = dc->u.s_operator.op;
+ int len = op->len;
d_append_string (dpi, "operator");
- c = dc->u.s_operator.op->name[0];
- if (IS_LOWER (c))
+ /* Add a space before new/delete. */
+ if (IS_LOWER (op->name[0]))
d_append_char (dpi, ' ');
- d_append_buffer (dpi, dc->u.s_operator.op->name,
- dc->u.s_operator.op->len);
+ /* Omit a trailing space. */
+ if (op->name[len-1] == ' ')
+ --len;
+ d_append_buffer (dpi, op->name, len);
return;
}
@@ -4295,55 +5021,59 @@
d_print_cast (dpi, options, dc);
return;
+ case DEMANGLE_COMPONENT_NULLARY:
+ d_print_expr_op (dpi, options, d_left (dc));
+ return;
+
case DEMANGLE_COMPONENT_UNARY:
- if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
- && d_left (dc)->u.s_operator.op->len == 1
- && d_left (dc)->u.s_operator.op->name[0] == '&'
- && d_right (dc)->type == DEMANGLE_COMPONENT_TYPED_NAME
- && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_QUAL_NAME
- && d_right (d_right (dc))->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
- {
- /* Address of a function (therefore in an expression context) must
- have its argument list suppressed.
-
- unary operator ... dc
- operator & ... d_left (dc)
- typed name ... d_right (dc)
- qualified name ... d_left (d_right (dc))
- <names>
- function type ... d_right (d_right (dc))
- argument list
- <arguments> */
+ {
+ struct demangle_component *op = d_left (dc);
+ struct demangle_component *operand = d_right (dc);
+ const char *code = NULL;
- d_print_expr_op (dpi, options, d_left (dc));
- d_print_comp (dpi, options, d_left (d_right (dc)));
- return;
- }
- else if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
- && d_left (dc)->u.s_operator.op->len == 1
- && d_left (dc)->u.s_operator.op->name[0] == '&'
- && d_right (dc)->type == DEMANGLE_COMPONENT_QUAL_NAME)
- {
- /* Keep also already processed variant without the argument list.
-
- unary operator ... dc
- operator & ... d_left (dc)
- qualified name ... d_right (dc)
- <names> */
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+ {
+ code = op->u.s_operator.op->code;
+ if (!strcmp (code, "ad"))
+ {
+ /* Don't print the argument list for the address of a
+ function. */
+ if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME
+ && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME
+ && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ operand = d_left (operand);
+ }
+ if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS)
+ {
+ /* This indicates a suffix operator. */
+ operand = d_left (operand);
+ d_print_subexpr (dpi, options, operand);
+ d_print_expr_op (dpi, options, op);
+ return;
+ }
+ }
- d_print_expr_op (dpi, options, d_left (dc));
- d_print_comp (dpi, options, d_right (dc));
- return;
- }
- else if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST)
- d_print_expr_op (dpi, options, d_left (dc));
- else
- {
- d_append_char (dpi, '(');
- d_print_cast (dpi, options, d_left (dc));
- d_append_char (dpi, ')');
- }
- d_print_subexpr (dpi, options, d_right (dc));
+ if (op->type != DEMANGLE_COMPONENT_CAST)
+ d_print_expr_op (dpi, options, op);
+ else
+ {
+ d_append_char (dpi, '(');
+ d_print_cast (dpi, options, op);
+ d_append_char (dpi, ')');
+ ...
[truncated message content] |
|
From: <sv...@va...> - 2014-06-30 20:58:41
|
Author: philippe
Date: Mon Jun 30 20:58:32 2014
New Revision: 14123
Log:
Add 'numbering identification' to the dedup pool.
The dedup pool can now be used to allocate elements and identify
them with a number rather than an address.
This new feature is not used (yet) but is intended to be used to
decrease the memory needed to store the CFSI information.
Modified:
trunk/coregrind/m_deduppoolalloc.c
trunk/include/pub_tool_deduppoolalloc.h
Modified: trunk/coregrind/m_deduppoolalloc.c
==============================================================================
--- trunk/coregrind/m_deduppoolalloc.c (original)
+++ trunk/coregrind/m_deduppoolalloc.c Mon Jun 30 20:58:32 2014
@@ -40,12 +40,14 @@
struct _DedupPoolAlloc {
SizeT poolSzB; /* Minimum size of a pool. */
+ SizeT fixedSzb; /* If using VG_(allocFixedEltDedupPA), size of elements */
SizeT eltAlign;
void* (*alloc)(const HChar*, SizeT); /* pool allocator */
const HChar* cc; /* pool allocator's cc */
void (*free)(void*); /* pool allocator's free-er */
/* XArray of void* (pointers to pools). The pools themselves.
- Each element is a pointer to a block of size at least PoolSzB bytes. */
+ Each element is a pointer to a block of size at least PoolSzB bytes.
+ The last block might be smaller due to a call to shrink_block. */
XArray *pools;
/* hash table of pool elements, used to dedup.
@@ -56,12 +58,17 @@
decrease memory overhead during insertion in the DedupPoolAlloc. */
PoolAlloc *ht_node_pa;
- UChar *curpool_free; /* Pos in current pool to allocate next elt. */
+ UChar *curpool; /* last allocated pool. */
+ UChar *curpool_free; /* Pos in current pool to allocate next elt.
+ always aligned on eltAlign. */
UChar *curpool_limit; /* Last pos in current pool. */
+ /* Note that for a fixed size pool, we only have a single pool to allow
+ simple/fast indexing. This single pool is grown, which might change
+ the address of the already allocated elements. */
/* Total nr of alloc calls, resulting in (we hope) a lot less
real (dedup) elements. */
- ULong nr_alloc_calls;
+ ULong nr_alloc_calls;
};
typedef
@@ -90,6 +97,7 @@
vg_assert(ddpa);
VG_(memset)(ddpa, 0, sizeof(*ddpa));
ddpa->poolSzB = poolSzB;
+ ddpa->fixedSzb = 0;
ddpa->eltAlign = eltAlign;
ddpa->alloc = alloc;
ddpa->cc = cc;
@@ -102,7 +110,7 @@
alloc,
cc,
free_fn);
-
+ ddpa->curpool = NULL;
ddpa->curpool_limit = NULL;
ddpa->curpool_free = ddpa->curpool_limit + 1;
vg_assert(ddpa->pools);
@@ -113,7 +121,8 @@
{
Word i;
if (ddpa->ht_elements)
- VG_(freezeDedupPA) (ddpa, NULL); // Free data structures used for insertion.
+ // Free data structures used for insertion.
+ VG_(freezeDedupPA) (ddpa, NULL);
for (i = 0; i < VG_(sizeXA) (ddpa->pools); i++)
ddpa->free (*(UWord **)VG_(indexXA) ( ddpa->pools, i ));
VG_(deleteXA) (ddpa->pools);
@@ -121,22 +130,46 @@
}
static __inline__
-void ddpa_align_curpool_free ( DedupPoolAlloc* ddpa )
+UChar* ddpa_align ( DedupPoolAlloc* ddpa, UChar *c )
{
- ddpa->curpool_free = (UChar*)VG_ROUNDUP(ddpa->curpool_free, ddpa->eltAlign);
+ return (UChar*)VG_ROUNDUP(c, ddpa->eltAlign);
}
-/* No space. Allocate a new pool. */
+/* Allocate a new pool or grow the (only) pool for a fixed size ddpa. */
__attribute__((noinline))
-static void ddpa_add_new_pool ( DedupPoolAlloc* ddpa )
+static void ddpa_add_new_pool_or_grow ( DedupPoolAlloc* ddpa )
{
vg_assert(ddpa);
- ddpa->curpool_free = ddpa->alloc( ddpa->cc, ddpa->poolSzB);
- vg_assert(ddpa->curpool_free);
- ddpa->curpool_limit = ddpa->curpool_free + ddpa->poolSzB - 1;
- /* add to our collection of pools */
- VG_(addToXA)( ddpa->pools, &ddpa->curpool_free );
- ddpa_align_curpool_free (ddpa);
+
+ if (ddpa->fixedSzb > 0 && ddpa->curpool != NULL) {
+ // Grow (* 2) the current (fixed elt) pool
+ UChar *curpool_align = ddpa_align(ddpa, ddpa->curpool);
+ SizeT curpool_used = ddpa->curpool_free - curpool_align;
+ SizeT curpool_size = ddpa->curpool_limit - ddpa->curpool + 1;
+ UChar *newpool = ddpa->alloc (ddpa->cc, 2 * curpool_size);
+ UChar *newpool_free = ddpa_align (ddpa, newpool);
+ UChar *newpool_limit = newpool + 2 * curpool_size - 1;
+
+ vg_assert (newpool);
+ VG_(memcpy) (newpool_free, curpool_align, curpool_used);
+ newpool_free += curpool_used;
+
+ VG_(dropHeadXA) (ddpa->pools, 1);
+ ddpa->free (ddpa->curpool);
+ ddpa->curpool = newpool;
+ ddpa->curpool_free = newpool_free;
+ ddpa->curpool_limit = newpool_limit;
+ VG_(addToXA)( ddpa->pools, &ddpa->curpool);
+ } else {
+ /* Allocate a new pool, or allocate the first/only pool for a
+ fixed size ddpa. */
+ ddpa->curpool = ddpa->alloc( ddpa->cc, ddpa->poolSzB);
+ vg_assert(ddpa->curpool);
+ ddpa->curpool_limit = ddpa->curpool + ddpa->poolSzB - 1;
+ ddpa->curpool_free = ddpa_align (ddpa, ddpa->curpool);
+ /* add to our collection of pools */
+ VG_(addToXA)( ddpa->pools, &ddpa->curpool );
+ }
}
static Word cmp_pool_elt (const void* node1, const void* node2 )
@@ -183,12 +216,9 @@
&& (VG_(clo_verbosity) > 2 || VG_(debugLog_getLevel) () >= 2)) {
print_stats(ddpa);
}
- if (shrink_block && ddpa->curpool_limit > ddpa->curpool_free) {
- UChar *last_added_pool =
- (*(UChar **)VG_(indexXA) ( ddpa->pools,
- VG_(sizeXA)(ddpa->pools) - 1));
- (*shrink_block)(last_added_pool, ddpa->curpool_free - last_added_pool);
- }
+ vg_assert (!ddpa->fixedSzb || VG_(sizeXA) (ddpa->pools) == 1);
+ if (shrink_block && ddpa->curpool_limit > ddpa->curpool_free)
+ (*shrink_block)(ddpa->curpool, ddpa->curpool_free - ddpa->curpool);
VG_(HT_destruct) ( ddpa->ht_elements, htelem_dummyfree);
ddpa->ht_elements = NULL;
VG_(deletePA) (ddpa->ht_node_pa);
@@ -225,15 +255,14 @@
/* Not found -> we need to allocate a new element from the pool
and insert it in the hash table of inserted elements. */
- // Add a new pool if not enough space in the current pool
+ // Add a new pool or grow pool if not enough space in the current pool
if (UNLIKELY(ddpa->curpool_free + eltSzB - 1 > ddpa->curpool_limit)) {
- ddpa_add_new_pool(ddpa);
+ ddpa_add_new_pool_or_grow (ddpa);
}
elt_ins = ddpa->curpool_free;
VG_(memcpy)(elt_ins, elt, eltSzB);
- ddpa->curpool_free = ddpa->curpool_free + eltSzB;
- ddpa_align_curpool_free (ddpa);
+ ddpa->curpool_free = ddpa_align(ddpa, ddpa->curpool_free + eltSzB);
ht_ins = VG_(allocEltPA) (ddpa->ht_node_pa);
ht_ins->key = ht_elt.key;
@@ -242,3 +271,50 @@
VG_(HT_add_node)(ddpa->ht_elements, ht_ins);
return elt_ins;
}
+
+static __inline__
+UInt elt2nr (DedupPoolAlloc *ddpa, const void *dedup_elt)
+{
+ vg_assert ((UChar*)dedup_elt >= ddpa->curpool
+ && (UChar*)dedup_elt < ddpa->curpool_free);
+ return 1 + ((UChar*)dedup_elt - ddpa->curpool)
+ / VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
+}
+
+UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa,
+ SizeT eltSzB, const void *elt)
+{
+ if (ddpa->fixedSzb == 0) {
+ // First insertion in this ddpa
+ vg_assert (ddpa->nr_alloc_calls == 0);
+ vg_assert (eltSzB > 0);
+ ddpa->fixedSzb = eltSzB;
+ }
+ vg_assert (ddpa->fixedSzb == eltSzB);
+ void *dedup_elt = VG_(allocEltDedupPA) (ddpa, eltSzB, elt);
+ return elt2nr (ddpa, dedup_elt);
+}
+
+void* VG_(indexEltNumber) (DedupPoolAlloc *ddpa,
+ UInt eltNr)
+{
+ void *dedup_elt;
+
+ dedup_elt = ddpa->curpool
+ + (eltNr - 1) * VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
+
+ vg_assert ((UChar*)dedup_elt >= ddpa->curpool
+ && (UChar*)dedup_elt < ddpa->curpool_free);
+
+ return dedup_elt;
+}
+
+UInt VG_(sizeDedupPA) (DedupPoolAlloc *ddpa)
+{
+ if (ddpa->curpool == NULL)
+ return 0;
+
+ vg_assert (ddpa->fixedSzb);
+ return (ddpa->curpool_free - ddpa_align(ddpa, ddpa->curpool))
+ / VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
+}
Modified: trunk/include/pub_tool_deduppoolalloc.h
==============================================================================
--- trunk/include/pub_tool_deduppoolalloc.h (original)
+++ trunk/include/pub_tool_deduppoolalloc.h Mon Jun 30 20:58:32 2014
@@ -35,7 +35,7 @@
//-----------------------------------------------------------------------------
// PURPOSE: Provides a pool allocator for elements, storing only once identical
-// elements. In other words, this can be considered a "dictionary" of elements.
+// elements. In other words, this can be considered a "dictionary" of elements.
//
// This pool allocator manages elements allocation by allocating "pools" of
// many elements from a lower level allocator (typically pub_tool_mallocfree.h).
@@ -43,6 +43,29 @@
// Currently, elements can only be allocated, elements cannot be freed
// individually.
// Once allocated, an element must not be modified anymore.
+//
+// Elements can be inserted in the pool using VG_(allocEltDedupPA)
+// or using VG_(allocFixedEltDedupPA).
+//
+// Use VG_(allocFixedEltDedupPA) to allocate elements that are all of
+// the same size and that you want to identify with a (small) number:
+// VG_(allocFixedEltDedupPA) will assign a sequence number to each
+// unique allocated element. This unique number can be translated to
+// an address when the element data must be used.
+// The idea is that such small numbers can be used as reference instead
+// of the element address, to spare memory.
+// Elements are numbered starting from 1. The nr 0 can thus be used
+// as 'null element'. The address identified by a nr can change
+// if new elements are inserted in the pool. Once the pool is frozen,
+// an element address does not change.
+//
+// Use VG_(allocEltDedupPA) for variable size elements or when the
+// memory needed to store the element reference is not critical or
+// when performance to access elements is critical.
+// The address of an element allocated with VG_(allocEltDedupPA) does
+// not change, even if new elements are inserted in the pool.
+//
+// In the same pool, you can only use one of the allocate element functions.
//
// A dedup pool allocator has significantly less memory overhead than
// calling directly pub_tool_mallocfree.h if the deduplication factor
@@ -50,7 +73,7 @@
// if an identical element is already in the pool.
//
// Note: the elements of the pool cannot be freed (at least currently).
-// The only way to free the elements is to delete the pool allocator.
+// The only way to free the elements is to delete the dedup pool allocator.
//--------------------------------------------------------------------
@@ -72,17 +95,30 @@
extern void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa,
SizeT eltSzB, const void *elt);
+/* Allocates a new (fixed size) element from ddpa. Returns the
+ unique number identifying this element. */
+extern UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa,
+ SizeT eltSzB, const void *elt);
+
+/* Translate an element number to its address. Note that the address
+ corresponding to eltNr can change if new elements are inserted
+ in the pool. */
+extern void* VG_(indexEltNumber) (DedupPoolAlloc *ddpa,
+ UInt eltNr);
/* The Dedup Pool Allocator must maintain a data structure to avoid
duplicates as long as new elements can be allocated from the pool.
Once no new elements will be allocated, this dedup data structure
can be released using VG_(freezeDedupPA). Once ddpa has been frozen,
- it is an error to call VG_(allocEltDedupPA).
+ it is an error to call VG_(allocEltDedupPA) or VG_(allocFixedEltDedupPA).
If shrink_block is not NULL, the last pool will be shrunk using
shrink_block. */
extern void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa,
void (*shrink_block)(void*, SizeT));
+/* How many (unique) elements are there in this ddpa now? */
+extern UInt VG_(sizeDedupPA) (DedupPoolAlloc *ddpa);
+
/* Free all memory associated with a DedupPoolAlloc. */
extern void VG_(deleteDedupPA) ( DedupPoolAlloc *ddpa);
|
|
From: <sv...@va...> - 2014-06-30 19:47:34
|
Author: philippe
Date: Mon Jun 30 19:47:24 2014
New Revision: 14122
Log:
Implement VG_(arena_realloc_shrink) similar to realloc, but can
only decrease the size of a block, does not change the address,
does not need to alloc another block and copy the memory,
and (if big enough) makes the excess memory available for other
allocations.
VG_(arena_realloc_shrink) is then used for debuginfo storage.c
(replacing an allocation + copy).
Also use it in the dedup pool, to recuperate the unused
memory of the last pool.
This also allows to re-increase the string pool size to the original
3.9.0 value of 64Kb. All this slightly decrease the peak and in use
memory of dinfo.
VG_(arena_realloc_shrink) will also be used to implement (in another patch)
a dedup pool which "numbers" the allocated elements.
Modified:
trunk/coregrind/m_debuginfo/misc.c
trunk/coregrind/m_debuginfo/priv_misc.h
trunk/coregrind/m_debuginfo/priv_storage.h
trunk/coregrind/m_debuginfo/storage.c
trunk/coregrind/m_deduppoolalloc.c
trunk/coregrind/m_mallocfree.c
trunk/coregrind/pub_core_mallocfree.h
trunk/include/pub_tool_deduppoolalloc.h
Modified: trunk/coregrind/m_debuginfo/misc.c
==============================================================================
--- trunk/coregrind/m_debuginfo/misc.c (original)
+++ trunk/coregrind/m_debuginfo/misc.c Mon Jun 30 19:47:24 2014
@@ -51,6 +51,10 @@
return v;
}
+void ML_(dinfo_shrink_block)( void* ptr, SizeT szB ) {
+ VG_(arena_realloc_shrink)( VG_AR_DINFO, ptr, szB );
+}
+
void ML_(dinfo_free) ( void* v ) {
VG_(arena_free)( VG_AR_DINFO, v );
}
Modified: trunk/coregrind/m_debuginfo/priv_misc.h
==============================================================================
--- trunk/coregrind/m_debuginfo/priv_misc.h (original)
+++ trunk/coregrind/m_debuginfo/priv_misc.h Mon Jun 30 19:47:24 2014
@@ -38,11 +38,12 @@
#include "pub_core_basics.h" // SizeT
-/* Allocate(zeroed), free, strdup, memdup, all in VG_AR_DINFO. */
+/* Allocate(zeroed), free, strdup, memdup, shrink, all in VG_AR_DINFO. */
void* ML_(dinfo_zalloc)( const HChar* cc, SizeT szB );
void ML_(dinfo_free)( void* v );
HChar* ML_(dinfo_strdup)( const HChar* cc, const HChar* str );
void* ML_(dinfo_memdup)( const HChar* cc, void* str, SizeT nStr );
+void ML_(dinfo_shrink_block)( void* ptr, SizeT szB );
/* Extract (possibly unaligned) data of various sizes from a buffer. */
Short ML_(read_Short)( UChar* data );
Modified: trunk/coregrind/m_debuginfo/priv_storage.h
==============================================================================
--- trunk/coregrind/m_debuginfo/priv_storage.h (original)
+++ trunk/coregrind/m_debuginfo/priv_storage.h Mon Jun 30 19:47:24 2014
@@ -537,7 +537,7 @@
/* To do with the string table in struct _DebugInfo (::strpool) */
-#define SEGINFO_STRPOOLSIZE (16*1024)
+#define SEGINFO_STRPOOLSIZE (64*1024)
/* We may encounter more than one .eh_frame section in an object --
Modified: trunk/coregrind/m_debuginfo/storage.c
==============================================================================
--- trunk/coregrind/m_debuginfo/storage.c (original)
+++ trunk/coregrind/m_debuginfo/storage.c Mon Jun 30 19:47:24 2014
@@ -331,21 +331,13 @@
/* Resize the LocTab (line number table) to save memory, by removing
(and, potentially, allowing m_mallocfree to unmap) any unused space
- at the end of the table.
-*/
+ at the end of the table. */
static void shrinkLocTab ( struct _DebugInfo* di )
{
- DiLoc* new_tab;
UWord new_sz = di->loctab_used;
if (new_sz == di->loctab_size) return;
vg_assert(new_sz < di->loctab_size);
-
- new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkLocTab",
- new_sz * sizeof(DiLoc) );
- VG_(memcpy)(new_tab, di->loctab, new_sz * sizeof(DiLoc));
-
- ML_(dinfo_free)(di->loctab);
- di->loctab = new_tab;
+ ML_(dinfo_shrink_block)( di->loctab, new_sz * sizeof(DiLoc));
di->loctab_size = new_sz;
}
@@ -484,21 +476,13 @@
/* Resize the InlTab (inlined call table) to save memory, by removing
(and, potentially, allowing m_mallocfree to unmap) any unused space
- at the end of the table.
-*/
+ at the end of the table. */
static void shrinkInlTab ( struct _DebugInfo* di )
{
- DiInlLoc* new_tab;
UWord new_sz = di->inltab_used;
if (new_sz == di->inltab_size) return;
vg_assert(new_sz < di->inltab_size);
-
- new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkInlTab",
- new_sz * sizeof(DiInlLoc) );
- VG_(memcpy)(new_tab, di->inltab, new_sz * sizeof(DiInlLoc));
-
- ML_(dinfo_free)(di->inltab);
- di->inltab = new_tab;
+ ML_(dinfo_shrink_block)( di->inltab, new_sz * sizeof(DiInlLoc));
di->inltab_size = new_sz;
}
@@ -1967,7 +1951,7 @@
ML_(canonicaliseCFI) ( di );
canonicaliseVarInfo ( di );
if (di->strpool)
- VG_(freezeDedupPA) (di->strpool);
+ VG_(freezeDedupPA) (di->strpool, ML_(dinfo_shrink_block));
}
Modified: trunk/coregrind/m_deduppoolalloc.c
==============================================================================
--- trunk/coregrind/m_deduppoolalloc.c (original)
+++ trunk/coregrind/m_deduppoolalloc.c Mon Jun 30 19:47:24 2014
@@ -113,7 +113,7 @@
{
Word i;
if (ddpa->ht_elements)
- VG_(freezeDedupPA) (ddpa); // Free data structures used for insertion.
+ VG_(freezeDedupPA) (ddpa, NULL); // Free data structures used for insertion.
for (i = 0; i < VG_(sizeXA) (ddpa->pools); i++)
ddpa->free (*(UWord **)VG_(indexXA) ( ddpa->pools, i ));
VG_(deleteXA) (ddpa->pools);
@@ -176,12 +176,19 @@
{
}
-void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa)
+void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa,
+ void (*shrink_block)(void*, SizeT))
{
if (VG_(clo_stats)
&& (VG_(clo_verbosity) > 2 || VG_(debugLog_getLevel) () >= 2)) {
print_stats(ddpa);
}
+ if (shrink_block && ddpa->curpool_limit > ddpa->curpool_free) {
+ UChar *last_added_pool =
+ (*(UChar **)VG_(indexXA) ( ddpa->pools,
+ VG_(sizeXA)(ddpa->pools) - 1));
+ (*shrink_block)(last_added_pool, ddpa->curpool_free - last_added_pool);
+ }
VG_(HT_destruct) ( ddpa->ht_elements, htelem_dummyfree);
ddpa->ht_elements = NULL;
VG_(deletePA) (ddpa->ht_node_pa);
Modified: trunk/coregrind/m_mallocfree.c
==============================================================================
--- trunk/coregrind/m_mallocfree.c (original)
+++ trunk/coregrind/m_mallocfree.c Mon Jun 30 19:47:24 2014
@@ -487,6 +487,44 @@
return b2[get_bszB(b) - sizeof(SizeT) - rz_byteno - 1];
}
+#if defined(ENABLE_INNER_CLIENT_REQUEST)
+/* When running as an inner, the block headers before and after
+ (see 'Layout of an in-use block:' above) are made non accessible
+ by VALGRIND_MALLOCLIKE_BLOCK/VALGRIND_FREELIKE_BLOCK
+ to allow the outer to detect block overrun.
+ The below two functions are used when these headers must be
+ temporarily accessed. */
+static void mkBhdrAccess( Arena* a, Block* b )
+{
+ VALGRIND_MAKE_MEM_DEFINED (b,
+ hp_overhead_szB() + sizeof(SizeT) + a->rz_szB);
+ VALGRIND_MAKE_MEM_DEFINED (b + get_bszB(b) - a->rz_szB - sizeof(SizeT),
+ a->rz_szB + sizeof(SizeT));
+}
+
+/* Mark block hdr as not accessible.
+ !!! Currently, we do not mark the cost center and szB fields unaccessible
+ as these are accessed at too many places. */
+static void mkBhdrNoAccess( Arena* a, Block* b )
+{
+ VALGRIND_MAKE_MEM_NOACCESS (b + hp_overhead_szB() + sizeof(SizeT),
+ a->rz_szB);
+ VALGRIND_MAKE_MEM_NOACCESS (b + get_bszB(b) - sizeof(SizeT) - a->rz_szB,
+ a->rz_szB);
+}
+
+/* Make the cc+szB fields accessible. */
+static void mkBhdrSzAccess( Arena* a, Block* b )
+{
+ VALGRIND_MAKE_MEM_DEFINED (b,
+ hp_overhead_szB() + sizeof(SizeT));
+ /* We cannot use get_bszB(b), as this reads the 'hi' szB we want
+ to mark accessible. So, we only access the 'lo' szB. */
+ SizeT bszB_lo = mk_plain_bszB(*(SizeT*)&b[0 + hp_overhead_szB()]);
+ VALGRIND_MAKE_MEM_DEFINED (b + bszB_lo - sizeof(SizeT),
+ sizeof(SizeT));
+}
+#endif
/*------------------------------------------------------------*/
/*--- Arena management ---*/
@@ -1130,11 +1168,7 @@
// to get_rz_hi_byte().
if (!a->clientmem && is_inuse_block(b)) {
// In the inner, for memcheck sake, temporarily mark redzone accessible.
- INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED
- (b + hp_overhead_szB() + sizeof(SizeT), a->rz_szB));
- INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED
- (b + get_bszB(b)
- - sizeof(SizeT) - a->rz_szB, a->rz_szB));
+ INNER_REQUEST(mkBhdrAccess(a,b));
for (i = 0; i < a->rz_szB; i++) {
if (get_rz_lo_byte(b, i) !=
(UByte)(((Addr)b&0xff) ^ REDZONE_LO_MASK))
@@ -1142,17 +1176,44 @@
if (get_rz_hi_byte(b, i) !=
(UByte)(((Addr)b&0xff) ^ REDZONE_HI_MASK))
{BLEAT("redzone-hi");return False;}
- }
- INNER_REQUEST(VALGRIND_MAKE_MEM_NOACCESS
- (b + hp_overhead_szB() + sizeof(SizeT), a->rz_szB));
- INNER_REQUEST(VALGRIND_MAKE_MEM_NOACCESS
- (b + get_bszB(b)
- - sizeof(SizeT) - a->rz_szB, a->rz_szB));
+ }
+ INNER_REQUEST(mkBhdrNoAccess(a,b));
}
return True;
# undef BLEAT
}
+// Sanity checks on a Block inside an unsplittable superblock
+static
+Bool unsplittableBlockSane ( Arena* a, Superblock *sb, Block* b )
+{
+# define BLEAT(str) VG_(printf)("unsplittableBlockSane: fail -- %s\n",str)
+ Block* other_b;
+ UByte* sb_start;
+ UByte* sb_end;
+
+ if (!blockSane (a, b))
+ {BLEAT("blockSane");return False;}
+
+ if (sb->unsplittable != sb)
+ {BLEAT("unsplittable");return False;}
+
+ sb_start = &sb->payload_bytes[0];
+ sb_end = &sb->payload_bytes[sb->n_payload_bytes - 1];
+
+ // b must be first block (i.e. no unused bytes at the beginning)
+ if ((Block*)sb_start != b)
+ {BLEAT("sb_start");return False;}
+
+ // b must be last block (i.e. no unused bytes at the end)
+ other_b = b + get_bszB(b);
+ if (other_b-1 != (Block*)sb_end)
+ {BLEAT("sb_end");return False;}
+
+ return True;
+# undef BLEAT
+}
+
// Print superblocks (only for debugging).
static
void ppSuperblocks ( Arena* a )
@@ -1248,7 +1309,7 @@
# ifdef VERBOSE_MALLOC
VG_(printf)( "sanity_check_malloc_arena: a->bytes_on_loan %lu, "
"arena_bytes_on_loan %lu: "
- "MISMATCH\n", a->bytes_on_loan, arena_bytes_on_loan);
+ "MISMATCH\n", a->stats__bytes_on_loan, arena_bytes_on_loan);
# endif
ppSuperblocks(a);
BOMB;
@@ -1378,12 +1439,15 @@
if (thisFree) continue;
+ if (VG_(clo_profile_heap))
+ cc = get_cc(b);
+ else
+ cc = "(--profile-heap=yes for details)";
if (0)
VG_(printf)("block: inUse=%d pszB=%d cc=%s\n",
(Int)(!thisFree),
(Int)bszB_to_pszB(a, b_bszB),
get_cc(b));
- cc = get_cc(b);
tl_assert(cc);
for (k = 0; k < n_ccs; k++) {
tl_assert(anCCs[k].cc);
@@ -1534,6 +1598,28 @@
# endif
}
+// Mark the bytes at b .. b+bszB-1 as being part of a block that has been shrunk.
+static
+void shrinkInuseBlock ( Arena* a, Block* b, SizeT bszB )
+{
+ UInt i;
+
+ vg_assert(bszB >= min_useful_bszB(a));
+ INNER_REQUEST(mkBhdrAccess(a,b));
+ set_bszB(b, mk_inuse_bszB(bszB));
+ if (!a->clientmem) {
+ for (i = 0; i < a->rz_szB; i++) {
+ set_rz_lo_byte(b, i, (UByte)(((Addr)b&0xff) ^ REDZONE_LO_MASK));
+ set_rz_hi_byte(b, i, (UByte)(((Addr)b&0xff) ^ REDZONE_HI_MASK));
+ }
+ }
+ INNER_REQUEST(mkBhdrNoAccess(a,b));
+
+# ifdef DEBUG_MALLOC
+ (void)blockSane(a,b);
+# endif
+}
+
// Remove a block from a given list. Does no sanity checking.
static
void unlinkBlock ( Arena* a, Block* b, UInt listno )
@@ -1857,15 +1943,89 @@
a->deferred_reclaimed_sb = sb;
}
-
-void VG_(arena_free) ( ArenaId aid, void* ptr )
+/* b must be a free block, of size b_bszB.
+ If b is followed by another free block, merge them.
+ If b is preceeded by another free block, merge them.
+ If the merge results in the superblock being fully free,
+ deferred_reclaimSuperblock the superblock. */
+static void mergeWithFreeNeighbours (Arena* a, Superblock* sb,
+ Block* b, SizeT b_bszB)
{
- Superblock* sb;
UByte* sb_start;
UByte* sb_end;
Block* other_b;
+ SizeT other_bszB;
+ UInt b_listno;
+
+ sb_start = &sb->payload_bytes[0];
+ sb_end = &sb->payload_bytes[sb->n_payload_bytes - 1];
+
+ b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
+
+ // See if this block can be merged with its successor.
+ // First test if we're far enough before the superblock's end to possibly
+ // have a successor.
+ other_b = b + b_bszB;
+ if (other_b+min_useful_bszB(a)-1 <= (Block*)sb_end) {
+ // Ok, we have a successor, merge if it's not in use.
+ other_bszB = get_bszB(other_b);
+ if (!is_inuse_block(other_b)) {
+ // VG_(printf)( "merge-successor\n");
+# ifdef DEBUG_MALLOC
+ vg_assert(blockSane(a, other_b));
+# endif
+ unlinkBlock( a, b, b_listno );
+ unlinkBlock( a, other_b,
+ pszB_to_listNo(bszB_to_pszB(a,other_bszB)) );
+ b_bszB += other_bszB;
+ b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
+ mkFreeBlock( a, b, b_bszB, b_listno );
+ if (VG_(clo_profile_heap))
+ set_cc(b, "admin.free-2");
+ }
+ } else {
+ // Not enough space for successor: check that b is the last block
+ // ie. there are no unused bytes at the end of the Superblock.
+ vg_assert(other_b-1 == (Block*)sb_end);
+ }
+
+ // Then see if this block can be merged with its predecessor.
+ // First test if we're far enough after the superblock's start to possibly
+ // have a predecessor.
+ if (b >= (Block*)sb_start + min_useful_bszB(a)) {
+ // Ok, we have a predecessor, merge if it's not in use.
+ other_b = get_predecessor_block( b );
+ other_bszB = get_bszB(other_b);
+ if (!is_inuse_block(other_b)) {
+ // VG_(printf)( "merge-predecessor\n");
+ unlinkBlock( a, b, b_listno );
+ unlinkBlock( a, other_b,
+ pszB_to_listNo(bszB_to_pszB(a, other_bszB)) );
+ b = other_b;
+ b_bszB += other_bszB;
+ b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
+ mkFreeBlock( a, b, b_bszB, b_listno );
+ if (VG_(clo_profile_heap))
+ set_cc(b, "admin.free-3");
+ }
+ } else {
+ // Not enough space for predecessor: check that b is the first block,
+ // ie. there are no unused bytes at the start of the Superblock.
+ vg_assert((Block*)sb_start == b);
+ }
+
+ /* If the block b just merged is the only block of the superblock sb,
+ then we defer reclaim sb. */
+ if ( ((Block*)sb_start == b) && (b + b_bszB-1 == (Block*)sb_end) ) {
+ deferred_reclaimSuperblock (a, sb);
+ }
+}
+
+void VG_(arena_free) ( ArenaId aid, void* ptr )
+{
+ Superblock* sb;
Block* b;
- SizeT b_bszB, b_pszB, other_bszB;
+ SizeT b_bszB, b_pszB;
UInt b_listno;
Arena* a;
@@ -1886,8 +2046,6 @@
b_bszB = get_bszB(b);
b_pszB = bszB_to_pszB(a, b_bszB);
sb = findSb( a, b );
- sb_start = &sb->payload_bytes[0];
- sb_end = &sb->payload_bytes[sb->n_payload_bytes - 1];
a->stats__bytes_on_loan -= b_pszB;
@@ -1907,63 +2065,8 @@
if (VG_(clo_profile_heap))
set_cc(b, "admin.free-1");
- // See if this block can be merged with its successor.
- // First test if we're far enough before the superblock's end to possibly
- // have a successor.
- other_b = b + b_bszB;
- if (other_b+min_useful_bszB(a)-1 <= (Block*)sb_end) {
- // Ok, we have a successor, merge if it's not in use.
- other_bszB = get_bszB(other_b);
- if (!is_inuse_block(other_b)) {
- // VG_(printf)( "merge-successor\n");
-# ifdef DEBUG_MALLOC
- vg_assert(blockSane(a, other_b));
-# endif
- unlinkBlock( a, b, b_listno );
- unlinkBlock( a, other_b,
- pszB_to_listNo(bszB_to_pszB(a,other_bszB)) );
- b_bszB += other_bszB;
- b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
- mkFreeBlock( a, b, b_bszB, b_listno );
- if (VG_(clo_profile_heap))
- set_cc(b, "admin.free-2");
- }
- } else {
- // Not enough space for successor: check that b is the last block
- // ie. there are no unused bytes at the end of the Superblock.
- vg_assert(other_b-1 == (Block*)sb_end);
- }
-
- // Then see if this block can be merged with its predecessor.
- // First test if we're far enough after the superblock's start to possibly
- // have a predecessor.
- if (b >= (Block*)sb_start + min_useful_bszB(a)) {
- // Ok, we have a predecessor, merge if it's not in use.
- other_b = get_predecessor_block( b );
- other_bszB = get_bszB(other_b);
- if (!is_inuse_block(other_b)) {
- // VG_(printf)( "merge-predecessor\n");
- unlinkBlock( a, b, b_listno );
- unlinkBlock( a, other_b,
- pszB_to_listNo(bszB_to_pszB(a, other_bszB)) );
- b = other_b;
- b_bszB += other_bszB;
- b_listno = pszB_to_listNo(bszB_to_pszB(a, b_bszB));
- mkFreeBlock( a, b, b_bszB, b_listno );
- if (VG_(clo_profile_heap))
- set_cc(b, "admin.free-3");
- }
- } else {
- // Not enough space for predecessor: check that b is the first block,
- // ie. there are no unused bytes at the start of the Superblock.
- vg_assert((Block*)sb_start == b);
- }
-
- /* If the block b just merged is the only block of the superblock sb,
- then we defer reclaim sb. */
- if ( ((Block*)sb_start == b) && (b + b_bszB-1 == (Block*)sb_end) ) {
- deferred_reclaimSuperblock (a, sb);
- }
+ /* Possibly merge b with its predecessor or successor. */
+ mergeWithFreeNeighbours (a, sb, b, b_bszB);
// Inform that ptr has been released. We give redzone size
// 0 instead of a->rz_szB as proper accessibility is done just after.
@@ -1991,12 +2094,7 @@
- sizeof(SizeT) - sizeof(void*),
sizeof(SizeT) + sizeof(void*)));
} else {
- // b must be first block (i.e. no unused bytes at the beginning)
- vg_assert((Block*)sb_start == b);
-
- // b must be last block (i.e. no unused bytes at the end)
- other_b = b + b_bszB;
- vg_assert(other_b-1 == (Block*)sb_end);
+ vg_assert(unsplittableBlockSane(a, sb, b));
// Inform that ptr has been released. Redzone size value
// is not relevant (so we give 0 instead of a->rz_szB)
@@ -2310,6 +2408,113 @@
}
+void VG_(arena_realloc_shrink) ( ArenaId aid,
+ void* ptr, SizeT req_pszB )
+{
+ SizeT req_bszB, frag_bszB, b_bszB;
+ Superblock* sb;
+ Arena* a;
+ SizeT old_pszB;
+ Block* b;
+
+ ensure_mm_init(aid);
+
+ a = arenaId_to_ArenaP(aid);
+ b = get_payload_block(a, ptr);
+ vg_assert(blockSane(a, b));
+ vg_assert(is_inuse_block(b));
+
+ old_pszB = get_pszB(a, b);
+ req_pszB = align_req_pszB(req_pszB);
+ vg_assert(old_pszB >= req_pszB);
+ if (old_pszB == req_pszB)
+ return;
+
+ sb = findSb( a, b );
+ if (sb->unsplittable) {
+ const UByte* sb_start = &sb->payload_bytes[0];
+ const UByte* sb_end = &sb->payload_bytes[sb->n_payload_bytes - 1];
+ Addr frag;
+
+ vg_assert(unsplittableBlockSane(a, sb, b));
+
+ frag = VG_PGROUNDUP((Addr) sb
+ + sizeof(Superblock) + pszB_to_bszB(a, req_pszB));
+ frag_bszB = (Addr)sb_end - frag + 1;
+
+ if (frag_bszB >= VKI_PAGE_SIZE) {
+ SysRes sres;
+
+ a->stats__bytes_on_loan -= old_pszB;
+ b_bszB = (UByte*)frag - sb_start;
+ shrinkInuseBlock(a, b, b_bszB);
+ INNER_REQUEST
+ (VALGRIND_RESIZEINPLACE_BLOCK(ptr,
+ old_pszB,
+ VG_(arena_malloc_usable_size)(aid, ptr),
+ a->rz_szB));
+ /* Have the minimum admin headers needed accessibility. */
+ INNER_REQUEST(mkBhdrSzAccess(a, b));
+ a->stats__bytes_on_loan += bszB_to_pszB(a, b_bszB);
+
+ sb->n_payload_bytes -= frag_bszB;
+ VG_(debugLog)(1, "mallocfree",
+ "shrink superblock %p to (pszB %7ld) "
+ "owner %s/%s (munmap-ing %p %7ld)\n",
+ sb, sb->n_payload_bytes,
+ a->clientmem ? "CLIENT" : "VALGRIND", a->name,
+ (void*) frag, frag_bszB);
+ if (a->clientmem) {
+ Bool need_discard = False;
+ sres = VG_(am_munmap_client)(&need_discard,
+ frag,
+ frag_bszB);
+ vg_assert (!need_discard);
+ } else {
+ sres = VG_(am_munmap_valgrind)(frag,
+ frag_bszB);
+ }
+ vg_assert2(! sr_isError(sres), "shrink superblock munmap failure\n");
+ a->stats__bytes_mmaped -= frag_bszB;
+
+ vg_assert(unsplittableBlockSane(a, sb, b));
+ }
+ } else {
+ req_bszB = pszB_to_bszB(a, req_pszB);
+ b_bszB = get_bszB(b);
+ frag_bszB = b_bszB - req_bszB;
+ if (frag_bszB < min_useful_bszB(a))
+ return;
+
+ a->stats__bytes_on_loan -= old_pszB;
+ shrinkInuseBlock(a, b, req_bszB);
+ INNER_REQUEST
+ (VALGRIND_RESIZEINPLACE_BLOCK(ptr,
+ old_pszB,
+ VG_(arena_malloc_usable_size)(aid, ptr),
+ a->rz_szB));
+ /* Have the minimum admin headers needed accessibility. */
+ INNER_REQUEST(mkBhdrSzAccess(a, b));
+
+ mkFreeBlock(a, &b[req_bszB], frag_bszB,
+ pszB_to_listNo(bszB_to_pszB(a, frag_bszB)));
+ /* Mark the admin headers as accessible. */
+ INNER_REQUEST(mkBhdrAccess(a, &b[req_bszB]));
+ if (VG_(clo_profile_heap))
+ set_cc(&b[req_bszB], "admin.fragmentation-2");
+ /* Possibly merge &b[req_bszB] with its free neighbours. */
+ mergeWithFreeNeighbours(a, sb, &b[req_bszB], frag_bszB);
+
+ b_bszB = get_bszB(b);
+ a->stats__bytes_on_loan += bszB_to_pszB(a, b_bszB);
+ }
+
+ vg_assert (blockSane(a, b));
+# ifdef DEBUG_MALLOC
+ sanity_check_malloc_arena(aid);
+# endif
+}
+
/* Inline just for the wrapper VG_(strdup) below */
__inline__ HChar* VG_(arena_strdup) ( ArenaId aid, const HChar* cc,
const HChar* s )
Modified: trunk/coregrind/pub_core_mallocfree.h
==============================================================================
--- trunk/coregrind/pub_core_mallocfree.h (original)
+++ trunk/coregrind/pub_core_mallocfree.h Mon Jun 30 19:47:24 2014
@@ -110,6 +110,16 @@
extern HChar* VG_(arena_strdup) ( ArenaId aid, const HChar* cc,
const HChar* s);
+/* Specialised version of realloc, that shrinks the size of the block ptr from
+ its current size to req_pszB.
+ req_pszB must be <= to the current size of ptr (otherwise it will assert).
+ Compared to VG_(arena_realloc):
+ * VG_(arena_realloc_shrink) cannot increase the size of ptr.
+ * If large enough, the unused memory is made usable for other allocation.
+ * ptr is shrunk in place, so as to avoid temporary allocation and memcpy. */
+extern void VG_(arena_realloc_shrink) ( ArenaId aid,
+ void* ptr, SizeT req_pszB);
+
extern SizeT VG_(arena_malloc_usable_size) ( ArenaId aid, void* payload );
extern SizeT VG_(arena_redzone_size) ( ArenaId aid );
Modified: trunk/include/pub_tool_deduppoolalloc.h
==============================================================================
--- trunk/include/pub_tool_deduppoolalloc.h (original)
+++ trunk/include/pub_tool_deduppoolalloc.h Mon Jun 30 19:47:24 2014
@@ -63,10 +63,10 @@
eltAlign is the minimum required alignement for the elements allocated
from the DedupPoolAlloc. */
extern DedupPoolAlloc* VG_(newDedupPA) ( SizeT poolSzB,
- SizeT eltAlign,
- void* (*alloc)(const HChar*, SizeT),
- const HChar* cc,
- void (*free_fn)(void*) );
+ SizeT eltAlign,
+ void* (*alloc)(const HChar*, SizeT),
+ const HChar* cc,
+ void (*free_fn)(void*) );
/* Allocates a new element from ddpa with eltSzB bytes to store elt. */
extern void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa,
@@ -77,8 +77,11 @@
duplicates as long as new elements can be allocated from the pool.
Once no new elements will be allocated, this dedup data structure
can be released using VG_(freezeDedupPA). Once ddpa has been frozen,
- it is an error to call VG_(allocEltDedupPA). */
-extern void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa);
+ it is an error to call VG_(allocEltDedupPA).
+ If shrink_block is not NULL, the last pool will be shrunk using
+ shrink_block. */
+extern void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa,
+ void (*shrink_block)(void*, SizeT));
/* Free all memory associated with a DedupPoolAlloc. */
extern void VG_(deleteDedupPA) ( DedupPoolAlloc *ddpa);
|
|
From: <sv...@va...> - 2014-06-30 07:35:28
|
Author: sewardj
Date: Mon Jun 30 07:35:19 2014
New Revision: 14121
Log:
arm64:
Add support for checking FPSR.QC effects of each instruction.
Implement: sadalp uadalp saddlp uaddlp saddlv uaddlv saddw{2} uaddw{2}
ssubw{2} usubw{2} shadd uhadd shsub uhsub sqadd uqadd sqsub uqsub
smaxp umaxp sminp uminp
Modified:
trunk/none/tests/arm64/fp_and_simd.c
Modified: trunk/none/tests/arm64/fp_and_simd.c
==============================================================================
--- trunk/none/tests/arm64/fp_and_simd.c (original)
+++ trunk/none/tests/arm64/fp_and_simd.c Mon Jun 30 07:35:19 2014
@@ -100,20 +100,23 @@
static void test_##INSN##_##SUFFIXD##_##SUFFIXN ( LaneTy ty ) { \
Int i; \
for (i = 0; i < ITERS; i++) { \
- V128 block[2]; \
+ V128 block[2+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q7, [%0, #0] ; " \
"ldr q8, [%0, #16] ; " \
#INSN " v8." #SUFFIXD ", v7." #SUFFIXN " ; " \
- "str q8, [%0, #16] " \
- : : "r"(&block[0]) : "memory", "v7", "v8" \
+ "str q8, [%0, #16] ; " \
+ "mrs x30, fpsr ; str x30, [%0, #32] " \
+ : : "r"(&block[0]) : "memory", "v7", "v8", "x30" \
); \
printf(#INSN " v8." #SUFFIXD ", v7." #SUFFIXN); \
+ UInt fpsr = 0xFFFFFF60 & block[2].u32[0]; \
showV128(&block[0]); printf(" "); \
- showV128(&block[1]); printf("\n"); \
+ showV128(&block[1]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -125,24 +128,27 @@
static void test_##INSN##_##SUFFIXD##_##SUFFIXN##_##SUFFIXM ( LaneTy ty ) { \
Int i; \
for (i = 0; i < ITERS; i++) { \
- V128 block[3]; \
+ V128 block[3+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
randV128(&block[2], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q7, [%0, #0] ; " \
"ldr q8, [%0, #16] ; " \
"ldr q9, [%0, #32] ; " \
#INSN " v9." #SUFFIXD ", v7." #SUFFIXN ", v8." #SUFFIXM " ; " \
- "str q9, [%0, #32] " \
- : : "r"(&block[0]) : "memory", "v7", "v8", "v9" \
+ "str q9, [%0, #32] ; " \
+ "mrs x30, fpsr ; str x30, [%0, #48] " \
+ : : "r"(&block[0]) : "memory", "v7", "v8", "v9", "x30" \
); \
printf(#INSN " v9." #SUFFIXD \
", v7." #SUFFIXN ", v8." #SUFFIXM " "); \
+ UInt fpsr = 0xFFFFFF60 & block[3].u32[0]; \
showV128(&block[0]); printf(" "); \
showV128(&block[1]); printf(" "); \
- showV128(&block[2]); printf("\n"); \
+ showV128(&block[2]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -154,20 +160,23 @@
static void test_##INSN##_##SUFFIXD##_##SUFFIXN##_##AMOUNT ( LaneTy ty ) { \
Int i; \
for (i = 0; i < ITERS; i++) { \
- V128 block[2]; \
+ V128 block[2+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q7, [%0, #0] ; " \
"ldr q8, [%0, #16] ; " \
#INSN " v8." #SUFFIXD ", v7." #SUFFIXN ", #" #AMOUNT " ; " \
- "str q8, [%0, #16] " \
- : : "r"(&block[0]) : "memory", "v7", "v8" \
+ "str q8, [%0, #16] ; " \
+ "mrs x30, fpsr ; str x30, [%0, #32] " \
+ : : "r"(&block[0]) : "memory", "v7", "v8", "x30" \
); \
printf(#INSN " v8." #SUFFIXD ", v7." #SUFFIXN ", #" #AMOUNT " "); \
+ UInt fpsr = 0xFFFFFF60 & block[2].u32[0]; \
showV128(&block[0]); printf(" "); \
- showV128(&block[1]); printf("\n"); \
+ showV128(&block[1]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -178,26 +187,30 @@
__attribute__((noinline)) \
static void test_##TESTNAME ( LaneTy ty ) { \
Int i; \
+ assert(INTREGNO != 30); \
for (i = 0; i < ITERS; i++) { \
- V128 block[4]; \
+ V128 block[4+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
randV128(&block[2], ty); \
randV128(&block[3], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q"#VECREGNO", [%0, #0] ; " \
"ldr x"#INTREGNO", [%0, #16] ; " \
INSN " ; " \
"str q"#VECREGNO", [%0, #32] ; " \
"str x"#INTREGNO", [%0, #48] ; " \
- : : "r"(&block[0]) : "memory", "v"#VECREGNO, "x"#INTREGNO \
+ "mrs x30, fpsr ; str x30, [%0, #64] " \
+ : : "r"(&block[0]) : "memory", "v"#VECREGNO, "x"#INTREGNO, "x30" \
); \
printf(INSN " "); \
+ UInt fpsr = 0xFFFFFF60 & block[4].u32[0]; \
showV128(&block[0]); printf(" "); \
showV128(&block[1]); printf(" "); \
showV128(&block[2]); printf(" "); \
- showV128(&block[3]); printf("\n"); \
+ showV128(&block[3]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -210,26 +223,29 @@
static void test_##TESTNAME ( LaneTy ty ) { \
Int i; \
for (i = 0; i < ITERS; i++) { \
- V128 block[4]; \
+ V128 block[4+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
randV128(&block[2], ty); \
randV128(&block[3], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q"#VECREG1NO", [%0, #0] ; " \
"ldr q"#VECREG2NO", [%0, #16] ; " \
INSN " ; " \
"str q"#VECREG1NO", [%0, #32] ; " \
"str q"#VECREG2NO", [%0, #48] ; " \
+ "mrs x30, fpsr ; str x30, [%0, #64] " \
: : "r"(&block[0]) \
- : "memory", "v"#VECREG1NO, "v"#VECREG2NO, "x10" \
+ : "memory", "v"#VECREG1NO, "v"#VECREG2NO, "x10", "x30" \
); \
printf(INSN " "); \
+ UInt fpsr = 0xFFFFFF60 & block[4].u32[0]; \
showV128(&block[0]); printf(" "); \
showV128(&block[1]); printf(" "); \
showV128(&block[2]); printf(" "); \
- showV128(&block[3]); printf("\n"); \
+ showV128(&block[3]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -242,7 +258,7 @@
static void test_##TESTNAME ( LaneTy ty ) { \
Int i; \
for (i = 0; i < ITERS; i++) { \
- V128 block[6]; \
+ V128 block[6+1]; \
memset(block, 0x55, sizeof(block)); \
randV128(&block[0], ty); \
randV128(&block[1], ty); \
@@ -251,6 +267,7 @@
randV128(&block[4], ty); \
randV128(&block[5], ty); \
__asm__ __volatile__( \
+ "mov x30, #0 ; msr fpsr, x30 ; " \
"ldr q"#VECREG1NO", [%0, #0] ; " \
"ldr q"#VECREG2NO", [%0, #16] ; " \
"ldr q"#VECREG3NO", [%0, #32] ; " \
@@ -258,17 +275,19 @@
"str q"#VECREG1NO", [%0, #48] ; " \
"str q"#VECREG2NO", [%0, #64] ; " \
"str q"#VECREG3NO", [%0, #80] ; " \
+ "mrs x30, fpsr ; str x30, [%0, #96] " \
: : "r"(&block[0]) \
: "memory", "v"#VECREG1NO, "v"#VECREG2NO, "v"#VECREG3NO, \
- "v16", "v17", "v18" \
+ "v16", "v17", "v18", "x30" \
); \
printf(INSN " "); \
+ UInt fpsr = 0xFFFFFF60 & block[6].u32[0]; \
showV128(&block[0]); printf(" "); \
showV128(&block[1]); printf(" "); \
showV128(&block[2]); printf(" "); \
showV128(&block[3]); printf(" "); \
showV128(&block[4]); printf(" "); \
- showV128(&block[5]); printf("\n"); \
+ showV128(&block[5]); printf(" fpsr=%08x\n", fpsr); \
} \
}
@@ -3847,18 +3866,18 @@
// sadalp 4h_8b,8h_16b,2s_4h,4s_8h,1d_2s,2d_4s
// uadalp 4h_8b,8h_16b,2s_4h,4s_8h,1d_2s,2d_4s
- if (0) test_sadalp_1d_2s(TyS);
- if (0) test_sadalp_2d_4s(TyS);
- if (0) test_sadalp_2s_4h(TyH);
- if (0) test_sadalp_4s_8h(TyH);
- if (0) test_sadalp_4h_8b(TyB);
- if (0) test_sadalp_8h_16b(TyB);
- if (0) test_uadalp_1d_2s(TyS);
- if (0) test_uadalp_2d_4s(TyS);
- if (0) test_uadalp_2s_4h(TyH);
- if (0) test_uadalp_4s_8h(TyH);
- if (0) test_uadalp_4h_8b(TyB);
- if (0) test_uadalp_8h_16b(TyB);
+ if (1) test_sadalp_1d_2s(TyS);
+ if (1) test_sadalp_2d_4s(TyS);
+ if (1) test_sadalp_2s_4h(TyH);
+ if (1) test_sadalp_4s_8h(TyH);
+ if (1) test_sadalp_4h_8b(TyB);
+ if (1) test_sadalp_8h_16b(TyB);
+ if (1) test_uadalp_1d_2s(TyS);
+ if (1) test_uadalp_2d_4s(TyS);
+ if (1) test_uadalp_2s_4h(TyH);
+ if (1) test_uadalp_4s_8h(TyH);
+ if (1) test_uadalp_4h_8b(TyB);
+ if (1) test_uadalp_8h_16b(TyB);
// saddl{2} 2d_(2s_2s)/(4s_4s), 4s_(4h_4h)/(8h_8h), 8h_(8b_8b)/(16b_16b)
// uaddl{2} 2d_(2s_2s)/(4s_4s), 4s_(4h_4h)/(8h_8h), 8h_(8b_8b)/(16b_16b)
@@ -3891,89 +3910,89 @@
// saddlp 4h_8b,8h_16b,2s_4h,4s_8h,1d_2s,2d_4s
// uaddlp 4h_8b,8h_16b,2s_4h,4s_8h,1d_2s,2d_4s
- if (0) test_saddlp_1d_2s(TyS);
- if (0) test_saddlp_2d_4s(TyS);
- if (0) test_saddlp_2s_4h(TyH);
- if (0) test_saddlp_4s_8h(TyH);
- if (0) test_saddlp_4h_8b(TyB);
- if (0) test_saddlp_8h_16b(TyB);
- if (0) test_uaddlp_1d_2s(TyS);
- if (0) test_uaddlp_2d_4s(TyS);
- if (0) test_uaddlp_2s_4h(TyH);
- if (0) test_uaddlp_4s_8h(TyH);
- if (0) test_uaddlp_4h_8b(TyB);
- if (0) test_uaddlp_8h_16b(TyB);
+ if (1) test_saddlp_1d_2s(TyS);
+ if (1) test_saddlp_2d_4s(TyS);
+ if (1) test_saddlp_2s_4h(TyH);
+ if (1) test_saddlp_4s_8h(TyH);
+ if (1) test_saddlp_4h_8b(TyB);
+ if (1) test_saddlp_8h_16b(TyB);
+ if (1) test_uaddlp_1d_2s(TyS);
+ if (1) test_uaddlp_2d_4s(TyS);
+ if (1) test_uaddlp_2s_4h(TyH);
+ if (1) test_uaddlp_4s_8h(TyH);
+ if (1) test_uaddlp_4h_8b(TyB);
+ if (1) test_uaddlp_8h_16b(TyB);
// saddlv h_16b/8b, s_8h/4h, d_4s
// uaddlv h_16b/8b, s_8h/4h, d_4s
- if (0) test_saddlv_h_16b(TyB);
- if (0) test_saddlv_h_8b(TyB);
- if (0) test_saddlv_s_8h(TyH);
- if (0) test_saddlv_s_4h(TyH);
- if (0) test_saddlv_d_4s(TyH);
- if (0) test_uaddlv_h_16b(TyB);
- if (0) test_uaddlv_h_8b(TyB);
- if (0) test_uaddlv_s_8h(TyH);
- if (0) test_uaddlv_s_4h(TyH);
- if (0) test_uaddlv_d_4s(TyH);
+ if (1) test_saddlv_h_16b(TyB);
+ if (1) test_saddlv_h_8b(TyB);
+ if (1) test_saddlv_s_8h(TyH);
+ if (1) test_saddlv_s_4h(TyH);
+ if (1) test_saddlv_d_4s(TyH);
+ if (1) test_uaddlv_h_16b(TyB);
+ if (1) test_uaddlv_h_8b(TyB);
+ if (1) test_uaddlv_s_8h(TyH);
+ if (1) test_uaddlv_s_4h(TyH);
+ if (1) test_uaddlv_d_4s(TyH);
// saddw{2} 8h_8h_16b/8b, 4s_4s_8h/4h, 2d_2d_4s/2s
// uaddw{2} 8h_8h_16b/8b, 4s_4s_8h/4h, 2d_2d_4s/2s
// ssubw{2} 8h_8h_16b/8b, 4s_4s_8h/4h, 2d_2d_4s/2s
// usubw{2} 8h_8h_16b/8b, 4s_4s_8h/4h, 2d_2d_4s/2s
- if (0) test_saddw2_8h_8h_16b(TyB);
- if (0) test_saddw_8h_8h_8b(TyB);
- if (0) test_saddw2_4s_4s_8h(TyH);
- if (0) test_saddw_4s_4s_4h(TyH);
- if (0) test_saddw2_2d_2d_4s(TyS);
- if (0) test_saddw_2d_2d_2s(TyS);
- if (0) test_uaddw2_8h_8h_16b(TyB);
- if (0) test_uaddw_8h_8h_8b(TyB);
- if (0) test_uaddw2_4s_4s_8h(TyH);
- if (0) test_uaddw_4s_4s_4h(TyH);
- if (0) test_uaddw2_2d_2d_4s(TyS);
- if (0) test_uaddw_2d_2d_2s(TyS);
- if (0) test_ssubw2_8h_8h_16b(TyB);
- if (0) test_ssubw_8h_8h_8b(TyB);
- if (0) test_ssubw2_4s_4s_8h(TyH);
- if (0) test_ssubw_4s_4s_4h(TyH);
- if (0) test_ssubw2_2d_2d_4s(TyS);
- if (0) test_ssubw_2d_2d_2s(TyS);
- if (0) test_usubw2_8h_8h_16b(TyB);
- if (0) test_usubw_8h_8h_8b(TyB);
- if (0) test_usubw2_4s_4s_8h(TyH);
- if (0) test_usubw_4s_4s_4h(TyH);
- if (0) test_usubw2_2d_2d_4s(TyS);
- if (0) test_usubw_2d_2d_2s(TyS);
+ if (1) test_saddw2_8h_8h_16b(TyB);
+ if (1) test_saddw_8h_8h_8b(TyB);
+ if (1) test_saddw2_4s_4s_8h(TyH);
+ if (1) test_saddw_4s_4s_4h(TyH);
+ if (1) test_saddw2_2d_2d_4s(TyS);
+ if (1) test_saddw_2d_2d_2s(TyS);
+ if (1) test_uaddw2_8h_8h_16b(TyB);
+ if (1) test_uaddw_8h_8h_8b(TyB);
+ if (1) test_uaddw2_4s_4s_8h(TyH);
+ if (1) test_uaddw_4s_4s_4h(TyH);
+ if (1) test_uaddw2_2d_2d_4s(TyS);
+ if (1) test_uaddw_2d_2d_2s(TyS);
+ if (1) test_ssubw2_8h_8h_16b(TyB);
+ if (1) test_ssubw_8h_8h_8b(TyB);
+ if (1) test_ssubw2_4s_4s_8h(TyH);
+ if (1) test_ssubw_4s_4s_4h(TyH);
+ if (1) test_ssubw2_2d_2d_4s(TyS);
+ if (1) test_ssubw_2d_2d_2s(TyS);
+ if (1) test_usubw2_8h_8h_16b(TyB);
+ if (1) test_usubw_8h_8h_8b(TyB);
+ if (1) test_usubw2_4s_4s_8h(TyH);
+ if (1) test_usubw_4s_4s_4h(TyH);
+ if (1) test_usubw2_2d_2d_4s(TyS);
+ if (1) test_usubw_2d_2d_2s(TyS);
// shadd 16b,8b,8h,4h,4s,2s
// uhadd 16b,8b,8h,4h,4s,2s
// shsub 16b,8b,8h,4h,4s,2s
// uhsub 16b,8b,8h,4h,4s,2s
- if (0) test_shadd_4s_4s_4s(TyS);
- if (0) test_shadd_2s_2s_2s(TyS);
- if (0) test_shadd_8h_8h_8h(TyH);
- if (0) test_shadd_4h_4h_4h(TyH);
- if (0) test_shadd_16b_16b_16b(TyB);
- if (0) test_shadd_8b_8b_8b(TyB);
- if (0) test_uhadd_4s_4s_4s(TyS);
- if (0) test_uhadd_2s_2s_2s(TyS);
- if (0) test_uhadd_8h_8h_8h(TyH);
- if (0) test_uhadd_4h_4h_4h(TyH);
- if (0) test_uhadd_16b_16b_16b(TyB);
- if (0) test_uhadd_8b_8b_8b(TyB);
- if (0) test_shsub_4s_4s_4s(TyS);
- if (0) test_shsub_2s_2s_2s(TyS);
- if (0) test_shsub_8h_8h_8h(TyH);
- if (0) test_shsub_4h_4h_4h(TyH);
- if (0) test_shsub_16b_16b_16b(TyB);
- if (0) test_shsub_8b_8b_8b(TyB);
- if (0) test_uhsub_4s_4s_4s(TyS);
- if (0) test_uhsub_2s_2s_2s(TyS);
- if (0) test_uhsub_8h_8h_8h(TyH);
- if (0) test_uhsub_4h_4h_4h(TyH);
- if (0) test_uhsub_16b_16b_16b(TyB);
- if (0) test_uhsub_8b_8b_8b(TyB);
+ if (1) test_shadd_4s_4s_4s(TyS);
+ if (1) test_shadd_2s_2s_2s(TyS);
+ if (1) test_shadd_8h_8h_8h(TyH);
+ if (1) test_shadd_4h_4h_4h(TyH);
+ if (1) test_shadd_16b_16b_16b(TyB);
+ if (1) test_shadd_8b_8b_8b(TyB);
+ if (1) test_uhadd_4s_4s_4s(TyS);
+ if (1) test_uhadd_2s_2s_2s(TyS);
+ if (1) test_uhadd_8h_8h_8h(TyH);
+ if (1) test_uhadd_4h_4h_4h(TyH);
+ if (1) test_uhadd_16b_16b_16b(TyB);
+ if (1) test_uhadd_8b_8b_8b(TyB);
+ if (1) test_shsub_4s_4s_4s(TyS);
+ if (1) test_shsub_2s_2s_2s(TyS);
+ if (1) test_shsub_8h_8h_8h(TyH);
+ if (1) test_shsub_4h_4h_4h(TyH);
+ if (1) test_shsub_16b_16b_16b(TyB);
+ if (1) test_shsub_8b_8b_8b(TyB);
+ if (1) test_uhsub_4s_4s_4s(TyS);
+ if (1) test_uhsub_2s_2s_2s(TyS);
+ if (1) test_uhsub_8h_8h_8h(TyH);
+ if (1) test_uhsub_4h_4h_4h(TyH);
+ if (1) test_uhsub_16b_16b_16b(TyB);
+ if (1) test_uhsub_8b_8b_8b(TyB);
// shll{2} 8h_8b/16b_#8, 4s_4h/8h_#16, 2d_2s/4s_#32
if (0) test_shll_8h_8b_8(TyB);
@@ -4097,30 +4116,30 @@
// umaxp 4s,2s,8h,4h,16b,8b
// sminp 4s,2s,8h,4h,16b,8b
// uminp 4s,2s,8h,4h,16b,8b
- if (0) test_smaxp_4s_4s_4s(TyS);
- if (0) test_smaxp_2s_2s_2s(TyS);
- if (0) test_smaxp_8h_8h_8h(TyH);
- if (0) test_smaxp_4h_4h_4h(TyH);
- if (0) test_smaxp_16b_16b_16b(TyB);
- if (0) test_smaxp_8b_8b_8b(TyB);
- if (0) test_umaxp_4s_4s_4s(TyS);
- if (0) test_umaxp_2s_2s_2s(TyS);
- if (0) test_umaxp_8h_8h_8h(TyH);
- if (0) test_umaxp_4h_4h_4h(TyH);
- if (0) test_umaxp_16b_16b_16b(TyB);
- if (0) test_umaxp_8b_8b_8b(TyB);
- if (0) test_sminp_4s_4s_4s(TyS);
- if (0) test_sminp_2s_2s_2s(TyS);
- if (0) test_sminp_8h_8h_8h(TyH);
- if (0) test_sminp_4h_4h_4h(TyH);
- if (0) test_sminp_16b_16b_16b(TyB);
- if (0) test_sminp_8b_8b_8b(TyB);
- if (0) test_uminp_4s_4s_4s(TyS);
- if (0) test_uminp_2s_2s_2s(TyS);
- if (0) test_uminp_8h_8h_8h(TyH);
- if (0) test_uminp_4h_4h_4h(TyH);
- if (0) test_uminp_16b_16b_16b(TyB);
- if (0) test_uminp_8b_8b_8b(TyB);
+ if (1) test_smaxp_4s_4s_4s(TyS);
+ if (1) test_smaxp_2s_2s_2s(TyS);
+ if (1) test_smaxp_8h_8h_8h(TyH);
+ if (1) test_smaxp_4h_4h_4h(TyH);
+ if (1) test_smaxp_16b_16b_16b(TyB);
+ if (1) test_smaxp_8b_8b_8b(TyB);
+ if (1) test_umaxp_4s_4s_4s(TyS);
+ if (1) test_umaxp_2s_2s_2s(TyS);
+ if (1) test_umaxp_8h_8h_8h(TyH);
+ if (1) test_umaxp_4h_4h_4h(TyH);
+ if (1) test_umaxp_16b_16b_16b(TyB);
+ if (1) test_umaxp_8b_8b_8b(TyB);
+ if (1) test_sminp_4s_4s_4s(TyS);
+ if (1) test_sminp_2s_2s_2s(TyS);
+ if (1) test_sminp_8h_8h_8h(TyH);
+ if (1) test_sminp_4h_4h_4h(TyH);
+ if (1) test_sminp_16b_16b_16b(TyB);
+ if (1) test_sminp_8b_8b_8b(TyB);
+ if (1) test_uminp_4s_4s_4s(TyS);
+ if (1) test_uminp_2s_2s_2s(TyS);
+ if (1) test_uminp_8h_8h_8h(TyH);
+ if (1) test_uminp_4h_4h_4h(TyH);
+ if (1) test_uminp_16b_16b_16b(TyB);
+ if (1) test_uminp_8b_8b_8b(TyB);
// smaxv s_4s,h_8h,h_4h,b_16b,b_8b
// umaxv s_4s,h_8h,h_4h,b_16b,b_8b
@@ -4303,34 +4322,34 @@
// uqadd 2d,4s,2s,8h,4h,16b,8b
// sqsub 2d,4s,2s,8h,4h,16b,8b
// uqsub 2d,4s,2s,8h,4h,16b,8b
- if (0) test_sqadd_2d_2d_2d(TyD);
- if (0) test_sqadd_4s_4s_4s(TyS);
- if (0) test_sqadd_2s_2s_2s(TyS);
- if (0) test_sqadd_8h_8h_8h(TyH);
- if (0) test_sqadd_4h_4h_4h(TyH);
- if (0) test_sqadd_16b_16b_16b(TyB);
- if (0) test_sqadd_8b_8b_8b(TyB);
- if (0) test_uqadd_2d_2d_2d(TyD);
- if (0) test_uqadd_4s_4s_4s(TyS);
- if (0) test_uqadd_2s_2s_2s(TyS);
- if (0) test_uqadd_8h_8h_8h(TyH);
- if (0) test_uqadd_4h_4h_4h(TyH);
- if (0) test_uqadd_16b_16b_16b(TyB);
- if (0) test_uqadd_8b_8b_8b(TyB);
- if (0) test_sqsub_2d_2d_2d(TyD);
- if (0) test_sqsub_4s_4s_4s(TyS);
- if (0) test_sqsub_2s_2s_2s(TyS);
- if (0) test_sqsub_8h_8h_8h(TyH);
- if (0) test_sqsub_4h_4h_4h(TyH);
- if (0) test_sqsub_16b_16b_16b(TyB);
- if (0) test_sqsub_8b_8b_8b(TyB);
- if (0) test_uqsub_2d_2d_2d(TyD);
- if (0) test_uqsub_4s_4s_4s(TyS);
- if (0) test_uqsub_2s_2s_2s(TyS);
- if (0) test_uqsub_8h_8h_8h(TyH);
- if (0) test_uqsub_4h_4h_4h(TyH);
- if (0) test_uqsub_16b_16b_16b(TyB);
- if (0) test_uqsub_8b_8b_8b(TyB);
+ if (1) test_sqadd_2d_2d_2d(TyD);
+ if (1) test_sqadd_4s_4s_4s(TyS);
+ if (1) test_sqadd_2s_2s_2s(TyS);
+ if (1) test_sqadd_8h_8h_8h(TyH);
+ if (1) test_sqadd_4h_4h_4h(TyH);
+ if (1) test_sqadd_16b_16b_16b(TyB);
+ if (1) test_sqadd_8b_8b_8b(TyB);
+ if (1) test_uqadd_2d_2d_2d(TyD);
+ if (1) test_uqadd_4s_4s_4s(TyS);
+ if (1) test_uqadd_2s_2s_2s(TyS);
+ if (1) test_uqadd_8h_8h_8h(TyH);
+ if (1) test_uqadd_4h_4h_4h(TyH);
+ if (1) test_uqadd_16b_16b_16b(TyB);
+ if (1) test_uqadd_8b_8b_8b(TyB);
+ if (1) test_sqsub_2d_2d_2d(TyD);
+ if (1) test_sqsub_4s_4s_4s(TyS);
+ if (1) test_sqsub_2s_2s_2s(TyS);
+ if (1) test_sqsub_8h_8h_8h(TyH);
+ if (1) test_sqsub_4h_4h_4h(TyH);
+ if (1) test_sqsub_16b_16b_16b(TyB);
+ if (1) test_sqsub_8b_8b_8b(TyB);
+ if (1) test_uqsub_2d_2d_2d(TyD);
+ if (1) test_uqsub_4s_4s_4s(TyS);
+ if (1) test_uqsub_2s_2s_2s(TyS);
+ if (1) test_uqsub_8h_8h_8h(TyH);
+ if (1) test_uqsub_4h_4h_4h(TyH);
+ if (1) test_uqsub_16b_16b_16b(TyB);
+ if (1) test_uqsub_8b_8b_8b(TyB);
// sqdmlal d_s_s[], s_h_h[]
// sqdmlsl d_s_s[], s_h_h[]
|
|
From: <sv...@va...> - 2014-06-30 07:34:16
|
Author: sewardj
Date: Mon Jun 30 07:33:56 2014
New Revision: 2895
Log:
arm64: implement: sadalp uadalp saddlp uaddlp saddlv uaddlv saddw{2}
uaddw{2} ssubw{2} usubw{2} shadd uhadd shsub uhsub sqadd uqadd sqsub
uqsub smaxp umaxp sminp uminp
Modified:
trunk/priv/guest_arm64_toIR.c
trunk/priv/host_arm64_defs.c
trunk/priv/host_arm64_defs.h
trunk/priv/host_arm64_isel.c
trunk/priv/ir_defs.c
Modified: trunk/priv/guest_arm64_toIR.c
==============================================================================
--- trunk/priv/guest_arm64_toIR.c (original)
+++ trunk/priv/guest_arm64_toIR.c Mon Jun 30 07:33:56 2014
@@ -539,6 +539,113 @@
}
}
+static IROp mkVecADD ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecQADDU ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_QAdd8Ux16, Iop_QAdd16Ux8, Iop_QAdd32Ux4, Iop_QAdd64Ux2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecQADDS ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_QAdd8Sx16, Iop_QAdd16Sx8, Iop_QAdd32Sx4, Iop_QAdd64Sx2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecSUB ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecQSUBU ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_QSub8Ux16, Iop_QSub16Ux8, Iop_QSub32Ux4, Iop_QSub64Ux2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecQSUBS ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_QSub8Sx16, Iop_QSub16Sx8, Iop_QSub32Sx4, Iop_QSub64Sx2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecSARN ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_SarN8x16, Iop_SarN16x8, Iop_SarN32x4, Iop_SarN64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecSHRN ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_ShrN8x16, Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecSHLN ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_ShlN8x16, Iop_ShlN16x8, Iop_ShlN32x4, Iop_ShlN64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecCATEVENLANES ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_CatEvenLanes8x16, Iop_CatEvenLanes16x8,
+ Iop_CatEvenLanes32x4, Iop_InterleaveLO64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecCATODDLANES ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_CatOddLanes8x16, Iop_CatOddLanes16x8,
+ Iop_CatOddLanes32x4, Iop_InterleaveHI64x2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecMAXU ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4, Iop_Max64Ux2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecMAXS ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4, Iop_Max64Sx2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecMINU ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4, Iop_Min64Ux2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
+static IROp mkVecMINS ( UInt size ) {
+ const IROp ops[4]
+ = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4, Iop_Min64Sx2 };
+ vassert(size < 4);
+ return ops[size];
+}
+
static IRExpr* mkU ( IRType ty, ULong imm ) {
switch (ty) {
case Ity_I32: return mkU32((UInt)(imm & 0xFFFFFFFFULL));
@@ -1730,6 +1837,14 @@
vassert(0);
}
+/* The same, but from an expression instead. */
+static IRExpr* math_MAYBE_ZERO_HI64_fromE ( UInt bitQ, IRExpr* fullWidth )
+{
+ IRTemp fullWidthT = newTemp(Ity_V128);
+ assign(fullWidthT, fullWidth);
+ return math_MAYBE_ZERO_HI64(bitQ, fullWidthT);
+}
+
/*------------------------------------------------------------*/
/*--- FP comparison helpers ---*/
@@ -5539,6 +5654,18 @@
assign(res, unop(Iop_ZeroHI96ofV128, mkexpr(max3210)));
return res;
}
+ case Iop_Add64x2: {
+ IRTemp x10 = src;
+ IRTemp x00 = newTemp(Ity_V128);
+ IRTemp x11 = newTemp(Ity_V128);
+ assign(x11, binop(Iop_InterleaveHI64x2, mkexpr(x10), mkexpr(x10)));
+ assign(x00, binop(Iop_InterleaveLO64x2, mkexpr(x10), mkexpr(x10)));
+ IRTemp max10 = newTemp(Ity_V128);
+ assign(max10, binop(op, mkexpr(x11), mkexpr(x00)));
+ IRTemp res = newTemp(Ity_V128);
+ assign(res, unop(Iop_ZeroHI64ofV128, mkexpr(max10)));
+ return res;
+ }
default:
vassert(0);
}
@@ -5688,8 +5815,8 @@
either the lower or upper set of lanes to twice-as-wide,
resulting in a new V128 value. */
static
-IRTemp math_WIDEN_LANES ( Bool zWiden, Bool fromUpperHalf,
- UInt sizeNarrow, IRExpr* srcE )
+IRTemp math_WIDEN_LO_OR_HI_LANES ( Bool zWiden, Bool fromUpperHalf,
+ UInt sizeNarrow, IRExpr* srcE )
{
IRTemp src = newTemp(Ity_V128);
IRTemp res = newTemp(Ity_V128);
@@ -5729,6 +5856,49 @@
}
+/* Generate IR that takes a V128 and sign- or zero-widens
+ either the even or odd lanes to twice-as-wide,
+ resulting in a new V128 value. */
+static
+IRTemp math_WIDEN_EVEN_OR_ODD_LANES ( Bool zWiden, Bool fromOdd,
+ UInt sizeNarrow, IRExpr* srcE )
+{
+ IRTemp src = newTemp(Ity_V128);
+ IRTemp res = newTemp(Ity_V128);
+ IROp opSAR = mkVecSARN(sizeNarrow+1);
+ IROp opSHR = mkVecSHRN(sizeNarrow+1);
+ IROp opSHL = mkVecSHLN(sizeNarrow+1);
+ IROp opSxR = zWiden ? opSHR : opSAR;
+ UInt amt = 0;
+ switch (sizeNarrow) {
+ case X10: amt = 32; break;
+ case X01: amt = 16; break;
+ case X00: amt = 8; break;
+ default: vassert(0);
+ }
+ assign(src, srcE);
+ if (fromOdd) {
+ assign(res, binop(opSxR, mkexpr(src), mkU8(amt)));
+ } else {
+ assign(res, binop(opSxR, binop(opSHL, mkexpr(src), mkU8(amt)),
+ mkU8(amt)));
+ }
+ return res;
+}
+
+
+/* Generate IR that takes two V128s and narrows (takes lower half)
+ of each lane, producing a single V128 value. */
+static
+IRTemp math_NARROW_LANES ( IRTemp argHi, IRTemp argLo, UInt sizeNarrow )
+{
+ IRTemp res = newTemp(Ity_V128);
+ assign(res, binop(mkVecCATEVENLANES(sizeNarrow),
+ mkexpr(argHi), mkexpr(argLo)));
+ return res;
+}
+
+
/* Let |new64| be a V128 in which only the lower 64 bits are interesting,
and the upper can contain any value -- it is ignored. If |is2| is False,
generate IR to put |new64| in the lower half of vector reg |dd| and zero
@@ -5759,6 +5929,22 @@
}
+/* QCFLAG tracks the SIMD sticky saturation status. Update the status
+ thusly: if |nres| and |qres| hold the same value, leave QCFLAG
+ unchanged. Otherwise, set it (implicitly) to 1. */
+static
+void updateQCFLAGwithDifference ( IRTemp nres, IRTemp qres )
+{
+ IRTemp diff = newTemp(Ity_V128);
+ IRTemp oldQCFLAG = newTemp(Ity_V128);
+ IRTemp newQCFLAG = newTemp(Ity_V128);
+ assign(diff, binop(Iop_XorV128, mkexpr(nres), mkexpr(qres)));
+ assign(oldQCFLAG, IRExpr_Get(OFFB_QCFLAG, Ity_V128));
+ assign(newQCFLAG, binop(Iop_OrV128, mkexpr(oldQCFLAG), mkexpr(diff)));
+ stmt(IRStmt_Put(OFFB_QCFLAG, mkexpr(newQCFLAG)));
+}
+
+
static
Bool dis_AdvSIMD_EXT(/*MB_OUT*/DisResult* dres, UInt insn)
{
@@ -5909,6 +6095,41 @@
UInt nn = INSN(9,5);
UInt dd = INSN(4,0);
+ if (opcode == BITS5(0,0,0,1,1)) {
+ /* -------- 0,xx,00011 SADDLV -------- */
+ /* -------- 1,xx,00011 UADDLV -------- */
+ /* size is the narrow size */
+ if (size == X11 || (size == X10 && bitQ == 0)) return False;
+ Bool isU = bitU == 1;
+ IRTemp src = newTemp(Ity_V128);
+ assign(src, getQReg128(nn));
+ /* The basic plan is to widen the lower half, and if Q = 1,
+ the upper half too. Add them together (if Q = 1), and in
+ either case fold with add at twice the lane width.
+ */
+ IRExpr* widened
+ = mkexpr(math_WIDEN_LO_OR_HI_LANES(
+ isU, False/*!fromUpperHalf*/, size, mkexpr(src)));
+ if (bitQ == 1) {
+ widened
+ = binop(mkVecADD(size+1),
+ widened,
+ mkexpr(math_WIDEN_LO_OR_HI_LANES(
+ isU, True/*fromUpperHalf*/, size, mkexpr(src)))
+ );
+ }
+ /* Now fold. */
+ IRTemp tWi = newTemp(Ity_V128);
+ assign(tWi, widened);
+ IRTemp res = math_FOLDV(tWi, mkVecADD(size+1));
+ putQReg128(dd, mkexpr(res));
+ const HChar* arr = nameArr_Q_SZ(bitQ, size);
+ const HChar ch = "bhsd"[size];
+ DIP("%s %s.%c, %s.%s\n", isU ? "uaddlv" : "saddlv",
+ nameQReg128(dd), ch, nameQReg128(nn), arr);
+ return True;
+ }
+
UInt ix = 0;
/**/ if (opcode == BITS5(0,1,0,1,0)) { ix = bitU == 0 ? 1 : 2; }
else if (opcode == BITS5(1,1,0,1,0)) { ix = bitU == 0 ? 3 : 4; }
@@ -7014,8 +7235,8 @@
vassert(size <= 2);
Bool isU = bitU == 1;
Bool isADD = opcode == BITS4(0,0,0,0);
- IRTemp argL = math_WIDEN_LANES(isU, is2, size, getQReg128(nn));
- IRTemp argR = math_WIDEN_LANES(isU, is2, size, getQReg128(mm));
+ IRTemp argL = math_WIDEN_LO_OR_HI_LANES(isU, is2, size, getQReg128(nn));
+ IRTemp argR = math_WIDEN_LO_OR_HI_LANES(isU, is2, size, getQReg128(mm));
IRTemp res = newTemp(Ity_V128);
assign(res, binop(isADD ? opADD[size] : opSUB[size],
mkexpr(argL), mkexpr(argR)));
@@ -7030,6 +7251,31 @@
return True;
}
+ if (opcode == BITS4(0,0,0,1) || opcode == BITS4(0,0,1,1)) {
+ /* -------- 0,0001 SADDW{2} -------- */
+ /* -------- 1,0001 UADDW{2} -------- */
+ /* -------- 0,0011 SSUBW{2} -------- */
+ /* -------- 1,0011 USUBW{2} -------- */
+ /* Widens, and size refers to the narrowed lanes. */
+ if (size == X11) return False;
+ vassert(size <= 2);
+ Bool isU = bitU == 1;
+ Bool isADD = opcode == BITS4(0,0,0,1);
+ IRTemp argR = math_WIDEN_LO_OR_HI_LANES(isU, is2, size, getQReg128(mm));
+ IRTemp res = newTemp(Ity_V128);
+ assign(res, binop(isADD ? mkVecADD(size+1) : mkVecSUB(size+1),
+ getQReg128(nn), mkexpr(argR)));
+ putQReg128(dd, mkexpr(res));
+ const HChar* arrNarrow = nameArr_Q_SZ(bitQ, size);
+ const HChar* arrWide = nameArr_Q_SZ(1, size+1);
+ const HChar* nm = isADD ? (isU ? "uaddw" : "saddw")
+ : (isU ? "usubw" : "ssubw");
+ DIP("%s%s %s.%s, %s.%s, %s.%s\n", nm, is2 ? "2" : "",
+ nameQReg128(dd), arrWide,
+ nameQReg128(nn), arrWide, nameQReg128(mm), arrNarrow);
+ return True;
+ }
+
if (opcode == BITS4(0,1,0,0) || opcode == BITS4(0,1,1,0)) {
/* -------- 0,0100 ADDHN{2} -------- */
/* -------- 1,0100 RADDHN{2} -------- */
@@ -7094,8 +7340,8 @@
vassert(size <= 2);
Bool isU = bitU == 1;
Bool isACC = opcode == BITS4(0,1,0,1);
- IRTemp argL = math_WIDEN_LANES(isU, is2, size, getQReg128(nn));
- IRTemp argR = math_WIDEN_LANES(isU, is2, size, getQReg128(mm));
+ IRTemp argL = math_WIDEN_LO_OR_HI_LANES(isU, is2, size, getQReg128(nn));
+ IRTemp argR = math_WIDEN_LO_OR_HI_LANES(isU, is2, size, getQReg128(mm));
IRTemp abd = math_ABD(isU, size+1, mkexpr(argL), mkexpr(argR));
IRTemp res = newTemp(Ity_V128);
assign(res, isACC ? binop(opADD[size], mkexpr(abd), getQReg128(dd))
@@ -7197,6 +7443,85 @@
UInt dd = INSN(4,0);
vassert(size < 4);
+ if (opcode == BITS5(0,0,0,0,0) || opcode == BITS5(0,0,1,0,0)) {
+ /* -------- 0,xx,00000 SHADD std6_std6_std6 -------- */
+ /* -------- 1,xx,00000 UHADD std6_std6_std6 -------- */
+ /* -------- 0,xx,00100 SHSUB std6_std6_std6 -------- */
+ /* -------- 1,xx,00100 UHSUB std6_std6_std6 -------- */
+ if (size == X11) return False;
+ Bool isADD = opcode == BITS5(0,0,0,0,0);
+ Bool isU = bitU == 1;
+ /* Widen both args out, do the math, narrow to final result. */
+ IRTemp argL = newTemp(Ity_V128);
+ IRTemp argLhi = IRTemp_INVALID;
+ IRTemp argLlo = IRTemp_INVALID;
+ IRTemp argR = newTemp(Ity_V128);
+ IRTemp argRhi = IRTemp_INVALID;
+ IRTemp argRlo = IRTemp_INVALID;
+ IRTemp resHi = newTemp(Ity_V128);
+ IRTemp resLo = newTemp(Ity_V128);
+ IRTemp res = IRTemp_INVALID;
+ assign(argL, getQReg128(nn));
+ argLlo = math_WIDEN_LO_OR_HI_LANES(isU, False, size, mkexpr(argL));
+ argLhi = math_WIDEN_LO_OR_HI_LANES(isU, True, size, mkexpr(argL));
+ assign(argR, getQReg128(mm));
+ argRlo = math_WIDEN_LO_OR_HI_LANES(isU, False, size, mkexpr(argR));
+ argRhi = math_WIDEN_LO_OR_HI_LANES(isU, True, size, mkexpr(argR));
+ IROp opADDSUB = isADD ? mkVecADD(size+1) : mkVecSUB(size+1);
+ IROp opSxR = isU ? mkVecSHRN(size+1) : mkVecSARN(size+1);
+ assign(resHi, binop(opSxR,
+ binop(opADDSUB, mkexpr(argLhi), mkexpr(argRhi)),
+ mkU8(1)));
+ assign(resLo, binop(opSxR,
+ binop(opADDSUB, mkexpr(argLlo), mkexpr(argRlo)),
+ mkU8(1)));
+ res = math_NARROW_LANES ( resHi, resLo, size );
+ putQReg128(dd, math_MAYBE_ZERO_HI64(bitQ, res));
+ const HChar* nm = isADD ? (isU ? "uhadd" : "shadd")
+ : (isU ? "uhsub" : "shsub");
+ const HChar* arr = nameArr_Q_SZ(bitQ, size);
+ DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
+ nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
+ return True;
+ }
+
+ if (opcode == BITS5(0,0,0,0,1) || opcode == BITS5(0,0,1,0,1)) {
+ /* -------- 0,xx,00001 SQADD std7_std7_std7 -------- */
+ /* -------- 1,xx,00001 UQADD std7_std7_std7 -------- */
+ /* -------- 0,xx,00101 SQSUB std7_std7_std7 -------- */
+ /* -------- 1,xx,00101 UQSUB std7_std7_std7 -------- */
+ if (bitQ == 0 && size == X11) return False; // implied 1d case
+ Bool isADD = opcode == BITS5(0,0,0,0,1);
+ Bool isU = bitU == 1;
+ IROp qop = Iop_INVALID;
+ IROp nop = Iop_INVALID;
+ if (isADD) {
+ qop = isU ? mkVecQADDU(size) : mkVecQADDS(size);
+ nop = mkVecADD(size);
+ } else {
+ qop = isU ? mkVecQSUBU(size) : mkVecQSUBS(size);
+ nop = mkVecSUB(size);
+ }
+ IRTemp argL = newTemp(Ity_V128);
+ IRTemp argR = newTemp(Ity_V128);
+ IRTemp qres = newTemp(Ity_V128);
+ IRTemp nres = newTemp(Ity_V128);
+ assign(argL, getQReg128(nn));
+ assign(argR, getQReg128(mm));
+ assign(qres, math_MAYBE_ZERO_HI64_fromE(
+ bitQ, binop(qop, mkexpr(argL), mkexpr(argR))));
+ assign(nres, math_MAYBE_ZERO_HI64_fromE(
+ bitQ, binop(nop, mkexpr(argL), mkexpr(argR))));
+ putQReg128(dd, mkexpr(qres));
+ updateQCFLAGwithDifference(nres, qres);
+ const HChar* nm = isADD ? (isU ? "uqadd" : "sqadd")
+ : (isU ? "uqsub" : "sqsub");
+ const HChar* arr = nameArr_Q_SZ(bitQ, size);
+ DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
+ nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
+ return True;
+ }
+
if (bitU == 0 && opcode == BITS5(0,0,0,1,1)) {
/* -------- 0,00,00011 AND 16b_16b_16b, 8b_8b_8b -------- */
/* -------- 0,01,00011 BIC 16b_16b_16b, 8b_8b_8b -------- */
@@ -7433,39 +7758,6 @@
return False;
}
- if (bitU == 0 && opcode == BITS5(1,0,1,1,1)) {
- if (bitQ == 0 && size == X11) return False; // implied 1d case
- /* -------- 0,xx,10111 ADDP std7_std7_std7 -------- */
- const IROp opsADD[4]
- = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 };
- const IROp opsCEV[4]
- = { Iop_CatEvenLanes8x16, Iop_CatEvenLanes16x8, Iop_CatEvenLanes32x4,
- Iop_InterleaveLO64x2 };
- const IROp opsCOD[4]
- = { Iop_CatOddLanes8x16, Iop_CatOddLanes16x8, Iop_CatOddLanes32x4,
- Iop_InterleaveHI64x2 };
- IRTemp vN = newTemp(Ity_V128);
- IRTemp vM = newTemp(Ity_V128);
- assign(vN, getQReg128(nn));
- assign(vM, getQReg128(mm));
- IRTemp res128 = newTemp(Ity_V128);
- assign(res128, binop(opsADD[size],
- binop(opsCEV[size], mkexpr(vM), mkexpr(vN)),
- binop(opsCOD[size], mkexpr(vM), mkexpr(vN))));
- /* In the half-width case, use CatEL32x4 to extract the half-width
- result from the full-width result. */
- IRExpr* res
- = bitQ == 0 ? unop(Iop_ZeroHI64ofV128,
- binop(Iop_CatEvenLanes32x4, mkexpr(res128),
- mkexpr(res128)))
- : mkexpr(res128);
- putQReg128(dd, res);
- const HChar* arr = nameArr_Q_SZ(bitQ, size);
- DIP("addp %s.%s, %s.%s, %s.%s\n",
- nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
- return True;
- }
-
if (opcode == BITS5(1,0,0,1,1)) {
/* -------- 0,xx,10011 MUL std7_std7_std7 -------- */
/* -------- 1,xx,10011 PMUL 16b_16b_16b, 8b_8b_8b -------- */
@@ -7488,6 +7780,67 @@
return False;
}
+ if (opcode == BITS5(1,0,1,0,0) || opcode == BITS5(1,0,1,0,1)) {
+ /* -------- 0,xx,10100 SMAXP std6_std6_std6 -------- */
+ /* -------- 1,xx,10100 UMAXP std6_std6_std6 -------- */
+ /* -------- 0,xx,10101 SMINP std6_std6_std6 -------- */
+ /* -------- 1,xx,10101 UMINP std6_std6_std6 -------- */
+ if (size == X11) return False;
+ Bool isU = bitU == 1;
+ Bool isMAX = opcode == BITS5(1,0,1,0,0);
+ IRTemp vN = newTemp(Ity_V128);
+ IRTemp vM = newTemp(Ity_V128);
+ IROp op = isMAX ? (isU ? mkVecMAXU(size) : mkVecMAXS(size))
+ : (isU ? mkVecMINU(size) : mkVecMINS(size));
+ assign(vN, getQReg128(nn));
+ assign(vM, getQReg128(mm));
+ IRTemp res128 = newTemp(Ity_V128);
+ assign(res128,
+ binop(op,
+ binop(mkVecCATEVENLANES(size), mkexpr(vM), mkexpr(vN)),
+ binop(mkVecCATODDLANES(size), mkexpr(vM), mkexpr(vN))));
+ /* In the half-width case, use CatEL32x4 to extract the half-width
+ result from the full-width result. */
+ IRExpr* res
+ = bitQ == 0 ? unop(Iop_ZeroHI64ofV128,
+ binop(Iop_CatEvenLanes32x4, mkexpr(res128),
+ mkexpr(res128)))
+ : mkexpr(res128);
+ putQReg128(dd, res);
+ const HChar* arr = nameArr_Q_SZ(bitQ, size);
+ const HChar* nm = isMAX ? (isU ? "umaxp" : "smaxp")
+ : (isU ? "uminp" : "sminp");
+ DIP("%s %s.%s, %s.%s, %s.%s\n", nm,
+ nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
+ return True;
+ }
+
+ if (bitU == 0 && opcode == BITS5(1,0,1,1,1)) {
+ /* -------- 0,xx,10111 ADDP std7_std7_std7 -------- */
+ if (bitQ == 0 && size == X11) return False; // implied 1d case
+ IRTemp vN = newTemp(Ity_V128);
+ IRTemp vM = newTemp(Ity_V128);
+ assign(vN, getQReg128(nn));
+ assign(vM, getQReg128(mm));
+ IRTemp res128 = newTemp(Ity_V128);
+ assign(res128,
+ binop(mkVecADD(size),
+ binop(mkVecCATEVENLANES(size), mkexpr(vM), mkexpr(vN)),
+ binop(mkVecCATODDLANES(size), mkexpr(vM), mkexpr(vN))));
+ /* In the half-width case, use CatEL32x4 to extract the half-width
+ result from the full-width result. */
+ IRExpr* res
+ = bitQ == 0 ? unop(Iop_ZeroHI64ofV128,
+ binop(Iop_CatEvenLanes32x4, mkexpr(res128),
+ mkexpr(res128)))
+ : mkexpr(res128);
+ putQReg128(dd, res);
+ const HChar* arr = nameArr_Q_SZ(bitQ, size);
+ DIP("addp %s.%s, %s.%s, %s.%s\n",
+ nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr);
+ return True;
+ }
+
if (bitU == 0 && opcode == BITS5(1,1,0,0,1)) {
/* -------- 0,0x,11001 FMLA 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
/* -------- 0,1x,11001 FMLS 2d_2d_2d, 4s_4s_4s, 2s_2s_2s -------- */
@@ -7705,6 +8058,36 @@
return True;
}
+ if (opcode == BITS5(0,0,0,1,0) || opcode == BITS5(0,0,1,1,0)) {
+ /* -------- 0,xx,00010: SADDLP std6_std6 -------- */
+ /* -------- 1,xx,00010: UADDLP std6_std6 -------- */
+ /* -------- 0,xx,00110: SADALP std6_std6 -------- */
+ /* -------- 1,xx,00110: UADALP std6_std6 -------- */
+ /* Widens, and size refers to the narrow size. */
+ if (size == X11) return False; // no 1d or 2d cases
+ Bool isU = bitU == 1;
+ Bool isACC = opcode == BITS5(0,0,1,1,0);
+ IRTemp src = newTemp(Ity_V128);
+ IRTemp sum = newTemp(Ity_V128);
+ IRTemp res = newTemp(Ity_V128);
+ assign(src, getQReg128(nn));
+ assign(sum,
+ binop(mkVecADD(size+1),
+ mkexpr(math_WIDEN_EVEN_OR_ODD_LANES(
+ isU, True/*fromOdd*/, size, mkexpr(src))),
+ mkexpr(math_WIDEN_EVEN_OR_ODD_LANES(
+ isU, False/*!fromOdd*/, size, mkexpr(src)))));
+ assign(res, isACC ? binop(mkVecADD(size+1), mkexpr(sum), getQReg128(dd))
+ : mkexpr(sum));
+ putQReg128(dd, math_MAYBE_ZERO_HI64(bitQ, res));
+ const HChar* arrNarrow = nameArr_Q_SZ(bitQ, size);
+ const HChar* arrWide = nameArr_Q_SZ(bitQ, size+1);
+ DIP("%s %s.%s, %s.%s\n", isACC ? (isU ? "uadalp" : "sadalp")
+ : (isU ? "uaddlp" : "saddlp"),
+ nameQReg128(dd), arrWide, nameQReg128(nn), arrNarrow);
+ return True;
+ }
+
if (opcode == BITS5(0,0,1,0,0)) {
/* -------- 0,xx,00100: CLS std6_std6 -------- */
/* -------- 1,xx,00100: CLZ std6_std6 -------- */
Modified: trunk/priv/host_arm64_defs.c
==============================================================================
--- trunk/priv/host_arm64_defs.c (original)
+++ trunk/priv/host_arm64_defs.c Mon Jun 30 07:33:56 2014
@@ -929,6 +929,22 @@
case ARM64vecb_SMULL2DSS: *nm = "smull"; *ar = "2dss"; return;
case ARM64vecb_SMULL4SHH: *nm = "smull"; *ar = "4shh"; return;
case ARM64vecb_SMULL8HBB: *nm = "smull"; *ar = "8hbb"; return;
+ case ARM64vecb_SQADD64x2: *nm = "sqadd"; *ar = "2d"; return;
+ case ARM64vecb_SQADD32x4: *nm = "sqadd"; *ar = "4s"; return;
+ case ARM64vecb_SQADD16x8: *nm = "sqadd"; *ar = "8h"; return;
+ case ARM64vecb_SQADD8x16: *nm = "sqadd"; *ar = "16b"; return;
+ case ARM64vecb_UQADD64x2: *nm = "uqadd"; *ar = "2d"; return;
+ case ARM64vecb_UQADD32x4: *nm = "uqadd"; *ar = "4s"; return;
+ case ARM64vecb_UQADD16x8: *nm = "uqadd"; *ar = "8h"; return;
+ case ARM64vecb_UQADD8x16: *nm = "uqadd"; *ar = "16b"; return;
+ case ARM64vecb_SQSUB64x2: *nm = "sqsub"; *ar = "2d"; return;
+ case ARM64vecb_SQSUB32x4: *nm = "sqsub"; *ar = "4s"; return;
+ case ARM64vecb_SQSUB16x8: *nm = "sqsub"; *ar = "8h"; return;
+ case ARM64vecb_SQSUB8x16: *nm = "sqsub"; *ar = "16b"; return;
+ case ARM64vecb_UQSUB64x2: *nm = "uqsub"; *ar = "2d"; return;
+ case ARM64vecb_UQSUB32x4: *nm = "uqsub"; *ar = "4s"; return;
+ case ARM64vecb_UQSUB16x8: *nm = "uqsub"; *ar = "8h"; return;
+ case ARM64vecb_UQSUB8x16: *nm = "uqsub"; *ar = "16b"; return;
default: vpanic("showARM64VecBinOp");
}
}
@@ -3461,12 +3477,14 @@
#define X000000 BITS8(0,0, 0,0,0,0,0,0)
#define X000001 BITS8(0,0, 0,0,0,0,0,1)
#define X000010 BITS8(0,0, 0,0,0,0,1,0)
+#define X000011 BITS8(0,0, 0,0,0,0,1,1)
#define X000100 BITS8(0,0, 0,0,0,1,0,0)
#define X000110 BITS8(0,0, 0,0,0,1,1,0)
#define X000111 BITS8(0,0, 0,0,0,1,1,1)
#define X001000 BITS8(0,0, 0,0,1,0,0,0)
#define X001001 BITS8(0,0, 0,0,1,0,0,1)
#define X001010 BITS8(0,0, 0,0,1,0,1,0)
+#define X001011 BITS8(0,0, 0,0,1,0,1,1)
#define X001101 BITS8(0,0, 0,0,1,1,0,1)
#define X001110 BITS8(0,0, 0,0,1,1,1,0)
#define X001111 BITS8(0,0, 0,0,1,1,1,1)
@@ -5151,6 +5169,26 @@
000 01110 10 1 m 110000 n d SMULL Vd.2d, Vn.2s, Vm.2s
000 01110 01 1 m 110000 n d SMULL Vd.4s, Vn.4h, Vm.4h
000 01110 00 1 m 110000 n d SMULL Vd.8h, Vn.8b, Vm.8b
+
+ 010 01110 11 1 m 000011 n d SQADD Vd.2d, Vn.2d, Vm.2d
+ 010 01110 10 1 m 000011 n d SQADD Vd.4s, Vn.4s, Vm.4s
+ 010 01110 01 1 m 000011 n d SQADD Vd.8h, Vn.8h, Vm.8h
+ 010 01110 00 1 m 000011 n d SQADD Vd.16b, Vn.16b, Vm.16b
+
+ 011 01110 11 1 m 000011 n d UQADD Vd.2d, Vn.2d, Vm.2d
+ 011 01110 10 1 m 000011 n d UQADD Vd.4s, Vn.4s, Vm.4s
+ 011 01110 01 1 m 000011 n d UQADD Vd.8h, Vn.8h, Vm.8h
+ 011 01110 00 1 m 000011 n d UQADD Vd.16b, Vn.16b, Vm.16b
+
+ 010 01110 11 1 m 001011 n d SQSUB Vd.2d, Vn.2d, Vm.2d
+ 010 01110 10 1 m 001011 n d SQSUB Vd.4s, Vn.4s, Vm.4s
+ 010 01110 01 1 m 001011 n d SQSUB Vd.8h, Vn.8h, Vm.8h
+ 010 01110 00 1 m 001011 n d SQSUB Vd.16b, Vn.16b, Vm.16b
+
+ 011 01110 11 1 m 001011 n d UQSUB Vd.2d, Vn.2d, Vm.2d
+ 011 01110 10 1 m 001011 n d UQSUB Vd.4s, Vn.4s, Vm.4s
+ 011 01110 01 1 m 001011 n d UQSUB Vd.8h, Vn.8h, Vm.8h
+ 011 01110 00 1 m 001011 n d UQSUB Vd.16b, Vn.16b, Vm.16b
*/
UInt vD = qregNo(i->ARM64in.VBinV.dst);
UInt vN = qregNo(i->ARM64in.VBinV.argL);
@@ -5402,6 +5440,58 @@
*p++ = X_3_8_5_6_5_5(X000, X01110001, vM, X110000, vN, vD);
break;
+ case ARM64vecb_SQADD64x2:
+ *p++ = X_3_8_5_6_5_5(X010, X01110111, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_SQADD32x4:
+ *p++ = X_3_8_5_6_5_5(X010, X01110101, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_SQADD16x8:
+ *p++ = X_3_8_5_6_5_5(X010, X01110011, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_SQADD8x16:
+ *p++ = X_3_8_5_6_5_5(X010, X01110001, vM, X000011, vN, vD);
+ break;
+
+ case ARM64vecb_UQADD64x2:
+ *p++ = X_3_8_5_6_5_5(X011, X01110111, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_UQADD32x4:
+ *p++ = X_3_8_5_6_5_5(X011, X01110101, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_UQADD16x8:
+ *p++ = X_3_8_5_6_5_5(X011, X01110011, vM, X000011, vN, vD);
+ break;
+ case ARM64vecb_UQADD8x16:
+ *p++ = X_3_8_5_6_5_5(X011, X01110001, vM, X000011, vN, vD);
+ break;
+
+ case ARM64vecb_SQSUB64x2:
+ *p++ = X_3_8_5_6_5_5(X010, X01110111, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_SQSUB32x4:
+ *p++ = X_3_8_5_6_5_5(X010, X01110101, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_SQSUB16x8:
+ *p++ = X_3_8_5_6_5_5(X010, X01110011, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_SQSUB8x16:
+ *p++ = X_3_8_5_6_5_5(X010, X01110001, vM, X001011, vN, vD);
+ break;
+
+ case ARM64vecb_UQSUB64x2:
+ *p++ = X_3_8_5_6_5_5(X011, X01110111, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_UQSUB32x4:
+ *p++ = X_3_8_5_6_5_5(X011, X01110101, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_UQSUB16x8:
+ *p++ = X_3_8_5_6_5_5(X011, X01110011, vM, X001011, vN, vD);
+ break;
+ case ARM64vecb_UQSUB8x16:
+ *p++ = X_3_8_5_6_5_5(X011, X01110001, vM, X001011, vN, vD);
+ break;
+
default:
goto bad;
}
Modified: trunk/priv/host_arm64_defs.h
==============================================================================
--- trunk/priv/host_arm64_defs.h (original)
+++ trunk/priv/host_arm64_defs.h Mon Jun 30 07:33:56 2014
@@ -350,6 +350,14 @@
ARM64vecb_UMULL4SHH, ARM64vecb_UMULL8HBB,
ARM64vecb_SMULL2DSS,
ARM64vecb_SMULL4SHH, ARM64vecb_SMULL8HBB,
+ ARM64vecb_SQADD64x2, ARM64vecb_SQADD32x4,
+ ARM64vecb_SQADD16x8, ARM64vecb_SQADD8x16,
+ ARM64vecb_UQADD64x2, ARM64vecb_UQADD32x4,
+ ARM64vecb_UQADD16x8, ARM64vecb_UQADD8x16,
+ ARM64vecb_SQSUB64x2, ARM64vecb_SQSUB32x4,
+ ARM64vecb_SQSUB16x8, ARM64vecb_SQSUB8x16,
+ ARM64vecb_UQSUB64x2, ARM64vecb_UQSUB32x4,
+ ARM64vecb_UQSUB16x8, ARM64vecb_UQSUB8x16,
ARM64vecb_INVALID
}
ARM64VecBinOp;
Modified: trunk/priv/host_arm64_isel.c
==============================================================================
--- trunk/priv/host_arm64_isel.c (original)
+++ trunk/priv/host_arm64_isel.c Mon Jun 30 07:33:56 2014
@@ -4414,8 +4414,8 @@
case Iop_Neg64Fx2: case Iop_Neg32Fx4:
case Iop_Abs64x2: case Iop_Abs32x4:
case Iop_Abs16x8: case Iop_Abs8x16:
- case Iop_Cls32x4: case Iop_Cls16x8: case Iop_Cls8x16:
- case Iop_Clz32x4: case Iop_Clz16x8: case Iop_Clz8x16:
+ case Iop_Cls32x4: case Iop_Cls16x8: case Iop_Cls8x16:
+ case Iop_Clz32x4: case Iop_Clz16x8: case Iop_Clz8x16:
case Iop_Cnt8x16:
case Iop_Reverse1sIn8_x16:
case Iop_Reverse8sIn16_x8:
@@ -4912,93 +4912,45 @@
addInstr(env, ARM64Instr_VQfromXX(res, argL, argR));
return res;
}
-//ZZ case Iop_AndV128: {
-//ZZ HReg res = newVRegV(env);
-//ZZ HReg argL = iselNeonExpr(env, e->Iex.Binop.arg1);
-//ZZ HReg argR = iselNeonExpr(env, e->Iex.Binop.arg2);
-//ZZ addInstr(env, ARMInstr_NBinary(ARMneon_VAND,
-//ZZ res, argL, argR, 4, True));
-//ZZ return res;
-//ZZ }
-//ZZ case Iop_OrV128: {
-//ZZ HReg res = newVRegV(env);
-//ZZ HReg argL = iselNeonExpr(env, e->Iex.Binop.arg1);
-//ZZ HReg argR = iselNeonExpr(env, e->Iex.Binop.arg2);
-//ZZ addInstr(env, ARMInstr_NBinary(ARMneon_VORR,
-//ZZ res, argL, argR, 4, True));
-//ZZ return res;
-//ZZ }
-//ZZ case Iop_XorV128: {
-//ZZ HReg res = newVRegV(env);
-//ZZ HReg argL = iselNeonExpr(env, e->Iex.Binop.arg1);
-//ZZ HReg argR = iselNeonExpr(env, e->Iex.Binop.arg2);
-//ZZ addInstr(env, ARMInstr_NBinary(ARMneon_VXOR,
-//ZZ res, argL, argR, 4, True));
-//ZZ return res;
-//ZZ }
-//ZZ case Iop_Add8x16:
-//ZZ case Iop_Add16x8:
-//ZZ case Iop_Add32x4:
case Iop_AndV128:
case Iop_OrV128:
case Iop_XorV128:
- case Iop_Max32Ux4:
- case Iop_Max16Ux8:
- case Iop_Max8Ux16:
- case Iop_Min32Ux4:
- case Iop_Min16Ux8:
- case Iop_Min8Ux16:
- case Iop_Max32Sx4:
- case Iop_Max16Sx8:
- case Iop_Max8Sx16:
- case Iop_Min32Sx4:
- case Iop_Min16Sx8:
- case Iop_Min8Sx16:
- case Iop_Add64x2:
- case Iop_Add32x4:
- case Iop_Add16x8:
- case Iop_Add8x16:
- case Iop_Sub64x2:
- case Iop_Sub32x4:
- case Iop_Sub16x8:
- case Iop_Sub8x16:
- case Iop_Mul32x4:
- case Iop_Mul16x8:
- case Iop_Mul8x16:
- case Iop_CmpEQ64x2:
- case Iop_CmpEQ32x4:
- case Iop_CmpEQ16x8:
- case Iop_CmpEQ8x16:
- case Iop_CmpGT64Ux2:
- case Iop_CmpGT32Ux4:
- case Iop_CmpGT16Ux8:
- case Iop_CmpGT8Ux16:
- case Iop_CmpGT64Sx2:
- case Iop_CmpGT32Sx4:
- case Iop_CmpGT16Sx8:
- case Iop_CmpGT8Sx16:
- case Iop_CmpEQ64Fx2:
- case Iop_CmpEQ32Fx4:
- case Iop_CmpLE64Fx2:
- case Iop_CmpLE32Fx4:
- case Iop_CmpLT64Fx2:
- case Iop_CmpLT32Fx4:
+ case Iop_Max32Ux4: case Iop_Max16Ux8: case Iop_Max8Ux16:
+ case Iop_Min32Ux4: case Iop_Min16Ux8: case Iop_Min8Ux16:
+ case Iop_Max32Sx4: case Iop_Max16Sx8: case Iop_Max8Sx16:
+ case Iop_Min32Sx4: case Iop_Min16Sx8: case Iop_Min8Sx16:
+ case Iop_Add64x2: case Iop_Add32x4:
+ case Iop_Add16x8: case Iop_Add8x16:
+ case Iop_Sub64x2: case Iop_Sub32x4:
+ case Iop_Sub16x8: case Iop_Sub8x16:
+ case Iop_Mul32x4: case Iop_Mul16x8: case Iop_Mul8x16:
+ case Iop_CmpEQ64x2: case Iop_CmpEQ32x4:
+ case Iop_CmpEQ16x8: case Iop_CmpEQ8x16:
+ case Iop_CmpGT64Ux2: case Iop_CmpGT32Ux4:
+ case Iop_CmpGT16Ux8: case Iop_CmpGT8Ux16:
+ case Iop_CmpGT64Sx2: case Iop_CmpGT32Sx4:
+ case Iop_CmpGT16Sx8: case Iop_CmpGT8Sx16:
+ case Iop_CmpEQ64Fx2: case Iop_CmpEQ32Fx4:
+ case Iop_CmpLE64Fx2: case Iop_CmpLE32Fx4:
+ case Iop_CmpLT64Fx2: case Iop_CmpLT32Fx4:
case Iop_Perm8x16:
- case Iop_InterleaveLO64x2:
- case Iop_CatEvenLanes32x4:
- case Iop_CatEvenLanes16x8:
- case Iop_CatEvenLanes8x16:
- case Iop_InterleaveHI64x2:
- case Iop_CatOddLanes32x4:
- case Iop_CatOddLanes16x8:
- case Iop_CatOddLanes8x16:
+ case Iop_InterleaveLO64x2: case Iop_CatEvenLanes32x4:
+ case Iop_CatEvenLanes16x8: case Iop_CatEvenLanes8x16:
+ case Iop_InterleaveHI64x2: case Iop_CatOddLanes32x4:
+ case Iop_CatOddLanes16x8: case Iop_CatOddLanes8x16:
case Iop_InterleaveHI32x4:
- case Iop_InterleaveHI16x8:
- case Iop_InterleaveHI8x16:
+ case Iop_InterleaveHI16x8: case Iop_InterleaveHI8x16:
case Iop_InterleaveLO32x4:
- case Iop_InterleaveLO16x8:
- case Iop_InterleaveLO8x16:
+ case Iop_InterleaveLO16x8: case Iop_InterleaveLO8x16:
case Iop_PolynomialMul8x16:
+ case Iop_QAdd64Sx2: case Iop_QAdd32Sx4:
+ case Iop_QAdd16Sx8: case Iop_QAdd8Sx16:
+ case Iop_QAdd64Ux2: case Iop_QAdd32Ux4:
+ case Iop_QAdd16Ux8: case Iop_QAdd8Ux16:
+ case Iop_QSub64Sx2: case Iop_QSub32Sx4:
+ case Iop_QSub16Sx8: case Iop_QSub8Sx16:
+ case Iop_QSub64Ux2: case Iop_QSub32Ux4:
+ case Iop_QSub16Ux8: case Iop_QSub8Ux16:
{
HReg res = newVRegV(env);
HReg argL = iselV128Expr(env, e->Iex.Binop.arg1);
@@ -5080,6 +5032,22 @@
case Iop_InterleaveLO8x16: op = ARM64vecb_ZIP18x16; sw = True;
break;
case Iop_PolynomialMul8x16: op = ARM64vecb_PMUL8x16; break;
+ case Iop_QAdd64Sx2: op = ARM64vecb_SQADD64x2; break;
+ case Iop_QAdd32Sx4: op = ARM64vecb_SQADD32x4; break;
+ case Iop_QAdd16Sx8: op = ARM64vecb_SQADD16x8; break;
+ case Iop_QAdd8Sx16: op = ARM64vecb_SQADD8x16; break;
+ case Iop_QAdd64Ux2: op = ARM64vecb_UQADD64x2; break;
+ case Iop_QAdd32Ux4: op = ARM64vecb_UQADD32x4; break;
+ case Iop_QAdd16Ux8: op = ARM64vecb_UQADD16x8; break;
+ case Iop_QAdd8Ux16: op = ARM64vecb_UQADD8x16; break;
+ case Iop_QSub64Sx2: op = ARM64vecb_SQSUB64x2; break;
+ case Iop_QSub32Sx4: op = ARM64vecb_SQSUB32x4; break;
+ case Iop_QSub16Sx8: op = ARM64vecb_SQSUB16x8; break;
+ case Iop_QSub8Sx16: op = ARM64vecb_SQSUB8x16; break;
+ case Iop_QSub64Ux2: op = ARM64vecb_UQSUB64x2; break;
+ case Iop_QSub32Ux4: op = ARM64vecb_UQSUB32x4; break;
+ case Iop_QSub16Ux8: op = ARM64vecb_UQSUB16x8; break;
+ case Iop_QSub8Ux16: op = ARM64vecb_UQSUB8x16; break;
default: vassert(0);
}
if (sw) {
Modified: trunk/priv/ir_defs.c
==============================================================================
--- trunk/priv/ir_defs.c (original)
+++ trunk/priv/ir_defs.c Mon Jun 30 07:33:56 2014
@@ -2818,14 +2818,14 @@
case Iop_Add8x16: case Iop_Add16x8:
case Iop_Add32x4: case Iop_Add64x2:
case Iop_QAdd8Ux16: case Iop_QAdd16Ux8:
- case Iop_QAdd32Ux4: //case Iop_QAdd64Ux2:
+ case Iop_QAdd32Ux4: case Iop_QAdd64Ux2:
case Iop_QAdd8Sx16: case Iop_QAdd16Sx8:
case Iop_QAdd32Sx4: case Iop_QAdd64Sx2:
case Iop_PwAdd8x16: case Iop_PwAdd16x8: case Iop_PwAdd32x4:
case Iop_Sub8x16: case Iop_Sub16x8:
case Iop_Sub32x4: case Iop_Sub64x2:
case Iop_QSub8Ux16: case Iop_QSub16Ux8:
- case Iop_QSub32Ux4: //case Iop_QSub64Ux2:
+ case Iop_QSub32Ux4: case Iop_QSub64Ux2:
case Iop_QSub8Sx16: case Iop_QSub16Sx8:
case Iop_QSub32Sx4: case Iop_QSub64Sx2:
case Iop_Mul8x16: case Iop_Mul16x8: case Iop_Mul32x4:
|