Add -ftst flag for Thumb TST instruction generation

Add two new Thumb instruction patterns gated behind a -ftst flag,
following the same mechanism as -fprologue-bugfix:

*andsi3_tst: when the AND result is dead and only flags are needed,
the combiner merges AND+CMP into a single TST instruction instead
of emitting `and Rd, Rm; cmp Rd, #0`.

*andsi3_setflags: when the AND result is live AND flags are needed,
eliminates the redundant `cmp Rd, #0` after AND. In Thumb mode, AND
always sets the CPSR flags, so the CMP is unnecessary.

This is needed for matching decompilation of GBA games where the
original SDK compiler emitted TST instructions that pret/agbcc
does not generate. The flag is opt-in to avoid breaking existing
matches in projects that rely on the AND+CMP sequence.

Files changed:
- gcc/thumb.md: Add *andsi3_tst and *andsi3_setflags patterns
- gcc/thumb.h: Update comment acknowledging TST support
- gcc/toplev.c: Register -ftst in f_options[] table
- gcc/flags.h: Declare extern int flag_tst
This commit is contained in:
Felipe Correa da Silva Sanches
2026-03-20 08:24:35 +00:00
parent da598c1d91
commit 49db04dd5b
4 changed files with 30 additions and 2 deletions

View File

@@ -457,3 +457,6 @@ extern int flag_fixed_debug_line_info;
/* Nonzero if prologue bug should be fixed. */
extern int flag_prologue_bugfix;
/* Nonzero if the TST instruction should be used instead of AND+CMP. */
extern int flag_tst;

View File

@@ -33,8 +33,8 @@ Boston, MA 02111-1307, USA. */
reload. These should be eliminated if possible by tightening the
predicates and/or constraints. This will give faster/smaller code. */
/* ??? There is no pattern for the TST instuction. Check for other unsupported
instructions. */
/* The TST instruction is emitted via the *andsi3_tst pattern in thumb.md.
Check for other unsupported instructions. */
#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr);

View File

@@ -820,6 +820,26 @@
""
"cmp\\t%0, #0")
(define_insn "*andsi3_tst"
[(set (cc0)
(and:SI (match_operand:SI 0 "s_register_operand" "l")
(match_operand:SI 1 "s_register_operand" "l")))]
"flag_tst"
"tst\\t%1, %0")
;; Thumb AND always sets flags. When the AND result is live AND flags are
;; needed, the combiner produces a PARALLEL. This pattern eliminates the
;; redundant cmp after and by using the implicit flag-setting of Thumb AND.
(define_insn "*andsi3_setflags"
[(parallel
[(set (cc0)
(and:SI (match_operand:SI 1 "s_register_operand" "%0")
(match_operand:SI 2 "s_register_operand" "l")))
(set (match_operand:SI 0 "s_register_operand" "=l")
(and:SI (match_dup 1) (match_dup 2)))])]
"flag_tst"
"and\\t%0, %0, %2")
(define_insn "cmnsi"
[(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l")
(neg:SI (match_operand:SI 1 "s_register_operand" "l"))))]

View File

@@ -591,6 +591,9 @@ int flag_fixed_debug_line_info = 0;
/* Fix prologue bug in new compiler. */
int flag_prologue_bugfix = 0;
/* Use TST instruction instead of AND+CMP for bitwise flag tests. */
int flag_tst = 0;
typedef struct
{
char *string;
@@ -739,6 +742,8 @@ lang_independent_options f_options[] =
{"prologue-bugfix", &flag_prologue_bugfix, 1,
"Prevent unnecessary saving of the lr register to the stack"},
#endif
{"tst", &flag_tst, 1,
"Use TST instruction instead of AND+CMP for bitwise flag tests"},
};
#define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0]))