https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95267
Bug ID: 95267
Summary: [ICE][gcse]: in process_insert_insn at gcse.c
Product: gcc
Version: 7.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: xuemaosheng at huawei dot com
Target Milestone: ---
In rtl-optimization gcse pass produces a invalid insn, and finally in function
process_insert_insn reach the code gcc_unreachable ().
static rtx_insn *
process_insert_insn (struct gcse_expr *expr)
{
......
else
{
rtx_insn *insn = emit_insn (gen_rtx_SET (reg, exp));
if (insn_invalid_p (insn, false))
gcc_unreachable ();
}
.....
}
function backtrace is shown as the following:
0xa127cc process_insert_insn
/gcc/gcse.c:2074
0xa12cce pre_edge_insert
gcc/gcse.c:2244
0xa137ee pre_gcse
/gcc/gcse.c:2636
0xa1394f one_pre_gcse_pass
/gcc/gcse.c:2691
0xa169cd execute_rtl_pre
/gcc/gcse.c:4097
0xa16a80 execute
/gcc/gcse.c:4141
the invalid insn produced by gcse pass is shown as the following:
(insn 423 0 0 (set (reg:V8HF16 442 [ userDagc ])
(unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 234 [ userDagc ])
] UNSPEC_MOVTVFM)) -1
(nil))
while the original valid insn is shown as the followig:
(insn 261 262 263 30 (set (reg/v:V8HF16 236 [ userDagc ])
(unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 236 [ userDagc ])
] UNSPEC_MOVTVFM))
"/home2/w00364751/L1Rat/UBBP/src/RatV2/L1Uudp/Srs/nMM/MeasProc/Scheduler/ProcSchedule/src/SRS_UserProc_FDDMM_Private.c":1156
433 {movtv8hf16}
(expr_list:REG_EQUAL (unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 234 [ userDagc ])
] UNSPEC_MOVTVFM)
(nil)))
After our analysis, we think that the source of invalid insn is the function
can_assign_to_reg_without_clobbers_p.
function backtrace is shown as the following:
#0 can_assign_to_reg_without_clobbers_p (x=0x7ffff7234460, mode=V8HF16mode) at
/gcc/gcse.c:882
#1 0x0000000000a0fe9e in want_to_gcse_p (x=0x7ffff7234460, mode=V8HF16mode,
max_distance_ptr=0x0) at /gcc/gcse.c:819
#2 0x0000000000a10a71 in hash_scan_set (set=0x7ffff71fe910,
insn=0x7ffff71ff370, table=0x1c39980 <expr_hash_table>)
at /gcc/gcse.c:1260
#3 0x0000000000a10dbc in hash_scan_insn (insn=0x7ffff71ff370, table=0x1c39980
<expr_hash_table>) at /gcc/gcse.c:1370
#4 0x0000000000a11947 in compute_hash_table_work (table=0x1c39980
<expr_hash_table>) at /gcc/gcse.c:1625
#5 0x0000000000a11a95 in compute_hash_table (table=0x1c39980
<expr_hash_table>) at /gcc/gcse.c:1674
#6 0x0000000000a138de in one_pre_gcse_pass () at
/gcc/gcse.c:2680
#7 0x0000000000a169ce in execute_rtl_pre () at
/gcc/gcse.c:4097
the function can_assign_to_reg_without_clobbers_p return true if we can assign
X to a pseudo register of mode MODE such that the resulting insn does not
result in clobbering a hard register as a side-effect.
In our target, the insn is valid since operands[0] is inout reg, this means
that
the insn 262 not only define reg/v:V8HF16 236, but also use reg/v:V8HF16 236.
(insn 261 262 263 30 (set (reg/v:V8HF16 236 [ userDagc ])
(unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 236 [ userDagc ])
] UNSPEC_MOVTVFM))
the REG_EQUAL is
(expr_list:REG_EQUAL (unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 234 [ userDagc ])
] UNSPEC_MOVTVFM)
(nil)))
the function can_assign_to_reg_without_clobbers_p use TEST_INSN to judge the
REG_EQUAL is valid or not.
the SET_DEST of TEST_INSN use the regno of FIRST_PSEUDO_REGISTER * 2;
if out target FIRST_PSEUDO_REGISTER is 117, which means that
FIRST_PSEUDO_REGISTER * 2 = 234.
the TEST_ISNN became the following code.
(insn 63 0 0 (set (reg:V8HF16 234)
(unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 234 [ userDagc ])
] UNSPEC_MOVTVFM)) -1
(nil))
the insn looks like a valid insn. However, this is a coincidence,because
FIRST_PSEUDO_REGISTER * 2 = 234, regno 234 is the same as the use reg
reg/v:V8HF16 234, the insn output operands[0],looks like a inout reg.
If FIRST_PSEUDO_REGISTER is 100 in my target, then the pattern would become
(insn 63 0 0 (set (reg:V8HF16 200)
(unspec:V8HF16 [
(reg:V8HF16 171 [ _54 ])
(reg/v:BF8 235 [ boolRsrp ])
(reg/v:V8HF16 234 [ userDagc ])
] UNSPEC_MOVTVFM)) -1
(nil))
Then the pattern would be invalid.
bool
can_assign_to_reg_without_clobbers_p (rtx x, machine_mode mode)
{
......
/* Otherwise, check if we can make a valid insn from it. First initialize
our test insn if we haven't already. */
if (test_insn == 0)
{
test_insn
= make_insn_raw (gen_rtx_SET (gen_rtx_REG (word_mode,
FIRST_PSEUDO_REGISTER * 2),
const0_rtx));
SET_NEXT_INSN (test_insn) = SET_PREV_INSN (test_insn) = 0;
INSN_LOCATION (test_insn) = UNKNOWN_LOCATION;
}
/* Now make an insn like the one we would make when GCSE'ing and see if
valid. */
PUT_MODE (SET_DEST (PATTERN (test_insn)), mode);
SET_SRC (PATTERN (test_insn)) = x;
icode = recog (PATTERN (test_insn), test_insn, &num_clobbers);
......
return can_assign;
}
So in my opinion, the TEST_INSN use a stable regno FIRST_PSEUDO_REGISTER * 2 in
some case would make some invalid pattern looks like a valid pattern, and
finally will cause internal compiler error.
So can we initialize the SET_DEST every times rather than only initialize once
And use max_reg_num to replace FIRST_PSEUDO_REGISTER * 2 ?
@@ -851,15 +851,12 @@ can_assign_to_reg_without_clobbers_p (rtx x, machine_mode
mode)
/* Otherwise, check if we can make a valid insn from it. First initialize
our test insn if we haven't already. */
- if (test_insn == 0)
- {
- test_insn
- = make_insn_raw (gen_rtx_SET (gen_rtx_REG (word_mode,
- FIRST_PSEUDO_REGISTER * 2),
- const0_rtx));
- SET_NEXT_INSN (test_insn) = SET_PREV_INSN (test_insn) = 0;
- INSN_LOCATION (test_insn) = UNKNOWN_LOCATION;
- }
+ test_insn = NULL;
+ test_insn
+ = make_insn_raw (gen_rtx_SET (gen_rtx_REG (word_mode, max_reg_num ()),
+ const0_rtx));
+ SET_NEXT_INSN (test_insn) = SET_PREV_INSN (test_insn) = 0;
+ INSN_LOCATION (test_insn) = UNKNOWN_LOCATION;