fixed_point_sub.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
  2. // RUN: %clang_cc1 -ffixed-point -fpadding-on-unsigned-fixed-point -S -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED
  3. void SignedSubtraction() {
  4. // CHECK-LABEL: SignedSubtraction
  5. short _Accum sa;
  6. _Accum a, b, c, d;
  7. long _Accum la;
  8. unsigned short _Accum usa;
  9. unsigned _Accum ua;
  10. unsigned long _Accum ula;
  11. short _Fract sf;
  12. _Fract f;
  13. long _Fract lf;
  14. unsigned short _Fract usf;
  15. unsigned _Fract uf;
  16. unsigned long _Fract ulf;
  17. // Same type
  18. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  19. // CHECK-NEXT: [[SA2:%[0-9]+]] = load i16, i16* %sa, align 2
  20. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i16 [[SA]], [[SA2]]
  21. // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
  22. sa = sa - sa;
  23. // To larger scale and larger width
  24. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  25. // CHECK-NEXT: [[A:%[0-9]+]] = load i32, i32* %a, align 4
  26. // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i32
  27. // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i32 [[EXT_SA]], 8
  28. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i32 [[SA]], [[A]]
  29. // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
  30. a = sa - a;
  31. // To same scale and smaller width
  32. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  33. // CHECK-NEXT: [[SF:%[0-9]+]] = load i8, i8* %sf, align 1
  34. // CHECK-NEXT: [[EXT_SF:%[a-z0-9]+]] = sext i8 [[SF]] to i16
  35. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i16 [[SA]], [[EXT_SF]]
  36. // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
  37. sa = sa - sf;
  38. // To smaller scale and same width.
  39. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  40. // CHECK-NEXT: [[F:%[0-9]+]] = load i16, i16* %f, align 2
  41. // CHECK-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i24
  42. // CHECK-NEXT: [[SA:%[a-z0-9]+]] = shl i24 [[EXT_SA]], 8
  43. // CHECK-NEXT: [[EXT_F:%[a-z0-9]+]] = sext i16 [[F]] to i24
  44. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i24 [[SA]], [[EXT_F]]
  45. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i24 [[SUM]], 8
  46. // CHECK-NEXT: [[TRUNC_RES:%[a-z0-9]+]] = trunc i24 [[RES]] to i16
  47. // CHECK-NEXT: store i16 [[TRUNC_RES]], i16* %sa, align 2
  48. sa = sa - f;
  49. // To smaller scale and smaller width
  50. // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
  51. // CHECK-NEXT: [[SF:%[0-9]+]] = load i8, i8* %sf, align 1
  52. // CHECK-NEXT: [[EXT_SF:%[a-z0-9]+]] = sext i8 [[SF]] to i32
  53. // CHECK-NEXT: [[SF:%[a-z0-9]+]] = shl i32 [[EXT_SF]], 8
  54. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i32 [[A]], [[SF]]
  55. // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
  56. a = a - sf;
  57. // To larger scale and same width
  58. // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
  59. // CHECK-NEXT: [[LF:%[0-9]+]] = load i32, i32* %lf, align 4
  60. // CHECK-NEXT: [[EXT_A:%[a-z0-9]+]] = sext i32 [[A]] to i48
  61. // CHECK-NEXT: [[A:%[a-z0-9]+]] = shl i48 [[EXT_A]], 16
  62. // CHECK-NEXT: [[EXT_LF:%[a-z0-9]+]] = sext i32 [[LF]] to i48
  63. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i48 [[A]], [[EXT_LF]]
  64. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = ashr i48 [[SUM]], 16
  65. // CHECK-NEXT: [[TRUNC_RES:%[a-z0-9]+]] = trunc i48 [[RES]] to i32
  66. // CHECK-NEXT: store i32 [[TRUNC_RES]], i32* %a, align 4
  67. a = a - lf;
  68. // With corresponding unsigned type
  69. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  70. // CHECK-NEXT: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  71. // SIGNED-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i17
  72. // SIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i17 [[SA_EXT]], 1
  73. // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i17
  74. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i17 [[SA]], [[USA_EXT]]
  75. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = ashr i17 [[SUM]], 1
  76. // SIGNED-NEXT: [[SUM:%[a-z0-9]+]] = trunc i17 [[RESULT]] to i16
  77. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i16 [[SA]], [[USA]]
  78. // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
  79. sa = sa - usa;
  80. // With unsigned of larger scale
  81. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  82. // CHECK-NEXT: [[USA:%[0-9]+]] = load i32, i32* %ua, align 4
  83. // SIGNED-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i33
  84. // SIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i33 [[SA_EXT]], 9
  85. // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i32 [[USA]] to i33
  86. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i33 [[SA]], [[USA_EXT]]
  87. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = ashr i33 [[SUM]], 1
  88. // SIGNED-NEXT: [[SUM:%[a-z0-9]+]] = trunc i33 [[RESULT]] to i32
  89. // UNSIGNED-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i32
  90. // UNSIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i32 [[EXT_SA]], 8
  91. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i32 [[SA]], [[USA]]
  92. // CHECK-NEXT: store i32 [[SUM]], i32* %a, align 4
  93. a = sa - ua;
  94. // With unsigned of smaller width
  95. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  96. // CHECK-NEXT: [[USF:%[0-9]+]] = load i8, i8* %usf, align 1
  97. // SIGNED-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i17
  98. // SIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i17 [[SA_EXT]], 1
  99. // SIGNED-NEXT: [[USF_EXT:%[a-z0-9]+]] = zext i8 [[USF]] to i17
  100. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i17 [[SA]], [[USF_EXT]]
  101. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = ashr i17 [[SUM]], 1
  102. // SIGNED-NEXT: [[SUM:%[a-z0-9]+]] = trunc i17 [[RESULT]] to i16
  103. // UNSIGNED-NEXT: [[EXT_USF:%[a-z0-9]+]] = zext i8 [[USF]] to i16
  104. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i16 [[SA]], [[EXT_USF]]
  105. // CHECK-NEXT: store i16 [[SUM]], i16* %sa, align 2
  106. sa = sa - usf;
  107. // With unsigned of larger width and smaller scale
  108. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  109. // CHECK-NEXT: [[ULF:%[0-9]+]] = load i32, i32* %ulf, align 4
  110. // SIGNED-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i41
  111. // SIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i41 [[SA_EXT]], 25
  112. // SIGNED-NEXT: [[ULF_EXT:%[a-z0-9]+]] = zext i32 [[ULF]] to i41
  113. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i41 [[SA]], [[ULF_EXT]]
  114. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = ashr i41 [[SUM]], 25
  115. // SIGNED-NEXT: [[RES_TRUNC:%[a-z0-9]+]] = trunc i41 [[RESULT]] to i16
  116. // UNSIGNED-NEXT: [[EXT_SA:%[a-z0-9]+]] = sext i16 [[SA]] to i40
  117. // UNSIGNED-NEXT: [[SA:%[a-z0-9]+]] = shl i40 [[EXT_SA]], 24
  118. // UNSIGNED-NEXT: [[EXT_ULF:%[a-z0-9]+]] = zext i32 [[ULF]] to i40
  119. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i40 [[SA]], [[EXT_ULF]]
  120. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = ashr i40 [[SUM]], 24
  121. // UNSIGNED-NEXT: [[RES_TRUNC:%[a-z0-9]+]] = trunc i40 [[RES]] to i16
  122. // CHECK-NEXT: store i16 [[RES_TRUNC]], i16* %sa, align 2
  123. sa = sa - ulf;
  124. // Chained additions of the same signed type should result in the same
  125. // semantics width.
  126. // CHECK: [[A:%[0-9]+]] = load i32, i32* %a, align 4
  127. // CHECK-NEXT: [[B:%[0-9]+]] = load i32, i32* %b, align 4
  128. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i32 [[A]], [[B]]
  129. // CHECK-NEXT: [[C:%[0-9]+]] = load i32, i32* %c, align 4
  130. // CHECK-NEXT: [[SUM2:%[0-9]+]] = sub i32 [[SUM]], [[C]]
  131. // CHECK-NEXT: [[D:%[0-9]+]] = load i32, i32* %d, align 4
  132. // CHECK-NEXT: [[SUM3:%[0-9]+]] = sub i32 [[SUM2]], [[D]]
  133. // CHECK-NEXT: store i32 [[SUM3]], i32* %a, align 4
  134. a = a - b - c - d;
  135. }
  136. void UnsignedSubtraction() {
  137. // CHECK-LABEL: UnsignedSubtraction
  138. unsigned short _Accum usa;
  139. unsigned _Accum ua;
  140. unsigned long _Accum ula;
  141. unsigned short _Fract usf;
  142. unsigned _Fract uf;
  143. unsigned long _Fract ulf;
  144. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  145. // CHECK-NEXT: [[USA2:%[0-9]+]] = load i16, i16* %usa, align 2
  146. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i16 [[USA]], [[USA2]]
  147. // CHECK-NEXT: store i16 [[SUM]], i16* %usa, align 2
  148. usa = usa - usa;
  149. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  150. // CHECK-NEXT: [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
  151. // CHECK-NEXT: [[EXT_USA:%[a-z0-9]+]] = zext i16 [[USA]] to i32
  152. // CHECK-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[EXT_USA]], 8
  153. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i32 [[USA]], [[UA]]
  154. // CHECK-NEXT: store i32 [[SUM]], i32* %ua, align 4
  155. ua = usa - ua;
  156. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  157. // CHECK-NEXT: [[USF:%[0-9]+]] = load i8, i8* %usf, align 1
  158. // CHECK-NEXT: [[EXT_USF:%[a-z0-9]+]] = zext i8 [[USF]] to i16
  159. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i16 [[USA]], [[EXT_USF]]
  160. // CHECK-NEXT: store i16 [[SUM]], i16* %usa, align 2
  161. usa = usa - usf;
  162. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  163. // CHECK-NEXT: [[UF:%[0-9]+]] = load i16, i16* %uf, align 2
  164. // CHECK-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i24
  165. // CHECK-NEXT: [[USA:%[a-z0-9]+]] = shl i24 [[USA_EXT]], 8
  166. // CHECK-NEXT: [[UF_EXT:%[a-z0-9]+]] = zext i16 [[UF]] to i24
  167. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i24 [[USA]], [[UF_EXT]]
  168. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = lshr i24 [[SUM]], 8
  169. // CHECK-NEXT: [[RES_TRUNC:%[a-z0-9]+]] = trunc i24 [[RES]] to i16
  170. // CHECK-NEXT: store i16 [[RES_TRUNC]], i16* %usa, align 2
  171. usa = usa - uf;
  172. }
  173. void IntSubtraction() {
  174. // CHECK-LABEL: IntSubtraction
  175. short _Accum sa;
  176. _Accum a;
  177. unsigned short _Accum usa;
  178. _Sat short _Accum sa_sat;
  179. int i;
  180. unsigned int ui;
  181. long _Fract lf;
  182. _Bool b;
  183. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  184. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  185. // CHECK-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i39
  186. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
  187. // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  188. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i39 [[SA_EXT]], [[I]]
  189. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
  190. // CHECK-NEXT: store i16 [[RES]], i16* %sa, align 2
  191. sa = sa - i;
  192. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  193. // CHECK-NEXT: [[UI:%[0-9]+]] = load i32, i32* %ui, align 4
  194. // CHECK-NEXT: [[SA_EXT:%[a-z0-9]+]] = sext i16 [[SA]] to i40
  195. // CHECK-NEXT: [[UI_EXT:%[a-z0-9]+]] = zext i32 [[UI]] to i40
  196. // CHECK-NEXT: [[UI:%[a-z0-9]+]] = shl i40 [[UI_EXT]], 7
  197. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i40 [[SA_EXT]], [[UI]]
  198. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
  199. // CHECK-NEXT: store i16 [[RES]], i16* %sa, align 2
  200. sa = sa - ui;
  201. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  202. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  203. // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i40
  204. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i40
  205. // SIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
  206. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i40 [[USA_EXT]], [[I]]
  207. // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
  208. // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i39
  209. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
  210. // UNSIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  211. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i39 [[USA_EXT]], [[I]]
  212. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
  213. // CHECK-NEXT: store i16 [[RES]], i16* %usa, align 2
  214. usa = usa - i;
  215. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  216. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  217. // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i40
  218. // SIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
  219. // SIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 8
  220. // SIGNED-NEXT: [[SUM:%[0-9]+]] = sub i40 [[USA_EXT]], [[I]]
  221. // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16
  222. // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i39
  223. // UNSIGNED-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i39
  224. // UNSIGNED-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  225. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = sub i39 [[USA_EXT]], [[I]]
  226. // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16
  227. // CHECK-NEXT: store i16 [[RES]], i16* %usa, align 2
  228. usa = usa - ui;
  229. // CHECK: [[LF:%[0-9]+]] = load i32, i32* %lf, align 4
  230. // CHECK-NEXT: [[UI:%[0-9]+]] = load i32, i32* %ui, align 4
  231. // CHECK-NEXT: [[LF_EXT:%[a-z0-9]+]] = sext i32 [[LF]] to i64
  232. // CHECK-NEXT: [[UI_EXT:%[a-z0-9]+]] = zext i32 [[UI]] to i64
  233. // CHECK-NEXT: [[UI:%[a-z0-9]+]] = shl i64 [[UI_EXT]], 31
  234. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i64 [[LF_EXT]], [[UI]]
  235. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i64 [[SUM]] to i32
  236. // CHECK-NEXT: store i32 [[RES]], i32* %lf, align 4
  237. lf = lf - ui;
  238. // CHECK: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4
  239. // CHECK-NEXT: [[BOOL:%[0-9]+]] = load i8, i8* %b, align 1
  240. // CHECK-NEXT: [[AS_BOOL:%[a-z0-9]+]] = trunc i8 [[BOOL]] to i1
  241. // CHECK-NEXT: [[BOOL_EXT:%[a-z0-9]+]] = zext i1 [[AS_BOOL]] to i32
  242. // CHECK-NEXT: [[ACCUM_EXT:%[a-z0-9]+]] = sext i32 [[ACCUM]] to i47
  243. // CHECK-NEXT: [[BOOL:%[a-z0-9]+]] = sext i32 [[BOOL_EXT]] to i47
  244. // CHECK-NEXT: [[BOOL_EXT:%[a-z0-9]+]] = shl i47 [[BOOL]], 15
  245. // CHECK-NEXT: [[SUM:%[0-9]+]] = sub i47 [[ACCUM_EXT]], [[BOOL_EXT]]
  246. // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i47 [[SUM]] to i32
  247. // CHECK-NEXT: store i32 [[RESULT]], i32* %a, align 4
  248. a = a - b;
  249. }
  250. void SaturatedSubtraction() {
  251. // CHECK-LABEL: SaturatedSubtraction
  252. short _Accum sa;
  253. _Accum a;
  254. long _Accum la;
  255. unsigned short _Accum usa;
  256. unsigned _Accum ua;
  257. unsigned long _Accum ula;
  258. _Sat short _Accum sa_sat;
  259. _Sat _Accum a_sat;
  260. _Sat long _Accum la_sat;
  261. _Sat unsigned short _Accum usa_sat;
  262. _Sat unsigned _Accum ua_sat;
  263. _Sat unsigned long _Accum ula_sat;
  264. _Sat unsigned _Fract uf_sat;
  265. int i;
  266. unsigned int ui;
  267. // CHECK: [[SA:%[0-9]+]] = load i16, i16* %sa, align 2
  268. // CHECK-NEXT: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
  269. // CHECK-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.ssub.sat.i16(i16 [[SA]], i16
  270. // [[SA_SAT]])
  271. // CHECK-NEXT: store i16 [[SUM]], i16* %sa_sat, align 2
  272. sa_sat = sa - sa_sat;
  273. // CHECK: [[USA:%[0-9]+]] = load i16, i16* %usa, align 2
  274. // CHECK-NEXT: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
  275. // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.usub.sat.i16(i16 [[USA]], i16 [[USA_SAT]])
  276. // SIGNED-NEXT: store i16 [[SUM]], i16* %usa_sat, align 2
  277. // UNSIGNED-NEXT: [[USA_TRUNC:%[a-z0-9]+]] = trunc i16 [[USA]] to i15
  278. // UNSIGNED-NEXT: [[USA_SAT_TRUNC:%[a-z0-9]+]] = trunc i16 [[USA_SAT]] to i15
  279. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i15 @llvm.usub.sat.i15(i15 [[USA_TRUNC]], i15 [[USA_SAT_TRUNC]])
  280. // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
  281. // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %usa_sat, align 2
  282. usa_sat = usa - usa_sat;
  283. // CHECK: [[UA:%[0-9]+]] = load i32, i32* %ua, align 4
  284. // CHECK-NEXT: [[USA:%[0-9]+]] = load i16, i16* %usa_sat, align 2
  285. // SIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i32
  286. // SIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i32 [[USA_EXT]], 8
  287. // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i32 @llvm.usub.sat.i32(i32 [[UA]], i32 [[USA]])
  288. // SIGNED-NEXT: store i32 [[SUM]], i32* %ua_sat, align 4
  289. // UNSIGNED-NEXT: [[UA_TRUNC:%[a-z0-9]+]] = trunc i32 [[UA]] to i31
  290. // UNSIGNED-NEXT: [[USA_EXT:%[a-z0-9]+]] = zext i16 [[USA]] to i31
  291. // UNSIGNED-NEXT: [[USA:%[a-z0-9]+]] = shl i31 [[USA_EXT]], 8
  292. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i31 @llvm.usub.sat.i31(i31 [[UA_TRUNC]], i31 [[USA]])
  293. // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i31 [[SUM]] to i32
  294. // UNSIGNED-NEXT: store i32 [[SUM_EXT]], i32* %ua_sat, align 4
  295. ua_sat = ua - usa_sat;
  296. // CHECK: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
  297. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  298. // CHECK-NEXT: [[SA_SAT_EXT:%[a-z0-9]+]] = sext i16 [[SA_SAT]] to i39
  299. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39
  300. // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7
  301. // CHECK-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.ssub.sat.i39(i39 [[SA_SAT_EXT]], i39 [[I]])
  302. // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767
  303. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]]
  304. // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RES]], -32768
  305. // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[RES]]
  306. // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i39 [[RES2]] to i16
  307. // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
  308. sa_sat = sa_sat - i;
  309. // CHECK: [[SA_SAT:%[0-9]+]] = load i16, i16* %sa_sat, align 2
  310. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %ui, align 4
  311. // CHECK-NEXT: [[SA_SAT_EXT:%[a-z0-9]+]] = sext i16 [[SA_SAT]] to i40
  312. // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40
  313. // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 7
  314. // CHECK-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.ssub.sat.i40(i40 [[SA_SAT_EXT]], i40 [[I]])
  315. // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 32767
  316. // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 32767, i40 [[SUM]]
  317. // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RES]], -32768
  318. // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 -32768, i40 [[RES]]
  319. // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i40 [[RES2]] to i16
  320. // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2
  321. sa_sat = sa_sat - ui;
  322. // CHECK: [[UF_SAT:%[0-9]+]] = load i16, i16* %uf_sat, align 2
  323. // CHECK-NEXT: [[UF_SAT2:%[0-9]+]] = load i16, i16* %uf_sat, align 2
  324. // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i16 @llvm.usub.sat.i16(i16 [[UF_SAT]], i16 [[UF_SAT2]])
  325. // SIGNED-NEXT: store i16 [[SUM]], i16* %uf_sat, align 2
  326. // UNSIGNED-NEXT: [[UF_SAT_TRUNC:%[a-z0-9]+]] = trunc i16 [[UF_SAT]] to i15
  327. // UNSIGNED-NEXT: [[UF_SAT_TRUNC2:%[a-z0-9]+]] = trunc i16 [[UF_SAT2]] to i15
  328. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i15 @llvm.usub.sat.i15(i15 [[UF_SAT_TRUNC]], i15 [[UF_SAT_TRUNC2]])
  329. // UNSIGNED-NEXT: [[SUM_EXT:%[a-z0-9]+]] = zext i15 [[SUM]] to i16
  330. // UNSIGNED-NEXT: store i16 [[SUM_EXT]], i16* %uf_sat, align 2
  331. uf_sat = uf_sat - uf_sat;
  332. // CHECK: [[USA_SAT:%[0-9]+]] = load i16, i16* %usa_sat, align 2
  333. // CHECK-NEXT: [[I:%[0-9]+]] = load i32, i32* %i, align 4
  334. // SIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i40
  335. // SIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i40
  336. // SIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i40 [[I_RESIZE]], 8
  337. // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.usub.sat.i40(i40 [[USA_SAT_RESIZE]], i40 [[I_UPSCALE]])
  338. // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 65535
  339. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[SUM]]
  340. // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RESULT]], 0
  341. // SIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[RESULT]]
  342. // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i40 [[RESULT2]] to i16
  343. // UNSIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i39
  344. // UNSIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i39
  345. // UNSIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i39 [[I_RESIZE]], 7
  346. // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.usub.sat.i39(i39 [[USA_SAT_RESIZE]], i39 [[I_UPSCALE]])
  347. // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767
  348. // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]]
  349. // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RESULT]], 0
  350. // UNSIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[RESULT]]
  351. // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i39 [[RESULT2]] to i16
  352. // CHECK-NEXT: store i16 [[RESULT]], i16* %usa_sat, align 2
  353. usa_sat = usa_sat - i;
  354. }