Skip to content

Commit f70715d

Browse files
authored
Merge pull request #313 from UQ-PAC/simplification-pass-sva
constraint generation
2 parents c06c210 + 3d4028c commit f70715d

File tree

8 files changed

+935
-6
lines changed

8 files changed

+935
-6
lines changed

src/main/scala/Main.scala

+18-2
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ object Main {
139139
name = "no-irreducible-loops",
140140
doc = "Disable producing irreducible loops when --analyse is passed (does nothing without --analyse)"
141141
)
142-
noIrreducibleLoops: Flag
142+
noIrreducibleLoops: Flag,
143+
@arg(name = "dsa", doc = "Perform Data Structure Analysis if no version is specified perform constraint generation (requires --simplify flag) (none|norm|field|set|all)")
144+
dsaType: Option[String],
143145
)
144146

145147
def main(args: Array[String]): Unit = {
@@ -205,6 +207,19 @@ object Main {
205207
None
206208
}
207209

210+
val dsa: Option[DSAConfig] = if (conf.simplify.value) {
211+
conf.dsaType match
212+
case Some("set") => Some(DSAConfig(immutable.Set(DSAAnalysis.Set)))
213+
case Some("field") => Some(DSAConfig(immutable.Set(DSAAnalysis.Field)))
214+
case Some("norm") => Some(DSAConfig(immutable.Set(DSAAnalysis.Norm)))
215+
case Some("all") => Some(DSAConfig(immutable.Set(DSAAnalysis.Set, DSAAnalysis.Field, DSAAnalysis.Norm)))
216+
case Some("none") => Some(DSAConfig(immutable.Set.empty))
217+
case None => None
218+
case Some(_) => throw new IllegalArgumentException("Illegal option to dsa, allowed are: (none|set|field|norm|all)")
219+
} else {
220+
None
221+
}
222+
208223
val boogieMemoryAccessMode = if (conf.lambdaStores.value) {
209224
BoogieMemoryAccessMode.LambdaStoreSelect
210225
} else {
@@ -240,7 +255,8 @@ object Main {
240255
validateSimp = conf.validateSimplify.value,
241256
staticAnalysis = staticAnalysis,
242257
boogieTranslation = boogieGeneratorConfig,
243-
outputPrefix = conf.outFileName
258+
outputPrefix = conf.outFileName,
259+
dsaConfig = dsa
244260
)
245261

246262
RunUtils.run(q)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package analysis.data_structure_analysis
2+
3+
import ir.{CFGPosition, Call, DirectCall, Expr, IndirectCall, IntraProcIRCursor, LocalVar, MemoryLoad, MemoryStore, Procedure, Statement, Variable, computeDomain}
4+
import util.ConstGenLogger
5+
6+
sealed trait Constraint {
7+
def source: CFGPosition
8+
val label: String
9+
def eval(evaluator: Expr => Any = identity): String
10+
}
11+
12+
def content(value: Any): String = s"[|${value.toString}|]}"
13+
14+
case class ConstraintArg(value: Expr, contents: Boolean = false) {
15+
override def toString: String = eval()
16+
def ignoreContents: ConstraintArg = ConstraintArg(value)
17+
def eval(evaluator: Expr => Any = identity): String = {
18+
val evaluated = evaluator(value)
19+
if contents then content(evaluated) else evaluated.toString
20+
}
21+
}
22+
23+
sealed trait BinaryConstraint extends Constraint {
24+
val arg1: ConstraintArg
25+
val arg2: ConstraintArg
26+
27+
private def name = this.getClass.getSimpleName
28+
override def toString: String = eval()
29+
override def eval(evaluator: Expr => Any = identity): String = s"(${arg1.eval(evaluator)} <==> ${arg2.eval(evaluator)}"
30+
}
31+
32+
case class AssignmentConstraint(pos: CFGPosition, ar1: Expr, ar2: Expr) extends BinaryConstraint {
33+
override def source: CFGPosition = pos
34+
override val label: String = labelToPC(Some(pos.toString))
35+
override val arg1: ConstraintArg = ConstraintArg(ar1)
36+
override val arg2: ConstraintArg = ConstraintArg(ar2)
37+
}
38+
39+
sealed trait MemoryAccessConstraint[T <: MemoryStore | MemoryLoad](pos: T, index: Expr, value: Expr, val size: Int)
40+
extends BinaryConstraint {
41+
val label: String = labelToPC(pos.label)
42+
override def source: T = pos
43+
44+
override val arg1: ConstraintArg = ConstraintArg(index, true)
45+
override val arg2: ConstraintArg = ConstraintArg(value)
46+
47+
override def toString: String = eval()
48+
49+
override def eval(evaluator: Expr => Any = identity): String =
50+
s"${this.getClass.getSimpleName}($label, size: $size): " + super.eval(evaluator)
51+
}
52+
53+
case class MemoryReadConstraint(pos: MemoryLoad)
54+
extends MemoryAccessConstraint[MemoryLoad](pos, pos.index, pos.lhs, pos.size/8)
55+
56+
case class MemoryWriteConstraint(pos: MemoryStore)
57+
extends MemoryAccessConstraint[MemoryStore](pos, pos.index, pos.value, pos.size/8)
58+
59+
sealed trait CallConstraint[T <: Call, V <: Procedure | Variable](call: T)
60+
extends Constraint {
61+
val label: String = labelToPC(call.label)
62+
def caller: Procedure = call.parent.parent
63+
def target: V
64+
val inParams: Map[LocalVar, Expr]
65+
val outParmas: Map[LocalVar, LocalVar]
66+
def inConstraints: Set[AssignmentConstraint] = inParams.map(pair => AssignmentConstraint(call, pair._1, pair._2)).toSet
67+
def outConstraints: Set[AssignmentConstraint] = outParmas.map(pair => AssignmentConstraint(call, pair._1, pair._2)).toSet
68+
override def source: T = call
69+
override def toString: String = eval()
70+
71+
override def eval(evaluator: Expr => Any = identity): String = {
72+
s"${this.getClass.getSimpleName}($label, Proc ${caller.name} calls $target" ++ s"\nIn Param Constraints: ${inConstraints.map(_.eval(evaluator))}"
73+
++ s"\nOut Param Constraints: ${outConstraints.map(_.eval(evaluator))}"
74+
}
75+
}
76+
77+
case class DirectCallConstraint(call: DirectCall)
78+
extends CallConstraint[DirectCall, Procedure] (call) {
79+
override def target: Procedure = call.target
80+
81+
override val inParams: Map[LocalVar, Expr] = call.actualParams
82+
override val outParmas: Map[LocalVar, LocalVar] = call.outParams.view.mapValues(_.asInstanceOf[LocalVar]).toMap
83+
}
84+
85+
case class IndirectCallConstraint(call: IndirectCall)
86+
extends CallConstraint[IndirectCall, Variable](call)
87+
{
88+
89+
override def target: Variable = call.target
90+
91+
override val inParams: Map[LocalVar, Expr] = Map.empty
92+
override val outParmas: Map[LocalVar, LocalVar] = Map.empty
93+
}
94+
95+
def generateConstraints(proc: Procedure): Set[Constraint] = {
96+
ConstGenLogger.info(s"Generating Constraints for ${proc.name}")
97+
val domain = computeDomain(IntraProcIRCursor, Set(proc))
98+
var constraints: Set[Constraint] = Set.empty
99+
100+
domain.foreach {
101+
case load: MemoryLoad =>
102+
constraints += MemoryReadConstraint(load)
103+
case write: MemoryStore =>
104+
constraints += MemoryWriteConstraint(write)
105+
case call: DirectCall =>
106+
constraints += DirectCallConstraint(call)
107+
case indirectCall: IndirectCall => constraints += IndirectCallConstraint(indirectCall)
108+
case _ =>
109+
}
110+
111+
constraints
112+
}
113+
114+
case class SVAConstraints(sva: SymbolicValues, constraints: Set[Constraint]) {
115+
def this(proc: Procedure) = {
116+
this(getSymbolicValues(proc), generateConstraints(proc))
117+
}
118+
def exprToSymVal(expr: Expr): SymValueSet = sva.exprToSymValSet(expr)
119+
}
120+
object SVAConstraints {
121+
def apply(proc: Procedure) = new SVAConstraints(proc)
122+
}

0 commit comments

Comments
 (0)