17#include <mlir/IR/Builders.h>
19#include <llvm/ADT/DynamicAPInt.h>
20#include <llvm/ADT/SmallString.h>
40struct BinaryFoldData {
41 DynamicAPInt lhsVal, rhsVal;
57static std::optional<BinaryFoldData> tryGetBinaryFoldData(Attribute lhsAttr, Attribute rhsAttr) {
58 auto lhs = llvm::dyn_cast_or_null<FeltConstAttr>(lhsAttr);
59 auto rhs = llvm::dyn_cast_or_null<FeltConstAttr>(rhsAttr);
64 StringAttr lhsFieldName = lhs.getFieldName();
65 StringAttr rhsFieldName = rhs.getFieldName();
66 if (!lhsFieldName || !rhsFieldName || lhsFieldName != rhsFieldName) {
71 if (failed(fieldRes)) {
75 return BinaryFoldData {
76 *lhs.getReducedValue(), *rhs.getReducedValue(), lhsFieldName.getValue(),
77 &fieldRes.value().get()
82static std::optional<UnaryFoldData> tryGetUnaryFoldData(Attribute operandAttr) {
83 auto operand = llvm::dyn_cast_or_null<FeltConstAttr>(operandAttr);
88 StringAttr fieldNameAttr = operand.getFieldName();
94 if (failed(fieldRes)) {
98 return UnaryFoldData {
99 *operand.getReducedValue(), fieldNameAttr.getValue(), &fieldRes.value().get()
104static FeltConstAttr buildFoldResult(
105 MLIRContext *ctx,
const DynamicAPInt &val,
const Field &field, StringRef fieldName
107 return FeltConstAttr::get(ctx, field.
reduce(val), fieldName);
118 llvm::raw_string_ostream(buf) <<
"felt_const_" <<
getValue().getRawValue();
126 FeltConstAttr valueAttr = op.
getValue();
127 auto reduced = valueAttr.getReducedValue();
128 if (!reduced || valueAttr.getRawValue() == *reduced) {
131 rewriter.modifyOpInPlace(op, [&]() {
132 op.
setValueAttr(FeltConstAttr::get(op.getContext(), *reduced, valueAttr.getType()));
138 MLIRContext *context, std::optional<Location> , Adaptor adaptor,
139 SmallVectorImpl<Type> &inferred
142 auto value = adaptor.getValue();
143 inferred[0] = value ? value.getType() :
FeltType::get(context, StringAttr());
154 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
158 return buildFoldResult(
159 getContext(), data->field->reduce(data->lhsVal + data->rhsVal), *data->field, data->fieldName
164 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
168 return buildFoldResult(
169 getContext(), data->field->reduce(data->lhsVal - data->rhsVal), *data->field, data->fieldName
174 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
178 return buildFoldResult(
179 getContext(), data->field->reduce(data->lhsVal * data->rhsVal), *data->field, data->fieldName
184 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
188 return buildFoldResult(
189 getContext(),
modExp(data->lhsVal, data->rhsVal, data->field->prime()), *data->field,
195 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
196 if (!data || data->rhsVal == 0) {
199 return buildFoldResult(
200 getContext(), data->field->reduce(data->lhsVal * data->field->inv(data->rhsVal)),
201 *data->field, data->fieldName
206 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
207 if (!data || data->rhsVal == 0) {
212 return buildFoldResult(getContext(), data->lhsVal / data->rhsVal, *data->field, data->fieldName);
216 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
220 const Field *field = data->field;
221 DynamicAPInt rhs = data->rhsVal;
222 if (rhs == 0 || rhs == field->
prime()) {
225 DynamicAPInt sRhs = field->
toSigned(rhs);
226 DynamicAPInt sLhs = field->
toSigned(data->lhsVal);
228 return buildFoldResult(getContext(), field->
reduce(sLhs / sRhs), *field, data->fieldName);
232 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
233 if (!data || data->rhsVal == 0) {
237 return buildFoldResult(getContext(), data->lhsVal % data->rhsVal, *data->field, data->fieldName);
241 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
245 const Field *field = data->field;
246 DynamicAPInt rhs = data->rhsVal;
247 if (rhs == 0 || rhs == field->
prime()) {
250 DynamicAPInt sRhs = field->
toSigned(rhs);
251 DynamicAPInt sLhs = field->
toSigned(data->lhsVal);
252 return buildFoldResult(getContext(), field->
reduce(sLhs % sRhs), *field, data->fieldName);
256 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
260 return buildFoldResult(
261 getContext(), data->field->reduce(data->lhsVal & data->rhsVal), *data->field, data->fieldName
266 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
270 return buildFoldResult(
271 getContext(), data->field->reduce(data->lhsVal | data->rhsVal), *data->field, data->fieldName
276 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
280 return buildFoldResult(
281 getContext(), data->field->reduce(data->lhsVal ^ data->rhsVal), *data->field, data->fieldName
286 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
290 return buildFoldResult(
293 data->lhsVal *
modExp(DynamicAPInt(2), data->rhsVal, data->field->prime())
295 *data->field, data->fieldName
300 auto data = tryGetBinaryFoldData(adaptor.
getLhs(), adaptor.
getRhs());
305 const Field *field = data->field;
306 if (data->rhsVal >= field->
bitWidth()) {
307 return buildFoldResult(getContext(), DynamicAPInt(0), *field, data->fieldName);
311 return buildFoldResult(getContext(), data->lhsVal >> data->rhsVal, *field, data->fieldName);
319 auto data = tryGetUnaryFoldData(adaptor.
getOperand());
323 return buildFoldResult(
324 getContext(), data->field->reduce(-data->val), *data->field, data->fieldName
329 auto data = tryGetUnaryFoldData(adaptor.
getOperand());
330 if (!data || data->val == 0) {
333 return buildFoldResult(getContext(), data->field->inv(data->val), *data->field, data->fieldName);
337 auto data = tryGetUnaryFoldData(adaptor.
getOperand());
344 DynamicAPInt maxMask = (DynamicAPInt(1) << data->field->bitWidth()) - 1;
345 return buildFoldResult(
346 getContext(), data->field->reduce(maxMask ^ data->val), *data->field, data->fieldName
This file implements helpers for DynamicAPInt operations and conversions that LLVM does not provide.
Information about the prime finite field used for the interval analysis.
static llvm::FailureOr< std::reference_wrapper< const Field > > tryGetField(llvm::StringRef fieldName)
Get a Field from a given field name string, or failure if the field is not defined.
llvm::DynamicAPInt toSigned(const llvm::DynamicAPInt &i) const
Converts a canonical field element to its signed integer representation: toSigned(f) = f if f < field...
llvm::DynamicAPInt prime() const
For the prime field p, returns p.
llvm::DynamicAPInt reduce(const llvm::DynamicAPInt &i) const
Returns the canonical representative of i mod p in [0, p).
unsigned bitWidth() const
Width sufficient for the modulus and its representatives, independent of literal storage.
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::llvm::LogicalResult canonicalize(FeltConstantOp op, ::mlir::PatternRewriter &rewriter)
Replaces a constant's raw value with its canonical field representative.
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::llzk::felt::FeltConstAttr getValueAttr()
::mlir::TypedValue<::mlir::Type > getResult()
void setValueAttr(::llzk::felt::FeltConstAttr attr)
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
static bool isCompatibleReturnTypes(::mlir::TypeRange l, ::mlir::TypeRange r)
::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::std::optional<::mlir::Location > location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::mlir::PropertyRef properties, ::mlir::RegionRange regions, ::llvm::SmallVectorImpl<::mlir::Type > &inferredReturnTypes)
::llzk::felt::FeltConstAttr getValue()
static FeltType get(::mlir::MLIRContext *context, ::mlir::StringAttr fieldName)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
DynamicAPInt modExp(const DynamicAPInt &base, const DynamicAPInt &exp, const DynamicAPInt &mod)