This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Dialects

This section contains the reference documentation for all of the dialects defined in HEIR.

1 - BGV

The BGV dialect defines the types and operations of the BGV cryptosystem.

BGV attributes

BGVRingsAttr

Syntax:

#bgv.rings<
  ::llvm::ArrayRef<::mlir::heir::polynomial::RingAttr>   # rings
>

Parameters:

ParameterC++ typeDescription
rings::llvm::ArrayRef<::mlir::heir::polynomial::RingAttr>

BGV types

CiphertextType

a BGV ciphertext

Syntax:

!bgv.ciphertext<
  ::mlir::heir::bgv::BGVRingsAttr,   # rings
  unsigned,   # dim
  std::optional<uint64_t>   # level
>

This type tracks the BGV ciphertext parameters, including the ciphertext dimension (number of polynomials) and the set of rings that were used for the particular BGV scheme instance. The default dimension is 2, representing a ciphertext that is canonically encrypted against the key basis $(1, s)$.

The type also includes a ring parameter specification.

For example, bgv.ciphertext<rings=#rings, dim=3> is a ciphertext with 3 polynomials $(c_0, c_1, c_2)$.

The optional attribute level specifies the “current ring”.

Parameters:

ParameterC++ typeDescription
rings::mlir::heir::bgv::BGVRingsAttr
dimunsigned
levelstd::optional<uint64_t>

BGV ops

bgv.add (heir::bgv::AddOp)

Addition operation between ciphertexts.

Syntax:

operation ::= `bgv.add` `(` operands `)` attr-dict `:` type($output)

Traits: Commutative, SameOperandsAndResultType

Interfaces: InferTypeOpInterface

Operands:

OperandDescription
xa BGV ciphertext
ya BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.modulus_switch (heir::bgv::ModulusSwitch)

Lower the modulus level of the ciphertext.

Syntax:

operation ::= `bgv.modulus_switch` `(` operands `)` attr-dict `:`  `(` type(operands) `)` `->` type(results)

Traits: SameOperandsAndResultRings

Attributes:

AttributeMLIR TypeDescription
from_level::mlir::IntegerAttr64-bit signless integer attribute
to_level::mlir::IntegerAttr64-bit signless integer attribute

Operands:

OperandDescription
xa BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.mul (heir::bgv::MulOp)

Multiplication operation between ciphertexts.

Syntax:

operation ::= `bgv.mul` `(` operands `)` attr-dict `:` type($x) `->` type($output)

Traits: Commutative, SameOperandsAndResultRings, SameTypeOperands

Operands:

OperandDescription
xa BGV ciphertext
ya BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.negate (heir::bgv::Negate)

Negate the coefficients of the ciphertext.

Syntax:

operation ::= `bgv.negate` `(` operands `)` attr-dict `:` type($output)

Traits: SameOperandsAndResultType

Interfaces: InferTypeOpInterface

Operands:

OperandDescription
xa BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.relinearize (heir::bgv::Relinearize)

Relinearize the ciphertext.

Syntax:

operation ::= `bgv.relinearize` `(` operands `)` attr-dict `:`  `(` type(operands) `)` `->` type(results)

This op takes integer array attributes from_basis and to_basis that are used to indicate the key basis from which and to which the ciphertext is encrypted against. A ciphertext is canonically encrypted against key basis (1, s). After a multiplication, its size will increase and the basis will be (1, s, s^2). The array that represents the key basis is constructed by listing the powers of s at each position of the array. For example, (1, s, s^2) corresponds to [0, 1, 2], while (1, s^2) corresponds to [0, 2].

Traits: SameOperandsAndResultRings

Attributes:

AttributeMLIR TypeDescription
from_basis::mlir::DenseI32ArrayAttri32 dense array attribute
to_basis::mlir::DenseI32ArrayAttri32 dense array attribute

Operands:

OperandDescription
xa BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.rotate (heir::bgv::Rotate)

Rotate the coefficients of the ciphertext using a Galois automorphism.

Syntax:

operation ::= `bgv.rotate` `(` operands `)` attr-dict `:`  `(` type(operands) `)` `->` type(results)

Traits: SameOperandsAndResultRings

Attributes:

AttributeMLIR TypeDescription
offset::mlir::IntegerAttr64-bit signless integer attribute

Operands:

OperandDescription
xa BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

bgv.sub (heir::bgv::SubOp)

Subtraction operation between ciphertexts.

Syntax:

operation ::= `bgv.sub` `(` operands `)` attr-dict `:` type($output)

Traits: SameOperandsAndResultType

Interfaces: InferTypeOpInterface

Operands:

OperandDescription
xa BGV ciphertext
ya BGV ciphertext

Results:

ResultDescription
outputa BGV ciphertext

2 - CGGI

A dialect for types and operations in the CGGI cryptosystem

CGGI attributes

CGGIParamsAttr

Syntax:

#cggi.cggi_params<
  ::mlir::heir::lwe::RLWEParamsAttr,   # rlweParams
  unsigned,   # bsk_noise_variance
  unsigned,   # bsk_gadget_base_log
  unsigned,   # bsk_gadget_num_levels
  unsigned,   # ksk_noise_variance
  unsigned,   # ksk_gadget_base_log
  unsigned   # ksk_gadget_num_levels
>

Parameters:

ParameterC++ typeDescription
rlweParams::mlir::heir::lwe::RLWEParamsAttr
bsk_noise_varianceunsigned
bsk_gadget_base_logunsigned
bsk_gadget_num_levelsunsigned
ksk_noise_varianceunsigned
ksk_gadget_base_logunsigned
ksk_gadget_num_levelsunsigned

CGGI ops

cggi.and (heir::cggi::AndOp)

Logical AND of two ciphertexts.

Syntax:

operation ::= `cggi.and` operands attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhsciphertext-like
rhsciphertext-like

Results:

ResultDescription
outputciphertext-like

cggi.lut2 (heir::cggi::Lut2Op)

A lookup table on two inputs.

Syntax:

operation ::= `cggi.lut2` `(` operands `)` attr-dict `:` qualified(type($output))

An op representing a lookup table applied to some number n of ciphertexts encrypting boolean input bits.

Over cleartext bits a, b, c, using n = 3 for example, the operation computed by this function can be interpreted as

  truth_table >> {c, b, a}

where {c, b, a} is the unsigned 3-bit integer with bits c, b, a from most significant bit to least-significant bit. The input are combined into a single ciphertext input to the lookup table using products with plaintexts and sums.

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, Scalarizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, LUTOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lookup_table::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
bciphertext-like
aciphertext-like

Results:

ResultDescription
outputciphertext-like

cggi.lut3 (heir::cggi::Lut3Op)

A lookup table on three inputs.

Syntax:

operation ::= `cggi.lut3` `(` operands `)` attr-dict `:` qualified(type($output))

An op representing a lookup table applied to some number n of ciphertexts encrypting boolean input bits.

Over cleartext bits a, b, c, using n = 3 for example, the operation computed by this function can be interpreted as

  truth_table >> {c, b, a}

where {c, b, a} is the unsigned 3-bit integer with bits c, b, a from most significant bit to least-significant bit. The input are combined into a single ciphertext input to the lookup table using products with plaintexts and sums.

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, Scalarizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, LUTOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lookup_table::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
cciphertext-like
bciphertext-like
aciphertext-like

Results:

ResultDescription
outputciphertext-like

cggi.not (heir::cggi::NotOp)

Logical NOT of two ciphertexts

Syntax:

operation ::= `cggi.not` operands attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Involution, SameOperandsAndResultType

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputA type for LWE ciphertexts

Results:

ResultDescription
outputA type for LWE ciphertexts

cggi.or (heir::cggi::OrOp)

Logical OR of two ciphertexts.

Syntax:

operation ::= `cggi.or` operands attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhsciphertext-like
rhsciphertext-like

Results:

ResultDescription
outputciphertext-like

cggi.xor (heir::cggi::XorOp)

Logical XOR of two ciphertexts.

Syntax:

operation ::= `cggi.xor` operands attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhsciphertext-like
rhsciphertext-like

Results:

ResultDescription
outputciphertext-like

3 - Comb

Types and operations for comb dialect This dialect defines the comb dialect, which is intended to be a generic representation of combinational logic outside of a particular use-case.

Operations

comb.add (heir::comb::AddOp)

Syntax:

operation ::= `comb.add` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.and (heir::comb::AndOp)

Syntax:

operation ::= `comb.and` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.concat (heir::comb::ConcatOp)

Concatenate a variadic list of operands together.

Syntax:

operation ::= `comb.concat` $inputs attr-dict `:` qualified(type($inputs))

See the comb rationale document for details on operand ordering.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.extract (heir::comb::ExtractOp)

Extract a range of bits into a smaller value, lowBit specifies the lowest bit included.

Syntax:

operation ::= `comb.extract` $input `from` $lowBit attr-dict `:` functional-type($input, $result)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lowBit::mlir::IntegerAttr32-bit signless integer attribute

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
resultsignless integer

comb.icmp (heir::comb::ICmpOp)

Compare two integer values

Syntax:

operation ::= `comb.icmp` (`bin` $twoState^)? $predicate $lhs `,` $rhs attr-dict `:` qualified(type($lhs))

This operation compares two integers using a predicate. If the predicate is true, returns 1, otherwise returns 0. This operation always returns a one bit wide result.

    %r = comb.icmp eq %a, %b : i4

Traits: AlwaysSpeculatableImplTrait, SameTypeOperands

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
predicate::mlir::heir::comb::ICmpPredicateAttrhw.icmp comparison predicate
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
lhssignless integer
rhssignless integer

Results:

ResultDescription
result1-bit signless integer

comb.mul (heir::comb::MulOp)

Syntax:

operation ::= `comb.mul` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.mux (heir::comb::MuxOp)

Return one or the other operand depending on a selector bit

Syntax:

operation ::= `comb.mux` (`bin` $twoState^)? $cond `,` $trueValue `,` $falseValue  attr-dict `:` qualified(type($result))
  %0 = mux %pred, %tvalue, %fvalue : i4

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
cond1-bit signless integer
trueValueany type
falseValueany type

Results:

ResultDescription
resultany type

comb.or (heir::comb::OrOp)

Syntax:

operation ::= `comb.or` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.parity (heir::comb::ParityOp)

Syntax:

operation ::= `comb.parity` (`bin` $twoState^)? $input attr-dict `:` qualified(type($input))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
result1-bit signless integer

comb.replicate (heir::comb::ReplicateOp)

Concatenate the operand a constant number of times

Syntax:

operation ::= `comb.replicate` $input attr-dict `:` functional-type($input, $result)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
resultsignless integer

comb.truth_table (heir::comb::TruthTableOp)

Return a true/false based on a lookup table

Syntax:

operation ::= `comb.truth_table` $inputs `->` $lookupTable attr-dict
  %a = ... : i1
  %b = ... : i1
  %0 = comb.truth_table %a, %b -> 6 : ui4

