InstEmitSimdArithmetic32.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using static ARMeilleure.Instructions.InstEmitFlowHelper;
  6. using static ARMeilleure.Instructions.InstEmitHelper;
  7. using static ARMeilleure.Instructions.InstEmitSimdHelper;
  8. using static ARMeilleure.Instructions.InstEmitSimdHelper32;
  9. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  10. namespace ARMeilleure.Instructions
  11. {
  12. static partial class InstEmit32
  13. {
  14. public static void Vabs_S(ArmEmitterContext context)
  15. {
  16. EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1));
  17. }
  18. public static void Vabs_V(ArmEmitterContext context)
  19. {
  20. OpCode32Simd op = (OpCode32Simd)context.CurrOp;
  21. if (op.F)
  22. {
  23. EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1));
  24. }
  25. else
  26. {
  27. EmitVectorUnaryOpSx32(context, (op1) => EmitAbs(context, op1));
  28. }
  29. }
  30. private static Operand EmitAbs(ArmEmitterContext context, Operand value)
  31. {
  32. Operand isPositive = context.ICompareGreaterOrEqual(value, Const(value.Type, 0));
  33. return context.ConditionalSelect(isPositive, value, context.Negate(value));
  34. }
  35. public static void Vadd_S(ArmEmitterContext context)
  36. {
  37. if (Optimizations.FastFP)
  38. {
  39. EmitScalarBinaryOpF32(context, (op1, op2) => context.Add(op1, op2));
  40. }
  41. else
  42. {
  43. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, op1, op2));
  44. }
  45. }
  46. public static void Vadd_V(ArmEmitterContext context)
  47. {
  48. if (Optimizations.FastFP)
  49. {
  50. EmitVectorBinaryOpF32(context, (op1, op2) => context.Add(op1, op2));
  51. }
  52. else
  53. {
  54. EmitVectorBinaryOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPAddFpscr, SoftFloat64.FPAddFpscr, op1, op2));
  55. }
  56. }
  57. public static void Vadd_I(ArmEmitterContext context)
  58. {
  59. EmitVectorBinaryOpZx32(context, (op1, op2) => context.Add(op1, op2));
  60. }
  61. public static void Vdup(ArmEmitterContext context)
  62. {
  63. OpCode32SimdDupGP op = (OpCode32SimdDupGP)context.CurrOp;
  64. Operand insert = GetIntA32(context, op.Rt);
  65. // Zero extend into an I64, then replicate. Saves the most time over elementwise inserts.
  66. switch (op.Size)
  67. {
  68. case 2:
  69. insert = context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u));
  70. break;
  71. case 1:
  72. insert = context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u));
  73. break;
  74. case 0:
  75. insert = context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u));
  76. break;
  77. default:
  78. throw new InvalidOperationException("Unknown Vdup Size.");
  79. }
  80. InsertScalar(context, op.Vd, insert);
  81. if (op.Q)
  82. {
  83. InsertScalar(context, op.Vd + 1, insert);
  84. }
  85. }
  86. public static void Vdup_1(ArmEmitterContext context)
  87. {
  88. OpCode32SimdDupElem op = (OpCode32SimdDupElem)context.CurrOp;
  89. Operand insert = EmitVectorExtractZx32(context, op.Vm >> 1, ((op.Vm & 1) << (3 - op.Size)) + op.Index, op.Size);
  90. // Zero extend into an I64, then replicate. Saves the most time over elementwise inserts.
  91. switch (op.Size)
  92. {
  93. case 2:
  94. insert = context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u));
  95. break;
  96. case 1:
  97. insert = context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u));
  98. break;
  99. case 0:
  100. insert = context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u));
  101. break;
  102. default:
  103. throw new InvalidOperationException("Unknown Vdup Size.");
  104. }
  105. InsertScalar(context, op.Vd, insert);
  106. if (op.Q)
  107. {
  108. InsertScalar(context, op.Vd | 1, insert);
  109. }
  110. }
  111. public static void Vext(ArmEmitterContext context)
  112. {
  113. OpCode32SimdExt op = (OpCode32SimdExt)context.CurrOp;
  114. int elems = op.GetBytesCount();
  115. int byteOff = op.Immediate;
  116. Operand res = GetVecA32(op.Qd);
  117. for (int index = 0; index < elems; index++)
  118. {
  119. Operand extract;
  120. if (byteOff >= elems)
  121. {
  122. extract = EmitVectorExtractZx32(context, op.Qm, op.Im + (byteOff - elems), op.Size);
  123. }
  124. else
  125. {
  126. extract = EmitVectorExtractZx32(context, op.Qn, op.In + byteOff, op.Size);
  127. }
  128. byteOff++;
  129. res = EmitVectorInsert(context, res, extract, op.Id + index, op.Size);
  130. }
  131. context.Copy(GetVecA32(op.Qd), res);
  132. }
  133. public static void Vmov_S(ArmEmitterContext context)
  134. {
  135. EmitScalarUnaryOpF32(context, (op1) => op1);
  136. }
  137. public static void Vmovn(ArmEmitterContext context)
  138. {
  139. EmitVectorUnaryNarrowOp32(context, (op1) => op1);
  140. }
  141. public static void Vneg_S(ArmEmitterContext context)
  142. {
  143. EmitScalarUnaryOpF32(context, (op1) => context.Negate(op1));
  144. }
  145. public static void Vnmul_S(ArmEmitterContext context)
  146. {
  147. EmitScalarBinaryOpF32(context, (op1, op2) => context.Negate(context.Multiply(op1, op2)));
  148. }
  149. public static void Vnmla_S(ArmEmitterContext context)
  150. {
  151. if (Optimizations.FastFP)
  152. {
  153. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  154. {
  155. return context.Negate(context.Add(op1, context.Multiply(op2, op3)));
  156. });
  157. }
  158. else
  159. {
  160. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  161. {
  162. return EmitSoftFloatCall(context, SoftFloat32.FPNegMulAdd, SoftFloat64.FPNegMulAdd, op1, op2, op3);
  163. });
  164. }
  165. }
  166. public static void Vnmls_S(ArmEmitterContext context)
  167. {
  168. if (Optimizations.FastFP)
  169. {
  170. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  171. {
  172. return context.Add(context.Negate(op1), context.Multiply(op2, op3));
  173. });
  174. }
  175. else
  176. {
  177. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  178. {
  179. return EmitSoftFloatCall(context, SoftFloat32.FPNegMulSub, SoftFloat64.FPNegMulSub, op1, op2, op3);
  180. });
  181. }
  182. }
  183. public static void Vneg_V(ArmEmitterContext context)
  184. {
  185. if ((context.CurrOp as OpCode32Simd).F)
  186. {
  187. EmitVectorUnaryOpF32(context, (op1) => context.Negate(op1));
  188. }
  189. else
  190. {
  191. EmitVectorUnaryOpSx32(context, (op1) => context.Negate(op1));
  192. }
  193. }
  194. public static void Vdiv_S(ArmEmitterContext context)
  195. {
  196. if (Optimizations.FastFP)
  197. {
  198. EmitScalarBinaryOpF32(context, (op1, op2) => context.Divide(op1, op2));
  199. }
  200. else
  201. {
  202. EmitScalarBinaryOpF32(context, (op1, op2) =>
  203. {
  204. return EmitSoftFloatCall(context, SoftFloat32.FPDiv, SoftFloat64.FPDiv, op1, op2);
  205. });
  206. }
  207. }
  208. public static void Vmaxnm_S(ArmEmitterContext context)
  209. {
  210. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPMaxNum, SoftFloat64.FPMaxNum, op1, op2));
  211. }
  212. public static void Vmaxnm_V(ArmEmitterContext context)
  213. {
  214. EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMaxNumFpscr, SoftFloat64.FPMaxNumFpscr, op1, op2));
  215. }
  216. public static void Vminnm_S(ArmEmitterContext context)
  217. {
  218. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPMinNum, SoftFloat64.FPMinNum, op1, op2));
  219. }
  220. public static void Vminnm_V(ArmEmitterContext context)
  221. {
  222. EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMinNumFpscr, SoftFloat64.FPMinNumFpscr, op1, op2));
  223. }
  224. public static void Vmax_V(ArmEmitterContext context)
  225. {
  226. EmitVectorBinaryOpF32(context, (op1, op2) =>
  227. {
  228. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMaxFpscr, SoftFloat64.FPMaxFpscr, op1, op2);
  229. });
  230. }
  231. public static void Vmax_I(ArmEmitterContext context)
  232. {
  233. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  234. if (op.U)
  235. {
  236. EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreaterUI(op1, op2), op1, op2));
  237. }
  238. else
  239. {
  240. EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreater(op1, op2), op1, op2));
  241. }
  242. }
  243. public static void Vmin_V(ArmEmitterContext context)
  244. {
  245. EmitVectorBinaryOpF32(context, (op1, op2) =>
  246. {
  247. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMinFpscr, SoftFloat64.FPMinFpscr, op1, op2);
  248. });
  249. }
  250. public static void Vmin_I(ArmEmitterContext context)
  251. {
  252. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  253. if (op.U)
  254. {
  255. EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLessUI(op1, op2), op1, op2));
  256. }
  257. else
  258. {
  259. EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLess(op1, op2), op1, op2));
  260. }
  261. }
  262. public static void Vmul_S(ArmEmitterContext context)
  263. {
  264. if (Optimizations.FastFP)
  265. {
  266. EmitScalarBinaryOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  267. }
  268. else
  269. {
  270. EmitScalarBinaryOpF32(context, (op1, op2) =>
  271. {
  272. return EmitSoftFloatCall(context, SoftFloat32.FPMul, SoftFloat64.FPMul, op1, op2);
  273. });
  274. }
  275. }
  276. public static void Vmul_V(ArmEmitterContext context)
  277. {
  278. if (Optimizations.FastFP)
  279. {
  280. EmitVectorBinaryOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  281. }
  282. else
  283. {
  284. EmitVectorBinaryOpF32(context, (op1, op2) =>
  285. {
  286. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulFpscr, SoftFloat64.FPMulFpscr, op1, op2);
  287. });
  288. }
  289. }
  290. public static void Vmul_I(ArmEmitterContext context)
  291. {
  292. if ((context.CurrOp as OpCode32SimdReg).U) throw new NotImplementedException("Polynomial mode not implemented");
  293. EmitVectorBinaryOpSx32(context, (op1, op2) => context.Multiply(op1, op2));
  294. }
  295. public static void Vmul_1(ArmEmitterContext context)
  296. {
  297. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  298. if (op.F)
  299. {
  300. if (Optimizations.FastFP)
  301. {
  302. EmitVectorByScalarOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  303. }
  304. else
  305. {
  306. EmitVectorByScalarOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulFpscr, SoftFloat64.FPMulFpscr, op1, op2));
  307. }
  308. }
  309. else
  310. {
  311. EmitVectorByScalarOpI32(context, (op1, op2) => context.Multiply(op1, op2), false);
  312. }
  313. }
  314. public static void Vmla_S(ArmEmitterContext context)
  315. {
  316. if (Optimizations.FastFP)
  317. {
  318. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  319. {
  320. return context.Add(op1, context.Multiply(op2, op3));
  321. });
  322. }
  323. else
  324. {
  325. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  326. {
  327. return EmitSoftFloatCall(context, SoftFloat32.FPMulAdd, SoftFloat64.FPMulAdd, op1, op2, op3);
  328. });
  329. }
  330. }
  331. public static void Vmla_V(ArmEmitterContext context)
  332. {
  333. if (Optimizations.FastFP)
  334. {
  335. EmitVectorTernaryOpF32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  336. }
  337. else
  338. {
  339. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  340. {
  341. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulAddFpscr, SoftFloat64.FPMulAddFpscr, op1, op2, op3);
  342. });
  343. }
  344. }
  345. public static void Vmla_I(ArmEmitterContext context)
  346. {
  347. EmitVectorTernaryOpZx32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  348. }
  349. public static void Vmla_1(ArmEmitterContext context)
  350. {
  351. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  352. if (op.F)
  353. {
  354. if (Optimizations.FastFP)
  355. {
  356. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  357. }
  358. else
  359. {
  360. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulAddFpscr, SoftFloat64.FPMulAddFpscr, op1, op2, op3));
  361. }
  362. }
  363. else
  364. {
  365. EmitVectorsByScalarOpI32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)), false);
  366. }
  367. }
  368. public static void Vmls_S(ArmEmitterContext context)
  369. {
  370. if (Optimizations.FastFP)
  371. {
  372. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  373. {
  374. return context.Subtract(op1, context.Multiply(op2, op3));
  375. });
  376. }
  377. else
  378. {
  379. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  380. {
  381. return EmitSoftFloatCall(context, SoftFloat32.FPMulSub, SoftFloat64.FPMulSub, op1, op2, op3);
  382. });
  383. }
  384. }
  385. public static void Vmls_V(ArmEmitterContext context)
  386. {
  387. if (Optimizations.FastFP)
  388. {
  389. EmitVectorTernaryOpF32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  390. }
  391. else
  392. {
  393. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  394. {
  395. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulSubFpscr, SoftFloat64.FPMulSubFpscr, op1, op2, op3);
  396. });
  397. }
  398. }
  399. public static void Vmls_I(ArmEmitterContext context)
  400. {
  401. EmitVectorTernaryOpZx32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  402. }
  403. public static void Vmls_1(ArmEmitterContext context)
  404. {
  405. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  406. if (op.F)
  407. {
  408. if (Optimizations.FastFP)
  409. {
  410. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  411. }
  412. else
  413. {
  414. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulSubFpscr, SoftFloat64.FPMulSubFpscr, op1, op2, op3));
  415. }
  416. }
  417. else
  418. {
  419. EmitVectorsByScalarOpI32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)), false);
  420. }
  421. }
  422. public static void Vpadd_V(ArmEmitterContext context)
  423. {
  424. EmitVectorPairwiseOpF32(context, (op1, op2) => context.Add(op1, op2));
  425. }
  426. public static void Vpadd_I(ArmEmitterContext context)
  427. {
  428. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  429. EmitVectorPairwiseOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
  430. }
  431. public static void Vrev(ArmEmitterContext context)
  432. {
  433. OpCode32Simd op = (OpCode32Simd)context.CurrOp;
  434. EmitVectorUnaryOpZx32(context, (op1) =>
  435. {
  436. switch (op.Opc)
  437. {
  438. case 0:
  439. switch (op.Size) // Swap bytes.
  440. {
  441. default:
  442. return op1;
  443. case 1:
  444. return InstEmitAluHelper.EmitReverseBytes16_32Op(context, op1);
  445. case 2:
  446. case 3:
  447. return context.ByteSwap(op1);
  448. }
  449. case 1:
  450. switch (op.Size)
  451. {
  452. default:
  453. return op1;
  454. case 2:
  455. return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff0000)), Const(16)),
  456. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x0000ffff)), Const(16)));
  457. case 3:
  458. return context.BitwiseOr(
  459. context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)),
  460. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))),
  461. context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)),
  462. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16))));
  463. }
  464. case 2:
  465. // Swap upper and lower halves.
  466. return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffffffff00000000ul)), Const(32)),
  467. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32)));
  468. }
  469. return op1;
  470. });
  471. }
  472. public static void Vrecpe(ArmEmitterContext context)
  473. {
  474. OpCode32SimdSqrte op = (OpCode32SimdSqrte)context.CurrOp;
  475. if (op.F)
  476. {
  477. EmitVectorUnaryOpF32(context, (op1) =>
  478. {
  479. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPRecipEstimateFpscr, SoftFloat64.FPRecipEstimateFpscr, op1);
  480. });
  481. }
  482. else
  483. {
  484. throw new NotImplementedException("Integer Vrecpe not currently implemented.");
  485. }
  486. }
  487. public static void Vrecps(ArmEmitterContext context)
  488. {
  489. EmitVectorBinaryOpF32(context, (op1, op2) =>
  490. {
  491. return EmitSoftFloatCall(context, SoftFloat32.FPRecipStep, SoftFloat64.FPRecipStep, op1, op2);
  492. });
  493. }
  494. public static void Vrsqrte(ArmEmitterContext context)
  495. {
  496. OpCode32SimdSqrte op = (OpCode32SimdSqrte)context.CurrOp;
  497. if (op.F)
  498. {
  499. EmitVectorUnaryOpF32(context, (op1) =>
  500. {
  501. return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPRSqrtEstimateFpscr, SoftFloat64.FPRSqrtEstimateFpscr, op1);
  502. });
  503. }
  504. else
  505. {
  506. throw new NotImplementedException("Integer Vrsqrte not currently implemented.");
  507. }
  508. }
  509. public static void Vrsqrts(ArmEmitterContext context)
  510. {
  511. EmitVectorBinaryOpF32(context, (op1, op2) =>
  512. {
  513. return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtStep, SoftFloat64.FPRSqrtStep, op1, op2);
  514. });
  515. }
  516. public static void Vsel(ArmEmitterContext context)
  517. {
  518. OpCode32SimdSel op = (OpCode32SimdSel)context.CurrOp;
  519. Operand condition = null;
  520. switch (op.Cc)
  521. {
  522. case OpCode32SimdSelMode.Eq:
  523. condition = GetCondTrue(context, Condition.Eq);
  524. break;
  525. case OpCode32SimdSelMode.Ge:
  526. condition = GetCondTrue(context, Condition.Ge);
  527. break;
  528. case OpCode32SimdSelMode.Gt:
  529. condition = GetCondTrue(context, Condition.Gt);
  530. break;
  531. case OpCode32SimdSelMode.Vs:
  532. condition = GetCondTrue(context, Condition.Vs);
  533. break;
  534. }
  535. EmitScalarBinaryOpI32(context, (op1, op2) =>
  536. {
  537. return context.ConditionalSelect(condition, op1, op2);
  538. });
  539. }
  540. public static void Vsqrt_S(ArmEmitterContext context)
  541. {
  542. EmitScalarUnaryOpF32(context, (op1) =>
  543. {
  544. return EmitSoftFloatCall(context, SoftFloat32.FPSqrt, SoftFloat64.FPSqrt, op1);
  545. });
  546. }
  547. public static void Vsub_S(ArmEmitterContext context)
  548. {
  549. EmitScalarBinaryOpF32(context, (op1, op2) => context.Subtract(op1, op2));
  550. }
  551. public static void Vsub_V(ArmEmitterContext context)
  552. {
  553. EmitVectorBinaryOpF32(context, (op1, op2) => context.Subtract(op1, op2));
  554. }
  555. public static void Vsub_I(ArmEmitterContext context)
  556. {
  557. EmitVectorBinaryOpZx32(context, (op1, op2) => context.Subtract(op1, op2));
  558. }
  559. }
  560. }