1
0

trampolines.xtensa 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. From a82c7d9030b67a6a76a5403d0e1641f9e42141ac Mon Sep 17 00:00:00 2001
  2. From: David Weatherford <weath@cadence.com>
  3. Date: Fri, 21 Mar 2014 11:53:42 +0000
  4. Subject: [PATCH] Add support to the Xtensa target for creating trampolines for
  5. out-of-range branches.
  6. * tc-xtensa.c (xtensa_check_frag_count, xtensa_create_trampoline_frag)
  7. (xtensa_maybe_create_trampoline_frag, init_trampoline_frag)
  8. (find_trampoline_seg, search_trampolines, get_best_trampoline)
  9. (check_and_update_trampolines, add_jump_to_trampoline)
  10. (dump_trampolines): New function.
  11. (md_parse_option): Add cases for --[no-]trampolines options.
  12. (md_assemble, finish_vinsn, xtensa_end): Add call to
  13. xtensa_check_frag_count.
  14. (xg_assemble_vliw_tokens): Add call to
  15. xtensa_maybe_create_trampoline_frag.
  16. (xtensa_relax_frag): Relax fragments with RELAX_TRAMPOLINE state.
  17. (relax_frag_immed): Relax jump instructions that cannot reach its
  18. target.
  19. * tc-xtensa.h (xtensa_relax_statesE::RELAX_TRAMPOLINE): New relax
  20. state.
  21. * as.texinfo: Document --[no-]trampolines command-line options.
  22. * c-xtensa.texi: Document trampolines relaxation and command line
  23. options.
  24. * frags.c (get_frag_count, clear_frag_count): New function.
  25. (frag_alloc): Increment totalfrags counter.
  26. * frags.h (get_frag_count, clear_frag_count): New function.
  27. * all.exp: Add test for trampoline relaxation.
  28. * trampoline.d: Trampoline relaxation expected dump.
  29. * trampoline.s: Trampoline relaxation test source.
  30. ---
  31. Backported from: a82c7d9030b67a6a76a5403d0e1641f9e42141ac
  32. Changes to Changelog files are dropped.
  33. gas/config/tc-xtensa.c | 558 +++++++++++++++++++++++++++++++++-
  34. gas/config/tc-xtensa.h | 5 +
  35. gas/frags.c | 15 +
  36. gas/frags.h | 3 +
  37. gas/testsuite/gas/xtensa/all.exp | 1 +
  38. gas/testsuite/gas/xtensa/trampoline.d | 26 ++
  39. gas/testsuite/gas/xtensa/trampoline.s | 21 ++
  40. 11 files changed, 753 insertions(+), 2 deletions(-)
  41. create mode 100644 gas/testsuite/gas/xtensa/trampoline.d
  42. create mode 100644 gas/testsuite/gas/xtensa/trampoline.s
  43. diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
  44. index fe8ec0f..ea23c96 100644
  45. --- a/gas/config/tc-xtensa.c
  46. +++ b/gas/config/tc-xtensa.c
  47. @@ -468,6 +468,12 @@ static void xtensa_set_frag_assembly_state (fragS *);
  48. static void finish_vinsn (vliw_insn *);
  49. static bfd_boolean emit_single_op (TInsn *);
  50. static int total_frag_text_expansion (fragS *);
  51. +static bfd_boolean use_trampolines = TRUE;
  52. +static void xtensa_check_frag_count (void);
  53. +static void xtensa_create_trampoline_frag (bfd_boolean);
  54. +static void xtensa_maybe_create_trampoline_frag (void);
  55. +struct trampoline_frag;
  56. +static int init_trampoline_frag (struct trampoline_frag *);
  57. /* Alignment Functions. */
  58. @@ -520,6 +526,7 @@ static void tinsn_from_chars (TInsn *, char *, int);
  59. static void tinsn_immed_from_frag (TInsn *, fragS *, int);
  60. static int get_num_stack_text_bytes (IStack *);
  61. static int get_num_stack_literal_bytes (IStack *);
  62. +static bfd_boolean tinsn_to_slotbuf (xtensa_format, int, TInsn *, xtensa_insnbuf);
  63. /* vliw_insn functions. */
  64. @@ -687,7 +694,10 @@ enum
  65. option_prefer_l32r,
  66. option_prefer_const16,
  67. - option_target_hardware
  68. + option_target_hardware,
  69. +
  70. + option_trampolines,
  71. + option_no_trampolines,
  72. };
  73. const char *md_shortopts = "";
  74. @@ -760,6 +770,9 @@ struct option md_longopts[] =
  75. { "target-hardware", required_argument, NULL, option_target_hardware },
  76. + { "trampolines", no_argument, NULL, option_trampolines },
  77. + { "no-trampolines", no_argument, NULL, option_no_trampolines },
  78. +
  79. { NULL, no_argument, NULL, 0 }
  80. };
  81. @@ -940,6 +953,14 @@ md_parse_option (int c, char *arg)
  82. directive_state[directive_transform] = FALSE;
  83. return 1;
  84. + case option_trampolines:
  85. + use_trampolines = TRUE;
  86. + return 1;
  87. +
  88. + case option_no_trampolines:
  89. + use_trampolines = FALSE;
  90. + return 1;
  91. +
  92. default:
  93. return 0;
  94. }
  95. @@ -963,7 +984,9 @@ Xtensa options:\n\
  96. flix bundles\n\
  97. --no-allow-flix neither allow hand-written nor generate\n\
  98. flix bundles\n\
  99. - --rename-section old=new Rename section 'old' to 'new'\n", stream);
  100. + --rename-section old=new Rename section 'old' to 'new'\n\
  101. + --[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
  102. + when jumps do not reach their targets\n", stream);
  103. }
  104. @@ -5568,6 +5591,8 @@ md_assemble (char *str)
  105. /* We've just emitted a new instruction so clear the list of labels. */
  106. xtensa_clear_insn_labels ();
  107. +
  108. + xtensa_check_frag_count ();
  109. }
  110. @@ -6372,6 +6397,8 @@ finish_vinsn (vliw_insn *vinsn)
  111. xg_assemble_vliw_tokens (vinsn);
  112. xg_clear_vinsn (vinsn);
  113. +
  114. + xtensa_check_frag_count ();
  115. }
  116. @@ -7140,6 +7167,7 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
  117. RELAX_UNREACHABLE,
  118. frag_now->fr_symbol, frag_now->fr_offset, NULL);
  119. xtensa_set_frag_assembly_state (frag_now);
  120. + xtensa_maybe_create_trampoline_frag ();
  121. }
  122. else if (is_branch && do_align_targets ())
  123. {
  124. @@ -7222,9 +7250,164 @@ xtensa_end (void)
  125. xtensa_sanity_check ();
  126. xtensa_add_config_info ();
  127. +
  128. + xtensa_check_frag_count ();
  129. +}
  130. +
  131. +
  132. +struct trampoline_frag
  133. +{
  134. + struct trampoline_frag *next;
  135. + bfd_boolean needs_jump_around;
  136. + fragS *fragP;
  137. + fixS *fixP;
  138. +};
  139. +
  140. +struct trampoline_seg
  141. +{
  142. + struct trampoline_seg *next;
  143. + asection *seg;
  144. + struct trampoline_frag trampoline_list;
  145. +};
  146. +
  147. +static struct trampoline_seg trampoline_seg_list;
  148. +#define J_RANGE (128 * 1024)
  149. +
  150. +static int unreachable_count = 0;
  151. +
  152. +
  153. +static void
  154. +xtensa_maybe_create_trampoline_frag (void)
  155. +{
  156. + if (!use_trampolines)
  157. + return;
  158. +
  159. + /* We create an area for possible trampolines every 10 unreachable frags.
  160. + These are preferred over the ones not preceded by an unreachable frag,
  161. + because we don't have to jump around them. This function is called after
  162. + each RELAX_UNREACHABLE frag is created. */
  163. +
  164. + if (++unreachable_count > 10)
  165. + {
  166. + xtensa_create_trampoline_frag (FALSE);
  167. + clear_frag_count ();
  168. + unreachable_count = 0;
  169. + }
  170. +}
  171. +
  172. +static void
  173. +xtensa_check_frag_count (void)
  174. +{
  175. + if (!use_trampolines || frag_now->tc_frag_data.is_no_transform)
  176. + return;
  177. +
  178. + /* We create an area for possible trampolines every 8000 frags or so. This
  179. + is an estimate based on the max range of a "j" insn (+/-128K) divided
  180. + by a typical frag byte count (16), minus a few for safety. This function
  181. + is called after each source line is processed. */
  182. +
  183. + if (get_frag_count () > 8000)
  184. + {
  185. + xtensa_create_trampoline_frag (TRUE);
  186. + clear_frag_count ();
  187. + unreachable_count = 0;
  188. + }
  189. +}
  190. +
  191. +static xtensa_insnbuf trampoline_buf = NULL;
  192. +static xtensa_insnbuf trampoline_slotbuf = NULL;
  193. +
  194. +#define TRAMPOLINE_FRAG_SIZE 3000
  195. +
  196. +static void
  197. +xtensa_create_trampoline_frag (bfd_boolean needs_jump_around)
  198. +{
  199. + /* Emit a frag where we can place intermediate jump instructions,
  200. + in case we need to jump farther than 128K bytes.
  201. + Each jump instruction takes three bytes.
  202. + We allocate enough for 1000 trampolines in each frag.
  203. + If that's not enough, oh well. */
  204. +
  205. + struct trampoline_seg *ts = trampoline_seg_list.next;
  206. + struct trampoline_frag *tf;
  207. + char *varP;
  208. + fragS *fragP;
  209. + int size = TRAMPOLINE_FRAG_SIZE;
  210. +
  211. + for ( ; ts; ts = ts->next)
  212. + {
  213. + if (ts->seg == now_seg)
  214. + break;
  215. + }
  216. +
  217. + if (ts == NULL)
  218. + {
  219. + ts = (struct trampoline_seg *)xcalloc(sizeof (struct trampoline_seg), 1);
  220. + ts->next = trampoline_seg_list.next;
  221. + trampoline_seg_list.next = ts;
  222. + ts->seg = now_seg;
  223. + }
  224. +
  225. + frag_wane (frag_now);
  226. + frag_new (0);
  227. + xtensa_set_frag_assembly_state (frag_now);
  228. + varP = frag_var (rs_machine_dependent, size, size, RELAX_TRAMPOLINE, NULL, 0, NULL);
  229. + fragP = (fragS *)(varP - SIZEOF_STRUCT_FRAG);
  230. + if (trampoline_buf == NULL)
  231. + {
  232. + trampoline_buf = xtensa_insnbuf_alloc (xtensa_default_isa);
  233. + trampoline_slotbuf = xtensa_insnbuf_alloc (xtensa_default_isa);
  234. + }
  235. + tf = (struct trampoline_frag *)xmalloc(sizeof (struct trampoline_frag));
  236. + tf->next = ts->trampoline_list.next;
  237. + ts->trampoline_list.next = tf;
  238. + tf->needs_jump_around = needs_jump_around;
  239. + tf->fragP = fragP;
  240. + tf->fixP = NULL;
  241. +}
  242. +
  243. +
  244. +static struct trampoline_seg *
  245. +find_trampoline_seg (asection *seg)
  246. +{
  247. + struct trampoline_seg *ts = trampoline_seg_list.next;
  248. +
  249. + for ( ; ts; ts = ts->next)
  250. + {
  251. + if (ts->seg == seg)
  252. + return ts;
  253. + }
  254. +
  255. + return NULL;
  256. }
  257. +void dump_trampolines (void);
  258. +
  259. +void
  260. +dump_trampolines (void)
  261. +{
  262. + struct trampoline_seg *ts = trampoline_seg_list.next;
  263. +
  264. + for ( ; ts; ts = ts->next)
  265. + {
  266. + asection *seg = ts->seg;
  267. +
  268. + if (seg == NULL)
  269. + continue;
  270. + fprintf(stderr, "SECTION %s\n", seg->name);
  271. + struct trampoline_frag *tf = ts->trampoline_list.next;
  272. + for ( ; tf; tf = tf->next)
  273. + {
  274. + if (tf->fragP == NULL)
  275. + continue;
  276. + fprintf(stderr, " 0x%08x: fix=%d, jump_around=%s\n",
  277. + (int)tf->fragP->fr_address, (int)tf->fragP->fr_fix,
  278. + tf->needs_jump_around ? "T" : "F");
  279. + }
  280. + }
  281. +}
  282. +
  283. static void
  284. xtensa_cleanup_align_frags (void)
  285. {
  286. @@ -8708,6 +8891,149 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
  287. new_stretch += relax_frag_for_align (fragP, stretch);
  288. break;
  289. + case RELAX_TRAMPOLINE:
  290. + if (fragP->tc_frag_data.relax_seen)
  291. + {
  292. + segment_info_type *seginfo = seg_info (now_seg);
  293. + fragS *fP; /* The out-of-range jump. */
  294. + fixS *fixP;
  295. +
  296. + /* Scan for jumps that will not reach. */
  297. + for (fixP = seginfo->fix_root; fixP ; fixP = fixP->fx_next)
  298. + {
  299. + symbolS *s = fixP->fx_addsy;
  300. + xtensa_opcode opcode;
  301. + int target;
  302. + int addr;
  303. + int delta;
  304. +
  305. + if (fixP->fx_r_type < BFD_RELOC_XTENSA_SLOT0_OP ||
  306. + fixP->fx_r_type > BFD_RELOC_XTENSA_SLOT14_OP)
  307. + continue;
  308. + xtensa_insnbuf_from_chars (isa, trampoline_buf,
  309. + (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where,
  310. + 0);
  311. + fmt = xtensa_format_decode (isa, trampoline_buf);
  312. + gas_assert (fmt != XTENSA_UNDEFINED);
  313. + slot = fixP->tc_fix_data.slot;
  314. + xtensa_format_get_slot (isa, fmt, slot, trampoline_buf, trampoline_slotbuf);
  315. + opcode = xtensa_opcode_decode (isa, fmt, slot, trampoline_slotbuf);
  316. + if (opcode != xtensa_j_opcode)
  317. + continue;
  318. + target = S_GET_VALUE (s);
  319. + addr = fixP->fx_frag->fr_address;
  320. + delta = target - addr + stretch;
  321. + if (delta > J_RANGE || delta < -1 * J_RANGE)
  322. + { /* Found an out-of-range jump; scan the list of trampolines for the best match. */
  323. + struct trampoline_seg *ts = find_trampoline_seg (now_seg);
  324. + struct trampoline_frag *tf = ts->trampoline_list.next;
  325. + struct trampoline_frag *prev = &ts->trampoline_list;
  326. + int lower = (target < addr) ? target : addr;
  327. + int upper = (target > addr) ? target : addr;
  328. + int midpoint = lower + (upper - lower) / 2;
  329. +
  330. + if ((upper - lower) > 2 * J_RANGE)
  331. + {
  332. + /* One trampoline won't suffice; we need multiple jumps.
  333. + Jump to the trampoline that's farthest, but still in
  334. + range relative to the original "j" instruction. */
  335. + for ( ; tf; prev = tf, tf = tf->next )
  336. + {
  337. + int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
  338. + int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0 ;
  339. +
  340. + if (addr == lower)
  341. + {
  342. + /* Forward jump. */
  343. + if (this_addr - addr < J_RANGE)
  344. + break;
  345. + }
  346. + else
  347. + {
  348. + /* Backward jump. */
  349. + if (next_addr == 0 || addr - next_addr > J_RANGE)
  350. + break;
  351. + }
  352. + }
  353. + }
  354. + else
  355. + {
  356. + struct trampoline_frag *best_tf = NULL;
  357. + int best_delta = 0;
  358. +
  359. + for ( ; tf; prev = tf, tf = tf->next )
  360. + {
  361. + int this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
  362. + int this_delta = abs (this_addr - midpoint);
  363. +
  364. + if (!best_tf || this_delta < best_delta)
  365. + {
  366. + best_tf = tf;
  367. + best_delta = this_delta;
  368. + }
  369. + }
  370. + tf = best_tf;
  371. + }
  372. + if (tf->fragP == fragP)
  373. + {
  374. + int trampaddr = fragP->fr_address + fragP->fr_fix;
  375. +
  376. + if (abs (addr - trampaddr) < J_RANGE)
  377. + { /* The trampoline is in range of original; fix it! */
  378. + fixS *newfixP;
  379. + int offset;
  380. + TInsn insn;
  381. + symbolS *lsym;
  382. +
  383. + new_stretch += init_trampoline_frag (tf);
  384. + offset = fragP->fr_fix; /* Where to assemble the j insn. */
  385. + lsym = fragP->fr_symbol;
  386. + fP = fixP->fx_frag;
  387. + /* Assemble a jump to the target label here. */
  388. + tinsn_init (&insn);
  389. + insn.insn_type = ITYPE_INSN;
  390. + insn.opcode = xtensa_j_opcode;
  391. + insn.ntok = 1;
  392. + set_expr_symbol_offset (&insn.tok[0], lsym, offset);
  393. + fmt = xg_get_single_format (xtensa_j_opcode);
  394. + tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
  395. + xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
  396. + xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fragP->fr_literal + offset, 3);
  397. + fragP->fr_fix += 3;
  398. + fragP->fr_var -= 3;
  399. + /* Add a fix-up for the original j insn. */
  400. + newfixP = fix_new (fP, fixP->fx_where, fixP->fx_size, lsym, fragP->fr_fix - 3, TRUE, fixP->fx_r_type);
  401. + newfixP->fx_no_overflow = 1;
  402. + newfixP->tc_fix_data.X_add_symbol = lsym;
  403. + newfixP->tc_fix_data.X_add_number = offset;
  404. + newfixP->tc_fix_data.slot = slot;
  405. + /* Move the fix-up from the original j insn to this one. */
  406. + fixP->fx_frag = fragP;
  407. + fixP->fx_where = fragP->fr_fix - 3;
  408. + fixP->tc_fix_data.slot = 0;
  409. + /* Adjust the jump around this trampoline (if present). */
  410. + if (tf->fixP != NULL)
  411. + {
  412. + tf->fixP->fx_offset += 3;
  413. + }
  414. + new_stretch += 3;
  415. + fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
  416. + /* Do we have room for more? */
  417. + if (fragP->fr_var < 3)
  418. + { /* No, convert to fill. */
  419. + frag_wane (fragP);
  420. + fragP->fr_subtype = 0;
  421. + /* Remove from the trampoline_list. */
  422. + prev->next = tf->next;
  423. + break;
  424. + }
  425. + }
  426. + }
  427. + }
  428. + }
  429. + }
  430. + break;
  431. +
  432. default:
  433. as_bad (_("bad relaxation state"));
  434. }
  435. @@ -9146,6 +9472,200 @@ bytes_to_stretch (fragS *this_frag,
  436. }
  437. +static struct trampoline_frag *
  438. +search_trampolines (TInsn *tinsn, fragS *fragP, bfd_boolean unreachable_only)
  439. +{
  440. + struct trampoline_seg *ts = find_trampoline_seg (now_seg);
  441. + struct trampoline_frag *tf = (ts) ? ts->trampoline_list.next : NULL;
  442. + struct trampoline_frag *best_tf = NULL;
  443. + int best_delta = 0;
  444. + int best_addr = 0;
  445. + symbolS *sym = tinsn->tok[0].X_add_symbol;
  446. + offsetT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
  447. + offsetT addr = fragP->fr_address;
  448. + offsetT lower = (addr < target) ? addr : target;
  449. + offsetT upper = (addr > target) ? addr : target;
  450. + int delta = upper - lower;
  451. + offsetT midpoint = lower + delta / 2;
  452. + int this_delta = -1;
  453. + int this_addr = -1;
  454. +
  455. + if (delta > 2 * J_RANGE)
  456. + {
  457. + /* One trampoline won't do; we need multiple.
  458. + Choose the farthest trampoline that's still in range of the original
  459. + and let a later pass finish the job. */
  460. + for ( ; tf; tf = tf->next)
  461. + {
  462. + int next_addr = (tf->next) ? tf->next->fragP->fr_address + tf->next->fragP->fr_fix : 0;
  463. +
  464. + this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
  465. + if (lower == addr)
  466. + {
  467. + /* Forward jump. */
  468. + if (this_addr - addr < J_RANGE)
  469. + break;
  470. + }
  471. + else
  472. + {
  473. + /* Backward jump. */
  474. + if (next_addr == 0 || addr - next_addr > J_RANGE)
  475. + break;
  476. + }
  477. + if (abs (addr - this_addr) < J_RANGE)
  478. + return tf;
  479. +
  480. + return NULL;
  481. + }
  482. + }
  483. + for ( ; tf; tf = tf->next)
  484. + {
  485. + this_addr = tf->fragP->fr_address + tf->fragP->fr_fix;
  486. + this_delta = abs (this_addr - midpoint);
  487. + if (unreachable_only && tf->needs_jump_around)
  488. + continue;
  489. + if (!best_tf || this_delta < best_delta)
  490. + {
  491. + best_tf = tf;
  492. + best_delta = this_delta;
  493. + best_addr = this_addr;
  494. + }
  495. + }
  496. +
  497. + if (best_tf &&
  498. + best_delta < J_RANGE &&
  499. + abs(best_addr - lower) < J_RANGE &&
  500. + abs(best_addr - upper) < J_RANGE)
  501. + return best_tf;
  502. +
  503. + return NULL; /* No suitable trampoline found. */
  504. +}
  505. +
  506. +
  507. +static struct trampoline_frag *
  508. +get_best_trampoline (TInsn *tinsn, fragS *fragP)
  509. +{
  510. + struct trampoline_frag *tf = NULL;
  511. +
  512. + tf = search_trampolines (tinsn, fragP, TRUE); /* Try unreachable first. */
  513. +
  514. + if (tf == NULL)
  515. + tf = search_trampolines (tinsn, fragP, FALSE); /* Try ones needing a jump-around, too. */
  516. +
  517. + return tf;
  518. +}
  519. +
  520. +
  521. +static void
  522. +check_and_update_trampolines (void)
  523. +{
  524. + struct trampoline_seg *ts = find_trampoline_seg (now_seg);
  525. + struct trampoline_frag *tf = ts->trampoline_list.next;
  526. + struct trampoline_frag *prev = &ts->trampoline_list;
  527. +
  528. + for ( ; tf; prev = tf, tf = tf->next)
  529. + {
  530. + if (tf->fragP->fr_var < 3)
  531. + {
  532. + frag_wane (tf->fragP);
  533. + prev->next = tf->next;
  534. + tf->fragP = NULL;
  535. + }
  536. + }
  537. +}
  538. +
  539. +
  540. +static int
  541. +init_trampoline_frag (struct trampoline_frag *trampP)
  542. +{
  543. + fragS *fp = trampP->fragP;
  544. + int growth = 0;
  545. +
  546. + if (fp->fr_fix == 0)
  547. + {
  548. + symbolS *lsym;
  549. + char label[10 + 2 * sizeof(fp)];
  550. + sprintf (label, ".L0_TR_%p", fp);
  551. +
  552. + lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
  553. + fp->fr_symbol = lsym;
  554. + if (trampP->needs_jump_around)
  555. + {
  556. + /* Add a jump around this block of jumps, in case
  557. + control flows into this block. */
  558. + fixS *fixP;
  559. + TInsn insn;
  560. + xtensa_format fmt;
  561. + xtensa_isa isa = xtensa_default_isa;
  562. +
  563. + fp->tc_frag_data.is_insn = 1;
  564. + /* Assemble a jump insn. */
  565. + tinsn_init (&insn);
  566. + insn.insn_type = ITYPE_INSN;
  567. + insn.opcode = xtensa_j_opcode;
  568. + insn.ntok = 1;
  569. + set_expr_symbol_offset (&insn.tok[0], lsym, 3);
  570. + fmt = xg_get_single_format (xtensa_j_opcode);
  571. + tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
  572. + xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
  573. + xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)fp->fr_literal, 3);
  574. + fp->fr_fix += 3;
  575. + fp->fr_var -= 3;
  576. + growth = 3;
  577. + fixP = fix_new (fp, 0, 3, lsym, 3, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
  578. + trampP->fixP = fixP;
  579. + }
  580. + }
  581. + return growth;
  582. +}
  583. +
  584. +
  585. +static int
  586. +add_jump_to_trampoline (struct trampoline_frag *trampP, fragS *origfrag)
  587. +{
  588. + fragS *tramp = trampP->fragP;
  589. + fixS *fixP;
  590. + int offset = tramp->fr_fix; /* Where to assemble the j insn. */
  591. + TInsn insn;
  592. + symbolS *lsym;
  593. + symbolS *tsym;
  594. + int toffset;
  595. + xtensa_format fmt;
  596. + xtensa_isa isa = xtensa_default_isa;
  597. + int growth = 0;
  598. +
  599. + lsym = tramp->fr_symbol;
  600. + /* Assemble a jump to the target label in the trampoline frag. */
  601. + tsym = origfrag->tc_frag_data.slot_symbols[0];
  602. + toffset = origfrag-> tc_frag_data.slot_offsets[0];
  603. + tinsn_init (&insn);
  604. + insn.insn_type = ITYPE_INSN;
  605. + insn.opcode = xtensa_j_opcode;
  606. + insn.ntok = 1;
  607. + set_expr_symbol_offset (&insn.tok[0], tsym, toffset);
  608. + fmt = xg_get_single_format (xtensa_j_opcode);
  609. + tinsn_to_slotbuf (fmt, 0, &insn, trampoline_slotbuf);
  610. + xtensa_format_set_slot (isa, fmt, 0, trampoline_buf, trampoline_slotbuf);
  611. + xtensa_insnbuf_to_chars (isa, trampoline_buf, (unsigned char *)tramp->fr_literal + offset, 3);
  612. + tramp->fr_fix += 3;
  613. + tramp->fr_var -= 3;
  614. + growth = 3;
  615. + /* add a fix-up for the trampoline jump. */
  616. + fixP = fix_new (tramp, tramp->fr_fix - 3, 3, tsym, toffset, TRUE, BFD_RELOC_XTENSA_SLOT0_OP);
  617. + /* Modify the jump at the start of this trampoline to point past the newly-added jump. */
  618. + fixP = trampP->fixP;
  619. + if (fixP)
  620. + fixP->fx_offset += 3;
  621. + /* Modify the original j to point here. */
  622. + origfrag->tc_frag_data.slot_symbols[0] = lsym;
  623. + origfrag->tc_frag_data.slot_offsets[0] = tramp->fr_fix - 3;
  624. + /* If trampoline is full, remove it from the list. */
  625. + check_and_update_trampolines ();
  626. +
  627. + return growth;
  628. +}
  629. +
  630. +
  631. static long
  632. relax_frag_immed (segT segP,
  633. fragS *fragP,
  634. @@ -9284,6 +9804,37 @@ relax_frag_immed (segT segP,
  635. if (negatable_branch && istack.ninsn > 1)
  636. update_next_frag_state (fragP);
  637. + /* If last insn is a jump, and it cannot reach its target, try to find a trampoline. */
  638. + if (istack.ninsn > 2 &&
  639. + istack.insn[istack.ninsn - 1].insn_type == ITYPE_LABEL &&
  640. + istack.insn[istack.ninsn - 2].insn_type == ITYPE_INSN &&
  641. + istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode)
  642. + {
  643. + TInsn *jinsn = &istack.insn[istack.ninsn - 2];
  644. +
  645. + if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, total_text_diff))
  646. + {
  647. + struct trampoline_frag *tf = get_best_trampoline (jinsn, fragP);
  648. +
  649. + if (tf)
  650. + {
  651. + this_text_diff += init_trampoline_frag (tf);
  652. + this_text_diff += add_jump_to_trampoline (tf, fragP);
  653. + }
  654. + else
  655. + {
  656. + /* If target symbol is undefined, assume it will reach once linked. */
  657. + expressionS *exp = &istack.insn[istack.ninsn - 2].tok[0];
  658. +
  659. + if (exp->X_op == O_symbol && S_IS_DEFINED (exp->X_add_symbol))
  660. + {
  661. + as_bad_where (fragP->fr_file, fragP->fr_line,
  662. + _("jump target out of range; no usable trampoline found"));
  663. + }
  664. + }
  665. + }
  666. + }
  667. +
  668. return this_text_diff;
  669. }
  670. @@ -9404,6 +9955,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp)
  671. else
  672. as_bad (_("invalid relaxation fragment result"));
  673. break;
  674. +
  675. + case RELAX_TRAMPOLINE:
  676. + break;
  677. }
  678. fragp->fr_var = 0;
  679. diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h
  680. index 0bf1240..4672bc6 100644
  681. --- a/gas/config/tc-xtensa.h
  682. +++ b/gas/config/tc-xtensa.h
  683. @@ -180,6 +180,11 @@ enum xtensa_relax_statesE
  684. prevent the linker from changing the size of any frag between the
  685. section start and the org frag. */
  686. + RELAX_TRAMPOLINE,
  687. + /* Every few thousand frags, we insert one of these, just in case we may
  688. + need some space for a trampoline (jump to a jump) because the function
  689. + has gotten too big. If not needed, it disappears. */
  690. +
  691. RELAX_NONE
  692. };
  693. diff --git a/gas/frags.c b/gas/frags.c
  694. index 5f68480..e14099d 100644
  695. --- a/gas/frags.c
  696. +++ b/gas/frags.c
  697. @@ -24,6 +24,20 @@
  698. extern fragS zero_address_frag;
  699. extern fragS predefined_address_frag;
  700. +
  701. +static int totalfrags;
  702. +
  703. +int
  704. +get_frag_count (void)
  705. +{
  706. + return totalfrags;
  707. +}
  708. +
  709. +void
  710. +clear_frag_count (void)
  711. +{
  712. + totalfrags = 0;
  713. +}
  714. /* Initialization for frag routines. */
  715. @@ -70,6 +84,7 @@ frag_alloc (struct obstack *ob)
  716. ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG);
  717. obstack_alignment_mask (ob) = oalign;
  718. memset (ptr, 0, SIZEOF_STRUCT_FRAG);
  719. + totalfrags++;
  720. return ptr;
  721. }
  722. diff --git a/gas/frags.h b/gas/frags.h
  723. index 319898f..2f9e1b5 100644
  724. --- a/gas/frags.h
  725. +++ b/gas/frags.h
  726. @@ -155,4 +155,7 @@ char *frag_var (relax_stateT type,
  727. bfd_boolean frag_offset_fixed_p (const fragS *, const fragS *, offsetT *);
  728. +int get_frag_count (void);
  729. +void clear_frag_count (void);
  730. +
  731. #endif /* FRAGS_H */
  732. diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp
  733. index 2b2c294..3683b78 100644
  734. --- a/gas/testsuite/gas/xtensa/all.exp
  735. +++ b/gas/testsuite/gas/xtensa/all.exp
  736. @@ -98,6 +98,7 @@ if [istarget xtensa*-*-*] then {
  737. run_dump_test "pcrel"
  738. run_dump_test "weak-call"
  739. run_dump_test "jlong"
  740. + run_dump_test "trampoline"
  741. }
  742. if [info exists errorInfo] then {
  743. diff --git a/gas/testsuite/gas/xtensa/trampoline.d b/gas/testsuite/gas/xtensa/trampoline.d
  744. new file mode 100644
  745. index 0000000..b4f65dc
  746. --- /dev/null
  747. +++ b/gas/testsuite/gas/xtensa/trampoline.d
  748. @@ -0,0 +1,26 @@
  749. +#as:
  750. +#objdump: -d
  751. +#name: trampolines relaxation
  752. +
  753. +.*: +file format .*xtensa.*
  754. +#...
  755. +.*0:.*j.0x1194c
  756. +.*3:.*j.0x1194f
  757. +.*6:.*j.0x11952
  758. +.*9:.*j.0x1d4e4
  759. +#...
  760. +.*11949:.*j.0x11955
  761. +.*1194c:.*j.0x24a0e
  762. +.*1194f:.*j.0x24a0e
  763. +.*11952:.*j.0x24a11
  764. +#...
  765. +.*1d4e1:.*j.0x1d4e7
  766. +.*1d4e4:.*j.0x33462
  767. +#...
  768. +.*24a0e:.*j.0x24a0e
  769. +.*24a11:.*j.0x24a11
  770. +#...
  771. +.*3345f:.*ret
  772. +.*33462:.*j.0x49407
  773. +#...
  774. +.*49407:.*j.0x49407
  775. diff --git a/gas/testsuite/gas/xtensa/trampoline.s b/gas/testsuite/gas/xtensa/trampoline.s
  776. new file mode 100644
  777. index 0000000..259a3bb
  778. --- /dev/null
  779. +++ b/gas/testsuite/gas/xtensa/trampoline.s
  780. @@ -0,0 +1,21 @@
  781. + .text
  782. + j 1f
  783. + j 1f
  784. + j 2f
  785. + j 3f
  786. + .rep 25000
  787. +99:
  788. + and a2, a2, a3
  789. + bne a2, a3, 99b
  790. + .endr
  791. +1:
  792. + j 1b
  793. +2:
  794. + j 2b
  795. +
  796. + .rep 25000
  797. + and a2, a2, a3
  798. + _ret
  799. + .endr
  800. +3:
  801. + j 3b
  802. --
  803. 1.8.1.4