110 lines · plain
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include <clc/clc_convert.h>10#include <clc/integer/clc_add_sat.h>11#include <clc/integer/clc_mad24.h>12#include <clc/integer/clc_mul_hi.h>13#include <clc/integer/clc_upsample.h>14#include <clc/integer/definitions.h>15#include <clc/internal/clc.h>16#include <clc/relational/clc_select.h>17#include <clc/shared/clc_clamp.h>18 19#define __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE, UP_TYPE, LIT_PREFIX) \20 _CLC_OVERLOAD _CLC_DEF TYPE __clc_mad_sat(TYPE x, TYPE y, TYPE z) { \21 UP_TYPE upscaled_mad = \22 __clc_mad24(__clc_convert_##UP_TYPE(x), __clc_convert_##UP_TYPE(y), \23 __clc_convert_##UP_TYPE(z)); \24 UP_TYPE clamped_mad = __clc_clamp(upscaled_mad, (UP_TYPE)LIT_PREFIX##_MIN, \25 (UP_TYPE)LIT_PREFIX##_MAX); \26 return __clc_convert_##TYPE(clamped_mad); \27 }28 29#define __CLC_DEFINE_SIMPLE_MAD_SAT_ALL_TYS(TYPE, UP_TYPE, LIT_PREFIX) \30 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE, UP_TYPE, LIT_PREFIX) \31 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE##2, UP_TYPE##2, LIT_PREFIX) \32 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE##3, UP_TYPE##3, LIT_PREFIX) \33 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE##4, UP_TYPE##4, LIT_PREFIX) \34 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE##8, UP_TYPE##8, LIT_PREFIX) \35 __CLC_DEFINE_SIMPLE_MAD_SAT(TYPE##16, UP_TYPE##16, LIT_PREFIX)36 37__CLC_DEFINE_SIMPLE_MAD_SAT_ALL_TYS(char, int, CHAR)38__CLC_DEFINE_SIMPLE_MAD_SAT_ALL_TYS(uchar, uint, UCHAR)39__CLC_DEFINE_SIMPLE_MAD_SAT_ALL_TYS(short, int, SHRT)40__CLC_DEFINE_SIMPLE_MAD_SAT_ALL_TYS(ushort, uint, USHRT)41 42// Macro for defining mad_sat variants for uint/ulong43#define __CLC_DEFINE_UINTLONG_MAD_SAT(UTYPE, STYPE, ULIT_PREFIX) \44 _CLC_OVERLOAD _CLC_DEF UTYPE __clc_mad_sat(UTYPE x, UTYPE y, UTYPE z) { \45 STYPE has_mul_hi = __clc_mul_hi(x, y) != (UTYPE)0; \46 return __clc_select(__clc_add_sat(x * y, z), (UTYPE)ULIT_PREFIX##_MAX, \47 has_mul_hi); \48 }49 50#define __CLC_DEFINE_UINTLONG_MAD_SAT_ALL_TYS(UTY, STY, ULIT_PREFIX) \51 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY, STY, ULIT_PREFIX) \52 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY##2, STY##2, ULIT_PREFIX) \53 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY##3, STY##3, ULIT_PREFIX) \54 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY##4, STY##4, ULIT_PREFIX) \55 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY##8, STY##8, ULIT_PREFIX) \56 __CLC_DEFINE_UINTLONG_MAD_SAT(UTY##16, STY##16, ULIT_PREFIX)57 58__CLC_DEFINE_UINTLONG_MAD_SAT_ALL_TYS(uint, int, UINT)59__CLC_DEFINE_UINTLONG_MAD_SAT_ALL_TYS(ulong, long, ULONG)60 61// Macro for defining mad_sat variants for int62#define __CLC_DEFINE_SINT_MAD_SAT(INTTY, UINTTY, SLONGTY) \63 _CLC_OVERLOAD _CLC_DEF INTTY __clc_mad_sat(INTTY x, INTTY y, INTTY z) { \64 INTTY mhi = __clc_mul_hi(x, y); \65 UINTTY mlo = __clc_as_##UINTTY(x * y); \66 SLONGTY m = __clc_upsample(mhi, mlo); \67 m += __clc_convert_##SLONGTY(z); \68 m = __clc_clamp(m, (SLONGTY)INT_MIN, (SLONGTY)INT_MAX); \69 return __clc_convert_##INTTY(m); \70 }71 72#define __CLC_DEFINE_SINT_MAD_SAT_ALL_TYS(INTTY, UINTTY, SLONGTY) \73 __CLC_DEFINE_SINT_MAD_SAT(INTTY, UINTTY, SLONGTY) \74 __CLC_DEFINE_SINT_MAD_SAT(INTTY##2, UINTTY##2, SLONGTY##2) \75 __CLC_DEFINE_SINT_MAD_SAT(INTTY##3, UINTTY##3, SLONGTY##3) \76 __CLC_DEFINE_SINT_MAD_SAT(INTTY##4, UINTTY##4, SLONGTY##4) \77 __CLC_DEFINE_SINT_MAD_SAT(INTTY##8, UINTTY##8, SLONGTY##8) \78 __CLC_DEFINE_SINT_MAD_SAT(INTTY##16, UINTTY##16, SLONGTY##16)79 80__CLC_DEFINE_SINT_MAD_SAT_ALL_TYS(int, uint, long)81 82// Macro for defining mad_sat variants for long83#define __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY, ULONGTY) \84 _CLC_OVERLOAD _CLC_DEF SLONGTY __clc_mad_sat(SLONGTY x, SLONGTY y, \85 SLONGTY z) { \86 SLONGTY hi = __clc_mul_hi(x, y); \87 ULONGTY ulo = __clc_as_##ULONGTY(x * y); \88 SLONGTY max1 = (x < 0) == (y < 0) && hi != 0; \89 SLONGTY max2 = hi == 0 && ulo >= LONG_MAX && \90 (z > 0 || (ulo + __clc_as_##ULONGTY(z)) > LONG_MAX); \91 SLONGTY min1 = (((x < 0) != (y < 0)) && hi != -1); \92 SLONGTY min2 = \93 hi == -1 && ulo <= ((ULONGTY)LONG_MAX + 1UL) && \94 (z < 0 || __clc_as_##ULONGTY(z) < ((ULONGTY)LONG_MAX - ulo)); \95 SLONGTY ret = __clc_as_##SLONGTY(ulo + __clc_as_##ULONGTY(z)); \96 ret = __clc_select(ret, (SLONGTY)LONG_MAX, (SLONGTY)(max1 || max2)); \97 ret = __clc_select(ret, (SLONGTY)LONG_MIN, (SLONGTY)(min1 || min2)); \98 return ret; \99 }100 101#define __CLC_DEFINE_SLONG_MAD_SAT_ALL_TYS(SLONGTY, ULONGTY) \102 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY, ULONGTY) \103 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY##2, ULONGTY##2) \104 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY##3, ULONGTY##3) \105 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY##4, ULONGTY##4) \106 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY##8, ULONGTY##8) \107 __CLC_DEFINE_SLONG_MAD_SAT(SLONGTY##16, ULONGTY##16)108 109__CLC_DEFINE_SLONG_MAD_SAT_ALL_TYS(long, ulong)110