Skip to content

Commit 020fb35

Browse files
committed
First version working for function parameters
1 parent c957125 commit 020fb35

File tree

10 files changed

+76
-39
lines changed

10 files changed

+76
-39
lines changed

examples/concepts/unique/arrays.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
context_everywhere x2 != NULL ** \pointer_length(x2) == n ** (\forall* int i; 0<=i && i<n; Perm(&x2[i], 1\2));
66
ensures (\forall int i; 0<=i && i<n; x0[i] == x1[i] + x2[i] );
77
@*/
8-
int main(int n, /*@ unique<1> @*/ int* x0, /*@ unique<1> @*/ /*@ unique<2> @*/ int* x1, /*@ unique<2> @*/ int* x2){
8+
int main(int n, /*@ unique<1> @*/ int* x0, /*@ unique<2> @*/ int* x1, /*@ unique<2> @*/ int* x2){
99
/*@
1010
loop_invariant 0 <= j && j <= n;
1111
loop_invariant (\forall int i; 0<=i && i<j; x0[i] == x1[i] + x2[i] );

src/col/vct/col/ast/Node.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,20 @@ final case class TUnion[G](types: Seq[Type[G]])(
128128
final case class TArray[G](element: Type[G])(
129129
implicit val o: Origin = DiagnosticOrigin
130130
) extends Type[G] with TArrayImpl[G]
131-
final case class TPointer[G](element: Type[G])(
132-
implicit val o: Origin = DiagnosticOrigin
133-
) extends Type[G] with TPointerImpl[G]
134131
final case class TType[G](t: Type[G])(implicit val o: Origin = DiagnosticOrigin)
135132
extends Type[G] with TTypeImpl[G]
136133
final case class TVar[G](ref: Ref[G, Variable[G]])(
137134
implicit val o: Origin = DiagnosticOrigin
138135
) extends Type[G] with TVarImpl[G]
139136

137+
sealed trait PointerType[G] extends Type[G] with PointerTypeImpl[G]
138+
final case class TPointer[G](element: Type[G])(
139+
implicit val o: Origin = DiagnosticOrigin
140+
) extends PointerType[G] with TPointerImpl[G]
141+
final case class TUniquePointer[G](element: Type[G], id: BigInt)(
142+
implicit val o: Origin = DiagnosticOrigin
143+
) extends PointerType[G] with TUniquePointerImpl[G]
144+
140145
sealed trait CompositeType[G] extends Type[G] with CompositeTypeImpl[G]
141146
sealed trait SizedType[G] extends CompositeType[G] with SizedTypeImpl[G]
142147
final case class TSeq[G](element: Type[G])(
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package vct.col.ast.`type`
2+
3+
import vct.col.ast.{PointerType, Type}
4+
5+
trait PointerTypeImpl[G] {
6+
this: PointerType[G] =>
7+
8+
val element: Type[G]
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package vct.col.ast.`type`
2+
3+
import vct.col.ast.TUniquePointer
4+
import vct.col.ast.ops.TUniquePointerOps
5+
import vct.col.print._
6+
7+
trait TUniquePointerImpl[G] extends TUniquePointerOps[G] {
8+
this: TUniquePointer[G] =>
9+
override def layoutSplitDeclarator(implicit ctx: Ctx): (Doc, Doc) = {
10+
val (spec, decl) = element.layoutSplitDeclarator
11+
(spec, decl <> "*")
12+
}
13+
14+
override def layout(implicit ctx: Ctx): Doc =
15+
Group(Text("unique_pointer") <> open <> element <> "," <> id.toString <> close)
16+
}

src/col/vct/col/ast/type/typeclass/TypeImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ trait TypeImpl[G] extends TypeFamilyOps[G] {
2121
def asVector: Option[TVector[G]] =
2222
CoercionUtils.getAnyVectorCoercion(this).map(_._2)
2323
def asBag: Option[TBag[G]] = CoercionUtils.getAnyBagCoercion(this).map(_._2)
24-
def asPointer: Option[TPointer[G]] =
24+
def asPointer: Option[PointerType[G]] =
2525
CoercionUtils.getAnyPointerCoercion(this).map(_._2)
2626
def asArray: Option[TArray[G]] =
2727
CoercionUtils.getAnyArrayCoercion(this).map(_._2)

src/col/vct/col/typerules/CoercingRewriter.scala

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ abstract class CoercingRewriter[Pre <: Generation]()
538538
(ApplyCoercion(e, coercion)(coercionOrigin(e)), t)
539539
case None => throw IncoercibleText(e, s"two-dimensional array")
540540
}
541-
def pointer(e: Expr[Pre]): (Expr[Pre], TPointer[Pre]) =
541+
def pointer(e: Expr[Pre]): (Expr[Pre], PointerType[Pre]) =
542542
CoercionUtils.getAnyPointerCoercion(e.t) match {
543543
case Some((coercion, t)) =>
544544
(ApplyCoercion(e, coercion)(coercionOrigin(e)), t)
@@ -2145,14 +2145,7 @@ abstract class CoercingRewriter[Pre <: Generation]()
21452145
implicit val o: Origin = stat.o
21462146
stat match {
21472147
case a @ Assert(assn) => Assert(res(assn))(a.blame)
2148-
case a @ Assign(target, value) =>
2149-
try {
2150-
Assign(target, coerce(value, target.t, canCDemote = true))(a.blame)
2151-
} catch {
2152-
case err: Incoercible =>
2153-
println(err.text)
2154-
throw err
2155-
}
2148+
case a @ Assign(target, value) => Assign(target, coerce(value, target.t, canCDemote = true))(a.blame)
21562149
case Assume(assn) => Assume(bool(assn))
21572150
case Block(statements) => Block(statements)
21582151
case Branch(branches) =>

src/col/vct/col/typerules/CoercionUtils.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ case object CoercionUtils {
122122
case (TNull(), JavaTClass(target, _)) => CoerceNullJavaClass(target)
123123
case (TNull(), TAnyClass()) => CoerceNullAnyClass()
124124
case (TNull(), TPointer(target)) => CoerceNullPointer(target)
125+
case (TNull(), TUniquePointer(target, id)) => CoerceNullPointer(target)
125126
case (TNull(), CTPointer(target)) => CoerceNullPointer(target)
126127
case (TNull(), TEnum(target)) => CoerceNullEnum(target)
127128

@@ -425,10 +426,11 @@ case object CoercionUtils {
425426

426427
def getAnyPointerCoercion[G](
427428
source: Type[G]
428-
): Option[(Coercion[G], TPointer[G])] =
429+
): Option[(Coercion[G], PointerType[G])] =
429430
source match {
430431
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyPointerCoercion)
431432
case t: TPointer[G] => Some((CoerceIdentity(source), t))
433+
case t: TUniquePointer[G] => Some((CoerceIdentity(source), t))
432434
case t: CTPointer[G] =>
433435
Some((CoerceIdentity(source), TPointer(t.innerType)))
434436
case t: CTArray[G] =>

src/rewrite/vct/rewrite/adt/ImportPointer.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import vct.col.util.AstBuildHelpers.{ExprBuildHelpers, const}
1010
import scala.collection.mutable
1111

1212
case object ImportPointer extends ImportADTBuilder("pointer") {
13-
private def PointerField(t: Type[_]): Origin =
14-
Origin(Seq(PreferredName(Seq(typeText(t))), LabelContext("pointer field")))
13+
private def PointerField(t: Type[_], uniqueId: Option[BigInt]): Origin =
14+
Origin(Seq(PreferredName(Seq(typeText(t) + uniqueId.map(_.toString).getOrElse(""))), LabelContext("pointer field")))
1515

1616
case class PointerNullOptNone(inner: Blame[PointerNull], expr: Expr[_])
1717
extends Blame[OptionNone] {
@@ -75,14 +75,18 @@ case class ImportPointer[Pre <: Generation](importer: ImportADTImporter)
7575
private lazy val pointerDeref = find[Function[Post]](pointerFile, "ptr_deref")
7676
private lazy val pointerAdd = find[Function[Post]](pointerFile, "ptr_add")
7777

78-
val pointerField: mutable.Map[Type[Post], SilverField[Post]] = mutable.Map()
78+
val pointerField: mutable.Map[(Type[Post], Option[BigInt]), SilverField[Post]] = mutable.Map()
7979

8080
private def getPointerField(ptr: Expr[Pre]): Ref[Post, SilverField[Post]] = {
81-
val tElement = dispatch(ptr.t.asPointer.get.element)
81+
val (tElementPre: Type[Pre], uniqueID) = ptr.t.asPointer.get match {
82+
case TUniquePointer(e, i) => (e, Some(i))
83+
case TPointer(e) => (e, None)
84+
}
85+
val tElement = dispatch(tElementPre)
8286
pointerField.getOrElseUpdate(
83-
tElement, {
87+
(tElement, uniqueID), {
8488
globalDeclarations
85-
.declare(new SilverField(tElement)(PointerField(tElement)))
89+
.declare(new SilverField(tElement)(PointerField(tElement, uniqueID)))
8690
},
8791
).ref
8892
}
@@ -98,6 +102,7 @@ case class ImportPointer[Pre <: Generation](importer: ImportADTImporter)
98102
override def postCoerce(t: Type[Pre]): Type[Post] =
99103
t match {
100104
case TPointer(_) => TOption(TAxiomatic(pointerAdt.ref, Nil))
105+
case TUniquePointer(_, _) => TOption(TAxiomatic(pointerAdt.ref, Nil))
101106
case other => rewriteDefault(other)
102107
}
103108

src/rewrite/vct/rewrite/lang/LangCToCol.scala

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ case object LangCToCol {
3030
example.o.messageInContext("Global variables in C are not supported.")
3131
}
3232

33-
case class CDeclarationSpecifierNotSupported(spec: CDeclarationSpecifier[_]) extends UserError {
34-
override def code: String = "notSupportedTypeDecl"
35-
override def text: String =
36-
spec.o.messageInContext("This decleration specifier is not supported.")
37-
}
38-
3933
case class MultipleSharedMemoryDeclaration(decl: Node[_]) extends UserError {
4034
override def code: String = "multipleSharedMemoryDeclaration"
4135
override def text: String =
@@ -60,7 +54,7 @@ case object LangCToCol {
6054
)
6155
}
6256

63-
case class WrongCType(decl: CLocalDeclaration[_]) extends UserError {
57+
case class WrongCType(decl: Declaration[_]) extends UserError {
6458
override def code: String = "wrongCType"
6559
override def text: String =
6660
decl.o
@@ -445,7 +439,7 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
445439
implicit val o: Origin = cParam.o
446440
val varO = o.sourceName(C.getDeclaratorInfo(cParam.declarator).name)
447441
val cRef = RefCParam(cParam)
448-
val tp = new TypeProperties(cParam.specifiers, cParam.declarator)
442+
val tp = new TypeProperties(cParam.specifiers, cParam)
449443

450444
kernelSpecifier match {
451445
case OpenCLKernel() =>
@@ -486,10 +480,11 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
486480
case GPULocal() => throw WrongGPUType(cParam)
487481
case GPUGlobal() => throw WrongGPUType(cParam)
488482
}
489-
val specType =
490-
cParam.specifiers.collectFirst { case t: CSpecificationType[Pre] =>
491-
rw.dispatch(t.t)
492-
}.get
483+
val prop = new TypeProperties(cParam.specifiers, cParam)
484+
if(!prop.validCParam) throw WrongCType(cParam)
485+
val specType = if(prop.unique.isEmpty)
486+
rw.dispatch(prop.mainType.get) else
487+
TUniquePointer(rw.dispatch(prop.innerType.get), prop.unique.get)(cParam.o)
493488

494489
cParam.drop()
495490
val v =
@@ -635,6 +630,7 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
635630
t match {
636631
case TArray(element) => element
637632
case TPointer(element) => element
633+
case TUniquePointer(element, _) => element
638634
case _ => throw Unreachable("Already checked on pointer or array type")
639635
}
640636

@@ -857,8 +853,7 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
857853
}
858854

859855
class TypeProperties(
860-
specs: Seq[CDeclarationSpecifier[Pre]],
861-
decl: CDeclarator[Pre],
856+
specs: Seq[CDeclarationSpecifier[Pre]], decl: Declaration[Pre]
862857
) {
863858
var arrayOrPointer = false
864859
var global = false
@@ -892,15 +887,22 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
892887
case CSpecificationType(t) =>
893888
mainType = Some(t)
894889
case CExtern() => extern = true
890+
case CUnique(i) if unique.isDefined => throw WrongCType(decl)
895891
case CUnique(i) => unique = Some(i)
896892
case CPure() => pure = true
897893
case CInline() => inline = true
898894
case CStatic() => static = true
899-
case _ =>
895+
// We want to make sure we process everything
896+
case _ => ???
900897
}
901898

902899
def isShared: Boolean = shared && !global
903900
def isGlobal: Boolean = !shared && global
901+
def validNonGpu: Boolean = !global && !shared &&
902+
(unique.isEmpty || (unique.isDefined && arrayOrPointer)) && mainType.isDefined
903+
def validReturn: Boolean = validNonGpu && !static
904+
def validCParam: Boolean = !pure && !inline && validNonGpu && !static
905+
def validCLocal = validCParam
904906
}
905907

906908
def addDynamicShared(
@@ -940,7 +942,7 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
940942
if (decl.decl.inits.size != 1)
941943
throw MultipleSharedMemoryDeclaration(decl)
942944

943-
val prop = new TypeProperties(decl.decl.specs, decl.decl.inits.head.decl)
945+
val prop = new TypeProperties(decl.decl.specs, decl)
944946
if (!prop.shared)
945947
return false
946948
val init: CInit[Pre] = decl.decl.inits.head
@@ -1266,9 +1268,11 @@ case class LangCToCol[Pre <: Generation](rw: LangSpecificToCol[Pre])
12661268

12671269
def isPointer(t: Type[Pre]): Boolean = getPointer(t).isDefined
12681270

1269-
def getPointer(t: Type[Pre]): Option[TPointer[Pre]] =
1271+
def getPointer(t: Type[Pre]): Option[Type[Pre]] =
12701272
getBaseType(t) match {
12711273
case t @ TPointer(_) => Some(t)
1274+
case t @ TUniquePointer(_, _) => Some(t)
1275+
case t @ CTPointer(_) => Some(t)
12721276
case _ => None
12731277
}
12741278

test/main/vct/test/integration/examples/UniqueFieldsSpec.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@ import vct.test.integration.helper.VercorsSpec
55
class UniqueFieldsSpec extends VercorsSpec {
66
vercors should verify using silicon example "concepts/unique/arrays.c"
77

8-
vercors should error withCode "???" in """int main(/*@ unique<1> @*/ /*@ unique<2> @*/ int* x0){}"""
8+
vercors should error withCode "wrongCType" in "multiple uniques" c """int main(/*@ unique<1> @*/ /*@ unique<2> @*/ int* x0){}"""
9+
vercors should error withCode "resolutionError:type" in "different uniques local" c """int main(/*@ unique<1> @*/ int* x0){ int* x1 = x0;}"""
10+
vercors should error withCode "resolutionError:type" in "multiple uniques parameter" c """int main(/*@ unique<1> @*/ int* x0, /*@ unique<2> @*/ int* x1){x1 = x0;}"""
11+
vercors should verify using silicon in "same uniques parameter" c """int main(/*@ unique<1> @*/ int* x0, /*@ unique<1> @*/ int* x1){x1 = x0;}"""
912
}

0 commit comments

Comments
 (0)