ash: less hackish implementation of evaltreenr()

Defining a function alias with __attribute__ ((alias("evaltree"),__noreturn__))
is not that usual, and clang had a bug which made it misunderstand
this construct.

Switch to:
ALWAYS_INLINE NORETURN evaltreenr() { evaltree(); unreachable(); }

Older gcc's do not know unreachable(), on them we pay the price of having
a few extra calls to abort():

function                                             old     new   delta
evalsubshell                                         151     156      +5
evalpipe                                             357     362      +5
argstr                                              1141    1144      +3

On newer gcc, code size does not change.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2017-07-28 15:28:33 +02:00
parent 46f3f16b58
commit 619d9b5e68
2 changed files with 21 additions and 6 deletions

View File

@ -45,6 +45,13 @@
#define UNUSED_PARAM __attribute__ ((__unused__)) #define UNUSED_PARAM __attribute__ ((__unused__))
#define NORETURN __attribute__ ((__noreturn__)) #define NORETURN __attribute__ ((__noreturn__))
#if __GNUC_PREREQ(4,5)
# define bb_unreachable(altcode) __builtin_unreachable()
#else
# define bb_unreachable(altcode) altcode
#endif
/* "The malloc attribute is used to tell the compiler that a function /* "The malloc attribute is used to tell the compiler that a function
* may be treated as if any non-NULL pointer it returns cannot alias * may be treated as if any non-NULL pointer it returns cannot alias
* any other pointer valid when the function returns. This will often * any other pointer valid when the function returns. This will often

View File

@ -6137,6 +6137,19 @@ struct backcmd { /* result of evalbackcmd */
#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
static int evaltree(union node *, int); static int evaltree(union node *, int);
/* An evaltree() which is known to never return.
* Used to use an alias:
* static int evaltreenr(union node *, int) __attribute__((alias("evaltree"),__noreturn__));
* but clang was reported to "transfer" noreturn-ness to evaltree() as well.
*/
static ALWAYS_INLINE NORETURN void
evaltreenr(union node *n, int flags)
{
evaltree(n, flags);
bb_unreachable(abort());
/* NOTREACHED */
}
static void FAST_FUNC static void FAST_FUNC
evalbackcmd(union node *n, struct backcmd *result) evalbackcmd(union node *n, struct backcmd *result)
{ {
@ -6173,7 +6186,7 @@ evalbackcmd(union node *n, struct backcmd *result)
*/ */
eflag = 0; eflag = 0;
ifsfree(); ifsfree();
evaltree(n, EV_EXIT); /* actually evaltreenr... */ evaltreenr(n, EV_EXIT);
/* NOTREACHED */ /* NOTREACHED */
} }
/* parent */ /* parent */
@ -8796,11 +8809,6 @@ evaltree(union node *n, int flags)
return exitstatus; return exitstatus;
} }
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
static
#endif
int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
static int static int
skiploop(void) skiploop(void)
{ {