+/* GCC generates several well-known sequences of instructions at the begining
+ of each function prologue when compiling with -fstack-check. If one of
+ such sequences starts at START_PC, then return the address of the
+ instruction immediately past this sequence. Otherwise, return START_PC. */
+
+static CORE_ADDR
+sparc_skip_stack_check (const CORE_ADDR start_pc)
+{
+ CORE_ADDR pc = start_pc;
+ unsigned long insn;
+ int offset_stack_checking_sequence = 0;
+ int probing_loop = 0;
+
+ /* With GCC, all stack checking sequences begin with the same two
+ instructions, plus an optional one in the case of a probing loop:
+
+ sethi <some immediate>, %g1
+ sub %sp, %g1, %g1
+
+ or:
+
+ sethi <some immediate>, %g1
+ sethi <some immediate>, %g4
+ sub %sp, %g1, %g1
+
+ or:
+
+ sethi <some immediate>, %g1
+ sub %sp, %g1, %g1
+ sethi <some immediate>, %g4
+
+ If the optional instruction is found (setting g4), assume that a
+ probing loop will follow. */
+
+ /* sethi <some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* optional: sethi <some immediate>, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+ {
+ probing_loop = 1;
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ }
+
+ /* sub %sp, %g1, %g1 */
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1))
+ return start_pc;
+
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+
+ /* optional: sethi <some immediate>, %g4 */
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+ {
+ probing_loop = 1;
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ }
+
+ /* First possible sequence:
+ [first two instructions above]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1 - some immediate] */
+ if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ /* Valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Second possible sequence: A small number of probes.
+ [first two instructions above]
+ clr [%g1]
+ add %g1, -<some immediate>, %g1
+ clr [%g1]
+ [repeat the two instructions above any (small) number of times]
+ clr [%g1 - some immediate] */
+
+ /* clr [%g1] */
+ else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+ {
+ while (1)
+ {
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ break;
+
+ /* clr [%g1] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+ return start_pc;
+ }
+
+ /* clr [%g1 - some immediate] */
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 0))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+ return pc;
+ }
+
+ /* Third sequence: A probing loop.
+ [first three instructions above]
+ sub %g1, %g4, %g4
+ cmp %g1, %g4
+ be <disp>
+ add %g1, -<some immediate>, %g1
+ ba <disp>
+ clr [%g1]
+
+ And an optional last probe for the remainder:
+
+ clr [%g4 - some immediate] */
+
+ if (probing_loop)
+ {
+ /* sub %g1, %g4, %g4 */
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+ && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* cmp %g1, %g4 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn)
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+ return start_pc;
+
+ /* be <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1))
+ return start_pc;
+
+ /* add %g1, -<some immediate>, %g1 */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn)
+ && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+ return start_pc;
+
+ /* ba <disp> */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8))
+ return start_pc;
+
+ /* clr [%g1] (st %g0, [%g1] or st %g0, [%g1+0]) */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4
+ && X_RD (insn) == 0 && X_RS1 (insn) == 1
+ && (!X_I(insn) || X_SIMM13 (insn) == 0)))
+ return start_pc;
+
+ /* We found a valid stack-check sequence, return the new PC. */
+
+ /* optional: clr [%g4 - some immediate] */
+ insn = sparc_fetch_instruction (pc);
+ pc = pc + 4;
+ if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+ && X_RS1 (insn) == 4 && X_RD (insn) == 0))
+ return pc - 4;
+ else
+ return pc;
+ }
+
+ /* No stack check code in our prologue, return the start_pc. */
+ return start_pc;
+}
+
+/* Record the effect of a SAVE instruction on CACHE. */
+
+void
+sparc_record_save_insn (struct sparc_frame_cache *cache)
+{
+ /* The frame is set up. */
+ cache->frameless_p = 0;
+
+ /* The frame pointer contains the CFA. */
+ cache->frame_offset = 0;
+
+ /* The `local' and `in' registers are all saved. */
+ cache->saved_regs_mask = 0xffff;
+
+ /* The `out' registers are all renamed. */
+ cache->copied_regs_mask = 0xff;
+}
+
+/* Do a full analysis of the prologue at PC and update CACHE accordingly.
+ Bail out early if CURRENT_PC is reached. Return the address where
+ the analysis stopped.
+
+ We handle both the traditional register window model and the single
+ register window (aka flat) model. */
+