diff mbox series

[v5,05/33] Add the __HAVE_FEATURE_IT and IT() macros

Message ID dc624e40b87ade85c07dbfe7f470d71e5f370c79.1610709584.git.gnu@danielengel.com
State New
Headers show
Series libgcc: Thumb-1 Floating-Point Library for Cortex M0 | expand

Commit Message

Daniel Engel Jan. 15, 2021, 11:30 a.m. UTC
These macros complement and extend the existing do_it() macro.
Together, they streamline the process of optimizing short branchless
contitional sequences to support ARM, Thumb-2, and Thumb-1.

The inherent architecture limitations of Thumb-1 means that writing
assembly code is somewhat more tedious.  And, while such code will run
unmodified in an ARM or Thumb-2 enfironment, it will lack one of the
key performance optimizations available there.

Initially, the first idea might be to split the an instruction sequence
with #ifdef(s): one path for Thumb-1 and the other for ARM/Thumb-2.
This could suffice if conditional execution optimizations were rare.

However, #ifdef(s) break flow of an algorithm and shift focus to the
architectural differences instead of the similarities.  On functions
with a high percentage of conditional execution, it starts to become
attractive to split everything into distinct architecture-specific
function objects -- even when the underlying algorithm is identical.

Additionally, duplicated code and comments (whether an individual
operand, a line, or a larger block) become a future maintenance
liability if the two versions aren't kept in sync.

See code comments for limitations and expecated usage.

gcc/libgcc/ChangeLog:
2021-01-14 Daniel Engel <gnu@danielengel.com>

	(__HAVE_FEATURE_IT, IT): New macros.
---
 libgcc/config/arm/lib1funcs.S | 68 +++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
diff mbox series

Patch

diff --git a/libgcc/config/arm/lib1funcs.S b/libgcc/config/arm/lib1funcs.S
index b8693be8e4f..1233b8c0992 100644
--- a/libgcc/config/arm/lib1funcs.S
+++ b/libgcc/config/arm/lib1funcs.S
@@ -230,6 +230,7 @@  LSYM(Lend_fde):
    ARM and Thumb-2.  However this is only supported by recent gas, so define
    a set of macros to allow ARM code on older assemblers.  */
 #if defined(__thumb2__)
+#define __HAVE_FEATURE_IT
 .macro do_it cond, suffix=""
 	it\suffix	\cond
 .endm
@@ -245,6 +246,9 @@  LSYM(Lend_fde):
 	\name \dest, \src1, \tmp
 .endm
 #else
+#if !defined(__thumb__)
+#define __HAVE_FEATURE_IT
+#endif
 .macro do_it cond, suffix=""
 .endm
 .macro shift1 op, arg0, arg1, arg2
@@ -259,6 +263,70 @@  LSYM(Lend_fde):
 
 #define COND(op1, op2, cond) op1 ## op2 ## cond
 
+
+/* The IT() macro streamlines the construction of short branchless contitional
+    sequences that support ARM, Thumb-2, and Thumb-1.  It is intended as an
+    extension to the .do_it macro defined above.  Code not written with the
+    intent to support Thumb-1 need not use IT().
+
+   IT()'s main advantage is the minimization of syntax differences.  Unified
+    functions can support Thumb-1 without imposiing an undue performance
+    penalty on ARM and Thumb-2.  Writing code without duplicate instructions
+    and operands keeps the high level function flow clearer and should reduce
+    the incidence of maintenance bugs.
+
+   Where conditional execution is supported by ARM and Thumb-2, the specified
+    instruction compiles with the conditional suffix 'c'.
+
+   Where Thumb-1 and v6m do not support IT, the given instruction compiles
+    with the standard unified syntax suffix "s", and a preceding branch
+    instruction is required to implement conditional behavior.
+
+   (Aside: The Thumb-1 "s"-suffix pattern is somewhat simplistic, since it
+    does not support 'cmp' or 'tst' with a non-"s" suffix.  It also appends
+    "s" to 'mov' and 'add' with high register operands which are otherwise
+    legal on v6m.  Use of IT() will result in a compiler error for all of
+    these exceptional cases, and a full #ifdef code split will be required.
+    However, it is unlikely that code written with Thumb-1 compatibility
+    in mind will use such patterns, so IT() still promises a good value.)
+
+   Typical if/then/else usage is:
+
+    #ifdef __HAVE_FEATURE_IT
+        // ARM and Thumb-2 'true' condition.
+        do_it   c,      tee
+    #else
+        // Thumb-1 'false' condition.  This must be opposite the
+        //  sense of the ARM and Thumb-2 condition, since the
+        //  branch is taken to skip the 'true' instruction block.
+        b!c     else_label
+    #endif
+
+        // Conditional 'true' execution for all compile modes.
+     IT(ins1,c) op1,    op2
+     IT(ins2,c) op1,    op2
+
+    #ifndef __HAVE_FEATURE_IT
+        // Thumb-1 branch to skip the 'else' instruction block.
+        // Omitted for if/then usage.
+        b       end_label
+    #endif
+
+   else_label:
+        // Conditional 'false' execution for all compile modes.
+        // Omitted for if/then usage.
+     IT(ins3,!c) op1,   op2
+     IT(ins4,!c) op1,   op2
+
+   end_label:
+        // Unconditional execution resumes here.
+ */
+#ifdef __HAVE_FEATURE_IT
+  #define IT(ins,c) ins##c
+#else
+  #define IT(ins,c) ins##s
+#endif
+
 #ifdef __ARM_EABI__
 .macro ARM_LDIV0 name signed
 	cmp	r0, #0