Canonicalize pass not folding all constants

I was playing around with the canonicalization pass and noticed some cases where constant folding was not fully implemented. For example, I tried passing the following code (which computes and then prints 2 - 3 * 5 / 4) through mlir-opt --canonicalize:

module  {
  func @main() {
    %cst = std.constant 2.000000e+00 : f64
    %cst_0 = std.constant 3.000000e+00 : f64
    %cst_1 = std.constant 5.000000e+00 : f64
    %0 = std.mulf %cst_0, %cst_1 : f64
    %cst_2 = std.constant 4.000000e+00 : f64
    %1 = std.divf %0, %cst_2 : f64
    %2 = std.subf %cst, %1 : f64
    "toy.print"(%2) : (f64) -> ()
    return
  }
}

Instead of producing something like the following

module {
  func @main() {
    %0 = std.constant -1.75e+00 : f64
    "toy.print"(%0) : (f64) -> ()
  }
}

it results in a partially-reduced

module {
  func @main() {
    %cst = constant 2.000000e+00 : f64
    %cst_0 = constant 1.500000e+01 : f64
    %cst_1 = constant 4.000000e+00 : f64
    %0 = divf %cst_0, %cst_1 : f64
    %1 = subf %cst, %0 : f64
    "toy.print"(%1) : (f64) -> ()
    return
  }
}

Why are the std.divf and std.subf operators with constant arguments not being simplified? According to the documentation on Operation Canonicalization, constant folding should be implemented on all levels of IR. Am I missing something here?

A correct, but perhaps not helpful, answer is that there is no folder implemented for divf: llvm-project/Ops.td at ceb3cdccd0fb597659147e0f538fdee91414541e · llvm/llvm-project · GitHub (notice that hasFolder is not set). I suspect this would be a case of “patches welcome” although I’m also guessing there may be some complicated details of float division with underflow/overflow/nan/inf that you’d need to watch out for.

1 Like

Could you elaborate on why it might be tricky to implement constant folding for divf? From my perspective, the floating division point division of two constants is well defined under IEEE. On an unrelated note, negf appears to lack a folder as well.

I always think that about floating point math and then I learn something new and weird about floating point math. That plus the fact that someone apparently didn’t add it when adding folders from mulf and addf makes me think there might be some nuance that I may be missing :slight_smile:

It’s not that tricky. We should be able to mostly copypaste the code from LLVM I think. (search for FDiv elsewhere in that file for more folds)

Most code that exists until now using these ops tends to lower through LLVM, and LLVM does all the constant folding already, so there has been limited prioritization for implementing folders for these ops.

1 Like