Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add overflow flags to lean semantics #471

Closed
wants to merge 9 commits into from

Conversation

AtticusKuhn
Copy link
Contributor

@AtticusKuhn AtticusKuhn added the bug Something isn't working label Jul 16, 2024
@AtticusKuhn AtticusKuhn linked an issue Jul 16, 2024 that may be closed by this pull request
Copy link
Collaborator

@goens goens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it seems like going in the right direction! I'm finding the guards with a bunch of negations somewhat confusing. If you feel these are the most idiomatic way because they reflect the document's semantics, maybe you can add a comment (quoting from the language ref) to at least justify these guards?

I think for merging this we also want to be sure that they really correspond to the LLVM behavior. Maybe you can

  • add the flags to the LLVM syntax and parse these params
  • check them with the flow in test/bruteforce-correctness/llvm.py
    This would give us more confidence your(/our) interpretation of the prose matches the implementation in LLVM

SSA/Projects/InstCombine/LLVM/Semantics.lean Outdated Show resolved Hide resolved
SSA/Projects/InstCombine/LLVM/Semantics.lean Outdated Show resolved Hide resolved
SSA/Projects/InstCombine/LLVM/Semantics.lean Outdated Show resolved Hide resolved
@AtticusKuhn
Copy link
Contributor Author

Thanks for the feedback. I guess it would be better to use if_then_else rather than guard, because it leads to an easier proof-state.

@AtticusKuhn
Copy link
Contributor Author

As for adding the flag to the parser, I think this would be a difficult task.

Copy link

Alive Statistics: 59 / 93 (34 failed)

Copy link

Alive Statistics: 59 / 93 (34 failed)

Copy link

Alive Statistics: 59 / 93 (34 failed)

@AtticusKuhn
Copy link
Contributor Author

I've added the overflow flags to the parser.
It seems that the disjoint and exact flags are not even implemented by MLIR.
See
llvm/llvm-project#99353

Copy link

Alive Statistics: 59 / 93 (34 failed)

| (.opaque_ "llvm.overflow" "nsw") => pure <| Sum.inl (MOp.BinaryOp.mul true false)
| (.opaque_ "llvm.overflow" "nuw") => pure <| Sum.inl (MOp.BinaryOp.mul false true)
| (.opaque_ "llvm.overflow" s ) =>throw <| .generic s!"flag {s} not allowed"
| _ => throw <| .generic s!"flag not allowed"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to include the flag that was present in the error. Something like unexpected attribute $att``

Comment on lines 120 to 123
let att := opStx.attrs.getAttr "overflowFlags"
match att with
| .none => pure <| Sum.inl (MOp.BinaryOp.add false false)
| .some y => match y with
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: since we use attr as an abbreviation for attribute elsewhere, it's best to be consistent and not use att as an alternative abbreviation as well.

Single letter variables can be fine when the scope is limited like here, but it's better to use a more descriptive name. In this case, we can use ? as a suffix to explicate which variable is the option, and which is the actual attribute

Suggested change
let att := opStx.attrs.getAttr "overflowFlags"
match att with
| .none => pure <| Sum.inl (MOp.BinaryOp.add false false)
| .some y => match y with
let attr? := opStx.attrs.getAttr "overflowFlags"
match attr? with
| .none => pure <| Sum.inl (MOp.BinaryOp.add false false)
| .some attr => match attr with

@@ -134,6 +135,7 @@ def alive_simplifyMulDivRem805 (w : Nat) :
rw [LLVM.sdiv?_denom_zero_eq_none]
apply Refinement.none_left
case neg =>
simp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-terminal simp (if a simp is not the last element of a proof, it should be simp only to reduce chances of the proof breaking when the global simp-set changes, you can use simp? to "squeeze" the simp)

@@ -191,7 +191,7 @@ def udiv {Γ : Ctxt _} (w : ℕ) (l r : Nat)
:= by get_elem_tactic) :
Expr InstCombine.LLVM Γ .pure (InstCombine.Ty.bitvec w) :=
Expr.mk
(op := InstCombine.MOp.udiv w)
(op := InstCombine.MOp.udiv false w)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(op := InstCombine.MOp.udiv false w)
(op := InstCombine.MOp.udiv false w)

let x' ← x
let y' ← y
or? x' y'
if disjoint ∧ x' &&& y' ≠ 0 then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be mindful of whitespace

Suggested change
if disjoint ∧ x' &&& y' ≠ 0 then
if disjoint ∧ x' &&& y' ≠ 0 then

def add {w : Nat} (x y : IntW w) (params : AddParams := {}) : IntW w := do
let x ← x
let y ← y
if (params.nsw ∧ (x.toInt + y.toInt) < -(2^(w-1)) ∧ (x.toInt + y.toInt) ≥ 2^w) ∨ ( params.nuw ∧ (x.toNat + y.toNat) ≥ 2^w) then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line you also have some inconsistent whitespace

Comment on lines +114 to +116
structure SubParams where
nuw : Bool := false
nsw : Bool := false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that AddParams is the same as SubParams is the same as MulParams, it makes sense to unify those into a single OverflowFlags structure

let x' ← x
let y' ← y
or? x' y'
if disjoint ∧ x' &&& y' ≠ 0 then
.none
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Option.none is brought into scope by the prelude, you don't need the dot here (nor the rest of the file)

Suggested change
.none
none

Comment on lines +242 to +243
sdiv? x' y'
@[simp, reducible]
Copy link
Collaborator

@alexkeizer alexkeizer Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave an empty line between definitions

@AtticusKuhn
Copy link
Contributor Author

See
#480

github-merge-queue bot pushed a commit that referenced this pull request Aug 8, 2024
This is a smaller, scaled back version of 
#471

```
I am wondering if we can scope it a bit smaller and just add overflow flags for addition. I feel this would allow us to iterate quickly on the right implementation and then expand it to all ops.
```



https://grosser.zulipchat.com/#narrow/stream/446584-Project---Lean4---BitVectors/topic/Overflow.20Flags.20in.20LLVM/near/453334239

---------

Co-authored-by: Atticus Kuhn <[email protected]>
Co-authored-by: Tobias Grosser <[email protected]>
Co-authored-by: Alex Keizer <[email protected]>
Co-authored-by: Atticus Kuhn <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: lean-mlir does not support overflow flags
4 participants