This operation assumes that the lookup table is described as an integer of 2^n bits to fully specify the table. Inputs are sorted MSB -> LSB from left to right and the offset into lookupTable is computed from them. The integer containing the truth table value’s LSB is the output for the input “all false”, and the MSB is the output for the input “all true”.

No difference from array_get into an array of constants except for xprop behavior. If one of the inputs is unknown, but said input doesn’t make a difference in the output (based on the lookup table) the result should not be ‘x’ – it should be the well-known result.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, LUTOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lookupTable::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
inputsvariadic of 1-bit signless integer

Results:

ResultDescription
result1-bit signless integer

comb.xor (heir::comb::XorOp)

Syntax:

operation ::= `comb.xor` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

Comb types

Comb ops

comb.add (heir::comb::AddOp)

Syntax:

operation ::= `comb.add` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.and (heir::comb::AndOp)

Syntax:

operation ::= `comb.and` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.concat (heir::comb::ConcatOp)

Concatenate a variadic list of operands together.

Syntax:

operation ::= `comb.concat` $inputs attr-dict `:` qualified(type($inputs))

See the comb rationale document for details on operand ordering.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.extract (heir::comb::ExtractOp)

Extract a range of bits into a smaller value, lowBit specifies the lowest bit included.

Syntax:

operation ::= `comb.extract` $input `from` $lowBit attr-dict `:` functional-type($input, $result)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lowBit::mlir::IntegerAttr32-bit signless integer attribute

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
resultsignless integer

comb.icmp (heir::comb::ICmpOp)

Compare two integer values

Syntax:

operation ::= `comb.icmp` (`bin` $twoState^)? $predicate $lhs `,` $rhs attr-dict `:` qualified(type($lhs))

This operation compares two integers using a predicate. If the predicate is true, returns 1, otherwise returns 0. This operation always returns a one bit wide result.

    %r = comb.icmp eq %a, %b : i4

Traits: AlwaysSpeculatableImplTrait, SameTypeOperands

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
predicate::mlir::heir::comb::ICmpPredicateAttrhw.icmp comparison predicate
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
lhssignless integer
rhssignless integer

Results:

ResultDescription
result1-bit signless integer

comb.mul (heir::comb::MulOp)

Syntax:

operation ::= `comb.mul` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.mux (heir::comb::MuxOp)

Return one or the other operand depending on a selector bit

Syntax:

operation ::= `comb.mux` (`bin` $twoState^)? $cond `,` $trueValue `,` $falseValue  attr-dict `:` qualified(type($result))
  %0 = mux %pred, %tvalue, %fvalue : i4

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
cond1-bit signless integer
trueValueany type
falseValueany type

Results:

ResultDescription
resultany type

comb.or (heir::comb::OrOp)

Syntax:

operation ::= `comb.or` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

comb.parity (heir::comb::ParityOp)

Syntax:

operation ::= `comb.parity` (`bin` $twoState^)? $input attr-dict `:` qualified(type($input))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
result1-bit signless integer

comb.replicate (heir::comb::ReplicateOp)

Concatenate the operand a constant number of times

Syntax:

operation ::= `comb.replicate` $input attr-dict `:` functional-type($input, $result)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputsignless integer

Results:

ResultDescription
resultsignless integer

comb.truth_table (heir::comb::TruthTableOp)

Return a true/false based on a lookup table

Syntax:

operation ::= `comb.truth_table` $inputs `->` $lookupTable attr-dict
  %a = ... : i1
  %b = ... : i1
  %0 = comb.truth_table %a, %b -> 6 : ui4

This operation assumes that the lookup table is described as an integer of 2^n bits to fully specify the table. Inputs are sorted MSB -> LSB from left to right and the offset into lookupTable is computed from them. The integer containing the truth table value’s LSB is the output for the input “all false”, and the MSB is the output for the input “all true”.

No difference from array_get into an array of constants except for xprop behavior. If one of the inputs is unknown, but said input doesn’t make a difference in the output (based on the lookup table) the result should not be ‘x’ – it should be the well-known result.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, LUTOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
lookupTable::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
inputsvariadic of 1-bit signless integer

Results:

ResultDescription
result1-bit signless integer

comb.xor (heir::comb::XorOp)

Syntax:

operation ::= `comb.xor` (`bin` $twoState^)? $inputs attr-dict `:` qualified(type($result))

Traits: AlwaysSpeculatableImplTrait, Commutative, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
twoState::mlir::UnitAttrunit attribute

Operands:

OperandDescription
inputsvariadic of signless integer

Results:

ResultDescription
resultsignless integer

4 - LWE

LWE attributes

BitFieldEncodingAttr

An attribute describing encoded LWE plaintexts using bit fields.

Syntax:

#lwe.bit_field_encoding<
  unsigned,   # cleartext_start
  unsigned   # cleartext_bitwidth
>

A bit field encoding of an integer describes which contiguous region of bits a small integer occupies within a larger integer.

The data describing the encoding consists of the starting bit positions of the cleartext bit field and its width, where the LSB is bit 0 and the MSB is bit bit_width-1. So the above example would have starting bit 30 and width 3. The bits not specified for the message have semantics defined by the scheme or lowering.

Note that this encoding does not specify the underlying bit width of the plaintext space. This is left for lowerings to decide.

The presence of this attribute as the encoding attribute of a tensor indicates that the tensor is an LWE ciphertext.

Example (CGGI):

#encoding = #lwe.bit_field_encoding<cleartext_start=30, cleartext_bitwidth=3>
!plaintext = !lwe.lwe_plaintext<encoding = #encoding>

