0005-committed-RISC-V-Avoid-sub-word-mode-comparisons-wit.patch 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. From ac7d33ee174d69be62cda1295324ab34338f71b1 Mon Sep 17 00:00:00 2001
  2. From: Jeff Law <jlaw@ventanamicro.com>
  3. Date: Tue, 1 Aug 2023 23:12:16 -0600
  4. Subject: [PATCH 05/30] [committed] [RISC-V] Avoid sub-word mode comparisons
  5. with Zicond
  6. c-torture/execute/pr59014-2.c fails with the Zicond work on rv64. We
  7. miscompile the "foo" routine because we have eliminated a required sign
  8. extension.
  9. The key routine looks like this:
  10. foo (long long int x, long long int y)
  11. {
  12. if (((int) x | (int) y) != 0)
  13. return 6;
  14. return x + y;
  15. }
  16. So we kindof do the expected thing. We IOR X and Y, sign extend the result
  17. from 32 to 64 bits, then emit a suitable conditional branch. ie:
  18. > (insn 10 4 12 2 (set (reg:DI 142)
  19. > (ior:DI (reg/v:DI 138 [ x ])
  20. > (reg/v:DI 139 [ y ]))) "j.c":6:16 99 {iordi3}
  21. > (nil))
  22. > (insn 12 10 13 2 (set (reg:DI 144)
  23. > (sign_extend:DI (subreg:SI (reg:DI 142) 0))) "j.c":6:6 116 {extendsidi2}
  24. > (nil))
  25. > (jump_insn 13 12 14 2 (set (pc)
  26. > (if_then_else (ne (reg:DI 144)
  27. > (const_int 0 [0]))
  28. > (label_ref:DI 27)
  29. > (pc))) "j.c":6:6 243 {*branchdi}
  30. > (expr_list:REG_DEAD (reg:DI 144)
  31. > (int_list:REG_BR_PROB 233216732 (nil)))
  32. When we if-convert that we generate this sequence:
  33. > (insn 10 4 12 2 (set (reg:DI 142)
  34. > (ior:DI (reg/v:DI 138 [ x ])
  35. > (reg/v:DI 139 [ y ]))) "j.c":6:16 99 {iordi3}
  36. > (nil))
  37. > (insn 12 10 30 2 (set (reg:DI 144)
  38. > (sign_extend:DI (subreg:SI (reg:DI 142) 0))) "j.c":6:6 116 {extendsidi2}
  39. > (nil))
  40. > (insn 30 12 31 2 (set (reg:DI 147)
  41. > (const_int 6 [0x6])) "j.c":8:12 179 {*movdi_64bit}
  42. > (nil))
  43. > (insn 31 30 33 2 (set (reg:DI 146)
  44. > (plus:DI (reg/v:DI 138 [ x ])
  45. > (reg/v:DI 139 [ y ]))) "j.c":8:12 5 {adddi3}
  46. > (nil))
  47. > (insn 33 31 34 2 (set (reg:DI 149)
  48. > (if_then_else:DI (ne:DI (reg:DI 144)
  49. > (const_int 0 [0]))
  50. > (const_int 0 [0])
  51. > (reg:DI 146))) "j.c":8:12 11368 {*czero.nez.didi}
  52. > (nil))
  53. > (insn 34 33 35 2 (set (reg:DI 148)
  54. > (if_then_else:DI (eq:DI (reg:DI 144)
  55. > (const_int 0 [0]))
  56. > (const_int 0 [0])
  57. > (reg:DI 147))) "j.c":8:12 11367 {*czero.eqz.didi}
  58. > (nil))
  59. > (insn 35 34 21 2 (set (reg:DI 137 [ <retval> ])
  60. > (ior:DI (reg:DI 148)
  61. > (reg:DI 149))) "j.c":8:12 99 {iordi3}
  62. > (nil))
  63. Which looks basically OK. The sign extended subreg is a bit worrisome though.
  64. And sure enough when we get into combine:
  65. > Failed to match this instruction:
  66. > (parallel [
  67. > (set (reg:DI 149)
  68. > (if_then_else:DI (eq:DI (subreg:SI (reg:DI 142) 0)
  69. > (const_int 0 [0]))
  70. > (reg:DI 146)
  71. > (const_int 0 [0])))
  72. > (set (reg:DI 144)
  73. > (sign_extend:DI (subreg:SI (reg:DI 142) 0)))
  74. > ])
  75. > Successfully matched this instruction:
  76. > (set (reg:DI 144)
  77. > (sign_extend:DI (subreg:SI (reg:DI 142) 0)))
  78. > Successfully matched this instruction:
  79. > (set (reg:DI 149)
  80. > (if_then_else:DI (eq:DI (subreg:SI (reg:DI 142) 0)
  81. > (const_int 0 [0]))
  82. > (reg:DI 146)
  83. > (const_int 0 [0])))
  84. > allowing combination of insns 12 and 33
  85. Since we need the side effect we first try the PARALLEL with two sets.
  86. That, as expected, fails. Generic combine code then tries to pull apart
  87. the two sets as distinct insns resulting in this conditional move:
  88. > (insn 33 31 34 2 (set (reg:DI 149)
  89. > (if_then_else:DI (eq:DI (subreg:SI (reg:DI 142) 0)
  90. > (const_int 0 [0]))
  91. > (reg:DI 146)
  92. > (const_int 0 [0]))) "j.c":8:12 11347 {*czero.nez.disi}
  93. > (expr_list:REG_DEAD (reg:DI 146)
  94. > (nil)))
  95. Bzzt. We can't actually implement this RTL in the hardware. Basically
  96. it's asking to do 32bit comparison on rv64, ignoring the upper 32 bits
  97. of the input register. That's not actually how zicond works.
  98. The operands to the comparison need to be in DImode for rv64 and SImode
  99. for rv32. That's the X iterator. Note the mode of the comparison
  100. operands may be different than the mode of the destination. ie, we might
  101. have a 64bit comparison and produce a 32bit sign extended result much
  102. like the setcc insns support.
  103. This patch changes the 6 zicond patterns to use the X iterator on the
  104. comparison inputs and fixes the testsuite failure.
  105. gcc/
  106. * config/riscv/zicond.md: Use the X iterator instead of ANYI
  107. on the comparison input operands.
  108. ---
  109. gcc/config/riscv/zicond.md | 24 ++++++++++++------------
  110. 1 file changed, 12 insertions(+), 12 deletions(-)
  111. diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
  112. index 723a22422e1..8f24b3a1690 100644
  113. --- a/gcc/config/riscv/zicond.md
  114. +++ b/gcc/config/riscv/zicond.md
  115. @@ -22,9 +22,9 @@
  116. (define_code_attr nez [(eq "eqz") (ne "nez")])
  117. ;; Zicond
  118. -(define_insn "*czero.<eqz>.<GPR:mode><ANYI:mode>"
  119. +(define_insn "*czero.<eqz>.<GPR:mode><X:mode>"
  120. [(set (match_operand:GPR 0 "register_operand" "=r")
  121. - (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
  122. + (if_then_else:GPR (eq_or_ne (match_operand:X 1 "register_operand" "r")
  123. (const_int 0))
  124. (match_operand:GPR 2 "register_operand" "r")
  125. (const_int 0)))]
  126. @@ -32,9 +32,9 @@
  127. "czero.<eqz>\t%0,%2,%1"
  128. )
  129. -(define_insn "*czero.<nez>.<GPR:mode><ANYI:mode>"
  130. +(define_insn "*czero.<nez>.<GPR:mode><X:mode>"
  131. [(set (match_operand:GPR 0 "register_operand" "=r")
  132. - (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
  133. + (if_then_else:GPR (eq_or_ne (match_operand:X 1 "register_operand" "r")
  134. (const_int 0))
  135. (const_int 0)
  136. (match_operand:GPR 2 "register_operand" "r")))]
  137. @@ -43,9 +43,9 @@
  138. )
  139. ;; Special optimization under eq/ne in primitive semantics
  140. -(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt1"
  141. +(define_insn "*czero.eqz.<GPR:mode><X:mode>.opt1"
  142. [(set (match_operand:GPR 0 "register_operand" "=r")
  143. - (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
  144. + (if_then_else:GPR (eq (match_operand:X 1 "register_operand" "r")
  145. (const_int 0))
  146. (match_operand:GPR 2 "register_operand" "1")
  147. (match_operand:GPR 3 "register_operand" "r")))]
  148. @@ -53,9 +53,9 @@
  149. "czero.eqz\t%0,%3,%1"
  150. )
  151. -(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt2"
  152. +(define_insn "*czero.eqz.<GPR:mode><X:mode>.opt2"
  153. [(set (match_operand:GPR 0 "register_operand" "=r")
  154. - (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
  155. + (if_then_else:GPR (eq (match_operand:X 1 "register_operand" "r")
  156. (const_int 0))
  157. (match_operand:GPR 2 "register_operand" "r")
  158. (match_operand:GPR 3 "register_operand" "1")))]
  159. @@ -63,9 +63,9 @@
  160. "czero.nez\t%0,%2,%1"
  161. )
  162. -(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt3"
  163. +(define_insn "*czero.nez.<GPR:mode><X:mode>.opt3"
  164. [(set (match_operand:GPR 0 "register_operand" "=r")
  165. - (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
  166. + (if_then_else:GPR (ne (match_operand:X 1 "register_operand" "r")
  167. (const_int 0))
  168. (match_operand:GPR 2 "register_operand" "r")
  169. (match_operand:GPR 3 "register_operand" "1")))]
  170. @@ -73,9 +73,9 @@
  171. "czero.eqz\t%0,%2,%1"
  172. )
  173. -(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt4"
  174. +(define_insn "*czero.nez.<GPR:mode><X:mode>.opt4"
  175. [(set (match_operand:GPR 0 "register_operand" "=r")
  176. - (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
  177. + (if_then_else:GPR (ne (match_operand:X 1 "register_operand" "r")
  178. (const_int 0))
  179. (match_operand:GPR 2 "register_operand" "1")
  180. (match_operand:GPR 3 "register_operand" "r")))]
  181. --
  182. 2.25.1