fixed_point_conversions.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
  2. // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
  3. // Between different fixed point types
  4. short _Accum sa_const = 2.5hk; // CHECK-DAG: @sa_const = {{.*}}global i16 320, align 2
  5. _Accum a_const = 2.5hk; // CHECK-DAG: @a_const = {{.*}}global i32 81920, align 4
  6. short _Accum sa_const2 = 2.5k; // CHECK-DAG: @sa_const2 = {{.*}}global i16 320, align 2
  7. short _Accum sa_from_f_const = 0.5r; // CHECK-DAG: sa_from_f_const = {{.*}}global i16 64, align 2
  8. _Fract f_from_sa_const = 0.5hk; // CHECK-DAG: f_from_sa_const = {{.*}}global i16 16384, align 2
  9. unsigned short _Accum usa_const = 2.5uk;
  10. unsigned _Accum ua_const = 2.5uhk;
  11. // SIGNED-DAG: @usa_const = {{.*}}global i16 640, align 2
  12. // SIGNED-DAG: @ua_const = {{.*}}global i32 163840, align 4
  13. // UNSIGNED-DAG: @usa_const = {{.*}}global i16 320, align 2
  14. // UNSIGNED-DAG: @ua_const = {{.*}}global i32 81920, align 4
  15. // FixedPoint to integer
  16. int i_const = -128.0hk; // CHECK-DAG: @i_const = {{.*}}global i32 -128, align 4
  17. int i_const2 = 128.0hk; // CHECK-DAG: @i_const2 = {{.*}}global i32 128, align 4
  18. int i_const3 = -128.0k; // CHECK-DAG: @i_const3 = {{.*}}global i32 -128, align 4
  19. int i_const4 = 128.0k; // CHECK-DAG: @i_const4 = {{.*}}global i32 128, align 4
  20. short s_const = -128.0k; // CHECK-DAG: @s_const = {{.*}}global i16 -128, align 2
  21. short s_const2 = 128.0k; // CHECK-DAG: @s_const2 = {{.*}}global i16 128, align 2
  22. // Integer to fixed point
  23. short _Accum sa_const5 = 2; // CHECK-DAG: @sa_const5 = {{.*}}global i16 256, align 2
  24. short _Accum sa_const6 = -2; // CHECK-DAG: @sa_const6 = {{.*}}global i16 -256, align 2
  25. short _Accum sa_const7 = -256; // CHECK-DAG: @sa_const7 = {{.*}}global i16 -32768, align 2
  26. // Signedness
  27. unsigned short _Accum usa_const2 = 2.5hk;
  28. // SIGNED-DAG: @usa_const2 = {{.*}}global i16 640, align 2
  29. // UNSIGNED-DAG: @usa_const2 = {{.*}}global i16 320, align 2
  30. short _Accum sa_const3 = 2.5hk; // CHECK-DAG: @sa_const3 = {{.*}}global i16 320, align 2
  31. int i_const5 = 128.0uhk;
  32. unsigned int ui_const = 128.0hk;
  33. // CHECK-DAG: @i_const5 = {{.*}}global i32 128, align 4
  34. // CHECK-DAG: @ui_const = {{.*}}global i32 128, align 4
  35. short _Accum sa_const9 = 2u; // CHECK-DAG: @sa_const9 = {{.*}}global i16 256, align 2
  36. unsigned short _Accum usa_const3 = 2;
  37. // SIGNED-DAG: @usa_const3 = {{.*}}global i16 512, align 2
  38. // UNSIGNED-DAG: @usa_const3 = {{.*}}global i16 256, align 2
  39. // Overflow (this is undefined but allowed)
  40. short _Accum sa_const4 = 256.0k;
  41. unsigned int ui_const2 = -2.5hk;
  42. short _Accum sa_const8 = 256;
  43. unsigned short _Accum usa_const4 = -2;
  44. // Saturation
  45. _Sat short _Accum sat_sa_const = 2.5hk; // CHECK-DAG: @sat_sa_const = {{.*}}global i16 320, align 2
  46. _Sat short _Accum sat_sa_const2 = 256.0k; // CHECK-DAG: @sat_sa_const2 = {{.*}}global i16 32767, align 2
  47. _Sat unsigned short _Accum sat_usa_const = -1.0hk;
  48. // CHECK-DAG: @sat_usa_const = {{.*}}global i16 0, align 2
  49. _Sat unsigned short _Accum sat_usa_const2 = 256.0k;
  50. // SIGNED-DAG: @sat_usa_const2 = {{.*}}global i16 -1, align 2
  51. // UNSIGNED-DAG: @sat_usa_const2 = {{.*}}global i16 32767, align 2
  52. _Sat short _Accum sat_sa_const3 = 256; // CHECK-DAG: @sat_sa_const3 = {{.*}}global i16 32767, align 2
  53. _Sat short _Accum sat_sa_const4 = -257; // CHECK-DAG: @sat_sa_const4 = {{.*}}global i16 -32768, align 2
  54. _Sat unsigned short _Accum sat_usa_const3 = -1;
  55. // CHECK-DAG: @sat_usa_const3 = {{.*}}global i16 0, align 2
  56. _Sat unsigned short _Accum sat_usa_const4 = 256;
  57. // SIGNED-DAG: @sat_usa_const4 = {{.*}}global i16 -1, align 2
  58. // UNSIGNED-DAG: @sat_usa_const4 = {{.*}}global i16 32767, align 2
  59. void TestFixedPointCastSameType() {
  60. _Accum a = 2.5k;
  61. _Accum a2 = a;
  62. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  63. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
  64. a2 = (_Accum)a;
  65. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  66. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a2, align 4
  67. }
  68. void TestFixedPointCastDown() {
  69. long _Accum la = 2.5lk;
  70. _Accum a = la;
  71. // CHECK: [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
  72. // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
  73. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
  74. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  75. a = (_Accum)la;
  76. // CHECK: [[LACCUM:%[0-9a-z]+]] = load i64, i64* %la, align 8
  77. // CHECK-NEXT: [[ACCUM_AS_I64:%[0-9a-z]+]] = ashr i64 [[LACCUM]], 16
  78. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i64 [[ACCUM_AS_I64]] to i32
  79. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  80. short _Accum sa = a;
  81. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  82. // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
  83. // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
  84. // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
  85. sa = (short _Accum)a;
  86. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  87. // CHECK-NEXT: [[SACCUM_AS_I32:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
  88. // CHECK-NEXT: [[SACCUM:%[0-9a-z]+]] = trunc i32 [[SACCUM_AS_I32]] to i16
  89. // CHECK-NEXT: store i16 [[SACCUM]], i16* %sa, align 2
  90. }
  91. void TestFixedPointCastUp() {
  92. short _Accum sa = 2.5hk;
  93. _Accum a = sa;
  94. // CHECK: [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
  95. // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
  96. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
  97. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  98. long _Accum la = a;
  99. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  100. // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
  101. // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
  102. // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
  103. a = (_Accum)sa;
  104. // CHECK: [[SACCUM:%[0-9a-z]+]] = load i16, i16* %sa, align 2
  105. // CHECK-NEXT: [[SACCUM_BUFF:%[0-9a-z]+]] = sext i16 [[SACCUM]] to i32
  106. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[SACCUM_BUFF]], 8
  107. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  108. la = (long _Accum)a;
  109. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  110. // CHECK-NEXT: [[ACCUM_BUFF:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
  111. // CHECK-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_BUFF]], 16
  112. // CHECK-NEXT: store i64 [[LACCUM]], i64* %la, align 8
  113. }
  114. void TestFixedPointCastSignedness() {
  115. _Accum a = 2.5k;
  116. unsigned _Accum ua = a;
  117. // SIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  118. // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
  119. // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
  120. // UNSIGNED: TestFixedPointCastSignedness
  121. // UNSIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  122. // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
  123. a = ua;
  124. // SIGNED: [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
  125. // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
  126. // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  127. // UNSIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
  128. // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  129. ua = (unsigned _Accum)a;
  130. // SIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  131. // SIGNED-NEXT: [[UACCUM:%[0-9a-z]+]] = shl i32 [[ACCUM]], 1
  132. // SIGNED-NEXT: store i32 [[UACCUM]], i32* %ua, align 4
  133. // UNSIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  134. // UNSIGNED-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
  135. a = (_Accum)ua;
  136. // SIGNED: [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
  137. // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = lshr i32 [[UACCUM]], 1
  138. // SIGNED-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  139. // UNSIGNED: [[UACCUM:%[0-9a-z]+]] = load i32, i32* %ua, align 4
  140. // UNSIGNED-NEXT: store i32 [[UACCUM]], i32* %a, align 4
  141. _Accum a2;
  142. unsigned long _Accum ula = a2;
  143. // SIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
  144. // SIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
  145. // SIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 17
  146. // SIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
  147. // UNSIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a2, align 4
  148. // UNSIGNED-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[ACCUM]] to i64
  149. // UNSIGNED-NEXT: [[LACCUM:%[0-9a-z]+]] = shl i64 [[ACCUM_EXT]], 16
  150. // UNSIGNED-NEXT: store i64 [[LACCUM]], i64* %ula, align 8
  151. }
  152. void TestFixedPointCastSaturation() {
  153. _Accum a;
  154. _Sat short _Accum sat_sa;
  155. _Sat _Accum sat_a;
  156. _Sat long _Accum sat_la;
  157. _Sat unsigned short _Accum sat_usa;
  158. _Sat unsigned _Accum sat_ua;
  159. _Sat unsigned long _Accum sat_ula;
  160. _Sat short _Fract sat_sf;
  161. _Sat _Fract sat_f;
  162. _Sat long _Fract sat_lf;
  163. // Casting down between types
  164. sat_sa = sat_a;
  165. // CHECK: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  166. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
  167. // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
  168. // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
  169. // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
  170. // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
  171. // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
  172. // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2
  173. // Accum to Fract, decreasing scale
  174. sat_sf = sat_a;
  175. // CHECK: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  176. // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
  177. // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127
  178. // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]]
  179. // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128
  180. // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]]
  181. // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8
  182. // CHECK-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1
  183. // Accum to Fract, same scale
  184. sat_f = a;
  185. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  186. // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
  187. // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
  188. // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768
  189. // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]]
  190. // CHECK-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
  191. // CHECK-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2
  192. // Accum to Fract, increasing scale
  193. sat_lf = sat_a;
  194. // CHECK: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  195. // CHECK-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48
  196. // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[RESIZE]], 16
  197. // CHECK-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647
  198. // CHECK-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]]
  199. // CHECK-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648
  200. // CHECK-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]]
  201. // CHECK-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32
  202. // CHECK-NEXT: store i32 [[TRUNC]], i32* %sat_lf, align 4
  203. // Signed to unsigned, decreasing scale
  204. _Sat _Accum sat_a2;
  205. sat_usa = sat_a2;
  206. // SIGNED: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
  207. // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7
  208. // SIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535
  209. // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]]
  210. // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
  211. // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
  212. // SIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
  213. // SIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
  214. // UNSIGNED: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4
  215. // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8
  216. // UNSIGNED-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767
  217. // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]]
  218. // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0
  219. // UNSIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]]
  220. // UNSIGNED-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16
  221. // UNSIGNED-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2
  222. // Signed to unsigned, increasing scale
  223. sat_ua = sat_a;
  224. // SIGNED: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  225. // SIGNED-NEXT: [[RESIZE:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33
  226. // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[RESIZE]], 1
  227. // SIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0
  228. // SIGNED-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]]
  229. // SIGNED-NEXT: [[TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32
  230. // SIGNED-NEXT: store i32 [[TRUNC]], i32* %sat_ua, align 4
  231. // UNSIGNED: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  232. // UNSIGNED-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
  233. // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]]
  234. // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
  235. // Nothing when saturating to the same type and size
  236. sat_a = a;
  237. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  238. // CHECK-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4
  239. // Nothing when assigning back
  240. a = sat_a;
  241. // CHECK: [[SAT_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4
  242. // CHECK-NEXT: store i32 [[SAT_ACCUM]], i32* %a, align 4
  243. // No overflow when casting from fract to signed accum
  244. sat_a = sat_f;
  245. // CHECK: [[FRACT:%[0-9a-z]+]] = load i16, i16* %sat_f, align 2
  246. // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
  247. // CHECK-NEXT: store i32 [[FRACT_EXT]], i32* %sat_a, align 4
  248. // Only get overflow checking if signed fract to unsigned accum
  249. sat_ua = sat_sf;
  250. // SIGNED: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
  251. // SIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
  252. // SIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9
  253. // SIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
  254. // SIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
  255. // SIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
  256. // UNSIGNED: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1
  257. // UNSIGNED-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
  258. // UNSIGNED-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
  259. // UNSIGNED-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0
  260. // UNSIGNED-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]]
  261. // UNSIGNED-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4
  262. }
  263. void TestFixedPointCastBetFractAccum() {
  264. short _Accum sa;
  265. _Accum a;
  266. long _Accum la;
  267. short _Fract sf;
  268. _Fract f;
  269. long _Fract lf;
  270. unsigned _Accum ua;
  271. unsigned _Fract uf;
  272. // To lower scale
  273. sf = a;
  274. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  275. // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[ACCUM]], 8
  276. // CHECK-NEXT: [[FRACT_TRUNC:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8
  277. // CHECK-NEXT: store i8 [[FRACT_TRUNC]], i8* %sf, align 1
  278. // To higher scale
  279. a = sf;
  280. // CHECK: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sf, align 1
  281. // CHECK-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32
  282. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8
  283. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  284. // To same scale
  285. f = a;
  286. // CHECK: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4
  287. // CHECK-NEXT: [[FRACT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16
  288. // CHECK-NEXT: store i16 [[FRACT]], i16* %f, align 2
  289. a = f;
  290. // CHECK: [[FRACT:%[0-9a-z]+]] = load i16, i16* %f, align 2
  291. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i16 [[FRACT]] to i32
  292. // CHECK-NEXT: store i32 [[ACCUM]], i32* %a, align 4
  293. // To unsigned
  294. ua = uf;
  295. // CHECK: [[FRACT:%[0-9a-z]+]] = load i16, i16* %uf, align 2
  296. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = zext i16 [[FRACT]] to i32
  297. // CHECK-NEXT: store i32 [[ACCUM]], i32* %ua, align 4
  298. uf = ua;
  299. // CHECK: [[FRACT:%[0-9a-z]+]] = load i32, i32* %ua, align 4
  300. // CHECK-NEXT: [[ACCUM:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i16
  301. // CHECK-NEXT: store i16 [[ACCUM]], i16* %uf, align 2
  302. }
  303. void TestFixedPointToInt() {
  304. int i;
  305. short _Accum sa;
  306. unsigned short _Accum usa;
  307. // Will need to check for negative values
  308. i = sa;
  309. // CHECK: [[FX:%[0-9]+]] = load i16, i16* %sa, align 2
  310. // CHECK-NEXT: [[NEG:%[0-9]+]] = icmp slt i16 [[FX]], 0
  311. // CHECK-NEXT: [[ROUNDED:%[0-9]+]] = add i16 [[FX]], 127
  312. // CHECK-NEXT: [[VAL:%[0-9]+]] = select i1 [[NEG]], i16 [[ROUNDED]], i16 [[FX]]
  313. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i16 [[VAL]], 7
  314. // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = sext i16 [[RES]] to i32
  315. // CHECK-NEXT: store i32 [[RES2]], i32* %i, align 4
  316. // No check needed for unsigned fixed points. Can just right shift.
  317. i = usa;
  318. // SIGNED: [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
  319. // SIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 8
  320. // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
  321. // SIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
  322. // UNSIGNED: [[FX:%[0-9]+]] = load i16, i16* %usa, align 2
  323. // UNSIGNED-NEXT: [[INT:%[a-z0-9]+]] = lshr i16 [[FX]], 7
  324. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = zext i16 [[INT]] to i32
  325. // UNSIGNED-NEXT: store i32 [[RES]], i32* %i, align 4
  326. }
  327. void TestIntToFixedPoint() {
  328. short s;
  329. int i, i2;
  330. unsigned int ui;
  331. short _Accum sa;
  332. long _Accum la;
  333. unsigned short _Accum usa;
  334. _Sat short _Accum sat_sa;
  335. _Sat unsigned short _Accum sat_usa;
  336. sa = i;
  337. // CHECK: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  338. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  339. // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
  340. // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
  341. sa = ui;
  342. // CHECK: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  343. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  344. // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
  345. // CHECK-NEXT: store i16 [[FX]], i16* %sa, align 2
  346. usa = i2;
  347. // SIGNED: [[I:%[0-9]+]] = load i32, i32* %i2, align 4
  348. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  349. // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
  350. // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
  351. // UNSIGNED: [[I:%[0-9]+]] = load i32, i32* %i2, align 4
  352. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  353. // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
  354. // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
  355. usa = ui;
  356. // SIGNED: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  357. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  358. // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 8
  359. // SIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
  360. // UNSIGNED: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  361. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = trunc i32 [[I]] to i16
  362. // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i16 [[I_EXT]], 7
  363. // UNSIGNED-NEXT: store i16 [[FX]], i16* %usa, align 2
  364. la = s;
  365. // CHECK: [[I:%[0-9]+]] = load i16, i16* %s, align 2
  366. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i16 [[I]] to i64
  367. // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i64 [[I_EXT]], 31
  368. // CHECK-NEXT: store i64 [[FX]], i64* %la, align 8
  369. }
  370. void TestIntToSatFixedPoint() {
  371. int i, i2;
  372. unsigned int ui;
  373. _Sat short _Accum sat_sa;
  374. _Sat unsigned short _Accum sat_usa;
  375. sat_sa = i;
  376. // CHECK: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  377. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
  378. // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  379. // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
  380. // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
  381. // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], -32768
  382. // CHECK-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[SATMAX]]
  383. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
  384. // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
  385. sat_sa = ui;
  386. // CHECK: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  387. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
  388. // CHECK-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  389. // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
  390. // CHECK-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
  391. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
  392. // CHECK-NEXT: store i16 [[RES]], i16* %sat_sa, align 2
  393. sat_usa = i2;
  394. // SIGNED: [[I:%[0-9]+]] = load i32, i32* %i2, align 4
  395. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i40
  396. // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
  397. // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[FX]], 65535
  398. // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
  399. // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SATMAX]], 0
  400. // SIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[SATMAX]]
  401. // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMIN]] to i16
  402. // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
  403. // UNSIGNED: [[I:%[0-9]+]] = load i32, i32* %i2, align 4
  404. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
  405. // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  406. // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[FX]], 32767
  407. // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
  408. // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SATMAX]], 0
  409. // UNSIGNED-NEXT: [[SATMIN:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[SATMAX]]
  410. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMIN]] to i16
  411. // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
  412. sat_usa = ui;
  413. // SIGNED: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  414. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
  415. // SIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
  416. // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i40 [[FX]], 65535
  417. // SIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[FX]]
  418. // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SATMAX]] to i16
  419. // SIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
  420. // UNSIGNED: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  421. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
  422. // UNSIGNED-NEXT: [[FX:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  423. // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp ugt i39 [[FX]], 32767
  424. // UNSIGNED-NEXT: [[SATMAX:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[FX]]
  425. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SATMAX]] to i16
  426. // UNSIGNED-NEXT: store i16 [[RES]], i16* %sat_usa, align 2
  427. }