LLZK 2.1.1
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
Ops.cpp
Go to the documentation of this file.
1//===-- Ops.cpp - Cast operation implementations ----------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
11
18
19#include <mlir/Dialect/Arith/IR/Arith.h>
20#include <mlir/Support/LLVM.h>
21
22#include <llvm/ADT/STLExtras.h>
23#include <llvm/ADT/TypeSwitch.h>
24
25// TableGen'd implementation files
26#define GET_OP_CLASSES
28using namespace mlir;
29
30static inline ParseResult
31parseOptionalOverflowSemantics(OpAsmParser &parser, llzk::cast::OverflowSemanticsAttr &overflow) {
32 StringRef keyword;
33 if (failed(parser.parseOptionalKeyword(&keyword))) {
34 return success();
35 }
36
37 std::optional<llzk::cast::OverflowSemantics> semantics =
39 if (!semantics) {
40 return parser.emitError(parser.getCurrentLocation()) << "expected overflow semantics keyword";
41 }
42
43 overflow = llzk::cast::OverflowSemanticsAttr::get(parser.getContext(), *semantics);
44 return success();
45}
46
47static inline void
48printOptionalOverflowSemantics(OpAsmPrinter &printer, llzk::cast::OverflowSemanticsAttr overflow) {
49 if (!overflow || overflow.getValue() == llzk::cast::OverflowSemantics::ASSERT) {
50 return;
51 }
52
53 printer << ' ' << stringifyOverflowSemantics(overflow.getValue());
54}
55
56namespace llzk::cast {
57
58bool IntToFeltOp::isCompatibleReturnTypes(::mlir::TypeRange lhs, ::mlir::TypeRange rhs) {
59 return lhs.size() == rhs.size() && llvm::all_of(llvm::zip_equal(lhs, rhs), [](auto pair) {
60 auto [lhsType, rhsType] = pair;
61 auto lhsFeltType = mlir::dyn_cast<llzk::felt::FeltType>(lhsType);
62 auto rhsFeltType = mlir::dyn_cast<llzk::felt::FeltType>(rhsType);
63
64 // If both types are felts but NOT structurally equal then check if the types are valid
65 // with the additional consideration that lhs is allowed to NOT have
66 // a declared field.
67 if (lhsFeltType && rhsFeltType && lhsFeltType != rhsFeltType) {
68 // If we reached this point we know that the felts are not equal and that only the lhs is
69 // allowed to not have a declared field. Thus, rhs must have a declared field. If lhs has a
70 // declared field, then, since they are not structurally equal, it must be a different field
71 // than rhs. With all that, the types are compatible if lhs does not have a field, so we can
72 // simply return that.
73 return !lhsFeltType.hasField();
74 }
75
76 // Any other case gets handled by standard equality.
77 return lhsType == rhsType;
78 });
79}
80
81LogicalResult IntToFeltOp::canonicalize(IntToFeltOp op, ::mlir::PatternRewriter &rewriter) {
82 // Instead of casting an arith.constant to felt, just generate a felt.const
83 if (!op.getValue().getDefiningOp()) {
84 return failure();
85 }
86
87 return llvm::TypeSwitch<Operation *, LogicalResult>(op.getValue().getDefiningOp())
88 .Case<arith::ConstantIndexOp, arith::ConstantIntOp>([&rewriter, &op](auto constOp) {
89 rewriter.replaceOpWithNewOp<felt::FeltConstantOp>(
90 op, felt::FeltConstAttr::get(op->getContext(), toAPInt(constOp.value()), op.getType())
91 );
92 return success();
93 }).Default([](auto) { return failure(); });
94}
95
96ParseResult
97IntToFeltOp::parseOptionalOverflowSemantics(OpAsmParser &parser, OverflowSemanticsAttr &overflow) {
98 return ::parseOptionalOverflowSemantics(parser, overflow);
99}
100
102 OpAsmPrinter &printer, IntToFeltOp /*op*/, OverflowSemanticsAttr overflow
103) {
104 ::printOptionalOverflowSemantics(printer, overflow);
105}
106
107LogicalResult FeltToIndexOp::canonicalize(FeltToIndexOp op, ::mlir::PatternRewriter &rewriter) {
108 // Instead of casting a felt.const to index, just generate an arith.constant
109 if (auto constOp = op.getValue().getDefiningOp<felt::FeltConstantOp>()) {
110 auto value = constOp.getValue().getValue();
111 if (value.getBitWidth() <= 64) {
112 rewriter.replaceOpWithNewOp<arith::ConstantIndexOp>(op, value.getSExtValue());
113 return success();
114 }
115 }
116 return failure();
117}
118
120 OpAsmParser &parser, OverflowSemanticsAttr &overflow
121) {
122 return ::parseOptionalOverflowSemantics(parser, overflow);
123}
124
126 OpAsmPrinter &printer, FeltToIndexOp /*op*/, OverflowSemanticsAttr overflow
127) {
128 ::printOptionalOverflowSemantics(printer, overflow);
129}
130
131} // namespace llzk::cast
::mlir::TypedValue<::llzk::felt::FeltType > getValue()
Definition Ops.h.inc:161
::llvm::LogicalResult canonicalize(FeltToIndexOp op, ::mlir::PatternRewriter &rewriter)
Definition Ops.cpp:107
static void printOptionalOverflowSemantics(::mlir::OpAsmPrinter &printer, FeltToIndexOp op, ::llzk::cast::OverflowSemanticsAttr overflow)
Definition Ops.cpp:125
::mlir::ParseResult parseOptionalOverflowSemantics(::mlir::OpAsmParser &parser, ::llzk::cast::OverflowSemanticsAttr &overflow)
Definition Ops.cpp:119
static void printOptionalOverflowSemantics(::mlir::OpAsmPrinter &printer, IntToFeltOp op, ::llzk::cast::OverflowSemanticsAttr overflow)
Definition Ops.cpp:101
::mlir::ParseResult parseOptionalOverflowSemantics(::mlir::OpAsmParser &parser, ::llzk::cast::OverflowSemanticsAttr &overflow)
Definition Ops.cpp:97
static bool isCompatibleReturnTypes(::mlir::TypeRange lhs, ::mlir::TypeRange rhs)
Definition Ops.cpp:58
::llvm::LogicalResult canonicalize(IntToFeltOp op, ::mlir::PatternRewriter &rewriter)
Definition Ops.cpp:81
::mlir::TypedValue<::mlir::Type > getValue()
Definition Ops.h.inc:411
::llvm::StringRef stringifyOverflowSemantics(OverflowSemantics val)
Definition Enums.cpp.inc:12
::std::optional< OverflowSemantics > symbolizeOverflowSemantics(::llvm::StringRef str)
Definition Enums.cpp.inc:22
APInt toAPInt(const DynamicAPInt &val, unsigned bitWidth)