[llvm] [InstCombine] Add folds for `(fp_binop ({s|u}itofp x), ({s|u}itofp y))` (PR #82555)

via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 29 10:11:23 PST 2024


================
@@ -1401,6 +1401,176 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
   return nullptr;
 }
 
+// Try to fold:
+//    1) (fp_binop ({s|u}itofp x), ({s|u}itofp y))
+//        -> ({s|u}itofp (int_binop x, y))
+//    2) (fp_binop ({s|u}itofp x), FpC)
+//        -> ({s|u}itofp (int_binop x, (fpto{s|u}i FpC)))
+Instruction *InstCombinerImpl::foldFBinOpOfIntCasts(BinaryOperator &BO) {
+  Value *IntOps[2] = {nullptr, nullptr};
+  Constant *Op1FpC = nullptr;
+
+  // Check for:
+  //    1) (binop ({s|u}itofp x), ({s|u}itofp y))
+  //    2) (binop ({s|u}itofp x), FpC)
+  if (!match(BO.getOperand(0), m_SIToFP(m_Value(IntOps[0]))) &&
+      !match(BO.getOperand(0), m_UIToFP(m_Value(IntOps[0]))))
+    return nullptr;
+
+  if (!match(BO.getOperand(1), m_Constant(Op1FpC)) &&
+      !match(BO.getOperand(1), m_SIToFP(m_Value(IntOps[1]))) &&
+      !match(BO.getOperand(1), m_UIToFP(m_Value(IntOps[1]))))
+    return nullptr;
+
+  Type *FPTy = BO.getType();
+  Type *IntTy = IntOps[0]->getType();
+
+  // Do we have signed casts?
+  bool OpsFromSigned = isa<SIToFPInst>(BO.getOperand(0));
+
+  unsigned IntSz = IntTy->getScalarSizeInBits();
+  // This is the maximum number of inuse bits by the integer where the int -> fp
+  // casts are exact.
+  unsigned MaxRepresentableBits =
+      APFloat::semanticsPrecision(FPTy->getScalarType()->getFltSemantics());
----------------
goldsteinn wrote:

Yes, we are overly conservative if `IntSz == MaxRepresentableBits + 1` and its signed (not we can't expand the bound for say `sitofp i16 to half` b.c it won't sign extend). So for things like `i12`, `i24`, ...
I'll add comment to the affect, although don't think its really worth increase code complexity to handle a special case that will almost never actually apply (weird integer widths are rare).
Proofs:
```
; $> /home/noah/programs/opensource/llvm-dev/src/alive2/build/alive-tv (-smt-to=200000000)

----------------------------------------
define half @src_sisi_add_i12(i12 noundef %x, i12 noundef %y) {
#0:
  %overflow_info = sadd_overflow i12 noundef %x, noundef %y
  %does_overflow = extractvalue {i12, i1, i8} %overflow_info, 1
  %doesnot_overflow = xor i1 %does_overflow, 1
  assume i1 %doesnot_overflow
  %xf = sitofp i12 noundef %x to half
  %yf = sitofp i12 noundef %y to half
  %r = fadd half %xf, %yf
  ret half %r
}
=>
define half @tgt_sisi_add_i12(i12 noundef %x, i12 noundef %y) {
#0:
  %overflow_info = sadd_overflow i12 noundef %x, noundef %y
  %does_overflow = extractvalue {i12, i1, i8} %overflow_info, 1
  %doesnot_overflow = xor i1 %does_overflow, 1
  assume i1 %doesnot_overflow
  %xy = add i12 noundef %x, noundef %y
  %r = sitofp i12 %xy to half
  ret half %r
}
Transformation seems to be correct!


----------------------------------------
define half @src_uiui_add_i12(i12 noundef %x, i12 noundef %y) {
#0:
  %overflow_info = uadd_overflow i12 noundef %x, noundef %y
  %does_overflow = extractvalue {i12, i1, i8} %overflow_info, 1
  %doesnot_overflow = xor i1 %does_overflow, 1
  assume i1 %doesnot_overflow
  %xf = uitofp i12 noundef %x to half
  %yf = uitofp i12 noundef %y to half
  %r = fadd half %xf, %yf
  ret half %r
}
=>
define half @tgt_uiui_add_i12(i12 noundef %x, i12 noundef %y) {
#0:
  %overflow_info = uadd_overflow i12 noundef %x, noundef %y
  %does_overflow = extractvalue {i12, i1, i8} %overflow_info, 1
  %doesnot_overflow = xor i1 %does_overflow, 1
  assume i1 %doesnot_overflow
  %xy = add i12 noundef %x, noundef %y
  %r = uitofp i12 %xy to half
  ret half %r
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:
i12 noundef %x = #x80d (2061, -2035)
i12 noundef %y = #x002 (2)

Source:
{i12, i1, i8} %overflow_info = { #x80f (2063, -2033), #x0 (0), poison }
i1 %does_overflow = #x0 (0)
i1 %doesnot_overflow = #x1 (1)
half %xf = #x6806 (2060)
half %yf = #x4000 (2)
half %r = #x6807 (2062)

Target:
{i12, i1, i8} %overflow_info = { #x80f (2063, -2033), #x0 (0), poison }
i1 %does_overflow = #x0 (0)
i1 %doesnot_overflow = #x1 (1)
i12 %xy = #x80f (2063, -2033)
half %r = #x6808 (2064)
Source value: #x6807 (2062)
Target value: #x6808 (2064)

Summary:
  1 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors

```

https://github.com/llvm/llvm-project/pull/82555


More information about the llvm-commits mailing list