%0 = arith.constant 4 : i3
%1 = lwe.encode %0 { encoding = #encoding }: i3 to !plaintext

The above represents an LWE plaintext encoding the 3-bit cleartext 4 as an LWE ciphertext in a 32-bit integer, with a single bit of padding at the MSB. This corresponds to the following, where 0 denotes a 0 bit, b denotes a bit of the cleartext, n denotes a bit reserved for noise, and | is a visual aid to show where the bit fields begin and end.

   0|bbb|nn...n
MSB^          ^LSB

Example (BGV):

Note: BGV uses the RLWE encodings, but they have the same bit-field encoding attributes as here. So this example serves mainly to show how this attribute can be used to specify storing bits in the LSB of a plaintext.

#encoding = #lwe.bit_field_encoding<cleartext_start=4, cleartext_bitwidth=4>
!plaintext = !lwe.lwe_plaintext<encoding = #encoding>

%0 = arith.constant 9 : i4
%1 = lwe.encode %0 { encoding = #encoding }: i4 to !plaintext

The above represents an LWE plaintext encoding a 4-bit cleartext as an LWE ciphertext in the least-significant bits of a larger integer. This corresponds to the following.

   nn...n|bbbb
MSB^         ^LSB

Parameters:

ParameterC++ typeDescription
cleartext_startunsigned
cleartext_bitwidthunsigned

LWEParamsAttr

Syntax:

#lwe.lwe_params<
  IntegerAttr,   # cmod
  unsigned   # dimension
>

Parameters:

ParameterC++ typeDescription
cmodIntegerAttr
dimensionunsigned

RLWEParamsAttr

Syntax:

#lwe.rlwe_params<
  IntegerAttr,   # cmod
  unsigned,   # dimension
  unsigned   # polyDegree
>

An attribute describing classical RLWE parameters:

  • cmod: the coefficient modulus for the polynomials.
  • dimension: the number of polynomials used in an RLWE sample, analogous to LWEParams.dimension.
  • polyDegree: the degree $N$ of the negacyclic polynomial modulus $x^N + 1$.

Parameters:

ParameterC++ typeDescription
cmodIntegerAttr
dimensionunsigned
polyDegreeunsigned

UnspecifiedBitFieldEncodingAttr

An attribute describing unspecified bit field encodings.

Syntax:

#lwe.unspecified_bit_field_encoding<
  unsigned   # cleartext_bitwidth
>

See LWE_BitFieldEncoding for a description of bit field encodings.

This attribute describes an unspecified bit field encoding; this is where the starting bit position of the cleartext bit field is unspecified, but its width is fixed. A noise growth analysis should be performed to determine the optimal amount of bits needed for noise and padding to specify the bit field encodings starting bit position.

Example:

#lwe_encoding = #lwe.unspecified_bit_field_encoding<cleartext_bitwidth=3>
%lwe_ciphertext = arith.constant <[1,2,3,4]> : tensor<4xi32, #lwe_encoding>

Parameters:

ParameterC++ typeDescription
cleartext_bitwidthunsigned

InverseCanonicalEmbeddingEncodingAttr

An attribute describing encoded RLWE plaintexts via the rounded inverse canonical embedding.

Syntax:

#lwe.inverse_canonical_embedding_encoding<
  unsigned,   # cleartext_start
  unsigned   # cleartext_bitwidth
>

Let $n$ be the degree of the polynomials in the plaintext space. An “inverse canonical embedding encoding” of a list of real or complex values $v_1, \dots, v_{n/2}$ is (almost) the inverse of the following decoding map.

Define a map $\tau_N$ that maps a polynomial $p \in \mathbb{Z}[x] / (x^N + 1) \to \mathbb{C}^{N/2}$ by evaluating it at the following $N/2$ points, where $\omega = e^{2 \pi i / 2N}$ is the primitive $2N$th root of unity:

[ \omega, \omega^3, \omega^5, \dots, \omega^{N-1} ]

Then the complete decoding operation is $\textup{Decode}(p) = (1/\Delta)\tau_N(p)$, where $\Delta$ is a scaling parameter and $\tau_N$ is the truncated canonical embedding above. The encoding operation is the inverse of the decoding operation, with some caveats explained below.

The map $\tau_N$ is derived from the so-called canonical embedding $\tau$, though in the standard canonical embedding, we evaluate at all odd powers of the root of unity, $\omega, \omega^3, \dots, \omega^{2N-1}$. For polynomials in the slightly larger space $\mathbb{R}[x] / (x^N + 1)$, the image of the canonical embedding is the subspace $H \subset \mathbb{C}^N$ defined by tuples $(z_1, \dots, z_N)$ such that $\overline{z_i} = \overline{z_{N-i+1}}$. Note that this property holds because polynomial evaluation commutes with complex conjugates, and the second half of the roots of unity evaluate are complex conjugates of the first half. The converse, that any such tuple with complex conjugate symmetry has an inverse under $\tau$ with all real coefficients, makes $\tau$ is a bijection onto $H$. $\tau$ and its inverse are explicitly computable as discrete Fourier Transforms.

Because of the symmetry in canonical embedding for real polynomials, inputs to this encoding can be represented as a list of $N/2$ complex points, with the extra symmetric structure left implicit. $\tau_N$ and its inverse can also be explicitly computed without need to expand the vectors to length $N$.

The rounding step is required to invert the decoding because, while cleartexts must be (implicitly) in the subspace $H$, they need not be the output of $\tau_N$ for an integer polynomial. The rounding step ensures we can use integer polynomial plaintexts for the FHE operations. There are multiple rounding mechanisms, and this attribute does not specify which is used, because in theory two ciphertexts that have used different roundings are still compatible, though they may have different noise growth patterns.

The scaling parameter $\Delta$ is specified by the cleartext_start and cleartext_bitwidth parameters, which are applied coefficient-wise using the same semantics as the bit_field_encoding.

This attribute can be used in multiple ways:

  • On a poly.poly, it asserts that the polynomial has been transformed from a coefficient list using the canonical embedding.
  • On a tensor of poly.poly, it asserts that the tensor is an RLWE ciphertext for some RLWE scheme that supports the approximate embedding encoding.

A typical flow for the CKKS scheme using this encoding would be to apply an inverse FFT operation to invert the canonical embedding to be a polynomial with real coefficients, then encrypt scale the resulting polynomial’s coefficients according to the scaling parameters, then round to get integer coefficients.

Example:

#generator = #poly.polynomial<1 + x**1024>
#ring = #poly.ring<cmod=65536, ideal=#generator>
#lwe_encoding = #lwe.polynomial_evaluation_encoding<cleartext_start=30, cleartext_bitwidth=3>

%evals = arith.constant <[1, 2, 4, 5]> : tensor<4xi16>
// TODO(#182): fix docs
// Note no `intt` operation exists in poly yet.
%poly1 = poly.intt %evals : tensor<4xi16> -> !poly.poly<#ring, #eval_encoding>
%poly2 = poly.intt %evals : tensor<4xi16> -> !poly.poly<#ring, #eval_encoding>
%rlwe_ciphertext = tensor.from_elements %poly1, %poly2 : tensor<2x!poly.poly<#ring, #eval_encoding>>

See bit_field_encoding for the definition of the cleartext_start and cleartext_bitwidth fields.

Parameters:

ParameterC++ typeDescription
cleartext_startunsigned
cleartext_bitwidthunsigned

PolynomialCoefficientEncodingAttr

An attribute describing encoded RLWE plaintexts via coefficients.

Syntax:

#lwe.polynomial_coefficient_encoding<
  unsigned,   # cleartext_start
  unsigned   # cleartext_bitwidth
>

A coefficient encoding of a list of integers asserts that the coefficients of the polynomials contain the cleartexts, with the same semantics as bit_field_encoding for per-coefficient encodings.

The presence of this attribute as the encoding attribute of a tensor of poly.poly indicates that the tensor is an RLWE ciphertext for some RLWE scheme that supports the coefficient encoding.

See bit_field_encoding for the definition of the cleartext_start and cleartext_bitwidth fields.

Example:

#generator = #poly.polynomial<1 + x**1024>
#ring = #poly.ring<cmod=65536, ideal=#generator>
#coeff_encoding = #lwe.polynomial_coefficient_encoding<cleartext_start=15, cleartext_bitwidth=4>

%poly1 = poly.from_tensor %coeffs1 : tensor<10xi16> -> !poly.poly<#ring>
%poly2 = poly.from_tensor %coeffs2 : tensor<10xi16> -> !poly.poly<#ring>
%rlwe_ciphertext = tensor.from_elements %poly1, %poly2 : tensor<2x!poly.poly<#ring>, #coeff_encoding>

Parameters:

ParameterC++ typeDescription
cleartext_startunsigned
cleartext_bitwidthunsigned

PolynomialEvaluationEncodingAttr

An attribute describing encoded RLWE plaintexts via evaluations at fixed points.

Syntax:

#lwe.polynomial_evaluation_encoding<
  unsigned,   # cleartext_start
  unsigned   # cleartext_bitwidth
>

A “evaluation encoding” of a list of integers $(v_1, \dots, v_n)$ asserts that $f(x_1 ) = v_1, \dots, f(x_n) = v_n$ for some implicit, but fixed and distinct choice of inputs $x_i$. The encoded values are also scaled by a scale factor, having the same semantics as bit_field_encoding, but applied entry-wise (to either the coefficient or evaluation representation).

This attribute can be used in multiple ways:

  • On a poly.poly, it asserts that the polynomial has been transformed from an evaluation tensor.
  • On a tensor of poly.poly, it asserts that the tensor is an RLWE ciphertext for some RLWE scheme that supports the evaluation encoding.

A typical workflow for the BFV/BGV schemes using this encoding would be to apply a INTT operation to the input list of cleartexts to convert from evaluation form to coefficient form, then encrypt the resulting polynomial in coefficient form, then apply NTT back to the evaluation form for faster multiplication of ciphertexts.

The points chosen are fixed to be the powers of a primitive root of unity of the coefficient ring of the plaintext space, which allows one to use NTT/INTT to tansform quickly between the coefficient and evaluation forms.

Example:

#generator = #poly.polynomial<1 + x**1024>
// note that the cmod should be chosen so as to ensure a primitive root of
// unity exists in the multiplicative group (Z / cmod Z)^*
#ring = #poly.ring<cmod=65536, ideal=#generator>
#lwe_encoding = #lwe.polynomial_evaluation_encoding<cleartext_start=30, cleartext_bitwidth=3>

%evals = arith.constant <[1, 2, 4, 5]> : tensor<4xi16>
// TODO(#182): fix docs
// Note no `intt` operation exists in poly yet.
%poly1 = poly.intt %evals : tensor<4xi16> -> !poly.poly<#ring, #eval_encoding>
%poly2 = poly.intt %evals : tensor<4xi16> -> !poly.poly<#ring, #eval_encoding>
%rlwe_ciphertext = tensor.from_elements %poly1, %poly2 : tensor<2x!poly.poly<#ring, #eval_encoding>>

See bit_field_encoding for the definition of the cleartext_start and cleartext_bitwidth fields.

Parameters:

ParameterC++ typeDescription
cleartext_startunsigned
cleartext_bitwidthunsigned

LWE types

BFloat16Type

bfloat16 floating-point type

ComplexType

Complex number with a parameterized element type

Syntax:

complex-type ::= `complex` `<` type `>`

The value of complex type represents a complex number with a parameterized element type, which is composed of a real and imaginary value of that element type. The element must be a floating point or integer scalar type.

Example:

complex<f32>
complex<i32>

Parameters:

ParameterC++ typeDescription
elementTypeType

Float8E4M3B11FNUZType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 11
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Related to: https://dl.acm.org/doi/10.5555/3454287.3454728

Float8E4M3FNType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values and only two NaN representations. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 7
  • infinities: Not supported
  • NaNs: supported with exponent bits and mantissa bits set to all 1s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E4M3FNUZType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 8
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E5M2Type

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions with the following characteristics:

  • bit encoding: S1E5M2
  • exponent bias: 15
  • infinities: supported with exponent set to all 1s and mantissa 0s
  • NaNs: supported with exponent bits set to all 1s and mantissa of (01, 10, or 11)
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E5M2FNUZType

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E5M2
  • exponent bias: 16
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2206.02915

Float16Type

16-bit floating-point type

Float32Type

32-bit floating-point type

Float64Type

64-bit floating-point type

Float80Type

80-bit floating-point type

Float128Type

128-bit floating-point type

FloatTF32Type

TF32 floating-point type

FunctionType

Map from a list of inputs to a list of results

Syntax:

// Function types may have multiple results.
function-result-type ::= type-list-parens | non-function-type
function-type ::= type-list-parens `->` function-result-type

The function type can be thought of as a function signature. It consists of a list of formal parameter types and a list of formal result types.

Example:

func.func @add_one(%arg0 : i64) -> i64 {
  %c1 = arith.constant 1 : i64
  %0 = arith.addi %arg0, %c1 : i64
  return %0 : i64
}

Parameters:

ParameterC++ typeDescription
inputsArrayRef<Type>
resultsArrayRef<Type>

IndexType

Integer-like type with unknown platform-dependent bit width

Syntax:

// Target word-sized integer.
index-type ::= `index`

The index type is a signless integer whose size is equal to the natural machine word of the target ( rationale ) and is used by the affine constructs in MLIR.

Rationale: integers of platform-specific bit widths are practical to express sizes, dimensionalities and subscripts.

IntegerType

Integer type with arbitrary precision up to a fixed limit

Syntax:

// Sized integers like i1, i4, i8, i16, i32.
signed-integer-type ::= `si` [1-9][0-9]*
unsigned-integer-type ::= `ui` [1-9][0-9]*
signless-integer-type ::= `i` [1-9][0-9]*
integer-type ::= signed-integer-type |
                 unsigned-integer-type |
                 signless-integer-type

Integer types have a designated bit width and may optionally have signedness semantics.

Rationale: low precision integers (like i2, i4 etc) are useful for low-precision inference chips, and arbitrary precision integers are useful for hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller than a 16 bit one).

Parameters:

ParameterC++ typeDescription
widthunsigned
signednessSignednessSemantics

MemRefType

Shaped reference to a region of memory

Syntax:

layout-specification ::= attribute-value
memory-space ::= attribute-value
memref-type ::= `memref` `<` dimension-list-ranked type
                (`,` layout-specification)? (`,` memory-space)? `>`

A memref type is a reference to a region of memory (similar to a buffer pointer, but more powerful). The buffer pointed to by a memref can be allocated, aliased and deallocated. A memref can be used to read and write data from/to the memory region which it references. Memref types use the same shape specifier as tensor types. Note that memref<f32>, memref<0 x f32>, memref<1 x 0 x f32>, and memref<0 x 1 x f32> are all different types.

A memref is allowed to have an unknown rank (e.g. memref<*xf32>). The purpose of unranked memrefs is to allow external library functions to receive memref arguments of any rank without versioning the functions based on the rank. Other uses of this type are disallowed or will have undefined behavior.

Are accepted as elements:

  • built-in integer types;
  • built-in index type;
  • built-in floating point types;
  • built-in vector types with elements of the above types;
  • another memref type;
  • any other type implementing MemRefElementTypeInterface.
Layout

A memref may optionally have a layout that indicates how indices are transformed from the multi-dimensional form into a linear address. The layout must avoid internal aliasing, i.e., two distinct tuples of in-bounds indices must be pointing to different elements in memory. The layout is an attribute that implements MemRefLayoutAttrInterface. The bulitin dialect offers two kinds of layouts: strided and affine map, each of which is available as an attribute. Other attributes may be used to represent the layout as long as they can be converted to a semi-affine map and implement the required interface. Users of memref are expected to fallback to the affine representation when handling unknown memref layouts. Multi-dimensional affine forms are interpreted in row-major fashion.

In absence of an explicit layout, a memref is considered to have a multi-dimensional identity affine map layout. Identity layout maps do not contribute to the MemRef type identification and are discarded on construction. That is, a type with an explicit identity map is memref<?x?xf32, (i,j)->(i,j)> is strictly the same as the one without a layout, memref<?x?xf32>.

Affine Map Layout

The layout may be represented directly as an affine map from the index space to the storage space. For example, the following figure shows an index map which maps a 2-dimensional index from a 2x2 index space to a 3x3 index space, using symbols S0 and S1 as offsets.

Index Map Example

Semi-affine maps are sufficiently flexible to represent a wide variety of dense storage layouts, including row- and column-major and tiled:

// MxN matrix stored in row major layout in memory:
#layout_map_row_major = (i, j) -> (i, j)

// MxN matrix stored in column major layout in memory:
#layout_map_col_major = (i, j) -> (j, i)

// MxN matrix stored in a 2-d blocked/tiled layout with 64x64 tiles.
#layout_tiled = (i, j) -> (i floordiv 64, j floordiv 64, i mod 64, j mod 64)
Strided Layout

Memref layout can be expressed using strides to encode the distance, in number of elements, in (linear) memory between successive entries along a particular dimension. For example, a row-major strided layout for memref<2x3x4xf32> is strided<[12, 4, 1]>, where the last dimension is contiguous as indicated by the unit stride and the remaining strides are products of the sizes of faster-variying dimensions. Strided layout can also express non-contiguity, e.g., memref<2x3, strided<[6, 2]>> only accesses even elements of the dense consecutive storage along the innermost dimension.

The strided layout supports an optional offset that indicates the distance, in the number of elements, between the beginning of the memref and the first accessed element. When omitted, the offset is considered to be zero. That is, memref<2, strided<[2], offset: 0>> and memref<2, strided<[2]>> are strictly the same type.

Both offsets and strides may be dynamic, that is, unknown at compile time. This is represented by using a question mark (?) instead of the value in the textual form of the IR.

The strided layout converts into the following canonical one-dimensional affine form through explicit linearization:

affine_map<(d0, ... dN)[offset, stride0, ... strideN] ->
            (offset + d0 * stride0 + ... dN * strideN)>

Therefore, it is never subject to the implicit row-major layout interpretation.

Codegen of Unranked Memref

Using unranked memref in codegen besides the case mentioned above is highly discouraged. Codegen is concerned with generating loop nests and specialized instructions for high-performance, unranked memref is concerned with hiding the rank and thus, the number of enclosing loops required to iterate over the data. However, if there is a need to code-gen unranked memref, one possible path is to cast into a static ranked type based on the dynamic rank. Another possible path is to emit a single while loop conditioned on a linear index and perform delinearization of the linear index to a dynamic array containing the (unranked) indices. While this is possible, it is expected to not be a good idea to perform this during codegen as the cost of the translations is expected to be prohibitive and optimizations at this level are not expected to be worthwhile. If expressiveness is the main concern, irrespective of performance, passing unranked memrefs to an external C++ library and implementing rank-agnostic logic there is expected to be significantly simpler.

Unranked memrefs may provide expressiveness gains in the future and help bridge the gap with unranked tensors. Unranked memrefs will not be expected to be exposed to codegen but one may query the rank of an unranked memref (a special op will be needed for this purpose) and perform a switch and cast to a ranked memref as a prerequisite to codegen.

Example:

// With static ranks, we need a function for each possible argument type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
call @helper_2D(%A) : (memref<16x32xf32>)->()
call @helper_3D(%B) : (memref<16x32x64xf32>)->()

// With unknown rank, the functions can be unified under one unranked type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
// Remove rank info
%A_u = memref_cast %A : memref<16x32xf32> -> memref<*xf32>
%B_u = memref_cast %B : memref<16x32x64xf32> -> memref<*xf32>
// call same function with dynamic ranks
call @helper(%A_u) : (memref<*xf32>)->()
call @helper(%B_u) : (memref<*xf32>)->()

The core syntax and representation of a layout specification is a semi-affine map. Additionally, syntactic sugar is supported to make certain layout specifications more intuitive to read. For the moment, a memref supports parsing a strided form which is converted to a semi-affine map automatically.

The memory space of a memref is specified by a target-specific attribute. It might be an integer value, string, dictionary or custom dialect attribute. The empty memory space (attribute is None) is target specific.

The notionally dynamic value of a memref value includes the address of the buffer allocated, as well as the symbols referred to by the shape, layout map, and index maps.

Examples of memref static type

// Identity index/layout map
#identity = affine_map<(d0, d1) -> (d0, d1)>

// Column major layout.
#col_major = affine_map<(d0, d1, d2) -> (d2, d1, d0)>

// A 2-d tiled layout with tiles of size 128 x 256.
#tiled_2d_128x256 = affine_map<(d0, d1) -> (d0 div 128, d1 div 256, d0 mod 128, d1 mod 256)>

// A tiled data layout with non-constant tile sizes.
#tiled_dynamic = affine_map<(d0, d1)[s0, s1] -> (d0 floordiv s0, d1 floordiv s1,
                             d0 mod s0, d1 mod s1)>

