0004-gas-use-literals-const16-for-xtensa-loop-relaxation.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. From 0dbdfb7918d0b0cfcb8883b24c1291574bf5bb7c Mon Sep 17 00:00:00 2001
  2. From: Max Filippov <jcmvbkbc@gmail.com>
  3. Date: Tue, 2 Apr 2019 14:32:42 -0700
  4. Subject: [PATCH] gas: use literals/const16 for xtensa loop relaxation
  5. Loop opcode relaxation that uses addi/addmi doesn't work well with other
  6. relaxations that may cause code movement. Instead of encoding fixed loop
  7. end offset in the relaxed sequence use l32r or a pair of const16 to load
  8. loop end address. This way the address of the loop end gets a relocation
  9. record and it gets updated appropriately.
  10. gas/
  11. 2019-04-02 Max Filippov <jcmvbkbc@gmail.com>
  12. * config/tc-xtensa.c (convert_frag_immed): Drop
  13. convert_frag_immed_finish_loop invocation.
  14. (convert_frag_immed_finish_loop): Drop declaration and
  15. definition.
  16. * config/xtensa-relax.c (widen_spec_list): Replace loop
  17. widening that uses addi/addmi with widening that uses l32r
  18. and const16.
  19. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
  20. ---
  21. gas/config/tc-xtensa.c | 120 ----------------------------------------------
  22. gas/config/xtensa-relax.c | 77 ++++++++++++++++++++---------
  23. 2 files changed, 55 insertions(+), 142 deletions(-)
  24. diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
  25. index 3bdbbc931cfc..0cc06361cf6f 100644
  26. --- a/gas/config/tc-xtensa.c
  27. +++ b/gas/config/tc-xtensa.c
  28. @@ -10668,7 +10668,6 @@ convert_frag_fill_nop (fragS *fragP)
  29. static fixS *fix_new_exp_in_seg
  30. (segT, subsegT, fragS *, int, int, expressionS *, int,
  31. bfd_reloc_code_real_type);
  32. -static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *);
  33. static void
  34. convert_frag_immed (segT segP,
  35. @@ -10910,9 +10909,6 @@ convert_frag_immed (segT segP,
  36. }
  37. }
  38. - if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1)
  39. - convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn);
  40. -
  41. if (expanded && is_direct_call_opcode (orig_tinsn.opcode))
  42. {
  43. /* Add an expansion note on the expanded instruction. */
  44. @@ -10949,122 +10945,6 @@ fix_new_exp_in_seg (segT new_seg,
  45. }
  46. -/* Relax a loop instruction so that it can span loop >256 bytes.
  47. -
  48. - loop as, .L1
  49. - .L0:
  50. - rsr as, LEND
  51. - wsr as, LBEG
  52. - addi as, as, lo8 (label-.L1)
  53. - addmi as, as, mid8 (label-.L1)
  54. - wsr as, LEND
  55. - isync
  56. - rsr as, LCOUNT
  57. - addi as, as, 1
  58. - .L1:
  59. - <<body>>
  60. - label:
  61. -*/
  62. -
  63. -static void
  64. -convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
  65. -{
  66. - TInsn loop_insn;
  67. - TInsn addi_insn;
  68. - TInsn addmi_insn;
  69. - unsigned long target;
  70. - static xtensa_insnbuf insnbuf = NULL;
  71. - unsigned int loop_length, loop_length_hi, loop_length_lo;
  72. - xtensa_isa isa = xtensa_default_isa;
  73. - addressT loop_offset;
  74. - addressT addi_offset = 9;
  75. - addressT addmi_offset = 12;
  76. - fragS *next_fragP;
  77. - int target_count;
  78. -
  79. - if (!insnbuf)
  80. - insnbuf = xtensa_insnbuf_alloc (isa);
  81. -
  82. - /* Get the loop offset. */
  83. - loop_offset = get_expanded_loop_offset (tinsn->opcode);
  84. -
  85. - /* Validate that there really is a LOOP at the loop_offset. Because
  86. - loops are not bundleable, we can assume that the instruction will be
  87. - in slot 0. */
  88. - tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0);
  89. - tinsn_immed_from_frag (&loop_insn, fragP, 0);
  90. -
  91. - gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
  92. - addi_offset += loop_offset;
  93. - addmi_offset += loop_offset;
  94. -
  95. - gas_assert (tinsn->ntok == 2);
  96. - if (tinsn->tok[1].X_op == O_constant)
  97. - target = tinsn->tok[1].X_add_number;
  98. - else if (tinsn->tok[1].X_op == O_symbol)
  99. - {
  100. - /* Find the fragment. */
  101. - symbolS *sym = tinsn->tok[1].X_add_symbol;
  102. - gas_assert (S_GET_SEGMENT (sym) == segP
  103. - || S_GET_SEGMENT (sym) == absolute_section);
  104. - target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number);
  105. - }
  106. - else
  107. - {
  108. - as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op);
  109. - target = 0;
  110. - }
  111. -
  112. - loop_length = target - (fragP->fr_address + fragP->fr_fix);
  113. - loop_length_hi = loop_length & ~0x0ff;
  114. - loop_length_lo = loop_length & 0x0ff;
  115. - if (loop_length_lo >= 128)
  116. - {
  117. - loop_length_lo -= 256;
  118. - loop_length_hi += 256;
  119. - }
  120. -
  121. - /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most
  122. - 32512. If the loop is larger than that, then we just fail. */
  123. - if (loop_length_hi > 32512)
  124. - as_bad_where (fragP->fr_file, fragP->fr_line,
  125. - _("loop too long for LOOP instruction"));
  126. -
  127. - tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0);
  128. - gas_assert (addi_insn.opcode == xtensa_addi_opcode);
  129. -
  130. - tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
  131. - gas_assert (addmi_insn.opcode == xtensa_addmi_opcode);
  132. -
  133. - set_expr_const (&addi_insn.tok[2], loop_length_lo);
  134. - tinsn_to_insnbuf (&addi_insn, insnbuf);
  135. -
  136. - fragP->tc_frag_data.is_insn = TRUE;
  137. - xtensa_insnbuf_to_chars
  138. - (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0);
  139. -
  140. - set_expr_const (&addmi_insn.tok[2], loop_length_hi);
  141. - tinsn_to_insnbuf (&addmi_insn, insnbuf);
  142. - xtensa_insnbuf_to_chars
  143. - (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0);
  144. -
  145. - /* Walk through all of the frags from here to the loop end
  146. - and mark them as no_transform to keep them from being modified
  147. - by the linker. If we ever have a relocation for the
  148. - addi/addmi of the difference of two symbols we can remove this. */
  149. -
  150. - target_count = 0;
  151. - for (next_fragP = fragP; next_fragP != NULL;
  152. - next_fragP = next_fragP->fr_next)
  153. - {
  154. - next_fragP->tc_frag_data.is_no_transform = TRUE;
  155. - if (next_fragP->tc_frag_data.is_loop_target)
  156. - target_count++;
  157. - if (target_count == 2)
  158. - break;
  159. - }
  160. -}
  161. -
  162. /* A map that keeps information on a per-subsegment basis. This is
  163. maintained during initial assembly, but is invalid once the
  164. diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c
  165. index cb296ed85ed2..daf15d52c259 100644
  166. --- a/gas/config/xtensa-relax.c
  167. +++ b/gas/config/xtensa-relax.c
  168. @@ -87,13 +87,7 @@
  169. when the first and second operands are not the same as specified
  170. by the "| %at!=%as" precondition clause.
  171. {"l32i %at,%as,%imm | %at!=%as",
  172. - "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"}
  173. -
  174. - There is special case for loop instructions here, but because we do
  175. - not currently have the ability to represent the difference of two
  176. - symbols, the conversion requires special code in the assembler to
  177. - write the operands of the addi/addmi pair representing the
  178. - difference of the old and new loop end label. */
  179. + "LITERAL %imm; l32r %at,%LITERAL; add %at,%at,%as; l32i %at,%at,0"} */
  180. #include "as.h"
  181. #include "xtensa-isa.h"
  182. @@ -306,44 +300,83 @@ static string_pattern_pair widen_spec_list[] =
  183. {"l32i %at,%as,%imm | %at!=%as ? IsaUseConst16",
  184. "const16 %at,HI16U(%imm); const16 %at,LOW16U(%imm); add %at,%at,%as; l32i %at,%at,0"},
  185. - /* This is only PART of the loop instruction. In addition,
  186. - hardcoded into its use is a modification of the final operand in
  187. - the instruction in bytes 9 and 12. */
  188. - {"loop %as,%label | %as!=1 ? IsaUseLoops",
  189. + /* Widening loops with literals. */
  190. + {"loop %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
  191. + "loop %as,%LABEL;"
  192. + "rsr.lend %as;" /* LEND */
  193. + "wsr.lbeg %as;" /* LBEG */
  194. + "LITERAL %label;"
  195. + "l32r %as, %LITERAL;"
  196. + "nop;"
  197. + "wsr.lend %as;"
  198. + "isync;"
  199. + "rsr.lcount %as;" /* LCOUNT */
  200. + "addi %as, %as, 1;"
  201. + "LABEL"},
  202. + {"loopgtz %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
  203. + "beqz %as,%label;"
  204. + "bltz %as,%label;"
  205. + "loopgtz %as,%LABEL;"
  206. + "rsr.lend %as;" /* LEND */
  207. + "wsr.lbeg %as;" /* LBEG */
  208. + "LITERAL %label;"
  209. + "l32r %as, %LITERAL;"
  210. + "nop;"
  211. + "wsr.lend %as;"
  212. + "isync;"
  213. + "rsr.lcount %as;" /* LCOUNT */
  214. + "addi %as, %as, 1;"
  215. + "LABEL"},
  216. + {"loopnez %as,%label | %as!=1 ? IsaUseLoops ? IsaUseL32R",
  217. + "beqz %as,%label;"
  218. + "loopnez %as,%LABEL;"
  219. + "rsr.lend %as;" /* LEND */
  220. + "wsr.lbeg %as;" /* LBEG */
  221. + "LITERAL %label;"
  222. + "l32r %as, %LITERAL;"
  223. + "nop;"
  224. + "wsr.lend %as;"
  225. + "isync;"
  226. + "rsr.lcount %as;" /* LCOUNT */
  227. + "addi %as, %as, 1;"
  228. + "LABEL"},
  229. +
  230. + /* Widening loops with const16. */
  231. + {"loop %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
  232. "loop %as,%LABEL;"
  233. "rsr.lend %as;" /* LEND */
  234. "wsr.lbeg %as;" /* LBEG */
  235. - "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
  236. - "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
  237. + "const16 %as,HI16U(%label);"
  238. + "const16 %as,LOW16U(%label);"
  239. "wsr.lend %as;"
  240. "isync;"
  241. "rsr.lcount %as;" /* LCOUNT */
  242. - "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
  243. + "addi %as, %as, 1;"
  244. "LABEL"},
  245. - {"loopgtz %as,%label | %as!=1 ? IsaUseLoops",
  246. + {"loopgtz %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
  247. "beqz %as,%label;"
  248. "bltz %as,%label;"
  249. "loopgtz %as,%LABEL;"
  250. "rsr.lend %as;" /* LEND */
  251. "wsr.lbeg %as;" /* LBEG */
  252. - "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
  253. - "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
  254. + "const16 %as,HI16U(%label);"
  255. + "const16 %as,LOW16U(%label);"
  256. "wsr.lend %as;"
  257. "isync;"
  258. "rsr.lcount %as;" /* LCOUNT */
  259. - "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
  260. + "addi %as, %as, 1;"
  261. "LABEL"},
  262. - {"loopnez %as,%label | %as!=1 ? IsaUseLoops",
  263. + {"loopnez %as,%label | %as!=1 ? IsaUseLoops ? IsaUseConst16",
  264. "beqz %as,%label;"
  265. "loopnez %as,%LABEL;"
  266. "rsr.lend %as;" /* LEND */
  267. "wsr.lbeg %as;" /* LBEG */
  268. - "addi %as, %as, 0;" /* lo8(%label-%LABEL1) */
  269. - "addmi %as, %as, 0;" /* mid8(%label-%LABEL1) */
  270. + "const16 %as,HI16U(%label);"
  271. + "const16 %as,LOW16U(%label);"
  272. "wsr.lend %as;"
  273. "isync;"
  274. "rsr.lcount %as;" /* LCOUNT */
  275. - "addi %as, %as, 1;" /* density -> addi.n %as, %as, 1 */
  276. + "addi %as, %as, 1;"
  277. "LABEL"},
  278. /* Relaxing to wide branches. Order is important here. With wide
  279. --
  280. 2.11.0