-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[mlir][Arith] Specify evaluation order of getExpr
#87859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[mlir][Arith] Specify evaluation order of getExpr
#87859
Conversation
The C++ standard does not specify an evaluation order for addition/... operands. E.g., in `a() + b()`, the compiler is free to evaluate `a` or `b` first. This lead to different `mlir-opt` outputs in #85895. (FileCheck passed when compiled with LLVM but failed when compiled with gcc.)
@llvm/pr-subscribers-mlir Author: Matthias Springer (matthias-springer) ChangesThe C++ standard does not specify an evaluation order for addition/... operands. E.g., in This lead to different Full diff: https://github.com/llvm/llvm-project/pull/87859.diff 1 Files Affected:
diff --git a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
index 9c6b50e767ea26..90895e381c74b5 100644
--- a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
@@ -24,8 +24,15 @@ struct AddIOpInterface
auto addIOp = cast<AddIOp>(op);
assert(value == addIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(addIOp.getLhs()) + cstr.getExpr(addIOp.getRhs());
+ // Note: `getExpr` has a side effect: it may add a new column to the
+ // constraint system. The evaluation order of addition operands is
+ // unspecified in C++. To make sure that all compilers produce the exact
+ // same results (that can be FileCheck'd), it is important that `getExpr`
+ // is called first and assigned to temporary variables, and the addition
+ // is performed afterwards.
+ AffineExpr lhs = cstr.getExpr(addIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(addIOp.getRhs());
+ cstr.bound(value) == lhs + rhs;
}
};
@@ -49,8 +56,9 @@ struct SubIOpInterface
auto subIOp = cast<SubIOp>(op);
assert(value == subIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(subIOp.getLhs()) - cstr.getExpr(subIOp.getRhs());
+ AffineExpr lhs = cstr.getExpr(subIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(subIOp.getRhs());
+ cstr.bound(value) == lhs - rhs;
}
};
@@ -61,8 +69,9 @@ struct MulIOpInterface
auto mulIOp = cast<MulIOp>(op);
assert(value == mulIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(mulIOp.getLhs()) * cstr.getExpr(mulIOp.getRhs());
+ AffineExpr lhs = cstr.getExpr(mulIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(mulIOp.getRhs());
+ cstr.bound(value) == lhs *rhs;
}
};
|
@llvm/pr-subscribers-mlir-arith Author: Matthias Springer (matthias-springer) ChangesThe C++ standard does not specify an evaluation order for addition/... operands. E.g., in This lead to different Full diff: https://github.com/llvm/llvm-project/pull/87859.diff 1 Files Affected:
diff --git a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
index 9c6b50e767ea26..90895e381c74b5 100644
--- a/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ValueBoundsOpInterfaceImpl.cpp
@@ -24,8 +24,15 @@ struct AddIOpInterface
auto addIOp = cast<AddIOp>(op);
assert(value == addIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(addIOp.getLhs()) + cstr.getExpr(addIOp.getRhs());
+ // Note: `getExpr` has a side effect: it may add a new column to the
+ // constraint system. The evaluation order of addition operands is
+ // unspecified in C++. To make sure that all compilers produce the exact
+ // same results (that can be FileCheck'd), it is important that `getExpr`
+ // is called first and assigned to temporary variables, and the addition
+ // is performed afterwards.
+ AffineExpr lhs = cstr.getExpr(addIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(addIOp.getRhs());
+ cstr.bound(value) == lhs + rhs;
}
};
@@ -49,8 +56,9 @@ struct SubIOpInterface
auto subIOp = cast<SubIOp>(op);
assert(value == subIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(subIOp.getLhs()) - cstr.getExpr(subIOp.getRhs());
+ AffineExpr lhs = cstr.getExpr(subIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(subIOp.getRhs());
+ cstr.bound(value) == lhs - rhs;
}
};
@@ -61,8 +69,9 @@ struct MulIOpInterface
auto mulIOp = cast<MulIOp>(op);
assert(value == mulIOp.getResult() && "invalid value");
- cstr.bound(value) ==
- cstr.getExpr(mulIOp.getLhs()) * cstr.getExpr(mulIOp.getRhs());
+ AffineExpr lhs = cstr.getExpr(mulIOp.getLhs());
+ AffineExpr rhs = cstr.getExpr(mulIOp.getRhs());
+ cstr.bound(value) == lhs *rhs;
}
};
|
…87860) This commit adds support for `scf.if` to `ValueBoundsConstraintSet`. Example: ``` %0 = scf.if ... -> index { scf.yield %a : index } else { scf.yield %b : index } ``` The following constraints hold for %0: * %0 >= min(%a, %b) * %0 <= max(%a, %b) Such constraints cannot be added to the constraint set; min/max is not supported by `IntegerRelation`. However, if we know which one of %a and %b is larger, we can add constraints for %0. E.g., if %a <= %b: * %0 >= %a * %0 <= %b This commit required a few minor changes to the `ValueBoundsConstraintSet` infrastructure, so that values can be compared while we are still in the process of traversing the IR/adding constraints. Note: This is a re-upload of #85895, which was reverted. The bug that caused the failure was fixed in #87859.
The C++ standard does not specify an evaluation order for addition/... operands. E.g., in
a() + b()
, the compiler is free to evaluatea
orb
first.This lead to different
mlir-opt
outputs in #85895. (FileCheck passed when compiled with LLVM but failed when compiled with gcc.)