// A layout that yields a padding on two at either end of the minor dimension.
#padded = affine_map<(d0, d1) -> (d0, (d1 + 2) floordiv 2, (d1 + 2) mod 2)>


// The dimension list "16x32" defines the following 2D index space:
//
//   { (i, j) : 0 <= i < 16, 0 <= j < 32 }
//
memref<16x32xf32, #identity>

// The dimension list "16x4x?" defines the following 3D index space:
//
//   { (i, j, k) : 0 <= i < 16, 0 <= j < 4, 0 <= k < N }
//
// where N is a symbol which represents the runtime value of the size of
// the third dimension.
//
// %N here binds to the size of the third dimension.
%A = alloc(%N) : memref<16x4x?xf32, #col_major>

// A 2-d dynamic shaped memref that also has a dynamically sized tiled
// layout. The memref index space is of size %M x %N, while %B1 and %B2
// bind to the symbols s0, s1 respectively of the layout map #tiled_dynamic.
// Data tiles of size %B1 x %B2 in the logical space will be stored
// contiguously in memory. The allocation size will be
// (%M ceildiv %B1) * %B1 * (%N ceildiv %B2) * %B2 f32 elements.
%T = alloc(%M, %N) [%B1, %B2] : memref<?x?xf32, #tiled_dynamic>

// A memref that has a two-element padding at either end. The allocation
// size will fit 16 * 64 float elements of data.
%P = alloc() : memref<16x64xf32, #padded>

// Affine map with symbol 's0' used as offset for the first dimension.
#imapS = affine_map<(d0, d1) [s0] -> (d0 + s0, d1)>
// Allocate memref and bind the following symbols:
// '%n' is bound to the dynamic second dimension of the memref type.
// '%o' is bound to the symbol 's0' in the affine map of the memref type.
%n = ...
%o = ...
%A = alloc (%n)[%o] : <16x?xf32, #imapS>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
layoutMemRefLayoutAttrInterface
memorySpaceAttribute

NoneType

A unit type

Syntax:

none-type ::= `none`

NoneType is a unit type, i.e. a type with exactly one possible value, where its value does not have a defined dynamic representation.

Example:

func.func @none_type() {
  %none_val = "foo.unknown_op"() : () -> none
  return
}

OpaqueType

Type of a non-registered dialect

Syntax:

opaque-type ::= `opaque` `<` type `>`

Opaque types represent types of non-registered dialects. These are types represented in their raw string form, and can only usefully be tested for type equality.

Example:

opaque<"llvm", "struct<(i32, float)>">
opaque<"pdl", "value">

Parameters:

ParameterC++ typeDescription
dialectNamespaceStringAttr
typeData::llvm::StringRef

RankedTensorType

Multi-dimensional array with a fixed number of dimensions

Syntax:

tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>`
dimension-list ::= (dimension `x`)*
dimension ::= `?` | decimal-literal
encoding ::= attribute-value

Values with tensor type represents aggregate N-dimensional data values, and have a known element type and a fixed rank with a list of dimensions. Each dimension may be a static non-negative decimal constant or be dynamically determined (indicated by ?).

The runtime representation of the MLIR tensor type is intentionally abstracted - you cannot control layout or get a pointer to the data. For low level buffer access, MLIR has a memref type. This abstracted runtime representation holds both the tensor data values as well as information about the (potentially dynamic) shape of the tensor. The dim operation returns the size of a dimension from a value of tensor type.

The encoding attribute provides additional information on the tensor. An empty attribute denotes a straightforward tensor without any specific structure. But particular properties, like sparsity or other specific characteristics of the data of the tensor can be encoded through this attribute. The semantics are defined by a type and attribute interface and must be respected by all passes that operate on tensor types. TODO: provide this interface, and document it further.

Note: hexadecimal integer literals are not allowed in tensor type declarations to avoid confusion between 0xf32 and 0 x f32. Zero sizes are allowed in tensors and treated as other sizes, e.g., tensor<0 x 1 x i32> and tensor<1 x 0 x i32> are different types. Since zero sizes are not allowed in some other types, such tensors should be optimized away before lowering tensors to vectors.

Example:

// Known rank but unknown dimensions.
tensor<? x ? x ? x ? x f32>

// Partially known dimensions.
tensor<? x ? x 13 x ? x f32>

// Full static shape.
tensor<17 x 4 x 13 x 4 x f32>

// Tensor with rank zero. Represents a scalar.
tensor<f32>

// Zero-element dimensions are allowed.
tensor<0 x 42 x f32>

// Zero-element tensor of f32 type (hexadecimal literals not allowed here).
tensor<0xf32>

// Tensor with an encoding attribute (where #ENCODING is a named alias).
tensor<?x?xf64, #ENCODING>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
encodingAttribute

TupleType

Fixed-sized collection of other types

Syntax:

tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`

The value of tuple type represents a fixed-size collection of elements, where each element may be of a different type.

Rationale: Though this type is first class in the type system, MLIR provides no standard operations for operating on tuple types (rationale).

Example:

// Empty tuple.
tuple<>

// Single element
tuple<f32>

// Many elements.
tuple<i32, f32, tensor<i1>, i5>

Parameters:

ParameterC++ typeDescription
typesArrayRef<Type>

UnrankedMemRefType

Shaped reference, with unknown rank, to a region of memory

Syntax:

unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>`
memory-space ::= attribute-value

A memref type with an unknown rank (e.g. memref<*xf32>). The purpose of unranked memrefs is to allow external library functions to receive memref arguments of any rank without versioning the functions based on the rank. Other uses of this type are disallowed or will have undefined behavior.

See MemRefType for more information on memref types.

Examples:

memref<*f32>

// An unranked memref with a memory space of 10.
memref<*f32, 10>

Parameters:

ParameterC++ typeDescription
elementTypeType
memorySpaceAttribute

UnrankedTensorType

Multi-dimensional array with unknown dimensions

Syntax:

tensor-type ::= `tensor` `<` `*` `x` type `>`

An unranked tensor is a type of tensor in which the set of dimensions have unknown rank. See RankedTensorType for more information on tensor types.

Examples:

tensor<*xf32>

Parameters:

ParameterC++ typeDescription
elementTypeType

VectorType

Multi-dimensional SIMD vector type

Syntax:

vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
vector-element-type ::= float-type | integer-type | index-type
vector-dim-list := (static-dim-list `x`)?
static-dim-list ::= static-dim (`x` static-dim)*
static-dim ::= (decimal-literal | `[` decimal-literal `]`)

The vector type represents a SIMD style vector used by target-specific operation sets like AVX or SVE. While the most common use is for 1D vectors (e.g. vector<16 x f32>) we also support multidimensional registers on targets that support them (like TPUs). The dimensions of a vector type can be fixed-length, scalable, or a combination of the two. The scalable dimensions in a vector are indicated between square brackets ([ ]).

Vector shapes must be positive decimal integers. 0D vectors are allowed by omitting the dimension: vector<f32>.

Note: hexadecimal integer literals are not allowed in vector type declarations, vector<0x42xi32> is invalid because it is interpreted as a 2D vector with shape (0, 42) and zero shapes are not allowed.

Examples:

// A 2D fixed-length vector of 3x42 i32 elements.
vector<3x42xi32>

// A 1D scalable-length vector that contains a multiple of 4 f32 elements.
vector<[4]xf32>

// A 2D scalable-length vector that contains a multiple of 2x8 f32 elements.
vector<[2]x[8]xf32>

// A 2D mixed fixed/scalable vector that contains 4 scalable vectors of 4 f32 elements.
vector<4x[4]xf32>

// A 3D mixed fixed/scalable vector in which only the inner dimension is
// scalable.
vector<2x[4]x8xf32>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
scalableDims::llvm::ArrayRef<bool>

LWECiphertextType

A type for LWE ciphertexts

Syntax:

!lwe.lwe_ciphertext<
  ::mlir::Attribute,   # encoding
  LWEParamsAttr   # lwe_params
>

A type for LWE ciphertexts.

This type keeps track of the plaintext integer encoding for the LWE Ciphertext to ensure proper decoding after decryption. It also keeps track of the ring where the LWE ciphertext is defined, which provides information on the ciphertext shape and the ring operations used in LWE operations.

Parameters:

ParameterC++ typeDescription
encoding::mlir::Attribute
lwe_paramsLWEParamsAttr

LWEPlaintextType

A type for LWE plaintexts

Syntax:

!lwe.lwe_plaintext<
  ::mlir::Attribute   # encoding
>

A type for LWE plaintexts.

This type keeps track of the plaintext integer encoding for the LWE plaintext before it is encrypted.

Parameters:

ParameterC++ typeDescription
encoding::mlir::Attribute

RLWECiphertextType

A type for RLWE ciphertexts

Syntax:

!lwe.rlwe_ciphertext<
  ::mlir::Attribute,   # encoding
  RLWEParamsAttr   # rlwe_params
>

Parameters:

ParameterC++ typeDescription
encoding::mlir::Attribute
rlwe_paramsRLWEParamsAttr

RLWEPlaintextType

A type for RLWE plaintexts

Syntax:

!lwe.rlwe_plaintext<
  ::mlir::Attribute   # encoding
>

Parameters:

ParameterC++ typeDescription
encoding::mlir::Attribute

LWE ops

lwe.encode (heir::lwe::EncodeOp)

Encode an integer to yield an LWE plaintext

Syntax:

operation ::= `lwe.encode` $plaintext attr-dict `:` qualified(type($plaintext)) `to` qualified(type($output))

Encode an integer to yield an LWE plaintext.

This op uses a an encoding attribute to encode the bits of the integer into an LWE plaintext value that can then be encrypted.

Examples:

%Y = lwe.encode %value {encoding = #enc}: i1 to !lwe.lwe_plaintext<encoding = #enc, ring = #ring>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
encoding::mlir::AttributeAn attribute describing encoded LWE plaintexts using bit fields. or An attribute describing unspecified bit field encodings.

Operands:

OperandDescription
plaintextsignless-integer-like

Results:

ResultDescription
outputA type for LWE plaintexts

lwe.trivial_encrypt (heir::lwe::TrivialEncryptOp)

Create a trivial encryption of a plaintext.

Syntax:

operation ::= `lwe.trivial_encrypt` operands attr-dict `:`  qualified(type(operands)) `to` qualified(type(results))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
params::mlir::heir::lwe::LWEParamsAttr

Operands:

OperandDescription
inputA type for LWE plaintexts

Results:

ResultDescription
outputA type for LWE ciphertexts

5 - Openfhe

The openfhe dialect is an exit dialect for generating c++ code against the OpenFHE library API.

See https://github.com/openfheorg/openfhe-development

Openfhe types

CryptoContextType

The CryptoContext required to perform homomorphic operations in OpenFHE.

Syntax: !openfhe.crypto_context

EvalKeyType

The evaluation key required to keyswitch/relinearize/rotate/automorphism operation in OpenFHE.

Syntax: !openfhe.eval_key

PublicKeyType

The public key required to encrypt plaintext in OpenFHE.

Syntax: !openfhe.public_key

Openfhe ops

openfhe.add (heir::openfhe::AddOp)

OpenFHE add operation of two ciphertexts.

Syntax:

operation ::= `openfhe.add` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
lhsA type for RLWE ciphertexts
rhsA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.automorph (heir::openfhe::AutomorphOp)

Syntax:

operation ::= `openfhe.automorph` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts
evalKeyThe evaluation key required to keyswitch/relinearize/rotate/automorphism operation in OpenFHE.

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.encrypt (heir::openfhe::EncryptOp)

Syntax:

operation ::= `openfhe.encrypt` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
plaintextA type for RLWE plaintexts
publicKeyThe public key required to encrypt plaintext in OpenFHE.

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.key_switch (heir::openfhe::KeySwitchOp)

Syntax:

operation ::= `openfhe.key_switch` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts
evalKeyThe evaluation key required to keyswitch/relinearize/rotate/automorphism operation in OpenFHE.

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.level_reduce (heir::openfhe::LevelReduceOp)

OpenFHE level_reduce operation of a ciphertext.

Syntax:

operation ::= `openfhe.level_reduce` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mod_reduce (heir::openfhe::ModReduceOp)

OpenFHE mod_reduce operation of a ciphertext. (used only for BGV/CKKS)

Syntax:

operation ::= `openfhe.mod_reduce` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mul_and_relin (heir::openfhe::MulAndRelinOp)

OpenFHE mul operation of two ciphertexts followed by relinearization to the lowest level.

Syntax:

operation ::= `openfhe.mul_and_relin` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
lhsA type for RLWE ciphertexts
rhsA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mul_const (heir::openfhe::MulConstOp)

OpenFHE mul operation of a ciphertext and a constant.

Syntax:

operation ::= `openfhe.mul_const` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts
constant64-bit signless integer

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mul_no_relin (heir::openfhe::MulNoRelinOp)

OpenFHE mul operation of two ciphertexts without relinearization.

Syntax:

operation ::= `openfhe.mul_no_relin` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
lhsA type for RLWE ciphertexts
rhsA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mul (heir::openfhe::MulOp)

OpenFHE mul operation of two ciphertexts with relinearization.

Syntax:

operation ::= `openfhe.mul` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
lhsA type for RLWE ciphertexts
rhsA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.mul_plain (heir::openfhe::MulPlainOp)

OpenFHE mul operation of a ciphertext and a plaintext.

Syntax:

operation ::= `openfhe.mul_plain` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts
plaintextA type for RLWE plaintexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.negate (heir::openfhe::NegateOp)

OpenFHE negate operation of a ciphertext.

Syntax:

operation ::= `openfhe.negate` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.relin (heir::openfhe::RelinOp)

OpenFHE relinearize operation of a ciphertext.

Syntax:

operation ::= `openfhe.relin` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.rot (heir::openfhe::RotOp)

Syntax:

operation ::= `openfhe.rot` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts
index64-bit signless integer

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.square (heir::openfhe::SquareOp)

OpenFHE square operation of a ciphertext.

Syntax:

operation ::= `openfhe.square` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
ciphertextA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

openfhe.sub (heir::openfhe::SubOp)

OpenFHE sub operation of two ciphertexts.

Syntax:

operation ::= `openfhe.sub` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cryptoContextThe CryptoContext required to perform homomorphic operations in OpenFHE.
lhsA type for RLWE ciphertexts
rhsA type for RLWE ciphertexts

Results:

ResultDescription
outputA type for RLWE ciphertexts

6 - PolyExt

The PolyExt dialect is a place for “external” operations on mlir::heir::polynomial::Polynomial.

PolyExt ops

poly_ext.cmod_switch (heir::poly_ext::CModSwitchOp)

Move polynomial into a ring with different cmod by scaling polynomial coefficients proportionally

Syntax:

operation ::= `poly_ext.cmod_switch` $x attr-dict `:` type($x) `->` type($output)

poly_ext.cmod_switch “moves” polynomial $x$ from ring $Z/QZ[X]/(f(x))$ to the ring $Z/qZ[X]/(f(x))$. The move is done by scaling the polynomial coefficients by $q/Q$ and “rounding” so input and output coufficients are congruent modulo congruence_modulus $t$. The resulting polynomial $\tilde{x} \approx (q/Q)x$ and $\tilde{x} \equiv x \mod t$.

Traits: AlwaysSpeculatableImplTrait, Elementwise, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
congruence_modulus::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
xpolynomial-like

Results:

ResultDescription
outputpolynomial-like

7 - Polynomial

The Polynomial dialect defines single-variable polynomial types and operations.

The simplest use of this dialect is to do math in a polynomial ring R[x], where R is another MLIR integer type like u32, and lower to arith.

More generally, this dialect represent polynomial operations in a quotient polynomial ring Z/qZ[X]/(f(x)) for some integer q and polynomial f(x). Polyomials p(x), q(x) are equal in this ring if they have the same remainder when dividing by f(x). The canonical representative for a polynomial p(x) is has degree less than deg(f(x)). When a modulus is given, ring operations are polynomial addition and multiplication performed with reductions modulo f(x) and q.

Polynomial attributes

PolynomialAttr

An attribute containing a single-variable polynomial.

#poly = #polynomial.poly<x**1024 + 1>

Parameters:

ParameterC++ typeDescription
valuePolynomial

RingAttr

An attribute specifying a ring.

An attribute specifying a polynomial quotient ring with integer coefficients, $\mathbb{Z}/n\mathbb{Z}[x] / (p(x))$.

cmod is the coefficient modulus $n$, and ideal is the ring ideal $(p(x))$. Because all ideals in a single-variable polynomial ring are principal, the ideal is defined by a single polynomial.

#ring = #polynomial.ring<cmod=1234, ideal=#polynomial.polynomial<x**1024 + 1»

Parameters:

ParameterC++ typeDescription
cmodIntegerAttr
idealPolynomial

Polynomial types

PolynomialType

An element of a polynomial quotient ring

Syntax:

!polynomial.polynomial<
  ::mlir::heir::polynomial::RingAttr,   # ring
  Attribute   # encoding
>

A type for polynomials in a polynomial quotient ring.

Parameters:

ParameterC++ typeDescription
ring::mlir::heir::polynomial::RingAttrAn attribute specifying a ring.
encodingAttribute

Polynomial ops

polynomial.add (heir::polynomial::AddOp)

Addition operation between polynomials.

Syntax:

operation ::= `polynomial.add` `(` operands `)` attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
outputpolynomial-like

polynomial.constant (heir::polynomial::ConstantOp)

Define a constant polynomial via an attribute.

Syntax:

operation ::= `polynomial.constant` $input attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
input::mlir::heir::polynomial::PolynomialAttrAn attribute containing a single-variable polynomial.

Results:

ResultDescription
outputAn element of a polynomial quotient ring

polynomial.from_tensor (heir::polynomial::FromTensorOp)

Creates a polynomial from integer coefficients stored in a tensor.

Syntax:

operation ::= `polynomial.from_tensor` $input attr-dict `:` type($input) `->` qualified(type($output))

polynomial.from_tensor creates a polynomial value from a tensor of coefficients. The input tensor must list the coefficients in degree-increasing order.

The input one-dimensional tensor may have size at most the degree of the ring’s ideal generator polynomial, with smaller dimension implying that all higher-degree terms have coefficient zero.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputranked tensor of integer values

Results:

ResultDescription
outputAn element of a polynomial quotient ring

polynomial.leading_term (heir::polynomial::LeadingTermOp)

Compute the leading term of the polynomial.

Syntax:

operation ::= `polynomial.leading_term` operands attr-dict `:` qualified(type($input)) `->` `(` type($degree) `,` type($coefficient) `)`

The degree of a polynomial is the largest $k$ for which the coefficient $a_k$ of $x^k$ is nonzero. The leading term is the term $a_k x^k$, which this op represents as a pair of results.

Operands:

OperandDescription
inputAn element of a polynomial quotient ring

Results:

ResultDescription
degreeindex
coefficientinteger

polynomial.monomial_mul (heir::polynomial::MonomialMulOp)

Multiply a polynomial by a monic monomial.

Syntax:

operation ::= `polynomial.monomial_mul` operands attr-dict `:`  `(` type(operands) `)` `->` type(results)

In the ring of polynomials mod $x^n - 1$, monomial_mul can be interpreted as a cyclic shift of the coefficients of the polynomial. For some rings, this results in optimized lowerings that involve rotations and rescaling of the coefficients of the input.

Interfaces: InferTypeOpInterface

Operands:

OperandDescription
inputAn element of a polynomial quotient ring
monomialDegreeindex

Results:

ResultDescription
outputAn element of a polynomial quotient ring

polynomial.monomial (heir::polynomial::MonomialOp)

Create a polynomial that consists of a single monomial.

Syntax:

operation ::= `polynomial.monomial` operands attr-dict `:`  `(` type(operands) `)` `->` type(results)

Operands:

OperandDescription
coefficientinteger
degreeindex

Results:

ResultDescription
outputAn element of a polynomial quotient ring

polynomial.mul (heir::polynomial::MulOp)

Multiplication operation between polynomials.

Syntax:

operation ::= `polynomial.mul` `(` operands `)` attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Commutative, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
outputpolynomial-like

polynomial.mul_scalar (heir::polynomial::MulScalarOp)

Multiplication by a scalar of the field.

Syntax:

operation ::= `polynomial.mul_scalar` operands attr-dict `:` qualified(type($polynomial)) `,` type($scalar)

Traits: Elementwise, Scalarizable, Tensorizable, Vectorizable

Interfaces: InferTypeOpInterface

Operands:

OperandDescription
polynomialpolynomial-like
scalarinteger

Results:

ResultDescription
outputpolynomial-like

polynomial.sub (heir::polynomial::SubOp)

Subtraction operation between polynomials.

Syntax:

operation ::= `polynomial.sub` `(` operands `)` attr-dict `:` qualified(type($output))

Traits: AlwaysSpeculatableImplTrait, Elementwise, SameOperandsAndResultType, Scalarizable, Tensorizable, Vectorizable

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
lhspolynomial-like
rhspolynomial-like

Results:

ResultDescription
outputpolynomial-like

polynomial.to_tensor (heir::polynomial::ToTensorOp)

Creates a tensor containing the coefficients of a polynomial.

Syntax:

operation ::= `polynomial.to_tensor` $input attr-dict `:` qualified(type($input)) `->` type($output)

polynomial.to_tensor creates a tensor value containing the coefficients of the input polynomial. The output tensor contains the coefficients in degree-increasing order.

Operations that act on the coefficients of a polynomial, such as extracting a specific coefficient or extracting a range of coefficients, should be implemented by composing to_tensor with the relevant tensor dialect ops.

The output tensor has shape equal to the degree of the ring’s ideal generator polynomial, including zeroes.

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputAn element of a polynomial quotient ring

Results:

ResultDescription
outputranked tensor of integer values

8 - Secret

Secret is a dialect for computations that operate on encrypted data.

Secret is intended to serve as a scheme-agnostic front-end for the HEIR ecosystem of dialects. It is supposed to be fully interoperable with the rest of MLIR via secret.generic, while lower-level HEIR dialects would have custom types for arithmetic on secret integers of various bit widths.

Secret types

SecretType

A secret value

Syntax:

!secret.secret<
  Type   # valueType
>

A generic wrapper around another MLIR type, representing an encrypted value but not specifying the manner of encryption. This is useful in HEIR because the compiler may choose various details of the FHE scheme based on the properties of the input program, the backend target hardware, and cost models of the various passes.

Parameters:

ParameterC++ typeDescription
valueTypeType

Secret ops

secret.cast (heir::secret::CastOp)

A placeholder cast from one secret type to another

Syntax:

operation ::= `secret.cast` $input attr-dict `:` qualified(type($input)) `to` qualified(type($output))

A cast operation represents a type cast from one secret type to another, that is used to enable the intermixing of various equivalent secret types before a lower-level FHE scheme has been chosen.

For example, secret.cast can be used to convert a secret<i8> to a secret<tensor<8xi1>> as a compatibility layer between boolean and non-boolean parts of a program. The pass that later lowers the IR to specific FHE schemes would need to replace these casts with appropriate scheme-specific operations, and it is left to those later passes to determine which casts are considered valid.

Example:

%result = secret.cast %0 : !secret.secret<i8> to !secret.secret<tensor<8xi1>>
%result2 = secret.cast %0 : !secret.secret<i8> to !secret.secret<tensor<2xi4>>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputA secret value

Results:

ResultDescription
outputA secret value

secret.conceal (heir::secret::ConcealOp)

Convert a non-secret value into a secret

Syntax:

operation ::= `secret.conceal` $cleartext attr-dict `:` type($cleartext) `->` type($output)

Convert a value to a secret containing the same value.

This op represents a scheme-agnostic encryption operation, as well as a “trivial encryption” operation which is needed for some FHE schemes. This op is also useful for type materialization in the dialect conversion framework.

Examples:

%Y = secret.conceal %value : i32 -> !secret.secret<i32>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
cleartextany type

Results:

ResultDescription
outputA secret value

secret.generic (heir::secret::GenericOp)

Lift a plaintext computation to operate on secrets.

secret.generic lifts a plaintext computation to operate on one or more secrets. The lifted computation is represented as a region containing a single block terminated by secret.yield. The arguments of the secret.generic may include one or more !secret.secret types. The arguments of the block in the op’s body correspond to the underlying plaintext types of the secrets.

secret.generic is not isolated from above, so you may directly reference values in the enclosing scope. This is required to support using secret.generic inside of ops with AffineScope, while having the body of the generic use the induction variables defined by the affine scope.

Basic examples:

Add two secret integers together

%Z = secret.generic ins(%X, %Y : !secret.secret<i32>, !secret.secret<i32>) {
  ^bb0(%x: i32, %y: i32):
    %z = arith.addi %x, %y: i32
    secret.yield %z : i32
  } -> (!secret.secret<i32>)

Add a secret value with a plaintext value. I.e., not all arguments to the op need be secret.

%Z = secret.generic ins(%X, %Y : i32, !secret.secret<i32>) {
  ^bb0(%x: i32, %y: i32):
    %z = arith.addi %x, %y: i32
    secret.yield %z : i32
  } -> (!secret.secret<i32>)

The same as above, but the plaintext op is not passed through the basic block.

%y = arith.constant 7: i32
%Z = secret.generic ins(%Y : !secret.secret<i32>) {
  ^bb0(%y: i32):
    %z = arith.addi %x, %y: i32
    secret.yield %z : i32
  } -> (!secret.secret<i32>)

Traits: SingleBlockImplicitTerminator<YieldOp>, SingleBlock

Operands:

OperandDescription
inputsvariadic of any type

Results:

ResultDescription
resultsvariadic of any type

secret.reveal (heir::secret::RevealOp)

Convert a secret value into a non-secret

Syntax:

operation ::= `secret.reveal` $input attr-dict `:` type($input) `->` type($cleartext)

Convert a secret into a non-secret containing the same value.

This op represents a scheme-agnostic decryption operation. This op is also useful for target materialization in the dialect conversion framework.

Examples:

%Y = secret.reveal %secret_value : !secret.secret<i32> -> i32

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
inputA secret value

Results:

ResultDescription
cleartextany type

secret.yield (heir::secret::YieldOp)

Secret yield operation

secret.yield is a special terminator operation for blocks inside regions in secret generic ops. It returns the cleartext value of the corresponding private computation to the immediately enclosing secret generic op.

Traits: AlwaysSpeculatableImplTrait, HasParent<GenericOp>, ReturnLike, Terminator

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), RegionBranchTerminatorOpInterface

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
valuesvariadic of any type

9 - TfheRust

The thfe_rust dialect is an exit dialect for generating rust code against the tfhe-rs library API, using the shortint parameters and encoding scheme.

See https://github.com/zama-ai/tfhe-rs

TfheRust types

BFloat16Type

bfloat16 floating-point type

ComplexType

Complex number with a parameterized element type

Syntax:

complex-type ::= `complex` `<` type `>`

The value of complex type represents a complex number with a parameterized element type, which is composed of a real and imaginary value of that element type. The element must be a floating point or integer scalar type.

Example:

complex<f32>
complex<i32>

Parameters:

ParameterC++ typeDescription
elementTypeType

Float8E4M3B11FNUZType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 11
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Related to: https://dl.acm.org/doi/10.5555/3454287.3454728

Float8E4M3FNType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values and only two NaN representations. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 7
  • infinities: Not supported
  • NaNs: supported with exponent bits and mantissa bits set to all 1s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E4M3FNUZType

8-bit floating point with 3 bit mantissa

An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E4M3
  • exponent bias: 8
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E5M2Type

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions with the following characteristics:

  • bit encoding: S1E5M2
  • exponent bias: 15
  • infinities: supported with exponent set to all 1s and mantissa 0s
  • NaNs: supported with exponent bits set to all 1s and mantissa of (01, 10, or 11)
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2209.05433

Float8E5M2FNUZType

8-bit floating point with 2 bit mantissa

An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. This is not a standard type as defined by IEEE-754, but it follows similar conventions, with the exception that there are no infinity values, no negative zero, and only one NaN representation. This type has the following characteristics:

  • bit encoding: S1E5M2
  • exponent bias: 16
  • infinities: Not supported
  • NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s
  • denormals when exponent is 0

Described in: https://arxiv.org/abs/2206.02915

Float16Type

16-bit floating-point type

Float32Type

32-bit floating-point type

Float64Type

64-bit floating-point type

Float80Type

80-bit floating-point type

Float128Type

128-bit floating-point type

FloatTF32Type

TF32 floating-point type

FunctionType

Map from a list of inputs to a list of results

Syntax:

// Function types may have multiple results.
function-result-type ::= type-list-parens | non-function-type
function-type ::= type-list-parens `->` function-result-type

The function type can be thought of as a function signature. It consists of a list of formal parameter types and a list of formal result types.

Example:

func.func @add_one(%arg0 : i64) -> i64 {
  %c1 = arith.constant 1 : i64
  %0 = arith.addi %arg0, %c1 : i64
  return %0 : i64
}

Parameters:

ParameterC++ typeDescription
inputsArrayRef<Type>
resultsArrayRef<Type>

IndexType

Integer-like type with unknown platform-dependent bit width

Syntax:

// Target word-sized integer.
index-type ::= `index`

The index type is a signless integer whose size is equal to the natural machine word of the target ( rationale ) and is used by the affine constructs in MLIR.

Rationale: integers of platform-specific bit widths are practical to express sizes, dimensionalities and subscripts.

IntegerType

Integer type with arbitrary precision up to a fixed limit

Syntax:

// Sized integers like i1, i4, i8, i16, i32.
signed-integer-type ::= `si` [1-9][0-9]*
unsigned-integer-type ::= `ui` [1-9][0-9]*
signless-integer-type ::= `i` [1-9][0-9]*
integer-type ::= signed-integer-type |
                 unsigned-integer-type |
                 signless-integer-type

Integer types have a designated bit width and may optionally have signedness semantics.

Rationale: low precision integers (like i2, i4 etc) are useful for low-precision inference chips, and arbitrary precision integers are useful for hardware synthesis (where a 13 bit multiplier is a lot cheaper/smaller than a 16 bit one).

Parameters:

ParameterC++ typeDescription
widthunsigned
signednessSignednessSemantics

MemRefType

Shaped reference to a region of memory

Syntax:

layout-specification ::= attribute-value
memory-space ::= attribute-value
memref-type ::= `memref` `<` dimension-list-ranked type
                (`,` layout-specification)? (`,` memory-space)? `>`

A memref type is a reference to a region of memory (similar to a buffer pointer, but more powerful). The buffer pointed to by a memref can be allocated, aliased and deallocated. A memref can be used to read and write data from/to the memory region which it references. Memref types use the same shape specifier as tensor types. Note that memref<f32>, memref<0 x f32>, memref<1 x 0 x f32>, and memref<0 x 1 x f32> are all different types.

A memref is allowed to have an unknown rank (e.g. memref<*xf32>). The purpose of unranked memrefs is to allow external library functions to receive memref arguments of any rank without versioning the functions based on the rank. Other uses of this type are disallowed or will have undefined behavior.

Are accepted as elements:

  • built-in integer types;
  • built-in index type;
  • built-in floating point types;
  • built-in vector types with elements of the above types;
  • another memref type;
  • any other type implementing MemRefElementTypeInterface.
Layout

A memref may optionally have a layout that indicates how indices are transformed from the multi-dimensional form into a linear address. The layout must avoid internal aliasing, i.e., two distinct tuples of in-bounds indices must be pointing to different elements in memory. The layout is an attribute that implements MemRefLayoutAttrInterface. The bulitin dialect offers two kinds of layouts: strided and affine map, each of which is available as an attribute. Other attributes may be used to represent the layout as long as they can be converted to a semi-affine map and implement the required interface. Users of memref are expected to fallback to the affine representation when handling unknown memref layouts. Multi-dimensional affine forms are interpreted in row-major fashion.

In absence of an explicit layout, a memref is considered to have a multi-dimensional identity affine map layout. Identity layout maps do not contribute to the MemRef type identification and are discarded on construction. That is, a type with an explicit identity map is memref<?x?xf32, (i,j)->(i,j)> is strictly the same as the one without a layout, memref<?x?xf32>.

Affine Map Layout

The layout may be represented directly as an affine map from the index space to the storage space. For example, the following figure shows an index map which maps a 2-dimensional index from a 2x2 index space to a 3x3 index space, using symbols S0 and S1 as offsets.

Index Map Example

Semi-affine maps are sufficiently flexible to represent a wide variety of dense storage layouts, including row- and column-major and tiled:

// MxN matrix stored in row major layout in memory:
#layout_map_row_major = (i, j) -> (i, j)

// MxN matrix stored in column major layout in memory:
#layout_map_col_major = (i, j) -> (j, i)

// MxN matrix stored in a 2-d blocked/tiled layout with 64x64 tiles.
#layout_tiled = (i, j) -> (i floordiv 64, j floordiv 64, i mod 64, j mod 64)
Strided Layout

Memref layout can be expressed using strides to encode the distance, in number of elements, in (linear) memory between successive entries along a particular dimension. For example, a row-major strided layout for memref<2x3x4xf32> is strided<[12, 4, 1]>, where the last dimension is contiguous as indicated by the unit stride and the remaining strides are products of the sizes of faster-variying dimensions. Strided layout can also express non-contiguity, e.g., memref<2x3, strided<[6, 2]>> only accesses even elements of the dense consecutive storage along the innermost dimension.

The strided layout supports an optional offset that indicates the distance, in the number of elements, between the beginning of the memref and the first accessed element. When omitted, the offset is considered to be zero. That is, memref<2, strided<[2], offset: 0>> and memref<2, strided<[2]>> are strictly the same type.

Both offsets and strides may be dynamic, that is, unknown at compile time. This is represented by using a question mark (?) instead of the value in the textual form of the IR.

The strided layout converts into the following canonical one-dimensional affine form through explicit linearization:

affine_map<(d0, ... dN)[offset, stride0, ... strideN] ->
            (offset + d0 * stride0 + ... dN * strideN)>

Therefore, it is never subject to the implicit row-major layout interpretation.

Codegen of Unranked Memref

Using unranked memref in codegen besides the case mentioned above is highly discouraged. Codegen is concerned with generating loop nests and specialized instructions for high-performance, unranked memref is concerned with hiding the rank and thus, the number of enclosing loops required to iterate over the data. However, if there is a need to code-gen unranked memref, one possible path is to cast into a static ranked type based on the dynamic rank. Another possible path is to emit a single while loop conditioned on a linear index and perform delinearization of the linear index to a dynamic array containing the (unranked) indices. While this is possible, it is expected to not be a good idea to perform this during codegen as the cost of the translations is expected to be prohibitive and optimizations at this level are not expected to be worthwhile. If expressiveness is the main concern, irrespective of performance, passing unranked memrefs to an external C++ library and implementing rank-agnostic logic there is expected to be significantly simpler.

Unranked memrefs may provide expressiveness gains in the future and help bridge the gap with unranked tensors. Unranked memrefs will not be expected to be exposed to codegen but one may query the rank of an unranked memref (a special op will be needed for this purpose) and perform a switch and cast to a ranked memref as a prerequisite to codegen.

Example:

// With static ranks, we need a function for each possible argument type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
call @helper_2D(%A) : (memref<16x32xf32>)->()
call @helper_3D(%B) : (memref<16x32x64xf32>)->()

// With unknown rank, the functions can be unified under one unranked type
%A = alloc() : memref<16x32xf32>
%B = alloc() : memref<16x32x64xf32>
// Remove rank info
%A_u = memref_cast %A : memref<16x32xf32> -> memref<*xf32>
%B_u = memref_cast %B : memref<16x32x64xf32> -> memref<*xf32>
// call same function with dynamic ranks
call @helper(%A_u) : (memref<*xf32>)->()
call @helper(%B_u) : (memref<*xf32>)->()

The core syntax and representation of a layout specification is a semi-affine map. Additionally, syntactic sugar is supported to make certain layout specifications more intuitive to read. For the moment, a memref supports parsing a strided form which is converted to a semi-affine map automatically.

The memory space of a memref is specified by a target-specific attribute. It might be an integer value, string, dictionary or custom dialect attribute. The empty memory space (attribute is None) is target specific.

The notionally dynamic value of a memref value includes the address of the buffer allocated, as well as the symbols referred to by the shape, layout map, and index maps.

Examples of memref static type

// Identity index/layout map
#identity = affine_map<(d0, d1) -> (d0, d1)>

// Column major layout.
#col_major = affine_map<(d0, d1, d2) -> (d2, d1, d0)>

// A 2-d tiled layout with tiles of size 128 x 256.
#tiled_2d_128x256 = affine_map<(d0, d1) -> (d0 div 128, d1 div 256, d0 mod 128, d1 mod 256)>

// A tiled data layout with non-constant tile sizes.
#tiled_dynamic = affine_map<(d0, d1)[s0, s1] -> (d0 floordiv s0, d1 floordiv s1,
                             d0 mod s0, d1 mod s1)>

// A layout that yields a padding on two at either end of the minor dimension.
#padded = affine_map<(d0, d1) -> (d0, (d1 + 2) floordiv 2, (d1 + 2) mod 2)>


// The dimension list "16x32" defines the following 2D index space:
//
//   { (i, j) : 0 <= i < 16, 0 <= j < 32 }
//
memref<16x32xf32, #identity>

// The dimension list "16x4x?" defines the following 3D index space:
//
//   { (i, j, k) : 0 <= i < 16, 0 <= j < 4, 0 <= k < N }
//
// where N is a symbol which represents the runtime value of the size of
// the third dimension.
//
// %N here binds to the size of the third dimension.
%A = alloc(%N) : memref<16x4x?xf32, #col_major>

// A 2-d dynamic shaped memref that also has a dynamically sized tiled
// layout. The memref index space is of size %M x %N, while %B1 and %B2
// bind to the symbols s0, s1 respectively of the layout map #tiled_dynamic.
// Data tiles of size %B1 x %B2 in the logical space will be stored
// contiguously in memory. The allocation size will be
// (%M ceildiv %B1) * %B1 * (%N ceildiv %B2) * %B2 f32 elements.
%T = alloc(%M, %N) [%B1, %B2] : memref<?x?xf32, #tiled_dynamic>

// A memref that has a two-element padding at either end. The allocation
// size will fit 16 * 64 float elements of data.
%P = alloc() : memref<16x64xf32, #padded>

// Affine map with symbol 's0' used as offset for the first dimension.
#imapS = affine_map<(d0, d1) [s0] -> (d0 + s0, d1)>
// Allocate memref and bind the following symbols:
// '%n' is bound to the dynamic second dimension of the memref type.
// '%o' is bound to the symbol 's0' in the affine map of the memref type.
%n = ...
%o = ...
%A = alloc (%n)[%o] : <16x?xf32, #imapS>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
layoutMemRefLayoutAttrInterface
memorySpaceAttribute

NoneType

A unit type

Syntax:

none-type ::= `none`

NoneType is a unit type, i.e. a type with exactly one possible value, where its value does not have a defined dynamic representation.

Example:

func.func @none_type() {
  %none_val = "foo.unknown_op"() : () -> none
  return
}

OpaqueType

Type of a non-registered dialect

Syntax:

opaque-type ::= `opaque` `<` type `>`

Opaque types represent types of non-registered dialects. These are types represented in their raw string form, and can only usefully be tested for type equality.

Example:

opaque<"llvm", "struct<(i32, float)>">
opaque<"pdl", "value">

Parameters:

ParameterC++ typeDescription
dialectNamespaceStringAttr
typeData::llvm::StringRef

RankedTensorType

Multi-dimensional array with a fixed number of dimensions

Syntax:

tensor-type ::= `tensor` `<` dimension-list type (`,` encoding)? `>`
dimension-list ::= (dimension `x`)*
dimension ::= `?` | decimal-literal
encoding ::= attribute-value

Values with tensor type represents aggregate N-dimensional data values, and have a known element type and a fixed rank with a list of dimensions. Each dimension may be a static non-negative decimal constant or be dynamically determined (indicated by ?).

The runtime representation of the MLIR tensor type is intentionally abstracted - you cannot control layout or get a pointer to the data. For low level buffer access, MLIR has a memref type. This abstracted runtime representation holds both the tensor data values as well as information about the (potentially dynamic) shape of the tensor. The dim operation returns the size of a dimension from a value of tensor type.

The encoding attribute provides additional information on the tensor. An empty attribute denotes a straightforward tensor without any specific structure. But particular properties, like sparsity or other specific characteristics of the data of the tensor can be encoded through this attribute. The semantics are defined by a type and attribute interface and must be respected by all passes that operate on tensor types. TODO: provide this interface, and document it further.

Note: hexadecimal integer literals are not allowed in tensor type declarations to avoid confusion between 0xf32 and 0 x f32. Zero sizes are allowed in tensors and treated as other sizes, e.g., tensor<0 x 1 x i32> and tensor<1 x 0 x i32> are different types. Since zero sizes are not allowed in some other types, such tensors should be optimized away before lowering tensors to vectors.

Example:

// Known rank but unknown dimensions.
tensor<? x ? x ? x ? x f32>

// Partially known dimensions.
tensor<? x ? x 13 x ? x f32>

// Full static shape.
tensor<17 x 4 x 13 x 4 x f32>

// Tensor with rank zero. Represents a scalar.
tensor<f32>

// Zero-element dimensions are allowed.
tensor<0 x 42 x f32>

// Zero-element tensor of f32 type (hexadecimal literals not allowed here).
tensor<0xf32>

// Tensor with an encoding attribute (where #ENCODING is a named alias).
tensor<?x?xf64, #ENCODING>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
encodingAttribute

TupleType

Fixed-sized collection of other types

Syntax:

tuple-type ::= `tuple` `<` (type ( `,` type)*)? `>`

The value of tuple type represents a fixed-size collection of elements, where each element may be of a different type.

Rationale: Though this type is first class in the type system, MLIR provides no standard operations for operating on tuple types (rationale).

Example:

// Empty tuple.
tuple<>

// Single element
tuple<f32>

// Many elements.
tuple<i32, f32, tensor<i1>, i5>

Parameters:

ParameterC++ typeDescription
typesArrayRef<Type>

UnrankedMemRefType

Shaped reference, with unknown rank, to a region of memory

Syntax:

unranked-memref-type ::= `memref` `<*x` type (`,` memory-space)? `>`
memory-space ::= attribute-value

A memref type with an unknown rank (e.g. memref<*xf32>). The purpose of unranked memrefs is to allow external library functions to receive memref arguments of any rank without versioning the functions based on the rank. Other uses of this type are disallowed or will have undefined behavior.

See MemRefType for more information on memref types.

Examples:

memref<*f32>

// An unranked memref with a memory space of 10.
memref<*f32, 10>

Parameters:

ParameterC++ typeDescription
elementTypeType
memorySpaceAttribute

UnrankedTensorType

Multi-dimensional array with unknown dimensions

Syntax:

tensor-type ::= `tensor` `<` `*` `x` type `>`

An unranked tensor is a type of tensor in which the set of dimensions have unknown rank. See RankedTensorType for more information on tensor types.

Examples:

tensor<*xf32>

Parameters:

ParameterC++ typeDescription
elementTypeType

VectorType

Multi-dimensional SIMD vector type

Syntax:

vector-type ::= `vector` `<` vector-dim-list vector-element-type `>`
vector-element-type ::= float-type | integer-type | index-type
vector-dim-list := (static-dim-list `x`)?
static-dim-list ::= static-dim (`x` static-dim)*
static-dim ::= (decimal-literal | `[` decimal-literal `]`)

The vector type represents a SIMD style vector used by target-specific operation sets like AVX or SVE. While the most common use is for 1D vectors (e.g. vector<16 x f32>) we also support multidimensional registers on targets that support them (like TPUs). The dimensions of a vector type can be fixed-length, scalable, or a combination of the two. The scalable dimensions in a vector are indicated between square brackets ([ ]).

Vector shapes must be positive decimal integers. 0D vectors are allowed by omitting the dimension: vector<f32>.

Note: hexadecimal integer literals are not allowed in vector type declarations, vector<0x42xi32> is invalid because it is interpreted as a 2D vector with shape (0, 42) and zero shapes are not allowed.

Examples:

// A 2D fixed-length vector of 3x42 i32 elements.
vector<3x42xi32>

// A 1D scalable-length vector that contains a multiple of 4 f32 elements.
vector<[4]xf32>

// A 2D scalable-length vector that contains a multiple of 2x8 f32 elements.
vector<[2]x[8]xf32>

// A 2D mixed fixed/scalable vector that contains 4 scalable vectors of 4 f32 elements.
vector<4x[4]xf32>

// A 3D mixed fixed/scalable vector in which only the inner dimension is
// scalable.
vector<2x[4]x8xf32>

Parameters:

ParameterC++ typeDescription
shape::llvm::ArrayRef<int64_t>
elementTypeType
scalableDims::llvm::ArrayRef<bool>

EncryptedInt8Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type

Syntax: !tfhe_rust.ei8

EncryptedInt16Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type

Syntax: !tfhe_rust.ei16

EncryptedInt32Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type

Syntax: !tfhe_rust.ei32

EncryptedInt64Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type

Syntax: !tfhe_rust.ei64

EncryptedInt128Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type

Syntax: !tfhe_rust.ei128

EncryptedInt256Type

An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

Syntax: !tfhe_rust.ei256

EncryptedUInt2Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type

Syntax: !tfhe_rust.eui2

EncryptedUInt3Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type

Syntax: !tfhe_rust.eui3

EncryptedUInt4Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type

Syntax: !tfhe_rust.eui4

EncryptedUInt8Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type

Syntax: !tfhe_rust.eui8

EncryptedUInt10Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type

Syntax: !tfhe_rust.eui10

EncryptedUInt12Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type

Syntax: !tfhe_rust.eui12

EncryptedUInt14Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type

Syntax: !tfhe_rust.eui14

EncryptedUInt16Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type

Syntax: !tfhe_rust.eui16

EncryptedUInt32Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type

Syntax: !tfhe_rust.eui32

EncryptedUInt64Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type

Syntax: !tfhe_rust.eui64

EncryptedUInt128Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type

Syntax: !tfhe_rust.eui128

EncryptedUInt256Type

An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type

Syntax: !tfhe_rust.eui256

LookupTableType

A univariate lookup table used for programmable bootstrapping.

Syntax: !tfhe_rust.lookup_table

ServerKeyType

The short int server key required to perform homomorphic operations.

Syntax: !tfhe_rust.server_key

TfheRust ops

tfhe_rust.add (heir::tfhe_rust::AddOp)

Syntax:

operation ::= `tfhe_rust.add` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
lhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type
rhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

tfhe_rust.apply_lookup_table (heir::tfhe_rust::ApplyLookupTableOp)

Syntax:

operation ::= `tfhe_rust.apply_lookup_table` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
inputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type
lookupTableA univariate lookup table used for programmable bootstrapping.

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

tfhe_rust.bitand (heir::tfhe_rust::BitAndOp)

Syntax:

operation ::= `tfhe_rust.bitand` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
lhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type
rhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

tfhe_rust.create_trivial (heir::tfhe_rust::CreateTrivialOp)

Syntax:

operation ::= `tfhe_rust.create_trivial` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
valueinteger

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

tfhe_rust.generate_lookup_table (heir::tfhe_rust::GenerateLookupTableOp)

Syntax:

operation ::= `tfhe_rust.generate_lookup_table` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

AttributeMLIR TypeDescription
truthTable::mlir::IntegerAttrAn Attribute containing a integer value

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.

Results:

ResultDescription
lookupTableA univariate lookup table used for programmable bootstrapping.

tfhe_rust.scalar_left_shift (heir::tfhe_rust::ScalarLeftShiftOp)

Syntax:

operation ::= `tfhe_rust.scalar_left_shift` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
ciphertextAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type
shiftAmount8-bit integer

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

tfhe_rust.sub (heir::tfhe_rust::SubOp)

Syntax:

operation ::= `tfhe_rust.sub` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe short int server key required to perform homomorphic operations.
lhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type
rhsAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

Results:

ResultDescription
outputAn encrypted unsigned integer corresponding to tfhe-rs’s FHEUint2 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint3 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint4 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint8 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint10 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint12 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint14 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint16 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint32 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint64 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint128 type or An encrypted unsigned integer corresponding to tfhe-rs’s FHEUint256 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt8 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt16 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt32 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt64 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt128 type or An encrypted signed integer corresponding to tfhe-rs’s FHEInt256 type

10 - TfheRustBool

The tfhe_rust_bool dialect is an exit dialect for generating rust code against the tfhe-rs library API, using the boolean parameter set.

See https://github.com/zama-ai/tfhe-rs

TfheRustBool types

EncryptedBoolType

An encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Syntax: !tfhe_rust_bool.eb

ServerKeyType

The boolean server key required to perform homomorphic operations.

Syntax: !tfhe_rust_bool.server_key

TfheRustBool ops

tfhe_rust_bool.and (heir::tfhe_rust_bool::AndOp)

Logical AND of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.and` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.create_trivial (heir::tfhe_rust_bool::CreateTrivialOp)

Syntax:

operation ::= `tfhe_rust_bool.create_trivial` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
value1-bit signless integer

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.mux (heir::tfhe_rust_bool::MuxOp)

Syntax:

operation ::= `tfhe_rust_bool.mux` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
cndAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.nand (heir::tfhe_rust_bool::NandOp)

Logical NAND of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.nand` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.nor (heir::tfhe_rust_bool::NorOp)

Logical NOR of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.nor` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.not (heir::tfhe_rust_bool::NotOp)

Syntax:

operation ::= `tfhe_rust_bool.not` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
inputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.or (heir::tfhe_rust_bool::OrOp)

Logical OR of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.or` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.xnor (heir::tfhe_rust_bool::XnorOp)

Logical XNOR of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.xnor` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

tfhe_rust_bool.xor (heir::tfhe_rust_bool::XorOp)

Logical XOR of two TFHE-rs Bool ciphertexts.

Syntax:

operation ::= `tfhe_rust_bool.xor` operands attr-dict `:` `(` type(operands) `)` `->` type(results)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

OperandDescription
serverKeyThe boolean server key required to perform homomorphic operations.
lhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type
rhsAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type

Results:

ResultDescription
outputAn encrypted Boolean corresponding to tfhe-rs’s FHEBool type