#include <stdbool.h> #include <stdint.h> #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f16_mul( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; bool signB; int_fast8_t expB; uint_fast16_t sigB; bool signZ; uint_fast16_t magBits; struct exp8_sig16 normExpSig; int_fast8_t expZ; uint_fast32_t sig32Z; uint_fast16_t sigZ, uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF16UI( uiB ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0xF; sigA = (sigA | 0x0400)<<4; sigB = (sigB | 0x0400)<<5; sig32Z = (uint_fast32_t) sigA * sigB; sigZ = sig32Z>>16; if ( sig32Z & 0xFFFF ) sigZ |= 1; if ( sigZ < 0x4000 ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF16( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; } else { uiZ = packToF16UI( signZ, 0x1F, 0 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF16UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }