/ src / Ryujinx.Graphics.Shader / Instructions / InstEmitIntegerArithmetic.cs
InstEmitIntegerArithmetic.cs
  1  using Ryujinx.Graphics.Shader.Decoders;
  2  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3  using Ryujinx.Graphics.Shader.Translation;
  4  
  5  using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
  6  using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  7  using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  8  
  9  namespace Ryujinx.Graphics.Shader.Instructions
 10  {
 11      static partial class InstEmit
 12      {
 13          public static void IaddR(EmitterContext context)
 14          {
 15              InstIaddR op = context.GetOp<InstIaddR>();
 16  
 17              var srcA = GetSrcReg(context, op.SrcA);
 18              var srcB = GetSrcReg(context, op.SrcB);
 19  
 20              EmitIadd(context, srcA, srcB, op.Dest, op.AvgMode, op.X, op.WriteCC);
 21          }
 22  
 23          public static void IaddI(EmitterContext context)
 24          {
 25              InstIaddI op = context.GetOp<InstIaddI>();
 26  
 27              var srcA = GetSrcReg(context, op.SrcA);
 28              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
 29  
 30              EmitIadd(context, srcA, srcB, op.Dest, op.AvgMode, op.X, op.WriteCC);
 31          }
 32  
 33          public static void IaddC(EmitterContext context)
 34          {
 35              InstIaddC op = context.GetOp<InstIaddC>();
 36  
 37              var srcA = GetSrcReg(context, op.SrcA);
 38              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
 39  
 40              EmitIadd(context, srcA, srcB, op.Dest, op.AvgMode, op.X, op.WriteCC);
 41          }
 42  
 43          public static void Iadd32i(EmitterContext context)
 44          {
 45              InstIadd32i op = context.GetOp<InstIadd32i>();
 46  
 47              var srcA = GetSrcReg(context, op.SrcA);
 48              var srcB = GetSrcImm(context, op.Imm32);
 49  
 50              EmitIadd(context, srcA, srcB, op.Dest, op.AvgMode, op.X, op.WriteCC);
 51          }
 52  
 53          public static void Iadd3R(EmitterContext context)
 54          {
 55              InstIadd3R op = context.GetOp<InstIadd3R>();
 56  
 57              var srcA = GetSrcReg(context, op.SrcA);
 58              var srcB = GetSrcReg(context, op.SrcB);
 59              var srcC = GetSrcReg(context, op.SrcC);
 60  
 61              EmitIadd3(context, op.Lrs, srcA, srcB, srcC, op.Apart, op.Bpart, op.Cpart, op.Dest, op.NegA, op.NegB, op.NegC);
 62          }
 63  
 64          public static void Iadd3I(EmitterContext context)
 65          {
 66              InstIadd3I op = context.GetOp<InstIadd3I>();
 67  
 68              var srcA = GetSrcReg(context, op.SrcA);
 69              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
 70              var srcC = GetSrcReg(context, op.SrcC);
 71  
 72              EmitIadd3(context, Lrs.None, srcA, srcB, srcC, HalfSelect.B32, HalfSelect.B32, HalfSelect.B32, op.Dest, op.NegA, op.NegB, op.NegC);
 73          }
 74  
 75          public static void Iadd3C(EmitterContext context)
 76          {
 77              InstIadd3C op = context.GetOp<InstIadd3C>();
 78  
 79              var srcA = GetSrcReg(context, op.SrcA);
 80              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
 81              var srcC = GetSrcReg(context, op.SrcC);
 82  
 83              EmitIadd3(context, Lrs.None, srcA, srcB, srcC, HalfSelect.B32, HalfSelect.B32, HalfSelect.B32, op.Dest, op.NegA, op.NegB, op.NegC);
 84          }
 85  
 86          public static void ImadR(EmitterContext context)
 87          {
 88              InstImadR op = context.GetOp<InstImadR>();
 89  
 90              var srcA = GetSrcReg(context, op.SrcA);
 91              var srcB = GetSrcReg(context, op.SrcB);
 92              var srcC = GetSrcReg(context, op.SrcC);
 93  
 94              EmitImad(context, srcA, srcB, srcC, op.Dest, op.AvgMode, op.ASigned, op.BSigned, op.Hilo);
 95          }
 96  
 97          public static void ImadI(EmitterContext context)
 98          {
 99              InstImadI op = context.GetOp<InstImadI>();
100  
101              var srcA = GetSrcReg(context, op.SrcA);
102              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
103              var srcC = GetSrcReg(context, op.SrcC);
104  
105              EmitImad(context, srcA, srcB, srcC, op.Dest, op.AvgMode, op.ASigned, op.BSigned, op.Hilo);
106          }
107  
108          public static void ImadC(EmitterContext context)
109          {
110              InstImadC op = context.GetOp<InstImadC>();
111  
112              var srcA = GetSrcReg(context, op.SrcA);
113              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
114              var srcC = GetSrcReg(context, op.SrcC);
115  
116              EmitImad(context, srcA, srcB, srcC, op.Dest, op.AvgMode, op.ASigned, op.BSigned, op.Hilo);
117          }
118  
119          public static void ImadRc(EmitterContext context)
120          {
121              InstImadRc op = context.GetOp<InstImadRc>();
122  
123              var srcA = GetSrcReg(context, op.SrcA);
124              var srcB = GetSrcReg(context, op.SrcC);
125              var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
126  
127              EmitImad(context, srcA, srcB, srcC, op.Dest, op.AvgMode, op.ASigned, op.BSigned, op.Hilo);
128          }
129  
130          public static void Imad32i(EmitterContext context)
131          {
132              InstImad32i op = context.GetOp<InstImad32i>();
133  
134              var srcA = GetSrcReg(context, op.SrcA);
135              var srcB = GetSrcImm(context, op.Imm32);
136              var srcC = GetSrcReg(context, op.Dest);
137  
138              EmitImad(context, srcA, srcB, srcC, op.Dest, op.AvgMode, op.ASigned, op.BSigned, op.Hilo);
139          }
140  
141          public static void ImulR(EmitterContext context)
142          {
143              InstImulR op = context.GetOp<InstImulR>();
144  
145              var srcA = GetSrcReg(context, op.SrcA);
146              var srcB = GetSrcReg(context, op.SrcB);
147  
148              EmitImad(context, srcA, srcB, Const(0), op.Dest, AvgMode.NoNeg, op.ASigned, op.BSigned, op.Hilo);
149          }
150  
151          public static void ImulI(EmitterContext context)
152          {
153              InstImulI op = context.GetOp<InstImulI>();
154  
155              var srcA = GetSrcReg(context, op.SrcA);
156              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
157  
158              EmitImad(context, srcA, srcB, Const(0), op.Dest, AvgMode.NoNeg, op.ASigned, op.BSigned, op.Hilo);
159          }
160  
161          public static void ImulC(EmitterContext context)
162          {
163              InstImulC op = context.GetOp<InstImulC>();
164  
165              var srcA = GetSrcReg(context, op.SrcA);
166              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
167  
168              EmitImad(context, srcA, srcB, Const(0), op.Dest, AvgMode.NoNeg, op.ASigned, op.BSigned, op.Hilo);
169          }
170  
171          public static void Imul32i(EmitterContext context)
172          {
173              InstImul32i op = context.GetOp<InstImul32i>();
174  
175              var srcA = GetSrcReg(context, op.SrcA);
176              var srcB = GetSrcImm(context, op.Imm32);
177  
178              EmitImad(context, srcA, srcB, Const(0), op.Dest, AvgMode.NoNeg, op.ASigned, op.BSigned, op.Hilo);
179          }
180  
181          public static void IscaddR(EmitterContext context)
182          {
183              InstIscaddR op = context.GetOp<InstIscaddR>();
184  
185              var srcA = GetSrcReg(context, op.SrcA);
186              var srcB = GetSrcReg(context, op.SrcB);
187  
188              EmitIscadd(context, srcA, srcB, op.Dest, op.Imm5, op.AvgMode, op.WriteCC);
189          }
190  
191          public static void IscaddI(EmitterContext context)
192          {
193              InstIscaddI op = context.GetOp<InstIscaddI>();
194  
195              var srcA = GetSrcReg(context, op.SrcA);
196              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
197  
198              EmitIscadd(context, srcA, srcB, op.Dest, op.Imm5, op.AvgMode, op.WriteCC);
199          }
200  
201          public static void IscaddC(EmitterContext context)
202          {
203              InstIscaddC op = context.GetOp<InstIscaddC>();
204  
205              var srcA = GetSrcReg(context, op.SrcA);
206              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
207  
208              EmitIscadd(context, srcA, srcB, op.Dest, op.Imm5, op.AvgMode, op.WriteCC);
209          }
210  
211          public static void Iscadd32i(EmitterContext context)
212          {
213              InstIscadd32i op = context.GetOp<InstIscadd32i>();
214  
215              var srcA = GetSrcReg(context, op.SrcA);
216              var srcB = GetSrcImm(context, op.Imm32);
217  
218              EmitIscadd(context, srcA, srcB, op.Dest, op.Imm5, AvgMode.NoNeg, op.WriteCC);
219          }
220  
221          public static void LeaR(EmitterContext context)
222          {
223              InstLeaR op = context.GetOp<InstLeaR>();
224  
225              var srcA = GetSrcReg(context, op.SrcA);
226              var srcB = GetSrcReg(context, op.SrcB);
227  
228              EmitLea(context, srcA, srcB, op.Dest, op.NegA, op.ImmU5);
229          }
230  
231          public static void LeaI(EmitterContext context)
232          {
233              InstLeaI op = context.GetOp<InstLeaI>();
234  
235              var srcA = GetSrcReg(context, op.SrcA);
236              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
237  
238              EmitLea(context, srcA, srcB, op.Dest, op.NegA, op.ImmU5);
239          }
240  
241          public static void LeaC(EmitterContext context)
242          {
243              InstLeaC op = context.GetOp<InstLeaC>();
244  
245              var srcA = GetSrcReg(context, op.SrcA);
246              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
247  
248              EmitLea(context, srcA, srcB, op.Dest, op.NegA, op.ImmU5);
249          }
250  
251          public static void LeaHiR(EmitterContext context)
252          {
253              InstLeaHiR op = context.GetOp<InstLeaHiR>();
254  
255              var srcA = GetSrcReg(context, op.SrcA);
256              var srcB = GetSrcReg(context, op.SrcB);
257              var srcC = GetSrcReg(context, op.SrcC);
258  
259              EmitLeaHi(context, srcA, srcB, srcC, op.Dest, op.NegA, op.ImmU5);
260          }
261  
262          public static void LeaHiC(EmitterContext context)
263          {
264              InstLeaHiC op = context.GetOp<InstLeaHiC>();
265  
266              var srcA = GetSrcReg(context, op.SrcA);
267              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
268              var srcC = GetSrcReg(context, op.SrcC);
269  
270              EmitLeaHi(context, srcA, srcB, srcC, op.Dest, op.NegA, op.ImmU5);
271          }
272  
273          public static void XmadR(EmitterContext context)
274          {
275              InstXmadR op = context.GetOp<InstXmadR>();
276  
277              var srcA = GetSrcReg(context, op.SrcA);
278              var srcB = GetSrcReg(context, op.SrcB);
279              var srcC = GetSrcReg(context, op.SrcC);
280  
281              EmitXmad(context, op.XmadCop, srcA, srcB, srcC, op.Dest, op.ASigned, op.BSigned, op.HiloA, op.HiloB, op.Psl, op.Mrg, op.X, op.WriteCC);
282          }
283  
284          public static void XmadI(EmitterContext context)
285          {
286              InstXmadI op = context.GetOp<InstXmadI>();
287  
288              var srcA = GetSrcReg(context, op.SrcA);
289              var srcB = GetSrcImm(context, op.Imm16);
290              var srcC = GetSrcReg(context, op.SrcC);
291  
292              EmitXmad(context, op.XmadCop, srcA, srcB, srcC, op.Dest, op.ASigned, op.BSigned, op.HiloA, false, op.Psl, op.Mrg, op.X, op.WriteCC);
293          }
294  
295          public static void XmadC(EmitterContext context)
296          {
297              InstXmadC op = context.GetOp<InstXmadC>();
298  
299              var srcA = GetSrcReg(context, op.SrcA);
300              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
301              var srcC = GetSrcReg(context, op.SrcC);
302  
303              EmitXmad(context, op.XmadCop, srcA, srcB, srcC, op.Dest, op.ASigned, op.BSigned, op.HiloA, op.HiloB, op.Psl, op.Mrg, op.X, op.WriteCC);
304          }
305  
306          public static void XmadRc(EmitterContext context)
307          {
308              InstXmadRc op = context.GetOp<InstXmadRc>();
309  
310              var srcA = GetSrcReg(context, op.SrcA);
311              var srcB = GetSrcReg(context, op.SrcC);
312              var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
313  
314              EmitXmad(context, op.XmadCop, srcA, srcB, srcC, op.Dest, op.ASigned, op.BSigned, op.HiloA, op.HiloB, false, false, op.X, op.WriteCC);
315          }
316  
317          private static void EmitIadd(
318              EmitterContext context,
319              Operand srcA,
320              Operand srcB,
321              int rd,
322              AvgMode avgMode,
323              bool extended,
324              bool writeCC)
325          {
326              srcA = context.INegate(srcA, avgMode == AvgMode.NegA);
327              srcB = context.INegate(srcB, avgMode == AvgMode.NegB);
328  
329              Operand res = context.IAdd(srcA, srcB);
330  
331              if (extended)
332              {
333                  res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1)));
334              }
335  
336              SetIaddFlags(context, res, srcA, srcB, writeCC, extended);
337  
338              // TODO: SAT.
339  
340              context.Copy(GetDest(rd), res);
341          }
342  
343          private static void EmitIadd3(
344              EmitterContext context,
345              Lrs mode,
346              Operand srcA,
347              Operand srcB,
348              Operand srcC,
349              HalfSelect partA,
350              HalfSelect partB,
351              HalfSelect partC,
352              int rd,
353              bool negateA,
354              bool negateB,
355              bool negateC)
356          {
357              Operand Extend(Operand src, HalfSelect part)
358              {
359                  if (part == HalfSelect.B32)
360                  {
361                      return src;
362                  }
363  
364                  if (part == HalfSelect.H0)
365                  {
366                      return context.BitwiseAnd(src, Const(0xffff));
367                  }
368                  else if (part == HalfSelect.H1)
369                  {
370                      return context.ShiftRightU32(src, Const(16));
371                  }
372                  else
373                  {
374                      context.TranslatorContext.GpuAccessor.Log($"Iadd3 has invalid component selection {part}.");
375                  }
376  
377                  return src;
378              }
379  
380              srcA = context.INegate(Extend(srcA, partA), negateA);
381              srcB = context.INegate(Extend(srcB, partB), negateB);
382              srcC = context.INegate(Extend(srcC, partC), negateC);
383  
384              Operand res = context.IAdd(srcA, srcB);
385  
386              if (mode != Lrs.None)
387              {
388                  if (mode == Lrs.LeftShift)
389                  {
390                      res = context.ShiftLeft(res, Const(16));
391                  }
392                  else if (mode == Lrs.RightShift)
393                  {
394                      res = context.ShiftRightU32(res, Const(16));
395                  }
396                  else
397                  {
398                      // TODO: Warning.
399                  }
400              }
401  
402              res = context.IAdd(res, srcC);
403  
404              context.Copy(GetDest(rd), res);
405  
406              // TODO: CC, X, corner cases.
407          }
408  
409          private static void EmitImad(
410              EmitterContext context,
411              Operand srcA,
412              Operand srcB,
413              Operand srcC,
414              int rd,
415              AvgMode avgMode,
416              bool signedA,
417              bool signedB,
418              bool high)
419          {
420              srcB = context.INegate(srcB, avgMode == AvgMode.NegA);
421              srcC = context.INegate(srcC, avgMode == AvgMode.NegB);
422  
423              Operand res;
424  
425              if (high)
426              {
427                  if (signedA && signedB)
428                  {
429                      res = context.MultiplyHighS32(srcA, srcB);
430                  }
431                  else
432                  {
433                      res = context.MultiplyHighU32(srcA, srcB);
434  
435                      if (signedA)
436                      {
437                          res = context.IAdd(res, context.IMultiply(srcB, context.ShiftRightS32(srcA, Const(31))));
438                      }
439                      else if (signedB)
440                      {
441                          res = context.IAdd(res, context.IMultiply(srcA, context.ShiftRightS32(srcB, Const(31))));
442                      }
443                  }
444              }
445              else
446              {
447                  res = context.IMultiply(srcA, srcB);
448              }
449  
450              if (srcC.Type != OperandType.Constant || srcC.Value != 0)
451              {
452                  res = context.IAdd(res, srcC);
453              }
454  
455              // TODO: CC, X, SAT, and more?
456  
457              context.Copy(GetDest(rd), res);
458          }
459  
460          private static void EmitIscadd(
461              EmitterContext context,
462              Operand srcA,
463              Operand srcB,
464              int rd,
465              int shift,
466              AvgMode avgMode,
467              bool writeCC)
468          {
469              srcA = context.ShiftLeft(srcA, Const(shift));
470  
471              srcA = context.INegate(srcA, avgMode == AvgMode.NegA);
472              srcB = context.INegate(srcB, avgMode == AvgMode.NegB);
473  
474              Operand res = context.IAdd(srcA, srcB);
475  
476              SetIaddFlags(context, res, srcA, srcB, writeCC, false);
477  
478              context.Copy(GetDest(rd), res);
479          }
480  
481          public static void EmitLea(EmitterContext context, Operand srcA, Operand srcB, int rd, bool negateA, int shift)
482          {
483              srcA = context.ShiftLeft(srcA, Const(shift));
484              srcA = context.INegate(srcA, negateA);
485  
486              Operand res = context.IAdd(srcA, srcB);
487  
488              context.Copy(GetDest(rd), res);
489  
490              // TODO: CC, X.
491          }
492  
493          private static void EmitLeaHi(
494              EmitterContext context,
495              Operand srcA,
496              Operand srcB,
497              Operand srcC,
498              int rd,
499              bool negateA,
500              int shift)
501          {
502              Operand aLow = context.ShiftLeft(srcA, Const(shift));
503              Operand aHigh = shift == 0 ? Const(0) : context.ShiftRightU32(srcA, Const(32 - shift));
504              aHigh = context.BitwiseOr(aHigh, context.ShiftLeft(srcC, Const(shift)));
505  
506              if (negateA)
507              {
508                  // Perform 64-bit negation by doing bitwise not of the value,
509                  // then adding 1 and carrying over from low to high.
510                  aLow = context.BitwiseNot(aLow);
511                  aHigh = context.BitwiseNot(aHigh);
512  
513  #pragma warning disable IDE0059 // Remove unnecessary value assignment
514                  aLow = AddWithCarry(context, aLow, Const(1), out Operand aLowCOut);
515  #pragma warning restore IDE0059
516                  aHigh = context.IAdd(aHigh, aLowCOut);
517              }
518  
519              Operand res = context.IAdd(aHigh, srcB);
520  
521              context.Copy(GetDest(rd), res);
522  
523              // TODO: CC, X.
524          }
525  
526          public static void EmitXmad(
527              EmitterContext context,
528              XmadCop2 mode,
529              Operand srcA,
530              Operand srcB,
531              Operand srcC,
532              int rd,
533              bool signedA,
534              bool signedB,
535              bool highA,
536              bool highB,
537              bool productShiftLeft,
538              bool merge,
539              bool extended,
540              bool writeCC)
541          {
542              XmadCop modeConv;
543              switch (mode)
544              {
545                  case XmadCop2.Cfull:
546                      modeConv = XmadCop.Cfull;
547                      break;
548                  case XmadCop2.Clo:
549                      modeConv = XmadCop.Clo;
550                      break;
551                  case XmadCop2.Chi:
552                      modeConv = XmadCop.Chi;
553                      break;
554                  case XmadCop2.Csfu:
555                      modeConv = XmadCop.Csfu;
556                      break;
557                  default:
558                      context.TranslatorContext.GpuAccessor.Log($"Invalid XMAD mode \"{mode}\".");
559                      return;
560              }
561  
562              EmitXmad(context, modeConv, srcA, srcB, srcC, rd, signedA, signedB, highA, highB, productShiftLeft, merge, extended, writeCC);
563          }
564  
565          public static void EmitXmad(
566              EmitterContext context,
567              XmadCop mode,
568              Operand srcA,
569              Operand srcB,
570              Operand srcC,
571              int rd,
572              bool signedA,
573              bool signedB,
574              bool highA,
575              bool highB,
576              bool productShiftLeft,
577              bool merge,
578              bool extended,
579              bool writeCC)
580          {
581              var srcBUnmodified = srcB;
582  
583              Operand Extend16To32(Operand src, bool high, bool signed)
584              {
585                  if (signed && high)
586                  {
587                      return context.ShiftRightS32(src, Const(16));
588                  }
589                  else if (signed)
590                  {
591                      return context.BitfieldExtractS32(src, Const(0), Const(16));
592                  }
593                  else if (high)
594                  {
595                      return context.ShiftRightU32(src, Const(16));
596                  }
597                  else
598                  {
599                      return context.BitwiseAnd(src, Const(0xffff));
600                  }
601              }
602  
603              srcA = Extend16To32(srcA, highA, signedA);
604              srcB = Extend16To32(srcB, highB, signedB);
605  
606              Operand res = context.IMultiply(srcA, srcB);
607  
608              if (productShiftLeft)
609              {
610                  res = context.ShiftLeft(res, Const(16));
611              }
612  
613              switch (mode)
614              {
615                  case XmadCop.Cfull:
616                      break;
617  
618                  case XmadCop.Clo:
619                      srcC = Extend16To32(srcC, high: false, signed: false);
620                      break;
621                  case XmadCop.Chi:
622                      srcC = Extend16To32(srcC, high: true, signed: false);
623                      break;
624  
625                  case XmadCop.Cbcc:
626                      srcC = context.IAdd(srcC, context.ShiftLeft(srcBUnmodified, Const(16)));
627                      break;
628  
629                  case XmadCop.Csfu:
630                      Operand signAdjustA = context.ShiftLeft(context.ShiftRightU32(srcA, Const(31)), Const(16));
631                      Operand signAdjustB = context.ShiftLeft(context.ShiftRightU32(srcB, Const(31)), Const(16));
632  
633                      srcC = context.ISubtract(srcC, context.IAdd(signAdjustA, signAdjustB));
634                      break;
635  
636                  default:
637                      context.TranslatorContext.GpuAccessor.Log($"Invalid XMAD mode \"{mode}\".");
638                      return;
639              }
640  
641              Operand product = res;
642  
643              if (extended)
644              {
645                  // Add with carry.
646                  res = context.IAdd(res, context.BitwiseAnd(GetCF(), Const(1)));
647              }
648              else
649              {
650                  // Add (no carry in).
651                  res = context.IAdd(res, srcC);
652              }
653  
654              SetIaddFlags(context, res, product, srcC, writeCC, extended);
655  
656              if (merge)
657              {
658                  res = context.BitwiseAnd(res, Const(0xffff));
659                  res = context.BitwiseOr(res, context.ShiftLeft(srcBUnmodified, Const(16)));
660              }
661  
662              context.Copy(GetDest(rd), res);
663          }
664  
665          private static void SetIaddFlags(EmitterContext context, Operand res, Operand srcA, Operand srcB, bool setCC, bool extended)
666          {
667              if (!setCC)
668              {
669                  return;
670              }
671  
672              if (extended)
673              {
674                  // C = (d == a && CIn) || d < a
675                  Operand tempC0 = context.ICompareEqual(res, srcA);
676                  Operand tempC1 = context.ICompareLessUnsigned(res, srcA);
677  
678                  tempC0 = context.BitwiseAnd(tempC0, GetCF());
679  
680                  context.Copy(GetCF(), context.BitwiseOr(tempC0, tempC1));
681              }
682              else
683              {
684                  // C = d < a
685                  context.Copy(GetCF(), context.ICompareLessUnsigned(res, srcA));
686              }
687  
688              // V = (d ^ a) & ~(a ^ b) < 0
689              Operand tempV0 = context.BitwiseExclusiveOr(res, srcA);
690              Operand tempV1 = context.BitwiseExclusiveOr(srcA, srcB);
691  
692              tempV1 = context.BitwiseNot(tempV1);
693  
694              Operand tempV = context.BitwiseAnd(tempV0, tempV1);
695  
696              context.Copy(GetVF(), context.ICompareLess(tempV, Const(0)));
697  
698              SetZnFlags(context, res, setCC: true, extended: extended);
699          }
700      }
701  }