reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
//===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the __addsf3 (single precision floating pointer number
// addition with the IEEE-754 default rounding (to nearest, ties to even)
// function for the ARM Thumb1 ISA.
//
//===----------------------------------------------------------------------===//

#include "../assembly.h"
#define significandBits 23
#define typeWidth 32

	.syntax unified
	.text
  .thumb
  .p2align 2

DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)

DEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
  push {r4, r5, r6, r7, lr}
  // Get the absolute value of a and b.
  lsls r2, r0, #1
  lsls r3, r1, #1
  lsrs r2, r2, #1  // aAbs
  beq  LOCAL_LABEL(a_zero_nan_inf)
  lsrs r3, r3, #1  // bAbs
  beq  LOCAL_LABEL(zero_nan_inf)

  // Detect if a or b is infinity or Nan.
  lsrs r6, r2, #(significandBits)
  lsrs r7, r3, #(significandBits)
  cmp  r6, #0xFF
  beq  LOCAL_LABEL(zero_nan_inf)
  cmp  r7, #0xFF
  beq  LOCAL_LABEL(zero_nan_inf)

  // Swap Rep and Abs so that a and aAbs has the larger absolute value.
  cmp r2, r3
  bhs LOCAL_LABEL(no_swap)
  movs r4, r0
  movs r5, r2
  movs r0, r1
  movs r2, r3
  movs r1, r4
  movs r3, r5
LOCAL_LABEL(no_swap):

  // Get the significands and shift them to give us round, guard and sticky.
  lsls r4, r0, #(typeWidth - significandBits)
  lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3
  lsls r5, r1, #(typeWidth - significandBits)
  lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3

  // Get the implicitBit.
  movs r6, #1
  lsls r6, r6, #(significandBits + 3)

  // Get aExponent and set implicit bit if necessary.
  lsrs r2, r2, #(significandBits)
  beq LOCAL_LABEL(a_done_implicit_bit)
  orrs r4, r6
LOCAL_LABEL(a_done_implicit_bit):

  // Get bExponent and set implicit bit if necessary.
  lsrs r3, r3, #(significandBits)
  beq LOCAL_LABEL(b_done_implicit_bit)
  orrs r5, r6
LOCAL_LABEL(b_done_implicit_bit):

  // Get the difference in exponents.
  subs r6, r2, r3
  beq LOCAL_LABEL(done_align)

  // If b is denormal, then a must be normal as align > 0, and we only need to
  // right shift bSignificand by (align - 1) bits.
  cmp  r3, #0
  bne  1f
  subs r6, r6, #1
1:

  // No longer needs bExponent. r3 is dead here.
  // Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
  movs r3, #(typeWidth)
  subs r3, r3, r6
  movs r7, r5
  lsls r7, r3
  beq 1f
  movs r7, #1
1:

  // bSignificand = bSignificand >> align | sticky;
  lsrs r5, r6
  orrs r5, r7
  bne LOCAL_LABEL(done_align)
  movs r5, #1 //  sticky; b is known to be non-zero.

LOCAL_LABEL(done_align):
  // isSubtraction = (aRep ^ bRep) >> 31;
  movs r7, r0
  eors r7, r1
  lsrs r7, #31
  bne LOCAL_LABEL(do_substraction)

  // Same sign, do Addition.

  // aSignificand += bSignificand;
  adds r4, r4, r5

  // Check carry bit.
  movs r6, #1
  lsls r6, r6, #(significandBits + 3 + 1)
  movs r7, r4
  ands r7, r6
  beq LOCAL_LABEL(form_result)
  // If the addition carried up, we need to right-shift the result and
  // adjust the exponent.
  movs r7, r4
  movs r6, #1
  ands r7, r6 // sticky = aSignificand & 1;
  lsrs r4, #1
  orrs r4, r7  // result Significand
  adds r2, #1  // result Exponent
  // If we have overflowed the type, return +/- infinity.
  cmp  r2, 0xFF
  beq  LOCAL_LABEL(ret_inf)

