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

Bool/Int type coercion #1170

Draft
wants to merge 7 commits into
base: dev
Choose a base branch
from
13 changes: 13 additions & 0 deletions examples/technical/intBoolCoercion.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

//@ requires i;
void check(int i) {
if(!i) {
//@ assert false;
}
}

void main() {
check(5==5);
int *p;
if(!p) return;
}
3 changes: 3 additions & 0 deletions src/col/vct/col/ast/Node.scala
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ final case class CoerceCIntCFloat[G](target: Type[G])(implicit val o: Origin) ex
final case class CoerceCIntInt[G]()(implicit val o: Origin) extends Coercion[G] with CoerceCIntIntImpl[G]
final case class CoerceCFloatFloat[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceCFloatFloatImpl[G]
final case class CoerceIntRat[G]()(implicit val o: Origin) extends Coercion[G] with CoerceIntRatImpl[G]
final case class CoerceBoolCInt[G]()(implicit val o: Origin) extends Coercion[G] with CoerceBoolCIntImpl[G]
final case class CoerceCIntBool[G]()(implicit val o: Origin) extends Coercion[G] with CoerceCIntBoolImpl[G]
final case class CoercePointerBool[G]()(implicit val o: Origin) extends Coercion[G] with CoercePointerBoolImpl[G]

final case class CoerceIncreasePrecision[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceIncreasePrecisionImpl[G]
final case class CoerceDecreasePrecision[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceDecreasePrecisionImpl[G]
Expand Down
9 changes: 9 additions & 0 deletions src/col/vct/col/ast/family/coercion/CoerceBoolCIntImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package vct.col.ast.family.coercion

import vct.col.ast.{CoerceBoolCInt, TBool}
import vct.col.ast.ops.CoerceBoolCIntOps

trait CoerceBoolCIntImpl[G] extends CoerceBoolCIntOps[G] { this: CoerceBoolCInt[G] =>
override def target: TBool[G] = TBool()

}
9 changes: 9 additions & 0 deletions src/col/vct/col/ast/family/coercion/CoerceCIntBoolImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package vct.col.ast.family.coercion

import vct.col.ast.{CoerceCIntBool, TBool}
import vct.col.ast.ops.CoerceCIntBoolOps

trait CoerceCIntBoolImpl[G] extends CoerceCIntBoolOps[G] { this: CoerceCIntBool[G] =>
override def target: TBool[G] = TBool()

}
10 changes: 10 additions & 0 deletions src/col/vct/col/ast/family/coercion/CoercePointerBoolImpl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package vct.col.ast.family.coercion

import vct.col.ast.ops.CoercePointerBoolOps
import vct.col.ast.{CoercePointerBool, TBool}

trait CoercePointerBoolImpl[G] extends CoercePointerBoolOps[G] {
this: CoercePointerBool[G] =>
// override def layout(implicit ctx: Ctx): Doc = ???
override def target: TBool[G] = TBool()
}
3 changes: 3 additions & 0 deletions src/col/vct/col/ast/family/coercion/CoercionImpl.scala
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sakehl I'm not sure what isCPromoting does. Should I add one of the coercions as a case there? In principle, I want all coercions to work in C code, so I'm reluctant to add e.g. CoerceCIntBool as false here, but it is not injective and thus not promoting...
Also, is it correct that some cases, like CoerceJoinUnion, call the regular isPromoting instead of the special C version isCPromoting? or is that just a copy-paste error?

Copy link
Contributor

Choose a reason for hiding this comment

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

What I wanted to capture here is that float/double can only be demoted to int (and double to float) in:

  • an assignment
  • an argument of a function call
    I based this mostly on this reference and here

This is called demotion, and is only valid in those cases. More specifically it is not valid with arithmetic conversions. (so 5 % 4.0 is not a valid statement, since 4.0 cannot be demoted to an int here, and % does not work on floating point numbers).

Anyway it seems that boolean is a bit harder. When looking specifically at if-statements and logical and/or statements of C:
https://en.cppreference.com/w/c/language/operator_logical

They work for an expression of any scalar type. Which is of course not how we defined this internally in VerCors.

I think we can then best encode this to always allow demoting pointers and integers to booleans.

So in that case, I'd say that we put:

case CoerceCIntBool() => false
    case CoercePointerBool() => false
  }

both to true.

(.... what is C a messy language)

Also, is it correct that some cases, like CoerceJoinUnion, call the regular isPromoting instead of the special C version isCPromoting? or is that just a copy-paste error?

This is definitely a copy paste error, thanks for spotting it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we can then best encode this to always allow demoting pointers and integers to booleans.

Ok, then I leave it as-is and let the default case handle it.

This is definitely a copy paste error

Ok, I'll fix it :)

Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,8 @@ trait CoercionImpl[G] extends CoercionFamilyOps[G] { this: Coercion[G] =>
case CoerceCFloatFloat(_, _) => true
case CoerceDecreasePrecision(_, _) => false
case CoerceCFloatCInt(_) => false
case CoerceBoolCInt() => true
case CoerceCIntBool() => false
case CoercePointerBool() => false
}
}
3 changes: 3 additions & 0 deletions src/col/vct/col/feature/FeatureRainbow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ class FeatureRainbow[G] {
case node: CoerceIdentity[G] => Coercions
case node: CoerceIncreasePrecision[G] => Coercions
case node: CoerceIntRat[G] => Coercions
case node: CoerceBoolCInt[G] => Coercions
case node: CoerceCIntBool[G] => Coercions
case node: CoercePointerBool[G] => Coercions
case node: CoerceJavaClassAnyClass[G] => Coercions
case node: CoerceJavaSupports[G] => Coercions
case node: CoerceJoinUnion[G] => Coercions
Expand Down
3 changes: 3 additions & 0 deletions src/col/vct/col/typerules/CoercingRewriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ abstract class CoercingRewriter[Pre <: Generation]() extends BaseCoercingRewrite
case CoerceRatZFrac() => e
case CoerceZFracFrac() => e

case CoerceBoolCInt() => e
case CoerceCIntBool() => e
case CoercePointerBool() => e
case CoerceDecreasePrecision(_, _) => e
case CoerceCFloatCInt(_) => e
case CoerceCIntCFloat(_) => e
Expand Down
5 changes: 5 additions & 0 deletions src/col/vct/col/typerules/CoercionUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ case object CoercionUtils {
case (TFraction(), TRational()) => CoercionSequence(Seq(CoerceFracZFrac(), CoerceZFracRat()))
case (TZFraction(), TRational()) => CoerceZFracRat()
case (source: FloatType[G], TRational()) => CoerceFloatRat(source)
case (TBool(), TCInt()) => CoerceBoolCInt()
case (TCInt(), TBool()) => CoerceCIntBool()
case (TCInt(), TResource()) => CoerceCIntBool()
ArmborstL marked this conversation as resolved.
Show resolved Hide resolved
case (TPointer(_), TBool()) => CoercePointerBool()
case (CTPointer(_), TBool()) => CoercePointerBool()

case (source @ TFloat(exponentL, mantissaL), target @ TFloat(exponentR, mantissaR)) if exponentL <= exponentR && mantissaL <= mantissaR =>
CoerceIncreasePrecision(source, target)
Expand Down
1 change: 1 addition & 0 deletions src/main/vct/main/stages/Transformation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ case class SilverTransformation
) extends Transformation(onBeforePassKey, onAfterPassKey, Seq(
// Replace leftover SYCL types
ReplaceSYCLTypes,
CIntBoolCoercion,
CFloatIntCoercion,

ComputeBipGlue,
Expand Down
27 changes: 27 additions & 0 deletions src/rewrite/vct/rewrite/CIntBoolCoercion.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package vct.col.rewrite

import vct.col.ast._
import vct.col.origin.Origin
import vct.col.typerules.CoercingRewriter

case object CIntBoolCoercion extends RewriterBuilder {
override def key: String = "CIntBool"
override def desc: String = "Introduce an explicit node to convert integers to boolean and vice versa for C."
}

case class CIntBoolCoercion[Pre <: Generation]() extends CoercingRewriter[Pre] {
override def applyCoercion(e: => Expr[Post], coercion: Coercion[Pre])(implicit o: Origin): Expr[Post] = coercion match {
case CoerceBoolCInt() =>
val zero = new CIntegerValue[Post](0)
val one = new CIntegerValue[Post](1)
new Select[Post](e, one, zero)
case CoerceCIntBool() =>
val zero = new CIntegerValue[Post](0)
new Neq[Post](e, zero)
case CoercePointerBool() =>
val ptr = new Null[Post]()
new Neq[Post](e, ptr)
case other => super.applyCoercion(e, other)
}

}
2 changes: 2 additions & 0 deletions test/main/vct/test/integration/examples/TechnicalSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ vercors should verify using silicon in "example using string primitive" pvl

vercors should verify using anyBackend example "technical/labeledEmbeddedStatement.c"

vercors should verify using anyBackend example "technical/intBoolCoercion.c"
sakehl marked this conversation as resolved.
Show resolved Hide resolved

vercors should verify using anyBackend in "usage of given/yields in C" c """
/*@
given int x;
Expand Down
Loading