Repository: opencompl/lean-mlir
Pull request #1112: feat: add `comb` dialect
Author: login: luisacicolini
Created: 2025-04-14T15:29:49Z | Merged: 2025-04-28T13:24:39Z

This PR adds the [`comb` dialect](https://circt.llvm.org/docs/Dialects/Comb/#combadd-circtcombaddop). 
`truthTable` operation and wildcard/cases SV semantics are missing, as they will require more infrastructure, e.g. establishing and defining 4-value logic. 

I have no idea what's wrong with the `InstCombine` files, git seems to think that there's been some changes but they look identical to me (and I did `git restore` the path, no changes)



Diff:
diff --git a/SSA/Projects/CIRCT/Comb/Comb.lean b/SSA/Projects/CIRCT/Comb/Comb.lean
new file mode 100644
index 0000000000..f37a5d262c
--- /dev/null
+++ b/SSA/Projects/CIRCT/Comb/Comb.lean
@@ -0,0 +1,331 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+import SSA.Core.Tactic.SimpSet
+import SSA.Projects.CIRCT.Comb.CombSemantics
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| typeSum (w₁ w₂ : Nat) : Ty
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w₁ : Nat) (w₂ : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w₁ w₂ => (Ty.bv w₁, Ty.bv w₂, Ty.bool) → (Ty.typeSum w₁ w₂)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .typeSum w₁ w₂ => BitVec w₁ ⊕ BitVec w₂
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => BitVec.sdiv
+  | .divu _ => BitVec.udiv
+  | .extract _ _ => fun x => CombOp.extract x _
+  | .icmp p _ => fun x y => CombOp.icmp (Option.get! (ofString? p)) x y
+  | .mods _ => BitVec.smod
+  | .modu _ => BitVec.umod
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ _ => fun x y => CombOp.mux x y
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun x => CombOp.parity x
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun x y => CombOp.shl x y
+  | .shrs _ => BitVec.sshiftRight'
+  | .shru _ => fun x y => CombOp.shru x y
+  | .sub _ => BitVec.sub
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["IcmpPred"] =>
+      return .icmpPred
+    | ["TypeSum", w₁, w₂] =>
+      match w₁.toNat?, w₂.toNat? with
+      | some w₁', some w₂' => return .typeSum w₁' w₂'
+      | _, _ => throw .unsupportedType
+    | _ => throw .unsupportedType
+  | MLIR.AST.MLIRType.int _ w =>
+    match w with
+    | .concrete w' => return .bv w'
+    | .mvar _ => throw <| .generic s!"Bitvec size can't be an mvar"
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def mkExpr (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) :
+    MLIR.AST.ReaderM Comb (Σ eff ty, Expr Comb Γ eff ty) := do
+  match opStx.name with
+  | op@"Comb.parity" | op@"Comb.concat" =>
+    match opStx.args with
+    | v₁Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      match ty₁, op with
+      | .bv w, "Comb.parity" =>
+        return ⟨_, .bool,
+          (Expr.mk (op := .parity w) (ty_eq := rfl) (eff_le := by constructor)
+            (args := .cons v₁ <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bool))⟩
+      | .hList l, "Comb.concat" =>
+        return ⟨_, .bv l.sum,
+          (Expr.mk (op := .concat l) (ty_eq := rfl) (eff_le := by constructor)
+            (args := .cons v₁ <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv (l.sum)))⟩
+      | _, _ => throw <| .generic s!"type mismatch for {opStx.name}"
+    | _ => throw <| .generic s!"expected one operand found #'{opStx.args.length}' in '{repr opStx.args}'"
+  | op@"Comb.add" | op@"Comb.and" | op@"Comb.mul" | op@"Comb.or" | op@"Comb.xor" =>
+      let args ← opStx.args.mapM (MLIR.AST.TypedSSAVal.mkVal Γ)
+      if hl: args.length ≤ 0 then
+        throw <| .generic s!"empty list of arguments for '{repr opStx.args}'"
+      else
+        match args[0] with
+        | ⟨.bv w, _⟩ =>
+          if hall : args.all (·.1 = .bv w) then
+            match op with
+            | "Comb.add" =>
+                return ⟨_, .bv w,
+                  (Expr.mk (op := .add w args.length) (ty_eq := rfl) (eff_le := by constructor)
+                    (args := ofList (.bv w) _ hall) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w))⟩
+            | "Comb.and" =>
+                return ⟨_, .bv w,
+                (Expr.mk (op := .and w args.length) (ty_eq := rfl) (eff_le := by constructor)
+                  (args := ofList (.bv w) _ hall) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w))⟩
+            | "Comb.mul" =>
+                return ⟨_, .bv w,
+                (Expr.mk (op := .mul w args.length) (ty_eq := rfl) (eff_le := by constructor)
+                  (args := ofList (.bv w) _ hall) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w))⟩
+            | "Comb.or" =>
+                return ⟨_, .bv w,
+                (Expr.mk (op := .or w args.length) (ty_eq := rfl) (eff_le := by constructor)
+                  (args := ofList (.bv w) _ hall) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w))⟩
+            | "Comb.xor" =>
+                return ⟨_, .bv w,
+                (Expr.mk (op := .xor w args.length) (ty_eq := rfl) (eff_le := by constructor)
+                  (args := ofList (.bv w) _ hall) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w))⟩
+            | _ => throw <| .generic s!"Unknown operation"
+          else
+            throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+        | _ => throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+  | op@"Comb.divs" | op@"Comb.divu" | op@"Comb.mods" | op@"Comb.modu" | op@"Comb.shl" | op@"Comb.shrs" | op@"Comb.shru" | op@"Comb.sub"  =>
+    match opStx.args with
+    | v₁Stx::v₂Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      let ⟨ty₂, v₂⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₂Stx
+      match ty₁, ty₂ with
+      | .bv w₁, .bv w₂=>
+        if h : w₁ = w₂ then
+          match op with
+          | "Comb.divs" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .divs w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.divu" =>
+            return ⟨_, .bv w₁,
+                (Expr.mk (op := .divu w₁) (ty_eq := rfl) (eff_le := by constructor)
+                  (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.mods" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .mods w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.modu" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .modu w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.shl" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .shl w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.shrs" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .shrs w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.shru" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .shru w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | "Comb.sub" =>
+            return ⟨_, .bv w₁,
+              (Expr.mk (op := .sub w₁) (ty_eq := rfl) (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv w₁))⟩
+          | _ => throw <| .generic s!"Unknown operation"
+        else
+          throw <| .generic s!"bitvector sizes don't match for '{repr opStx.args}' in {opStx.name}"
+      | _, _ => throw <| .generic s!"type mismatch in {opStx.name}"
+    | _ => throw <| .generic s!"expected two operands, found #'{opStx.args.length}' in '{repr opStx.args}'"
+  | op@"Comb.mux" =>
+    match opStx.args with
+    | v₁Stx::v₂Stx::v₃Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      let ⟨ty₂, v₂⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₂Stx
+      let ⟨ty₃, v₃⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₃Stx
+      match ty₁, ty₂, ty₃, op with
+      | .bv w₁, .bv w₂, .bool, "Comb.mux" =>
+        /- mux currently only works if w₁ = w₂, since we need to fix the output type of the operation
+          it should work even if w₁ ≠ w₂ but i need to think about how to implement that in an elegant way -/
+        return ⟨_, .typeSum w₁ w₂,
+          (Expr.mk (op := .mux w₁ w₂) (ty_eq := rfl) (eff_le := by constructor)
+            (args := .cons v₁ <| .cons v₂ <| .cons v₃ <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.typeSum w₁ w₂))⟩
+      | _, _, _, _ => throw <| .generic s!"type mismatch"
+    | _ => throw <| .generic s!"expected three operands, found #'{opStx.args.length}' in '{repr opStx.args}'"
+  |  _ =>
+    match (opStx.name).splitOn "_" with
+    | ["Comb.replicate", n]=>
+      match opStx.args with
+      | v₁Stx::[] =>
+        let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+        match ty₁, n.toNat? with
+        | .bv w, some n' =>
+          return ⟨_, .bv (w * n'),
+            (Expr.mk (op := .replicate w n') (ty_eq := rfl) (eff_le := by constructor)
+              (args := .cons v₁ <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv (w * n')))⟩
+        | _, none => throw <| .generic s!"invalid parameter in {repr opStx}"
+        | _, _ => throw <| .generic s!"type mismatch in {repr opStx}"
+      | _ => throw <| .generic s!"type mismatch in {repr opStx}"
+    | ["Comb.extract", n] =>
+      match opStx.args with
+      | v₁Stx::[] =>
+        let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+        match ty₁, n.toNat? with
+        | .bv w, some n' =>
+          return ⟨_, .bv (w - n'),
+            (Expr.mk (op := .extract w n') (ty_eq := rfl) (eff_le := by constructor)
+              (args := .cons v₁ <| .nil) (regArgs := .nil) : Expr (Comb) Γ .pure (.bv (w - n')))⟩
+        | _, none => throw <| .generic s!"invalid parameter in {repr opStx}"
+        | _, _ => throw <| .generic s!"type mismatch in {repr opStx}"
+      | _ => throw <| .generic s!"type mismatch in {repr opStx}"
+    | ["Comb.icmp", p] =>
+      match opStx.args with
+      | v₁Stx::v₂Stx::[] =>
+        let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+        let ⟨ty₂, v₂⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₂Stx
+        match ty₁, ty₂, (ofString? p) with
+        | .bv w₁, .bv w₂, some p' =>
+          if h : w₁ = w₂ then
+            return ⟨_, .bool,
+              (Expr.mk (op := .icmp p w₁)  (ty_eq := rfl)  (eff_le := by constructor)
+                (args := .cons v₁ <| .cons (h ▸ v₂) <| .nil) (regArgs := .nil): Expr (Comb) Γ .pure (.bool))⟩
+          else throw <| .generic s!"bitvector sizes don't match for '{repr opStx.args}' in {opStx.name}"
+        | _, _, none => throw <| .generic s!"unknown predicate in {repr opStx}"
+        | _, _, _ => throw <| .generic s!"type mismatch in {repr opStx}"
+      | _ => throw <| .generic s!"expected two operands, found #'{opStx.args.length}' in '{repr opStx.args}'"
+    | _ => throw <| .unsupportedOp s!"unsupported operation {repr opStx}"
+
+
+instance : MLIR.AST.TransformExpr (Comb) 0 where
+  mkExpr := mkExpr
+
+def mkReturn (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) : MLIR.AST.ReaderM (Comb)
+    (Σ eff ty, Com Comb Γ eff ty) :=
+  if opStx.name == "return"
+  then match opStx.args with
+  | vStx::[] => do
+    let ⟨ty, v⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ vStx
+    return ⟨.pure, ty, Com.ret v⟩
+  | _ => throw <| .generic s!"Ill-formed return statement (wrong arity, expected 1, got {opStx.args.length})"
+  else throw <| .generic s!"Tried to build return out of non-return statement {opStx.name}"
+
+instance : MLIR.AST.TransformReturn (Comb) 0 where
+  mkReturn := mkReturn
+
+instance : DialectToExpr Comb where
+  toExprM := .const ``Id [0]
+  toExprDialect := .const ``Comb []
+
+open Qq MLIR AST Lean Elab Term Meta in
+elab "[Comb_com| " reg:mlir_region "]" : term => do SSA.elabIntoCom' reg Comb
+
+end MLIR2Comb
diff --git a/SSA/Projects/CIRCT/Comb/CombExample.lean b/SSA/Projects/CIRCT/Comb/CombExample.lean
new file mode 100644
index 0000000000..d0ca143cc2
--- /dev/null
+++ b/SSA/Projects/CIRCT/Comb/CombExample.lean
@@ -0,0 +1,120 @@
+import SSA.Projects.CIRCT.Comb.Comb
+import SSA.Projects.CIRCT.Stream.Stream
+import SSA.Projects.CIRCT.Stream.WeakBisim
+import SSA.Core.Tactic
+import SSA.Core.ErasedContext
+import SSA.Core.HVector
+import SSA.Core.EffectKind
+import SSA.Core.Util
+
+open MLIR AST in
+
+unseal String.splitOnAux in
+def CombEg1 := [Comb_com| {
+  ^entry(%0: !Bool):
+    "return" (%0) : (!Bool) -> ()
+  }]
+
+#check CombEg1
+#eval CombEg1
+#reduce CombEg1
+#check CombEg1.denote
+#print axioms CombEg1
+
+def CombEg2 := [Comb_com| {
+    ^entry(%0: i4, %1 : i4):
+      %2 = "Comb.add" (%0, %1) : (i4, i4) -> i4
+      "return" (%2) : (i4) -> ()
+    }]
+
+#print CombEg2
+#eval CombEg2
+#reduce CombEg2
+#check CombEg2
+#print axioms CombEg2
+
+def bv1 : BitVec 4 := BitVec.ofNat 4 5 -- 0010
+def bv2 : BitVec 4 := BitVec.ofNat 4 1 -- 0011
+
+def test2 : BitVec 4 :=
+  CombEg2.denote (Ctxt.Valuation.ofPair bv1 bv2)
+
+#eval test2
+
+def CombEg3 := [Comb_com| {
+  ^entry(%0: i4, %1 : i4):
+    %2 = "Comb.icmp_slt" (%0, %1) : (i4, i4) -> !Bool
+    "return" (%2) : (!Bool) -> ()
+  }]
+
+#check CombEg3
+#eval CombEg3
+#reduce CombEg3
+#check CombEg3.denote
+#print axioms CombEg3
+
+def bv1' : BitVec 4 := BitVec.ofNat 4 1
+def bv2' : BitVec 4 := BitVec.ofNat 4 6
+
+def test3 : Bool :=
+  CombEg3.denote (Ctxt.Valuation.ofPair bv2' bv1')
+
+#eval test3
+
+def CombEg4 := [Comb_com| {
+  ^entry(%0: i4, %1 : i4):
+    %2 = "Comb.icmp_eq" (%0, %1) : (i4, i4) -> !Bool
+    "return" (%2) : (!Bool) -> ()
+  }]
+
+#check CombEg4
+#eval CombEg4
+#reduce CombEg4
+#check CombEg4.denote
+#print axioms CombEg4
+
+def bv1'' : BitVec 4 := BitVec.ofNat 4 3
+def bv2'' : BitVec 4 := BitVec.ofNat 4 3
+
+def test4 : Bool :=
+  CombEg4.denote (Ctxt.Valuation.ofPair bv2'' bv1'')
+
+#eval test4
+
+def CombEg5 := [Comb_com| {
+  ^entry(%0: i1, %1: i1):
+    %2 = "Comb.replicate_3" (%0) : (i1) -> (i3)
+    "return" (%2) : (i3) -> ()
+}]
+
+#check CombEg5
+#eval CombEg5
+#reduce CombEg5
+#check CombEg5.denote
+#print axioms CombEg5
+
+def bv0 : BitVec 1 := BitVec.ofNat 1 1
+
+def test5 : BitVec 3 :=
+  CombEg5.denote (Ctxt.Valuation.ofPair bv0 bv0)
+
+#eval test5
+
+def CombEg6 := [Comb_com| {
+    ^entry (%0 : i2, %1 : i4, %2 : !Bool):
+      %3 = "Comb.mux" (%0, %1, %2) : (i2, i4, !Bool) -> !TypeSum_2_4
+      "return" (%3) : (!TypeSum_2_4) -> ()
+}]
+
+#check CombEg6
+#eval CombEg6
+#reduce CombEg6
+#check CombEg6.denote
+#print axioms CombEg6
+
+def bv6₁ : BitVec 2 := BitVec.ofNat 2 1
+def bv6₂ : BitVec 4 := BitVec.ofNat 4 3
+def bv6c : Bool := true
+
+def test6 : BitVec 2 ⊕ BitVec 4 :=
+  CombEg6.denote (Ctxt.Valuation.ofHVector (.cons bv6c <| .cons bv6₂ <| .cons bv6₁ <| .nil))
diff --git a/SSA/Projects/CIRCT/Comb/CombSemantics.lean b/SSA/Projects/CIRCT/Comb/CombSemantics.lean
new file mode 100644
index 0000000000..69d45380b9
--- /dev/null
+++ b/SSA/Projects/CIRCT/Comb/CombSemantics.lean
@@ -0,0 +1,101 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any types α, β -/
+def mux (x : BitVec w₁) (y : BitVec w₂) (cond : Bool) : BitVec w₁ ⊕ BitVec w₂ :=
+  if cond then .inl x else .inr y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
diff --git a/SSA/Projects/InstCombine/scripts/cfg.py b/SSA/Projects/InstCombine/scripts/cfg.py
index 5384b395d0..12fccceef5 100644
--- a/SSA/Projects/InstCombine/scripts/cfg.py
+++ b/SSA/Projects/InstCombine/scripts/cfg.py
@@ -118,4 +118,4 @@ class Msg(Enum):
     E_PTRARG = 9
     
     def is_error(self):
-        return self.value > 2
+        return self.value > 2
\ No newline at end of file
diff --git a/SSA/Projects/InstCombine/scripts/proof-gen.py b/SSA/Projects/InstCombine/scripts/proof-gen.py
index c0ee12787e..dd8b9c6578 100644
--- a/SSA/Projects/InstCombine/scripts/proof-gen.py
+++ b/SSA/Projects/InstCombine/scripts/proof-gen.py
@@ -124,4 +124,4 @@ def main():
 
 
 if __name__ == "__main__":
-    main()
+    main()
\ No newline at end of file
diff --git a/SSA/Projects/InstCombine/scripts/read-logs.py b/SSA/Projects/InstCombine/scripts/read-logs.py
index 1492dcff14..2a65ffec60 100644
--- a/SSA/Projects/InstCombine/scripts/read-logs.py
+++ b/SSA/Projects/InstCombine/scripts/read-logs.py
@@ -75,4 +75,4 @@ def main():
 
 
 if __name__ == "__main__":
-    main()
+    main()
\ No newline at end of file
diff --git a/SSA/Projects/InstCombine/scripts/run.sh b/SSA/Projects/InstCombine/scripts/run.sh
index a2f2e6534d..fbca5eee5c 100644
--- a/SSA/Projects/InstCombine/scripts/run.sh
+++ b/SSA/Projects/InstCombine/scripts/run.sh
@@ -4,4 +4,4 @@ python SSA/Projects/InstCombine/scripts/test-gen.py
 
 python SSA/Projects/InstCombine/scripts/proof-gen.py
 
-python SSA/Projects/InstCombine/scripts/read-logs.py
+python SSA/Projects/InstCombine/scripts/read-logs.py
\ No newline at end of file
diff --git a/SSA/Projects/InstCombine/scripts/test-gen.py b/SSA/Projects/InstCombine/scripts/test-gen.py
index 9c4bfc23ed..d6e56868a0 100644
--- a/SSA/Projects/InstCombine/scripts/test-gen.py
+++ b/SSA/Projects/InstCombine/scripts/test-gen.py
@@ -239,4 +239,4 @@ def process_file(file):
 if __name__ == "__main__":
     remove()
     with Pool(300) as p:
-        p.map(process_file, os.listdir(directory))
+        p.map(process_file, os.listdir(directory))
\ No newline at end of file


Reviews:
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T08:34:56Z
user: login: alexkeizer
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-17T15:32:26Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:27:39Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:28:41Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:42:36Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:46:37Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:47:34Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:48:52Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:49:52Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:51:12Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:52:30Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T20:52:57Z
user: login: ymherklotz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-17T22:33:31Z
user: login: ymherklotz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-17T22:35:33Z
user: login: alexkeizer
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T13:34:54Z
user: login: alexkeizer
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T13:51:51Z
user: login: alexkeizer
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-18T13:57:01Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T15:23:22Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T15:25:28Z

Review comments:
diff_hunk: @@ -239,4 +239,4 @@ def process_file(file):
 if __name__ == "__main__":
     remove()
     with Pool(300) as p:
-        p.map(process_file, os.listdir(directory))
+        p.map(process_file, os.listdir(directory))
path: SSA/Projects/InstCombine/scripts/test-gen.py
user: login: luisacicolini
body: ```suggestion
        p.map(process_file, os.listdir(directory))
```
created_at: 2025-04-17T08:34:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -118,4 +118,4 @@ class Msg(Enum):
     E_PTRARG = 9
     
     def is_error(self):
-        return self.value > 2
+        return self.value > 2
path: SSA/Projects/InstCombine/scripts/cfg.py
user: login: alexkeizer
body: Seemingly unrelated whitespace change. You've got a few more of these in other files also
created_at: 2025-04-17T14:51:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Do we need all of these to be separate definitions? I believe you only use them in `def_denote`, right?
created_at: 2025-04-17T14:55:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: ```suggestion
  | .mods _ => BitVec.mods
  | .modu _ => BitVec.modu
```
Could we not just write it like so? Removing the need for all those `CompOp` definitions that just wrap a BitVec operation.

Also, the naming of your argument is a bit misleading. `xs` suggest a list or vector, but I *think* it's just a `(xs : BitVec w)`, right? Then you apply `CombOp.mods xs` implying that `mods` is somehow operating on a list of values, but what's really happening (IIUC) is that you're partially applying the first argument of a binary BitVec def, returning a `BitVec _ -> BitVec _` function, and `def_denote` is happy with that. I'd suggest either going all in on point-free, and just writing `BitVec.mods` (or `CombOp.mods` if you don't take the suggestion) *or* fully explicate all arguments, as in `fun x y => BitVec.mods x y`.

The same applies to all other non-variadic operations.
created_at: 2025-04-17T15:01:05Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: For the variadic operations, I'd suggest writing a `fold` combinator, that combines `HVector.replicateToList` with `List.foldr`, so that we can then write the variadic operations as:
```
| .add _ _ => CombOp.fold (· + ·) 0#_
| .mul _ _ => CombOp.fold (· * ·) 1#_
```
created_at: 2025-04-17T15:05:38Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: You might want to match on `MLIRType.int` instead, and map that to your `.bv` type (have a look at LLVM, I believe that's what we do there as well).

That way you can use the builtin `i64` type in your programs (which I believe CIRCT uses for comb, right?), and also you won't have to use `String.splitOn` here anymore, you can just directly match on the strings for the other cases.
created_at: 2025-04-17T15:08:13Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Here again you've got a huge number of boilerplate definitions. Do we actually need these? I know we have similar constructors in other dialects where we didn't bother writing a parser, but for Comb you did write a parser, so there should be no need for these defs.

Of course, I see you've used them in the definition of said parser, but you should be able to write that much more concisely.
created_at: 2025-04-17T15:10:07Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: This should likely go to the HVector file. Also, do we need both? They seem very similar.
If we do need both, we should have some docstring that points out the difference.
created_at: 2025-04-17T15:29:13Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
+
+def mkExpr (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) :
+    MLIR.AST.ReaderM Comb (Σ eff ty, Expr Comb Γ eff ty) := do
+  match opStx.name with
+  | op@"Comb.parity" | op@"Comb.concat" =>
+    match opStx.args with
+    | v₁Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      match ty₁, op with
+      | .bv w, "Comb.parity" => return ⟨_, .bool, parity v₁⟩
+      | .hList l, "Comb.concat" => return ⟨_, .bv l.sum, concat v₁⟩
+      | _, _ => throw <| .generic s!"type mismatch"
+    | _ => throw <| .generic s!"expected one operand for `monomial`, found #'{opStx.args.length}' in '{repr opStx.args}'"
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Your error mentions `monomial`!
created_at: 2025-04-17T15:30:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
+
+def mkExpr (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) :
+    MLIR.AST.ReaderM Comb (Σ eff ty, Expr Comb Γ eff ty) := do
+  match opStx.name with
+  | op@"Comb.parity" | op@"Comb.concat" =>
+    match opStx.args with
+    | v₁Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      match ty₁, op with
+      | .bv w, "Comb.parity" => return ⟨_, .bool, parity v₁⟩
+      | .hList l, "Comb.concat" => return ⟨_, .bv l.sum, concat v₁⟩
+      | _, _ => throw <| .generic s!"type mismatch"
+    | _ => throw <| .generic s!"expected one operand for `monomial`, found #'{opStx.args.length}' in '{repr opStx.args}'"
+  | op@"Comb.add" | op@"Comb.and" | op@"Comb.mul" | op@"Comb.or" | op@"Comb.xor" =>
+      let args ← opStx.args.mapM (MLIR.AST.TypedSSAVal.mkVal Γ)
+      if hl: args.length ≤ 0 then
+        throw <| .generic s!"empty list of arguments for '{repr opStx.args}'"
+      else
+        have hl' : (0 : Nat) < args.length := by
+          simp [Nat.gt_of_not_le (n := args.length) (m := 0) hl]
+        match args[0], op with
+        | ⟨.bv w, _⟩, "Comb.add" =>
+          if hall : args.all (·.1 = .bv w) then
+            let argsᵥ := ofList (.bv w) _ hall
+            have heq : args.length - 1 + 1 = args.length := by omega
+            return ⟨_, .bv w, add args.length (heq ▸ argsᵥ)⟩
+          else
+            throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+        | ⟨.bv w, _⟩, "Comb.and" =>
+            if hall : args.all (·.1 = .bv w) then
+              let argsᵥ := ofList (.bv w) _ hall
+              have heq : args.length - 1 + 1 = args.length := by omega
+              return ⟨_, .bv w, and args.length (heq ▸ argsᵥ)⟩
+            else
+              throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+        | ⟨.bv w, _⟩, "Comb.mul" =>
+            if hall : args.all (·.1 = .bv w) then
+              let argsᵥ := ofList (.bv w) _ hall
+              have heq : args.length - 1 + 1 = args.length := by omega
+              return ⟨_, .bv w, mul args.length (heq ▸ argsᵥ)⟩
+            else
+              throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: This code is highly repetitive and doing more-or-less the same thing in each branch, modulo the specific opcode emitted, there should be some function we can factor out of this to reduce the duplication.
created_at: 2025-04-17T15:31:43Z
author_association: COLLABORATOR
diff_hunk: @@ -118,4 +118,4 @@ class Msg(Enum):
     E_PTRARG = 9
     
     def is_error(self):
-        return self.value > 2
+        return self.value > 2
path: SSA/Projects/InstCombine/scripts/cfg.py
user: login: luisacicolini
body: ```suggestion
        return self.value > 2
```
created_at: 2025-04-17T20:27:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: that is correct - I maintained the definitions separate to mirror exactly the operators of `Comb`.
created_at: 2025-04-17T20:28:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: ah yes I had not thought of that! Indeed those operations are not variadic. I've updated that for the cases where bitvec operations exist and left the remaining ones unchanged (modulo the naming suggestion which I've applied). In some cases the corresponding bitvec operation does not exist, e.g., `BitVec.shiftLeft` takes a bitvec and a nat, while `comb.shl` takes two bitvecs, so I could not use the `BitVec` API. (The same happened for the other ops that have not been updated.)
created_at: 2025-04-17T20:42:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: [`comb`](https://circt.llvm.org/docs/Dialects/Comb/#combshl-circtcombshlop) actually uses bitvecs for almost everything afaict, so it would be nice to maintain that I guess?
created_at: 2025-04-17T20:46:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: ah no I forgot to delete one - I just wanted to keep both the implementations you and Leo proposed! will delete one.
created_at: 2025-04-17T20:47:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
+
+def mkExpr (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) :
+    MLIR.AST.ReaderM Comb (Σ eff ty, Expr Comb Γ eff ty) := do
+  match opStx.name with
+  | op@"Comb.parity" | op@"Comb.concat" =>
+    match opStx.args with
+    | v₁Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      match ty₁, op with
+      | .bv w, "Comb.parity" => return ⟨_, .bool, parity v₁⟩
+      | .hList l, "Comb.concat" => return ⟨_, .bv l.sum, concat v₁⟩
+      | _, _ => throw <| .generic s!"type mismatch"
+    | _ => throw <| .generic s!"expected one operand for `monomial`, found #'{opStx.args.length}' in '{repr opStx.args}'"
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-17T20:48:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: done
created_at: 2025-04-17T20:49:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: Do you think this would be better than having the `fold` in the definition of each variadic op? I thought it would be better to have each op in the denotation referring to its `CombOp` semantics
created_at: 2025-04-17T20:51:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: could you please make an example? I don't understand how these can be avoided 
created_at: 2025-04-17T20:52:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
+
+def divs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def divu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .divu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def extract {Γ : Ctxt _} (a : Γ.Var (.bv w)) (n : Nat) : Expr (Comb) Γ .pure (.bv (w - n)) :=
+  Expr.mk
+    (op := .extract w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def icmp {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (p : String): Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .icmp p w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mods {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mods w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def modu {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .modu w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def mul {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mul w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def mux {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) (cond : Γ.Var (.bool)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .mux w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .cons cond <| .nil)
+    (regArgs := .nil)
+
+def or {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .or w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def parity {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bool) :=
+  Expr.mk
+    (op := .parity w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def replicate {Γ : Ctxt _} (a : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv (w * n)) :=
+  Expr.mk
+    (op := .replicate w n)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .nil)
+    (regArgs := .nil)
+
+def shl {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shl w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shrs {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shrs w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def shru {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .shru w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def sub {Γ : Ctxt _} (a : Γ.Var (.bv w)) (b : Γ.Var (.bv w)) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .sub w)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons a <| .cons b <| .nil)
+    (regArgs := .nil)
+
+def xor {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .xor w arity)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+
+/-- Convert a list of dependent pairs into an HVector -/
+def ofList {Γ : Ctxt _} ty : (l : List ((ty : Comb.Ty) × Γ.Var ty)) → (h : l.all (·.1 = ty)) → HVector (Γ.Var) (List.replicate l.length ty)
+| [], h => .nil
+| ⟨ty', var⟩::rest, h =>
+  have hty : ty' = ty := by simp_all
+  have hrest : rest.all (·.1 = ty) := by simp_all
+  .cons (hty ▸ var) (ofList _ rest hrest)
+
+def ofList' {α : Type u} {f : α → Type v} :
+    (xs : List (Σ a, f a)) → HVector f (xs.map Sigma.fst)
+  | ⟨_, x⟩ :: xs => .cons x (ofList' xs)
+  | [] => .nil
+
+def mkExpr (Γ : Ctxt _) (opStx : MLIR.AST.Op 0) :
+    MLIR.AST.ReaderM Comb (Σ eff ty, Expr Comb Γ eff ty) := do
+  match opStx.name with
+  | op@"Comb.parity" | op@"Comb.concat" =>
+    match opStx.args with
+    | v₁Stx::[] =>
+      let ⟨ty₁, v₁⟩ ← MLIR.AST.TypedSSAVal.mkVal Γ v₁Stx
+      match ty₁, op with
+      | .bv w, "Comb.parity" => return ⟨_, .bool, parity v₁⟩
+      | .hList l, "Comb.concat" => return ⟨_, .bv l.sum, concat v₁⟩
+      | _, _ => throw <| .generic s!"type mismatch"
+    | _ => throw <| .generic s!"expected one operand for `monomial`, found #'{opStx.args.length}' in '{repr opStx.args}'"
+  | op@"Comb.add" | op@"Comb.and" | op@"Comb.mul" | op@"Comb.or" | op@"Comb.xor" =>
+      let args ← opStx.args.mapM (MLIR.AST.TypedSSAVal.mkVal Γ)
+      if hl: args.length ≤ 0 then
+        throw <| .generic s!"empty list of arguments for '{repr opStx.args}'"
+      else
+        have hl' : (0 : Nat) < args.length := by
+          simp [Nat.gt_of_not_le (n := args.length) (m := 0) hl]
+        match args[0], op with
+        | ⟨.bv w, _⟩, "Comb.add" =>
+          if hall : args.all (·.1 = .bv w) then
+            let argsᵥ := ofList (.bv w) _ hall
+            have heq : args.length - 1 + 1 = args.length := by omega
+            return ⟨_, .bv w, add args.length (heq ▸ argsᵥ)⟩
+          else
+            throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+        | ⟨.bv w, _⟩, "Comb.and" =>
+            if hall : args.all (·.1 = .bv w) then
+              let argsᵥ := ofList (.bv w) _ hall
+              have heq : args.length - 1 + 1 = args.length := by omega
+              return ⟨_, .bv w, and args.length (heq ▸ argsᵥ)⟩
+            else
+              throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
+        | ⟨.bv w, _⟩, "Comb.mul" =>
+            if hall : args.all (·.1 = .bv w) then
+              let argsᵥ := ofList (.bv w) _ hall
+              have heq : args.length - 1 + 1 = args.length := by omega
+              return ⟨_, .bv w, mul args.length (heq ▸ argsᵥ)⟩
+            else
+              throw <| .generic s!"Unexpected argument types for '{repr opStx.args}'"
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: of course, I will extract some functions depending on the number of operands I guess
created_at: 2025-04-17T20:52:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: ymherklotz
body: What does this mean for the denotation of concrete programs? With the unfolded version does it mean we get unfolded definitions in the final denotation, i.e will the fold also completely disappear?

If not, I think I agree with Luisa that wrapping them into CombOp definitions might be nice to then use further rewrites to unfold them, but I'm guessing that the current denotation should already unfold everything correctly, in which case the intermediate definition is maybe unnecessary.
created_at: 2025-04-17T22:33:31Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: ymherklotz
body: Im guessing that the definitions can just be completely inlined, because they are only used in the parser and not needed again. And in addition to that the main thing that changes in each definition is the constructor and number of arguments, so it might be possible to make this much more concise using some helper functions.
created_at: 2025-04-17T22:35:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Yes, "signless integer bitvector" in the documentation means `i$x`, for some `$x`. See, e.g., the [canonicalization](https://github.com/llvm/circt/blob/main/test/Dialect/Comb/canonicalization.mlir) test file which has the following example program:
```
hw.module @idempotentDeduped1(in %arg0 : i7, in %arg1 : i7, out resAnd: i7, out resOr: i7) {
  %0 = comb.and %arg0    : i7
  %1 = comb.and %0, %arg1 : i7
  %2 = comb.or %arg0    : i7
  %3 = comb.or %0, %arg1 : i7
  hw.output %1, %3 : i7, i7
}
```

LeanMLIR's generic MLIR AST parser special-cases the `i...` types, since they're builtin, and parses them into the `MLIRType.int` constructor (which has extra parameters for the signed-ness and width). I guess we ought to improve the documentation of that type to emphasize it means "int" in the fixed-width `i$x` sense rather than true integers.
created_at: 2025-04-18T13:34:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Hmm, that's a good point. What do you mean by "final denotation" exactly?

If you mean "the result of simplifying with `simp_peephole`": by default it should unfold to exactly the rhs of `def_denote` applied to a concrete HVector of arguments. The intention being that dialect implementors then add further, dialect-specific rewrites as needed. For example, we could add a rewrite like
```
CombOp.fold (· + ·) 0#_ (x ::h xs) = x + CombOp.fold  (· + ·) 0#_ xs
```
plus the analogue for an empty vector, and it should then unfold the variadic operations as desired.

Speaking off, I've been slightly tweaking how that tactic works in #1127, so that adding dialect-specific rewrites becomes much easier. Currently, you'd have to wrap `simp_peephole` with a dialect-specific `simp_comb_peephole` that passes in the extra rewrites; after #1127 gets merged you'd only have to tag your dialect-specific rewrite with `@[simp_denote]` and it gets picked up by plain `simp_peephole` automatically.
created_at: 2025-04-18T13:51:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: alexkeizer
body: Fair point. I personally dislike having huge files with a lot of boilerplate, hence my suggestion to eliminate them. Still, I'll concede that having a clear API boundary has benefits as well.

In that case, I'd suggest putting these wrappers in a separate file (akin to how we have LLVM/Semantics.lean), as I feel that's a bit more maintainable. In a similar vein, I'd have personally put the parsing code in a separate file, to keep a cleaner organization. This is partly based on personal opinion, though, so as always feel free to ignore if you disagree.


created_at: 2025-04-18T13:57:01Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: happy to split it into different files, sounds very reasonable.
created_at: 2025-04-18T15:23:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,617 @@
+import SSA.Core.Framework
+import SSA.Core.Framework.Macro
+import SSA.Core.MLIRSyntax.GenericParser
+import SSA.Core.MLIRSyntax.EDSL2
+
+namespace CombOp
+
+inductive IcmpPredicate where
+  | eq
+  | ne
+  | slt
+  | sle
+  | sgt
+  | sge
+  | ult
+  | ule
+  | ugt
+  | uge
+deriving Inhabited, DecidableEq, Repr
+
+instance : ToString IcmpPredicate where
+  toString
+  | .eq  => "eq"
+  | .ne  => "ne"
+  | .slt => "slt"
+  | .sle => "sle"
+  | .sgt => "sgt"
+  | .sge => "sge"
+  | .ult => "ult"
+  | .ule => "ule"
+  | .ugt => "ugt"
+  | .uge => "uge"
+
+/-- Variadic `add` operation with a list of bitvectors with width `w` as input -/
+def add {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.add (0#w) l
+
+/-- Variadic `and` operation with a list of bitvectors with width `w` as input -/
+def and {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.and (0#w) l
+
+/-- Concatenate a list of bitvecs `xs`, where the length of bitvec `xs[i]` is given by
+  element `ls[i]` in a list of nat `ls` -/
+def concat {ls : List Nat} (xs : HVector BitVec ls) : BitVec (List.sum ls) :=
+  match (xs) with
+  | (.nil) => 0#0
+  | (.cons x xs) =>
+     let xsSum := concat xs
+     x ++ xsSum
+
+/-- Signed division -/
+def divs (x y : BitVec w) : BitVec w :=
+  BitVec.sdiv x y
+
+/-- Unsigned division -/
+def divu (x y : BitVec w) : BitVec w :=
+  BitVec.udiv x y
+
+/-- Extract the `lb` lower bits from BitVec `x` -/
+def extract (x : BitVec w) (lb : Nat) : BitVec (w - lb) :=
+  BitVec.truncate (w - lb) (BitVec.ushiftRight x lb)
+
+/-- Boolean comparison between two input BitVecs -/
+def icmp {w : Nat} (p : IcmpPredicate) (x y : BitVec w) : Bool :=
+  match p with
+  | .eq  => (x == y)
+  | .ne => (x != y)
+  | .sgt => (y.slt x)
+  | .sge => (y.sle x)
+  | .slt => (x.slt y)
+  | .sle => (x.sle y)
+  | .ugt => (x > y)
+  | .uge => (x ≥ y)
+  | .ult => (x < y)
+  | .ule => (x ≤ y)
+
+
+/-- Signed modulo -/
+def mods (x y : BitVec w) : BitVec w :=
+  BitVec.smod x y
+
+/-- Unsigned modulo -/
+def modu (x y : BitVec w) : BitVec w :=
+  BitVec.umod x y
+
+/-- Variadic `mul` operation with a list of bitvectors with width `w` as input -/
+def mul {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.mul (1#w) l
+
+/- Generic `mux` operation for any type α -/
+def mux (x y : α) (cond : Bool) : α :=
+  bif cond then x else y
+
+/-- Variadic `or` operation with a list of bitvectors with width `w` as input -/
+def or {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.or (BitVec.zero w) l
+
+/-- Returns boolean parity value of BitVec `x` -/
+def parity (x : BitVec w) : Bool :=
+  (BitVec.umod x 2#w) == 1
+
+/-- Replicate input BitVec `x` `n` times -/
+def replicate (x : BitVec w) (n : Nat) : BitVec (w * n) :=
+  BitVec.replicate n x
+
+/-- Shift left -/
+def shl (x y : BitVec w) : BitVec w :=
+  x <<< y
+
+/-- Signed shift right -/
+def shrs (x y : BitVec w) : BitVec w :=
+  BitVec.sshiftRight' x y
+
+/-- Unsigned shift right -/
+def shru (x y : BitVec w) : BitVec w :=
+  BitVec.ushiftRight x y.toNat
+
+/-- Subtraction -/
+def sub (x y : BitVec w) : BitVec w :=
+  x - y
+
+/-- Variadic `xor` operation with a list of bitvectors with width `w` as input -/
+def xor {w : Nat} (l : List (BitVec w)) : BitVec w :=
+  List.foldr BitVec.xor (BitVec.zero w) l
+
+end CombOp
+
+namespace MLIR2Comb
+
+section Dialect
+
+inductive Ty
+| bv (w : Nat) : Ty -- A bitvector of width `w`.
+| bool : Ty
+| nat : Ty
+| hList (l : List Nat) : Ty -- List of bitvecs whose length are defined in l
+| icmpPred : Ty
+deriving DecidableEq, Repr, Lean.ToExpr
+
+inductive Op
+| add (w : Nat) (arity : Nat)
+| and (w : Nat) (arity : Nat)
+| concat (w : List Nat) -- len(w) = #args, wi is the width of the i-th arg
+| divs (w : Nat)
+| divu (w : Nat)
+| extract (w : Nat) (n : Nat)
+| icmp (p : String) (w : Nat)
+| mods (w : Nat)
+| modu (w : Nat)
+| mul (w : Nat) (arity : Nat)
+| mux (w : Nat)
+| or (w : Nat) (arity : Nat)
+| parity (w : Nat)
+| replicate (w : Nat) (n : Nat)
+| shl (w : Nat)
+| shrs (w : Nat)
+| shru (w : Nat)
+| sub (w : Nat)
+| xor (w : Nat) (arity : Nat)
+deriving DecidableEq, Repr, Lean.ToExpr
+
+abbrev Comb : Dialect where
+  Op := Op
+  Ty := Ty
+
+def_signature for Comb where
+  | .add w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .and w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .concat l => (Ty.hList l) → (Ty.bv l.sum)
+  | .divs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .divu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .extract w n => (Ty.bv w) → (Ty.bv (w - n))
+  | .icmp _ w => (Ty.bv w, Ty.bv w) → (Ty.bool)
+  | .mods w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .modu w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .mul w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .mux w => (Ty.bv w, Ty.bv w, Ty.bool) → (Ty.bv w)
+  | .or w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+  | .parity w => (Ty.bv w) → (Ty.bool)
+  | .replicate w n => (Ty.bv w) → (Ty.bv (w * n))
+  | .shl w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shrs w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .shru w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .sub w => (Ty.bv w, Ty.bv w) → (Ty.bv w)
+  | .xor w n => ${List.replicate n (Ty.bv w)} → (Ty.bv w)
+
+instance : TyDenote (Dialect.Ty Comb) where
+  toType := fun
+  | .bv w => BitVec w
+  | .nat  => Nat
+  | .bool => Bool
+  | .hList l => HVector BitVec l -- het list of bitvec whose lengths are contained in l
+  | .icmpPred => CombOp.IcmpPredicate
+
+def HVector.replicateToList {α : Type} {f : α → Type} {a : α} :
+    {n : Nat} → HVector f (List.replicate n a) → List (f a)
+  | 0, _ => []
+  | n+1, HVector.cons x xs => x :: replicateToList xs
+
+def ofString? (s : String) : Option CombOp.IcmpPredicate :=
+  match s with
+  | "eq" => some .eq
+  | "ne" => some .ne
+  | "slt" => some .slt
+  | "sle" => some .sle
+  | "sgt" => some .sgt
+  | "sge" => some .sge
+  | "ult" => some .ult
+  | "ule" => some .ule
+  | "ugt" => some .ugt
+  | "uge" => some .uge
+  | _     => none
+
+def_denote for Comb where
+  | .add _ _ => fun xs => CombOp.add (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .and _ _ => fun xs => CombOp.and (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .concat _ => fun xs => CombOp.concat xs
+  | .divs _ => fun xs => CombOp.divs xs
+  | .divu _ => fun xs => CombOp.divu xs
+  | .extract _ n => fun xs => CombOp.extract xs n
+  | .icmp p _ => fun xs =>
+      let p' := Option.get! (ofString? p)
+      CombOp.icmp p' xs
+  | .mods _ => fun xs => CombOp.mods xs
+  | .modu _ => fun xs => CombOp.modu xs
+  | .mul _ _ => fun xs => CombOp.mul (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .mux _ => fun xs => CombOp.mux xs
+  | .or _ _ => fun xs => CombOp.or (HVector.replicateToList (f := TyDenote.toType) xs)
+  | .parity _ => fun xs => CombOp.parity xs
+  | .replicate _ n => fun xs => CombOp.replicate xs n
+  | .shl _ => fun xs => CombOp.shl xs
+  | .shrs _ => fun xs => CombOp.shrs xs
+  | .shru _ => fun xs => CombOp.shru xs
+  | .sub _ => fun xs => CombOp.sub xs
+  | .xor _ _ => fun xs => CombOp.xor (HVector.replicateToList (f := TyDenote.toType) xs)
+
+end Dialect
+
+/-- we currently do not support the parsing of heterogeneous vectors -/
+def mkTy : MLIR.AST.MLIRType φ → MLIR.AST.ExceptM Comb Ty
+  | MLIR.AST.MLIRType.undefined s => do
+    match s.splitOn "_" with
+    | ["Bool"] =>
+      return .bool
+    | ["Nat"] =>
+      return .nat
+    | ["BitVec", r] =>
+      return .bv (r.toNat!)
+    | ["IcmpPred"] =>
+      -- match icmp
+      return .icmpPred
+    | _ => throw .unsupportedType
+  | _ => throw .unsupportedType
+
+instance instTransformTy : MLIR.AST.TransformTy Comb 0 where
+  mkTy := mkTy
+
+
+def add {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .add w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a) -- cast a to the right type
+    (regArgs := .nil)
+
+def and {Γ : Ctxt _} (arity: Nat) (a : HVector Γ.Var (List.replicate arity (.bv w))) : Expr (Comb) Γ .pure (.bv w) :=
+  Expr.mk
+    (op := .and w arity)
+    (ty_eq := by rfl)
+    (eff_le := by constructor)
+    (args := a)
+    (regArgs := .nil)
+
+def concat {l : List Nat} {Γ : Ctxt _} (ls : Γ.Var (.hList l)): Expr (Comb) Γ .pure (.bv (l.sum)) :=
+  Expr.mk
+    (op := .concat l)
+    (ty_eq := rfl)
+    (eff_le := by constructor)
+    (args := .cons ls <| .nil)
+    (regArgs := .nil)
path: SSA/Projects/CIRCT/Comb/Comb.lean
user: login: luisacicolini
body: Okay I'll refactor the parser to extract some functions based on the number of argumens and inline this as well
created_at: 2025-04-18T15:25:28Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-14T15:34:21Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-16T16:53:40Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-16T17:29:18Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T07:12:13Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T07:12:22Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T07:19:10Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:34:38Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:35:43Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:36:50Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:36:53Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:37:36Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:44:14Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T08:46:29Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T20:49:41Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T20:50:50Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: ymherklotz
created_at: 2025-04-17T22:39:54Z
body: I just wanted to say that to me the definition looks quite good already, so I was wondering if it should already be merged before trying to make definitions more concise, as that will maybe be a bit more work, and isn't critical for the semantics?
author_association: COLLABORATOR
user: login: luisacicolini
created_at: 2025-04-18T06:33:27Z
body: @ymherklotz I agree - as we use the dialect we'll likely change a few things anyways, @alexkeizer let me know if you agree!
author_association: CONTRIBUTOR
user: login: alexkeizer
created_at: 2025-04-18T13:42:30Z
body: Yeah, that makes sense! In general, I think we settled on a policy that stuff that doesn't affect the core framework (and doesn't break CI) is fine to merge without review / explicit approval.
author_association: COLLABORATOR
user: login: luisacicolini
created_at: 2025-04-18T15:26:06Z
body: I'll split the semantics and parser into different files (eta: tomorrow morning), inline the boilerplate in the parser and then merge.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T17:15:24Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T17:27:14Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T19:17:45Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T20:33:43Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T20:51:41Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T21:06:03Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T21:15:46Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-27T21:48:48Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-28T13:04:55Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: luisacicolini
created_at: 2025-04-28T13:22:35Z
body: opened #1152 in case more refactoring is needed. will merge this to continue with the work.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-28T13:22:35Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-28T13:22:36Z
body: Alive Statistics: 90 / 93 (3 failed)
author_association: CONTRIBUTOR