This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/46711] New: __builtin_choose_expr checks not chosen expression


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46711

           Summary: __builtin_choose_expr checks not chosen expression
           Product: gcc
           Version: 4.4.5
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: przemoc@gmail.com


Created attachment 22569
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=22569
Test case.

Built-in Function: type __builtin_choose_expr (const_exp, exp1, exp2)

Excerpts from doc:

This built-in function is analogous to the `? :' operator in C, except that the
expression returned has its type unaltered by promotion rules. Also, the
built-in function does not evaluate the expression that was not chosen.

Note: This construct is only available for C. Furthermore, the unused
expression (exp1 or exp2 depending on the value of const_exp) may still
generate syntax errors. This may change in future revisions.

-- http://gcc.gnu.org/onlinedocs/gcc-4.5.1/gcc/Other-Builtins.html


#include <stdio.h>

int main()
{
    int a = 0;

    printf("a is %s\n", 
        __builtin_choose_expr(__builtin_constant_p(a),
            __builtin_choose_expr((a) == 0,
                "constant 0",
                __builtin_choose_expr((a) == 1,
                    "constant 1",
                    "constant non-{0,1}"
                )
            ),
            "non-constant"
        )
    );

    return 0;
}
(attached also as a file)

__builtin_choose_expr.c: In function âmainâ:
__builtin_choose_expr.c:11: error: first argument to â__builtin_choose_exprâ
not a constant
__builtin_choose_expr.c:9: error: first argument to â__builtin_choose_exprâ not
a constant


It's theoretically correct according to the note mentioned before, but it
rather should compile without errors.
[ BTW when you run gcc with optimization, i.e. -On, where n > 0, it shows also
a bug 19449:
__builtin_choose_expr.c:8: error: first argument to â__builtin_choose_exprâ not
a constant ]

Expressions are checked in bottom-up order, which is fine, but only for
const_exp part. exp1 or exp2 shall be checked only if const_exp is true or
false respectively, avoiding the not chosen expression.

Example I gave you above is simple and imaginary, but it shows that
__builtin_choose_expr combined with other builtins (such as
__builtin_constant_p) can be useful. Moreover, as it can return lvalue, it's
cannot be easily replaced without introducing function with ifs or switch and
returning pointer to some type.


Better example (linux kernel-space):

#ifdef CONFIG_X86_64
# define PARAM0(regs) (regs)->di
# define PARAM1(regs) (regs)->si
# define PARAM2(regs) (regs)->dx
# define PARAM3(regs) (regs)->r10
# define PARAM4(regs) (regs)->r8
# define PARAM5(regs) (regs)->r9
static inline unsigned long *
_param(struct pt_regs *regs, int num)
{
    switch (num) {
    case 0: return &PARAM0(regs);
    case 1: return &PARAM1(regs);
    case 2: return &PARAM2(regs);
    case 3: return &PARAM3(regs);
    case 4: return &PARAM4(regs);
    case 5: return &PARAM5(regs);
    }

    /* should not happen */
    return NULL;
}
# define PARAM(regs, num) \
    __builtin_choose_expr(__builtin_constant_p((num)), \
        __builtin_choose_expr((num) == 0, PARAM0(regs), \
        __builtin_choose_expr((num) == 1, PARAM1(regs), \
        __builtin_choose_expr((num) == 2, PARAM2(regs), \
        __builtin_choose_expr((num) == 3, PARAM3(regs), \
        __builtin_choose_expr((num) == 4, PARAM4(regs), \
        __builtin_choose_expr((num) == 5, PARAM5(regs), 0)))))), \
        *_param(regs, num)
    )
#endif

PARAM can be even simplified:

# define PARAM(regs, num) \
    __builtin_choose_expr(__builtin_constant_p(num), \
        __builtin_choose_expr((num) < 6, \
            PARAM##num(regs), \
            0 \
        ), \
        *_param(regs, num)) \
    )

In either case it unfortunately doesn't work now.
Theoretically I can use the function directly, but it isn't inlined with known
result for constant expressions.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]