LOCAL_LABEL(form_result):
  // Shift the sign, exponent and significand into place.
  lsrs r0, #(typeWidth - 1)
  lsls r0, #(typeWidth - 1) // Get Sign.
  lsls r2, #(significandBits)
  orrs r0, r2
  movs r1, r4
  lsls r4, #(typeWidth - significandBits - 3)
  lsrs r4, #(typeWidth - significandBits)
  orrs r0, r4

  // Final rounding.  The result may overflow to infinity, but that is the
  // correct result in that case.
  // roundGuardSticky = aSignificand & 0x7;
  movs r2, #0x7
  ands r1, r2
  // if (roundGuardSticky > 0x4) result++;

  cmp r1, #0x4
  blt LOCAL_LABEL(done_round)
  beq 1f
  adds r0, #1
  pop {r4, r5, r6, r7, pc}
1:

  // if (roundGuardSticky == 0x4) result += result & 1;
  movs r1, r0
  lsrs r1, #1
  bcc  LOCAL_LABEL(done_round)
  adds r0, r0, #1
LOCAL_LABEL(done_round):
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(do_substraction):
  subs r4, r4, r5 // aSignificand -= bSignificand;
  beq  LOCAL_LABEL(ret_zero)
  movs r6, r4
  cmp  r2, 0
  beq  LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
  // If partial cancellation occured, we need to left-shift the result
  // and adjust the exponent:
  lsrs r6, r6, #(significandBits + 3)
  bne LOCAL_LABEL(form_result)

  push {r0, r1, r2, r3}
  movs r0, r4
  bl   SYMBOL_NAME(__clzsi2)
  movs r5, r0
  pop {r0, r1, r2, r3}
  // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
  subs r5, r5, #(typeWidth - significandBits - 3 - 1)
  // aSignificand <<= shift; aExponent -= shift;
  lsls r4, r5
  subs  r2, r2, r5
  bgt LOCAL_LABEL(form_result)

  // Do normalization if aExponent <= 0.
  movs r6, #1
  subs r6, r6, r2 // 1 - aExponent;
  movs r2, #0 // aExponent = 0;
  movs r3, #(typeWidth) // bExponent is dead.
  subs r3, r3, r6
  movs r7, r4
  lsls r7, r3  // stickyBit = (bool)(aSignificant << (typeWidth - align))
  beq 1f
  movs r7, #1
1:
  lsrs r4, r6 // aSignificand >> shift
  orrs r4, r7
  b LOCAL_LABEL(form_result)

LOCAL_LABEL(ret_zero):
  movs r0, #0
  pop {r4, r5, r6, r7, pc}


LOCAL_LABEL(a_zero_nan_inf):
  lsrs r3, r3, #1

LOCAL_LABEL(zero_nan_inf):
  // Here  r2 has aAbs, r3 has bAbs
  movs r4, #0xFF
  lsls r4, r4, #(significandBits) // Make +inf.

  cmp r2, r4
  bhi LOCAL_LABEL(a_is_nan)
  cmp r3, r4
  bhi LOCAL_LABEL(b_is_nan)

  cmp r2, r4
  bne LOCAL_LABEL(a_is_rational)
  // aAbs is INF.
  eors r1, r0 // aRep ^ bRep.
  movs r6, #1
  lsls r6, r6, #(typeWidth - 1) // get sign mask.
  cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
  beq LOCAL_LABEL(a_is_nan)
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(a_is_rational):
  cmp r3, r4
  bne LOCAL_LABEL(b_is_rational)
  movs r0, r1
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(b_is_rational):
  // either a or b or both are zero.
  adds r4, r2, r3
  beq  LOCAL_LABEL(both_zero)
  cmp r2, #0 // is absA 0 ?
  beq LOCAL_LABEL(ret_b)
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(both_zero):
  ands r0, r1 // +0 + -0 = +0
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(ret_b):
  movs r0, r1

LOCAL_LABEL(ret):
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(b_is_nan):
  movs r0, r1
LOCAL_LABEL(a_is_nan):
  movs r1, #1
  lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
  orrs r0, r1
  pop {r4, r5, r6, r7, pc}

LOCAL_LABEL(ret_inf):
  movs r4, #0xFF
  lsls r4, r4, #(significandBits)
  orrs r0, r4
  lsrs r0, r0, #(significandBits)
  lsls r0, r0, #(significandBits)
  pop {r4, r5, r6, r7, pc}


END_COMPILERRT_FUNCTION(__addsf3)

NO_EXEC_STACK_DIRECTIVE