This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c/46711] New: __builtin_choose_expr checks not chosen expression
- From: "przemoc at gmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Mon, 29 Nov 2010 19:34:53 +0000
- Subject: [Bug c/46711] New: __builtin_choose_expr checks not chosen expression
- Auto-submitted: auto-generated
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.