Skip to content

Commit

Permalink
Merge pull request #324 from csanadtelbisz/oc-optimizer-fix
Browse files Browse the repository at this point in the history
Xcfa oc checker optimization fix
  • Loading branch information
leventeBajczi authored Nov 14, 2024
2 parents f7bdc13 + b13c139 commit c2d8ae3
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 94 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ buildscript {

allprojects {
group = "hu.bme.mit.theta"
version = "6.8.3"
version = "6.8.4"

apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,10 @@ public Expr<?> visitGccPrettyFunc(CParser.GccPrettyFuncContext ctx) {
@Override
public Expr<?> visitPrimaryExpressionId(CParser.PrimaryExpressionIdContext ctx) {
final var variable = getVar(ctx.Identifier().getText());
if (atomicVars.contains(variable)) {
preStatements.add(new CCall("__VERIFIER_atomic_begin", List.of(), parseContext));
postStatements.add(new CCall("__VERIFIER_atomic_end", List.of(), parseContext));
}
return variable.getRef();
}

Expand Down Expand Up @@ -983,7 +987,7 @@ public Function<Expr<?>, Expr<?>> visitPostfixExpressionIncrement(
cexpr = new CExpr(expr, parseContext);
// no need to truncate here, as left and right side types are the same
CAssignment cAssignment = new CAssignment(primary, cexpr, "=", parseContext);
postStatements.add(cAssignment);
postStatements.add(0, cAssignment);
functionVisitor.recordMetadata(ctx, cAssignment);
functionVisitor.recordMetadata(ctx, cexpr);
return primary;
Expand All @@ -1004,7 +1008,7 @@ public Function<Expr<?>, Expr<?>> visitPostfixExpressionDecrement(
cexpr = new CExpr(expr, parseContext);
// no need to truncate here, as left and right side types are the same
CAssignment cAssignment = new CAssignment(primary, cexpr, "=", parseContext);
postStatements.add(cAssignment);
postStatements.add(0, cAssignment);
functionVisitor.recordMetadata(ctx, cAssignment);
functionVisitor.recordMetadata(ctx, cexpr);
return expr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,9 @@ class FrontendXcfaBuilder(
xcfaEdge = XcfaEdge(elseEnd, endLoc, metadata = getMetadata(statement))
builder.addEdge(xcfaEdge)
} else {
xcfaEdge = XcfaEdge(elseBranch, endLoc, metadata = getMetadata(statement))
val elseAfterGuard =
buildPostStatement(guard, ParamPack(builder, elseBranch, breakLoc, continueLoc, returnLoc))
xcfaEdge = XcfaEdge(elseAfterGuard, endLoc, metadata = getMetadata(statement))
builder.addEdge(xcfaEdge)
}
xcfaEdge = XcfaEdge(mainEnd, endLoc, metadata = getMetadata(statement))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import hu.bme.mit.theta.analysis.algorithm.oc.OcChecker
import hu.bme.mit.theta.analysis.algorithm.oc.Relation
import hu.bme.mit.theta.analysis.algorithm.oc.RelationType
import hu.bme.mit.theta.analysis.unit.UnitPrec
import hu.bme.mit.theta.common.exception.NotSolvableException
import hu.bme.mit.theta.common.logging.Logger
import hu.bme.mit.theta.core.decl.ConstDecl
import hu.bme.mit.theta.core.decl.Decls
Expand All @@ -50,21 +51,25 @@ import hu.bme.mit.theta.solver.SolverStatus
import hu.bme.mit.theta.xcfa.*
import hu.bme.mit.theta.xcfa.analysis.XcfaPrec
import hu.bme.mit.theta.xcfa.model.*
import hu.bme.mit.theta.xcfa.passes.*
import kotlin.time.measureTime

private val Expr<*>.vars
get() = ExprUtils.getVars(this)

class XcfaOcChecker(
private val xcfa: XCFA,
xcfa: XCFA,
decisionProcedure: OcDecisionProcedureType,
private val logger: Logger,
conflictInput: String?,
private val outputConflictClauses: Boolean,
nonPermissiveValidation: Boolean,
private val autoConflictConfig: AutoConflictFinderConfig,
private val acceptUnreliableSafe: Boolean = false,
) : SafetyChecker<EmptyProof, Cex, XcfaPrec<UnitPrec>> {

private val xcfa = xcfa.optimizeFurther(OcExtraPasses())

private var indexing = VarIndexingFactory.indexing(0)
private val localVars = mutableMapOf<VarDecl<*>, MutableMap<Int, VarDecl<*>>>()
private val memoryDecl = Decls.Var("__oc_checker_memory_declaration__", Int())
Expand Down Expand Up @@ -147,7 +152,16 @@ class XcfaOcChecker(
else -> SafetyResult.unknown()
}
}
.also { logger.writeln(Logger.Level.MAINSTEP, "OC checker result: $it") }
.also {
logger.writeln(Logger.Level.MAINSTEP, "OC checker result: $it")
if (xcfa.unsafeUnrollUsed && !acceptUnreliableSafe) {
logger.writeln(
Logger.Level.MAINSTEP,
"Incomplete loop unroll used: safe result is unreliable.",
)
throw NotSolvableException()
}
}

private inner class ThreadProcessor(private val thread: Thread) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fun getOcChecker(
ocConfig.outputConflictClauses,
ocConfig.nonPermissiveValidation,
ocConfig.autoConflict,
config.outputConfig.acceptUnreliableSafe,
)
return SafetyChecker { ocChecker.check() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import hu.bme.mit.theta.xcfa.cli.params.Refinement.SEQ_ITP
import hu.bme.mit.theta.xcfa.cli.params.Search.*
import hu.bme.mit.theta.xcfa.cli.runConfig
import hu.bme.mit.theta.xcfa.model.XCFA
import hu.bme.mit.theta.xcfa.model.optimizeFurther
import hu.bme.mit.theta.xcfa.passes.*
import java.nio.file.Paths

Expand Down Expand Up @@ -124,20 +123,9 @@ fun complexPortfolio25(
debugConfig = portfolioConfig.debugConfig,
)

val forceUnrolledXcfa =
xcfa.optimizeFurther(
listOf(
AssumeFalseRemovalPass(),
MutexToVarPass(),
AtomicReadsOneWritePass(),
LoopUnrollPass(2),
)
)

val ocConfig = { inProcess: Boolean ->
XcfaConfig(
inputConfig =
baseConfig.inputConfig.copy(xcfaWCtx = Triple(forceUnrolledXcfa, mcm, parseContext)),
inputConfig = baseConfig.inputConfig.copy(xcfaWCtx = Triple(xcfa, mcm, parseContext)),
frontendConfig = baseConfig.frontendConfig,
backendConfig =
BackendConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class XcfaAdapter(val gsonSupplier: () -> Gson) : TypeAdapter<XCFA>() {
lateinit var vars: Set<XcfaGlobalVar>
lateinit var xcfaProcedures: Map<String, XcfaProcedure>
lateinit var initProcedures: List<Pair<XcfaProcedure, List<Expr<*>>>>
var unsafeUnrollUsed: Boolean = false
var unsafeUnrollUsed = false

val varsType = object : TypeToken<Set<XcfaGlobalVar>>() {}.type

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ constructor(
private val procedures: MutableSet<XcfaProcedureBuilder> = LinkedHashSet(),
private val initProcedures: MutableList<Pair<XcfaProcedureBuilder, List<Expr<*>>>> = ArrayList(),
val metaData: MutableMap<String, Any> = LinkedHashMap(),
var unsafeUnrollUsed: Boolean = false,
) {

fun getVars(): Set<XcfaGlobalVar> = vars
Expand All @@ -49,7 +48,6 @@ constructor(
globalVars = vars,
procedureBuilders = procedures,
initProcedureBuilders = initProcedures,
unsafeUnrollUsed = unsafeUnrollUsed,
)
}

Expand Down Expand Up @@ -80,6 +78,7 @@ constructor(
private val locs: MutableSet<XcfaLocation> = LinkedHashSet(),
private val edges: MutableSet<XcfaEdge> = LinkedHashSet(),
val metaData: MutableMap<String, Any> = LinkedHashMap(),
unsafeUnrollUsed: Boolean = false,
) {

lateinit var initLoc: XcfaLocation
Expand All @@ -91,6 +90,9 @@ constructor(
var errorLoc: Optional<XcfaLocation> = Optional.empty()
private set

var unsafeUnrollUsed: Boolean = unsafeUnrollUsed
private set

lateinit var parent: XcfaBuilder
private lateinit var built: XcfaProcedure
private lateinit var optimized: XcfaProcedureBuilder
Expand Down Expand Up @@ -322,6 +324,6 @@ constructor(
}

fun setUnsafeUnroll() {
parent.unsafeUnrollUsed = true
unsafeUnrollUsed = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ class XCFA(
val globalVars: Set<XcfaGlobalVar>, // global variables
val procedureBuilders: Set<XcfaProcedureBuilder> = emptySet(),
val initProcedureBuilders: List<Pair<XcfaProcedureBuilder, List<Expr<*>>>> = emptyList(),
val unsafeUnrollUsed: Boolean = false,
var unsafeUnrollUsed: Boolean = false,
) {

val pointsToGraph by this.lazyPointsToGraph
private var cachedHash: Int? = null

var cachedHash: Int? = null
val pointsToGraph by this.lazyPointsToGraph

var procedures: Set<XcfaProcedure> // procedure definitions
private set
Expand All @@ -51,6 +51,8 @@ class XCFA(

procedures = procedureBuilders.map { it.build(this) }.toSet()
initProcedures = initProcedureBuilders.map { Pair(it.first.build(this), it.second) }
unsafeUnrollUsed =
(procedureBuilders + initProcedureBuilders.map { it.first }).any { it.unsafeUnrollUsed }
}

/** Recreate an existing XCFA by substituting the procedures and initProcedures fields. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,20 @@
*/
package hu.bme.mit.theta.xcfa.model

import hu.bme.mit.theta.xcfa.passes.ProcedurePass
import hu.bme.mit.theta.xcfa.passes.ProcedurePassManager

fun XCFA.optimizeFurther(passes: List<ProcedurePass>): XCFA {
if (passes.isEmpty()) return this
val passManager = ProcedurePassManager(passes)
val copy: XcfaProcedureBuilder.() -> XcfaProcedureBuilder = {
val newLocs = getLocs().associateWith { it.copy() }
fun XCFA.optimizeFurther(passManager: ProcedurePassManager): XCFA {
if (passManager.passes.isEmpty()) return this
val deepCopy: XcfaProcedure.() -> XcfaProcedureBuilder = {
val newLocs = locs.associateWith { it.copy() }
XcfaProcedureBuilder(
name = name,
manager = passManager,
params = getParams().toMutableList(),
vars = getVars().toMutableSet(),
locs = getLocs().map { newLocs[it]!! }.toMutableSet(),
params = params.toMutableList(),
vars = vars.toMutableSet(),
locs = locs.map { newLocs[it]!! }.toMutableSet(),
edges =
getEdges()
edges
.map {
val source = newLocs[it.source]!!
val target = newLocs[it.target]!!
Expand All @@ -40,10 +38,11 @@ fun XCFA.optimizeFurther(passes: List<ProcedurePass>): XCFA {
edge
}
.toMutableSet(),
metaData = metaData.toMutableMap(),
metaData = mutableMapOf(),
unsafeUnrollUsed = unsafeUnrollUsed,
)
.also {
it.copyMetaLocs(
.also { proc ->
proc.copyMetaLocs(
newLocs[initLoc]!!,
finalLoc.map { newLocs[it] },
errorLoc.map { newLocs[it] },
Expand All @@ -52,9 +51,9 @@ fun XCFA.optimizeFurther(passes: List<ProcedurePass>): XCFA {
}

val builder = XcfaBuilder(name, globalVars.toMutableSet())
procedureBuilders.forEach { builder.addProcedure(it.copy()) }
initProcedureBuilders.forEach { (proc, params) ->
val initProc = builder.getProcedures().find { it.name == proc.name } ?: proc.copy()
procedures.forEach { builder.addProcedure(it.deepCopy()) }
initProcedures.forEach { (proc, params) ->
val initProc = builder.getProcedures().find { it.name == proc.name } ?: proc.deepCopy()
builder.addEntryPoint(initProc, params)
}
return builder.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ package hu.bme.mit.theta.xcfa.passes
import hu.bme.mit.theta.common.logging.Logger
import hu.bme.mit.theta.frontend.ParseContext

open class ProcedurePassManager(vararg passes: List<ProcedurePass>) {
open class ProcedurePassManager(val passes: List<List<ProcedurePass>>) {

val passes: List<List<ProcedurePass>> = passes.toList()
constructor(vararg passes: List<ProcedurePass>) : this(passes.toList())
}

class CPasses(checkOverflow: Boolean, parseContext: ParseContext, uniqueWarningLogger: Logger) :
Expand Down Expand Up @@ -52,7 +52,7 @@ class CPasses(checkOverflow: Boolean, parseContext: ParseContext, uniqueWarningL
// trying to inline procedures
InlineProceduresPass(parseContext),
EmptyEdgeRemovalPass(),
RemoveDeadEnds(),
RemoveDeadEnds(parseContext),
EliminateSelfLoops(),
),
listOf(StaticCoiPass()),
Expand Down Expand Up @@ -87,7 +87,7 @@ class ChcPasses(parseContext: ParseContext, uniqueWarningLogger: Logger) :
listOf(
// trying to inline procedures
InlineProceduresPass(parseContext),
RemoveDeadEnds(),
RemoveDeadEnds(parseContext),
EliminateSelfLoops(),
// handling remaining function calls
LbePass(parseContext),
Expand All @@ -99,3 +99,13 @@ class ChcPasses(parseContext: ParseContext, uniqueWarningLogger: Logger) :
)

class LitmusPasses : ProcedurePassManager()

class OcExtraPasses :
ProcedurePassManager(
listOf(
AssumeFalseRemovalPass(),
MutexToVarPass(),
AtomicReadsOneWritePass(),
LoopUnrollPass(2), // force loop unroll for BMC
)
)
Loading

0 comments on commit c2d8ae3

Please sign in to comment.