summaryrefslogtreecommitdiff
path: root/libgcc/config/rl78/cmpsi2.S
diff options
context:
space:
mode:
Diffstat (limited to 'libgcc/config/rl78/cmpsi2.S')
-rw-r--r--libgcc/config/rl78/cmpsi2.S172
1 files changed, 172 insertions, 0 deletions
diff --git a/libgcc/config/rl78/cmpsi2.S b/libgcc/config/rl78/cmpsi2.S
new file mode 100644
index 0000000000..20899973cc
--- /dev/null
+++ b/libgcc/config/rl78/cmpsi2.S
@@ -0,0 +1,172 @@
+; Copyright (C) 2011-2017 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+;
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+; <http://www.gnu.org/licenses/>.
+
+
+#include "vregs.h"
+
+ .text
+
+ ;; int __cmpsi2 (signed long A, signed long B)
+ ;;
+ ;; Performs a signed comparison of A and B.
+ ;; If A is less than B it returns 0. If A is greater
+ ;; than B it returns 2. If they are equal it returns 1.
+
+START_FUNC ___cmpsi2
+
+ ;; A is at [sp+4]
+ ;; B is at [sp+8]
+ ;; Result put in R8
+
+ ;; Initialise default return value.
+ onew bc
+
+ ;; Compare the high words.
+ movw ax, [sp + 10]
+ movw de, ax
+ movw ax, [sp + 6]
+ cmpw ax, de
+ skz
+ br !!.Lconvert_to_signed
+
+.Lcompare_bottom_words:
+ ;; The top words are equal - compare the bottom words.
+ ;; Note - code from __ucmpsi2 branches into here.
+ movw ax, [sp + 8]
+ movw de, ax
+ movw ax, [sp + 4]
+ cmpw ax, de
+ sknz
+ br !!.Lless_than_or_greater_than
+ ;; The words are equal - return 1.
+ ;; Note - we could branch to the return code at the end of the
+ ;; function but a branch instruction takes 4 bytes, and the
+ ;; return sequence itself is only 4 bytes long...
+ movw ax, bc
+ movw r8, ax
+ ret
+
+.Lconvert_to_signed:
+ ;; The top words are different. Unfortunately the comparison
+ ;; is always unsigned, so to get a signed result we XOR the CY
+ ;; flag with the top bits of AX and DE.
+ xor1 cy, a.7
+ mov a, d
+ xor1 cy, a.7
+ ;; Fall through.
+
+.Lless_than_or_greater_than:
+ ;; We now have a signed less than/greater than result in CY.
+ ;; Return 0 for less than, 2 for greater than.
+ ;; Note - code from __ucmpsi2 branches into here.
+ incw bc
+ sknc
+ clrw bc
+
+ ;; Get the result value, currently in BC, into r8
+ movw ax, bc
+ movw r8, ax
+ ret
+
+END_FUNC ___cmpsi2
+
+;; ------------------------------------------------------
+
+ ;; int __ucmpsi2 (unsigned long A, unsigned long B)
+ ;;
+ ;; Performs an unsigned comparison of A and B.
+ ;; If A is less than B it returns 0. If A is greater
+ ;; than B it returns 2. If they are equal it returns 1.
+
+START_FUNC ___ucmpsi2
+
+ ;; A is at [sp+4]
+ ;; B is at [sp+8]
+ ;; Result put in R8..R9
+
+ ;; Initialise default return value.
+ onew bc
+
+ ;; Compare the high words.
+ movw ax, [sp + 10]
+ movw de, ax
+ movw ax, [sp + 6]
+ cmpw ax, de
+ skz
+ ;; Note: These branches go into the __cmpsi2 code!
+ br !!.Lless_than_or_greater_than
+ br !!.Lcompare_bottom_words
+
+END_FUNC ___ucmpsi2
+
+;; ------------------------------------------------------
+
+ ;; signed int __gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
+ ;; Result is negative if S1 is less than S2,
+ ;; positive if S1 is greater, 0 if S1 and S2 are equal.
+
+START_FUNC __gcc_bcmp
+
+ ;; S1 is at [sp+4]
+ ;; S2 is at [sp+6]
+ ;; SIZE is at [sp+8]
+ ;; Result in r8/r9
+
+ movw r10, #0
+1:
+ ;; Compare R10 against the SIZE parameter
+ movw ax, [sp+8]
+ subw ax, r10
+ sknz
+ br !!1f
+
+ ;; Load S2[r10] into R8
+ movw ax, [sp+6]
+ addw ax, r10
+ movw hl, ax
+ mov a, [hl]
+ mov r8, a
+
+ ;; Load S1[r10] into A
+ movw ax, [sp+4]
+ addw ax, r10
+ movw hl, ax
+ mov a, [hl]
+
+ ;; Increment offset
+ incw r10
+
+ ;; Compare loaded bytes
+ cmp a, r8
+ sknz
+ br !!1b
+
+ ;; They differ. Subtract *S2 from *S1 and return as the result.
+ mov x, a
+ mov a, #0
+ mov r9, #0
+ subw ax, r8
+1:
+ movw r8, ax
+ ret
+
+END_FUNC __gcc_bcmp