Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions compiler/include/graphalg/GraphAlgOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -723,10 +723,8 @@ def MulOp : Core_Op<"mul", [Pure, SameOperandsAndResultType]> {
let hasFolder = 1;
}

def EqOp : Core_Op<"eq", [Pure, AllTypesMatch<["lhs", "rhs"]>]> {
let summary = "Scalar equality comparison";

let arguments = (ins AnySemiring:$lhs, AnySemiring:$rhs);
class CompareOp<string mnemonic> : Core_Op<mnemonic, [Pure, AllTypesMatch<["lhs", "rhs"]>]> {
let arguments = (ins PartialOrd:$lhs, PartialOrd:$rhs);

let results = (outs I1:$result);

Expand All @@ -737,6 +735,23 @@ def EqOp : Core_Op<"eq", [Pure, AllTypesMatch<["lhs", "rhs"]>]> {
let hasFolder = 1;
}

def EqOp : CompareOp<"eq"> {
let summary = "Scalar equality comparison";

// Arguments do not need to be partially ordered
let arguments = (ins AnySemiring:$lhs, AnySemiring:$rhs);

let hasCanonicalizer = 1;
}

def LtOp : CompareOp<"lt"> {
let summary = "Scalar less-than comparison";
}

def LeOp : CompareOp<"le"> {
let summary = "Scalar less-than-or-equal comparison";
}

// Note: In spec but not used in implementation: OneVector.
// Its functionality is subsumed by BroadcastOp.

Expand Down
2 changes: 2 additions & 0 deletions compiler/include/graphalg/GraphAlgTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ def AnySemiring : Type<
CPred<"::llvm::isa<SemiringTypeInterface>($_self)">,
"semiring">;

def PartialOrd : AnyTypeOf<[I64, F64]>;

class AllSemiringsMatch<list<string> names> : AllMatchSameOperatorTrait<
names,
"llvm::cast<graphalg::MatrixType>($_self.getType()).getSemiring()",
Expand Down
41 changes: 41 additions & 0 deletions compiler/src/garel/GraphAlgToRel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,46 @@ mlir::LogicalResult OpConversion<graphalg::EqOp>::matchAndRewrite(
return mlir::success();
}

template <>
mlir::LogicalResult OpConversion<graphalg::LtOp>::matchAndRewrite(
graphalg::LtOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto lhs = adaptor.getLhs();
auto rhs = adaptor.getRhs();
if (lhs.getType().isF64()) {
assert(rhs.getType().isF64());
rewriter.replaceOpWithNewOp<mlir::arith::CmpFOp>(
op, mlir::arith::CmpFPredicate::OLT, lhs, rhs);
} else {
assert(lhs.getType().isSignlessInteger());
assert(rhs.getType().isSignlessInteger());
rewriter.replaceOpWithNewOp<mlir::arith::CmpIOp>(
op, mlir::arith::CmpIPredicate::slt, lhs, rhs);
}

return mlir::success();
}

template <>
mlir::LogicalResult OpConversion<graphalg::LeOp>::matchAndRewrite(
graphalg::LeOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto lhs = adaptor.getLhs();
auto rhs = adaptor.getRhs();
if (lhs.getType().isF64()) {
assert(rhs.getType().isF64());
rewriter.replaceOpWithNewOp<mlir::arith::CmpFOp>(
op, mlir::arith::CmpFPredicate::OLE, lhs, rhs);
} else {
assert(lhs.getType().isSignlessInteger());
assert(rhs.getType().isSignlessInteger());
rewriter.replaceOpWithNewOp<mlir::arith::CmpIOp>(
op, mlir::arith::CmpIPredicate::sle, lhs, rhs);
}

return mlir::success();
}

template <>
mlir::LogicalResult OpConversion<graphalg::MulOp>::matchAndRewrite(
graphalg::MulOp op, OpAdaptor adaptor,
Expand Down Expand Up @@ -1453,6 +1493,7 @@ void GraphAlgToRel::runOnOperation() {
.add<OpConversion<graphalg::ApplyReturnOp>,
OpConversion<graphalg::ConstantOp>, OpConversion<graphalg::AddOp>,
OpConversion<graphalg::CastScalarOp>, OpConversion<graphalg::EqOp>,
OpConversion<graphalg::LtOp>, OpConversion<graphalg::LeOp>,
OpConversion<graphalg::MulOp>>(semiringTypeConverter, &getContext());

if (mlir::failed(mlir::applyFullConversion(getOperation(), target,
Expand Down
87 changes: 87 additions & 0 deletions compiler/src/graphalg/GraphAlgCanonicalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/ErrorHandling.h>
#include <mlir/IR/Attributes.h>
#include <mlir/IR/Builders.h>
#include <mlir/IR/BuiltinAttributeInterfaces.h>
Expand Down Expand Up @@ -522,6 +523,92 @@ mlir::OpFoldResult EqOp::fold(FoldAdaptor adaptor) {
return nullptr;
}

static bool isLessThan(mlir::IntegerAttr lhs, mlir::IntegerAttr rhs) {
return lhs.getValue().slt(rhs.getValue());
}

static bool isLessThan(mlir::FloatAttr lhs, mlir::FloatAttr rhs) {
return lhs.getValueAsDouble() < rhs.getValueAsDouble();
}

static bool isLessThan(mlir::Attribute lhs, mlir::Attribute rhs) {
if (auto lhsInt = llvm::dyn_cast<mlir::IntegerAttr>(lhs)) {
return isLessThan(lhsInt, llvm::cast<mlir::IntegerAttr>(rhs));
} else if (auto lhsFloat = llvm::dyn_cast<mlir::FloatAttr>(lhs)) {
return isLessThan(lhsFloat, llvm::cast<mlir::FloatAttr>(rhs));
} else {
llvm_unreachable("unsupported type for less-than comparison");
}
}

mlir::OpFoldResult LtOp::fold(FoldAdaptor adaptor) {
if (getLhs() == getRhs()) {
return mlir::BoolAttr::get(getContext(), false);
}

auto lhs = adaptor.getLhs();
auto rhs = adaptor.getRhs();
if (lhs && rhs) {
return mlir::BoolAttr::get(getContext(), isLessThan(lhs, rhs));
}

return nullptr;
}

mlir::OpFoldResult LeOp::fold(FoldAdaptor adaptor) {
if (getLhs() == getRhs()) {
return mlir::BoolAttr::get(getContext(), true);
}

auto lhs = adaptor.getLhs();
auto rhs = adaptor.getRhs();
if (lhs && rhs) {
return mlir::BoolAttr::get(getContext(),
isLessThan(lhs, rhs) || (lhs == rhs));
}

return nullptr;
}

// Fold the negation of a compare op.
//
// !(a < b) => b <= a
// !(a <= b) => b < a
//
// The negation of the comparison is expressed as `eq false, (cmp a b)`.
static mlir::LogicalResult negateCompare(EqOp op,
mlir::PatternRewriter &rewriter) {
// One operand must be the boolean constant `false`.
mlir::Value cmp;
if (isFalse(op.getLhs())) {
cmp = op.getRhs();
} else if (isFalse(op.getRhs())) {
cmp = op.getLhs();
} else {
return mlir::failure();
}

// The other operand must be a less-than / less-than-or-equal comparison.
if (auto ltOp = cmp.getDefiningOp<LtOp>()) {
// !(a < b) => b <= a
rewriter.replaceOpWithNewOp<LeOp>(op, ltOp.getRhs(), ltOp.getLhs());
return mlir::success();
}

if (auto leOp = cmp.getDefiningOp<LeOp>()) {
// !(a <= b) => b < a
rewriter.replaceOpWithNewOp<LtOp>(op, leOp.getRhs(), leOp.getLhs());
return mlir::success();
}

return mlir::failure();
}

void EqOp::getCanonicalizationPatterns(mlir::RewritePatternSet &patterns,
mlir::MLIRContext *context) {
patterns.add(negateCompare);
}

// Test if the value is equal to the additive identity.
static bool isAdditiveIdentity(mlir::Value v) {
mlir::Attribute constantValue;
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/graphalg/GraphAlgScalarizeApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,13 @@ mlir::FailureOr<mlir::Value> createScalarOpFor(mlir::Location loc, BinaryOp op,
return mlir::Value(builder.create<EqOp>(loc, falseOp, eqOp));
}
case BinaryOp::LT:
return mlir::Value(builder.create<LtOp>(loc, lhs, rhs));
case BinaryOp::GT:
return mlir::Value(builder.create<LtOp>(loc, rhs, lhs));
case BinaryOp::LE:
return mlir::Value(builder.create<LeOp>(loc, lhs, rhs));
case BinaryOp::GE:
return mlir::emitError(loc)
<< "operator " << stringifyBinaryOp(op) << " is not yet supported";
return mlir::Value(builder.create<LeOp>(loc, rhs, lhs));
}
}

Expand Down
38 changes: 36 additions & 2 deletions compiler/src/graphalg/evaluate/Evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class ScalarEvaluator {
mlir::LogicalResult evaluate(MulOp op);
mlir::LogicalResult evaluate(CastScalarOp op);
mlir::LogicalResult evaluate(EqOp op);
mlir::LogicalResult evaluate(LtOp op);
mlir::LogicalResult evaluate(LeOp op);
mlir::LogicalResult evaluate(mlir::arith::DivFOp op);
mlir::LogicalResult evaluate(mlir::arith::SubIOp op);
mlir::LogicalResult evaluate(mlir::arith::SubFOp op);
Expand Down Expand Up @@ -421,12 +423,44 @@ mlir::LogicalResult ScalarEvaluator::evaluate(CastScalarOp op) {
}

mlir::LogicalResult ScalarEvaluator::evaluate(EqOp op) {
auto ring = llvm::cast<SemiringTypeInterface>(op.getType());
bool eq = _values[op.getLhs()] == _values[op.getRhs()];
_values[op] = mlir::BoolAttr::get(op.getContext(), eq);
return mlir::success();
}

static bool isLessThan(mlir::IntegerAttr lhs, mlir::IntegerAttr rhs) {
return lhs.getValue().slt(rhs.getValue());
}

static bool isLessThan(mlir::FloatAttr lhs, mlir::FloatAttr rhs) {
return lhs.getValueAsDouble() < rhs.getValueAsDouble();
}

static bool isLessThan(mlir::Attribute lhs, mlir::Attribute rhs) {
if (auto lhsInt = llvm::dyn_cast<mlir::IntegerAttr>(lhs)) {
return isLessThan(lhsInt, llvm::cast<mlir::IntegerAttr>(rhs));
} else if (auto lhsFloat = llvm::dyn_cast<mlir::FloatAttr>(lhs)) {
return isLessThan(lhsFloat, llvm::cast<mlir::FloatAttr>(rhs));
} else {
llvm_unreachable("unsupported type for less-than comparison");
}
}

mlir::LogicalResult ScalarEvaluator::evaluate(LtOp op) {
auto lhs = _values[op.getLhs()];
auto rhs = _values[op.getRhs()];
_values[op] = mlir::BoolAttr::get(op.getContext(), isLessThan(lhs, rhs));
return mlir::success();
}

mlir::LogicalResult ScalarEvaluator::evaluate(LeOp op) {
auto lhs = _values[op.getLhs()];
auto rhs = _values[op.getRhs()];
_values[op] =
mlir::BoolAttr::get(op.getContext(), isLessThan(lhs, rhs) || lhs == rhs);
return mlir::success();
}

mlir::LogicalResult ScalarEvaluator::evaluate(mlir::arith::DivFOp op) {
auto lhs =
llvm::cast<mlir::FloatAttr>(_values[op.getLhs()]).getValueAsDouble();
Expand Down Expand Up @@ -461,7 +495,7 @@ mlir::LogicalResult ScalarEvaluator::evaluate(mlir::Operation *op) {
GA_CASE(ConstantOp) GA_CASE(mlir::arith::ConstantOp) GA_CASE(AddOp)
GA_CASE(MulOp) GA_CASE(CastScalarOp) GA_CASE(EqOp)
GA_CASE(mlir::arith::DivFOp) GA_CASE(mlir::arith::SubIOp)
GA_CASE(mlir::arith::SubFOp)
GA_CASE(mlir::arith::SubFOp) GA_CASE(LtOp) GA_CASE(LeOp)
#undef GA_CASE
.Default([](mlir::Operation *op) {
return op->emitOpError("unsupported op");
Expand Down
Loading