https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124007
Bug ID: 124007
Summary: Improve branch-on-bit code generation
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: law at gcc dot gnu.org
Target Milestone: ---
Marking as tree-optimization for now. Depending on what is found during
investigation that could clearly change.
Compile with -O2 -march=rv64gcb_zicond on riscv64:
union tree_node;
typedef union tree_node *tree;
typedef const union tree_node *const_tree;
typedef struct
{
unsigned long low;
long high;
} double_int;
struct tree_base {
unsigned int code : 16;
unsigned side_effects_flag : 1;
unsigned constant_flag : 1;
unsigned addressable_flag : 1;
unsigned volatile_flag : 1;
unsigned readonly_flag : 1;
unsigned unsigned_flag : 1;
unsigned asm_written_flag: 1;
unsigned nowarning_flag : 1;
unsigned used_flag : 1;
unsigned nothrow_flag : 1;
unsigned static_flag : 1;
unsigned public_flag : 1;
unsigned private_flag : 1;
unsigned protected_flag : 1;
unsigned deprecated_flag : 1;
unsigned saturating_flag : 1;
unsigned default_def_flag : 1;
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
unsigned lang_flag_2 : 1;
unsigned lang_flag_3 : 1;
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned visited : 1;
unsigned packed_flag : 1;
unsigned user_align : 1;
unsigned spare : 13;
unsigned address_space : 8;
};
struct tree_common {
struct tree_base base;
tree chain;
tree type;
};
struct tree_int_cst {
double_int int_cst;
};
union tree_node {
struct tree_base base;
struct tree_common common;
struct tree_int_cst int_cst;
};
int tree_int_cst_sgn (const_tree);
int
tree_int_cst_lt (const_tree t1, const_tree t2)
{
if (t1 == t2)
return 0;
if (((((t1)->common.type))->base.unsigned_flag) !=
((((t2)->common.type))->base.unsigned_flag))
{
int t1_sgn = tree_int_cst_sgn (t1);
int t2_sgn = tree_int_cst_sgn (t2);
if (t1_sgn < t2_sgn)
return 1;
else if (t1_sgn > t2_sgn)
return 0;
}
else if (!((((t1)->common.type))->base.unsigned_flag))
return ((((t1)->int_cst.int_cst).high) < (((t2)->int_cst.int_cst).high) ||
((((t1)->int_cst.int_cst).high) == (((t2)->int_cst.int_cst).h
igh) && (((t1)->int_cst.int_cst).low) < (((t2)->int_cst.int_cst).low)));
return (((unsigned long) (((t1)->int_cst.int_cst).high) < (unsigned long)
(((t2)->int_cst.int_cst).high)) || (((unsigned long) (((t1)->int
_cst.int_cst).high) == (unsigned long) (((t2)->int_cst.int_cst).high)) &&
(((t1)->int_cst.int_cst).low) < (((t2)->int_cst.int_cst).low)));
}
Note the insns starting with the xor:
xor a5,a4,a5
slli a3,a5,42
blt a3,zero,.L19
slli a5,a4,42
bge a5,zero,.L20
It seems like the xor+2 slli instructions could be replaced with two bexti
instrutions (and corresponding adjustments to the branches). My notes indicate
that LLVM handles this better than GCC.