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

Optimize blocks #919

Merged
merged 51 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
be35cf1
Extracted classes into separate files
keyboardDrummer Jul 24, 2024
52d696b
Print splits and various small fixes
keyboardDrummer Jul 24, 2024
5e2d548
Update tests
keyboardDrummer Jul 24, 2024
c4a0342
Update tests
keyboardDrummer Jul 24, 2024
b89dde0
Add back /print
keyboardDrummer Jul 24, 2024
70ec2a0
Optimize blocks
keyboardDrummer Jul 24, 2024
51d1322
Update expect file
keyboardDrummer Jul 24, 2024
8393fce
Update expect file
keyboardDrummer Jul 24, 2024
1a161c8
Update split expect files
keyboardDrummer Jul 24, 2024
149c07e
Merge branch 'printSplit' into optimizeBlocks
keyboardDrummer Jul 24, 2024
8bed7e5
Fix bug and update test
keyboardDrummer Jul 24, 2024
e98b27e
Move deadVarElim.cs classes into separate files
keyboardDrummer Jul 24, 2024
07ad293
Clean up code in BlockCoalescer and remove duplicate feature in Block…
keyboardDrummer Jul 24, 2024
e08091b
Fix test
keyboardDrummer Jul 24, 2024
83ae368
Refactoring
keyboardDrummer Jul 24, 2024
9e868e4
Remove unused import
keyboardDrummer Jul 25, 2024
2b64f97
Merge commit 'c7878aa7ac1' into optimizeBlocks
keyboardDrummer Jul 25, 2024
e522dbf
Fixes
keyboardDrummer Jul 25, 2024
9cd2a55
Fix
keyboardDrummer Jul 25, 2024
6aa492c
Fix tests
keyboardDrummer Jul 26, 2024
78a851d
Merge remote-tracking branch 'origin/master' into optimizeBlocks
keyboardDrummer Aug 1, 2024
61f5902
Merge branch 'master' into optimizeBlocks
keyboardDrummer Aug 7, 2024
5eed5f6
Configure a VC timeout for all tests
keyboardDrummer Aug 8, 2024
c79011b
Fix concurrency issue in QuantifierInstantiationEngine
keyboardDrummer Aug 8, 2024
2870fb0
Add a process limit timeout
keyboardDrummer Aug 8, 2024
735fee4
Make trace output culture invariant
keyboardDrummer Aug 8, 2024
830ac55
Fix Rlimitouts0.bpl
keyboardDrummer Aug 8, 2024
9d5ef3d
Fix tests
keyboardDrummer Aug 8, 2024
bb5a3a6
Merge remote-tracking branch 'origin/master' into setTimeout
keyboardDrummer Aug 8, 2024
43ca15e
Fix indentation
keyboardDrummer Aug 8, 2024
f98fe32
Fix comp error
keyboardDrummer Aug 9, 2024
b57c1ed
Increase timeout of KeyboardClass test
keyboardDrummer Aug 9, 2024
2b662ef
Add more cancellation
keyboardDrummer Aug 9, 2024
1e9f7ce
Interrupt threads when disposing custom stack scheduler
keyboardDrummer Aug 9, 2024
972c9be
Add blame-hang-timeout to unit test
keyboardDrummer Aug 9, 2024
3d84ae9
Fix
keyboardDrummer Aug 9, 2024
3e9470b
Refactoring
keyboardDrummer Aug 9, 2024
2e8ca55
Fix warning
keyboardDrummer Aug 9, 2024
02b3561
Removed output that causes tests to fail
keyboardDrummer Aug 9, 2024
dabf0ef
Delete accident
keyboardDrummer Aug 10, 2024
00ef399
Add process time limit
keyboardDrummer Aug 10, 2024
8d49878
Merge branch 'setTimeout' into optimizeBlocks
keyboardDrummer Aug 10, 2024
df7861b
Increase timeout for treiber
keyboardDrummer Aug 10, 2024
3fe0fc5
Infinite timeout for treiber-stack
keyboardDrummer Aug 12, 2024
d6711d3
Merge commit 'a3cc4bae85db' into optimizeBlocks
keyboardDrummer Aug 13, 2024
4c2cfee
Reduce changes
keyboardDrummer Aug 13, 2024
24d5acc
Undo changes
keyboardDrummer Aug 13, 2024
7f3d836
Reduce changes
keyboardDrummer Aug 13, 2024
c258866
Merge remote-tracking branch 'origin/master' into optimizeBlocks
keyboardDrummer Aug 13, 2024
100ee6c
Cleanup
keyboardDrummer Aug 15, 2024
b4d6abc
Merge branch 'master' into optimizeBlocks
keyboardDrummer Aug 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Source/Core/AST/AbsyCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3539,6 +3539,11 @@ public GotoCmd(IToken /*!*/ tok, List<Block> /*!*/ blockSeq)
this.labelTargets = blockSeq;
}

public void RemoveTarget(Block b) {
labelNames.Remove(b.Label);
labelTargets.Remove(b);
}

public void AddTarget(Block b)
{
Contract.Requires(b != null);
Expand Down
21 changes: 12 additions & 9 deletions Source/Core/AST/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using Microsoft.Boogie.GraphUtil;

namespace Microsoft.Boogie;
Expand Down Expand Up @@ -501,26 +500,30 @@ public static Graph<Implementation> BuildCallGraph(CoreOptions options, Program

public static Graph<Block> GraphFromBlocks(List<Block> blocks, bool forward = true)
{
Graph<Block> g = new Graph<Block>();
var result = new Graph<Block>();
if (!blocks.Any())
{
return result;
}
void AddEdge(Block a, Block b) {
Contract.Assert(a != null && b != null);
if (forward) {
g.AddEdge(a, b);
result.AddEdge(a, b);
} else {
g.AddEdge(b, a);
result.AddEdge(b, a);
}
}

g.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
foreach (Block b in blocks)
result.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
foreach (var block in blocks)
{
if (b.TransferCmd is GotoCmd gtc)
if (block.TransferCmd is GotoCmd gtc)
{
Contract.Assume(gtc.labelTargets != null);
gtc.labelTargets.ForEach(dest => AddEdge(b, dest));
gtc.labelTargets.ForEach(dest => AddEdge(block, dest));
}
}
return g;
return result;
}

public static Graph<Block /*!*/> /*!*/ GraphFromImpl(Implementation impl, bool forward = true)
Expand Down
168 changes: 82 additions & 86 deletions Source/Core/Analysis/BlockCoalescer.cs
Original file line number Diff line number Diff line change
@@ -1,165 +1,161 @@
#nullable enable

using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace Microsoft.Boogie;

public class BlockCoalescer : ReadOnlyVisitor
{
public static void CoalesceBlocks(Program program)
{
Contract.Requires(program != null);
BlockCoalescer blockCoalescer = new BlockCoalescer();
var blockCoalescer = new BlockCoalescer();
blockCoalescer.Visit(program);
}

private static HashSet<Block /*!*/> /*!*/ ComputeMultiPredecessorBlocks(Implementation /*!*/ impl)
private static HashSet<Block> ComputeMultiPredecessorBlocks(Block rootBlock)
{
Contract.Requires(impl != null);
Contract.Ensures(cce.NonNullElements(Contract.Result<HashSet<Block>>()));
HashSet<Block /*!*/> visitedBlocks = new HashSet<Block /*!*/>();
HashSet<Block /*!*/> multiPredBlocks = new HashSet<Block /*!*/>();
Stack<Block /*!*/> dfsStack = new Stack<Block /*!*/>();
dfsStack.Push(impl.Blocks[0]);
var visitedBlocks = new HashSet<Block /*!*/>();
var result = new HashSet<Block>();
var dfsStack = new Stack<Block>();
dfsStack.Push(rootBlock);
while (dfsStack.Count > 0)
{
Block /*!*/
b = dfsStack.Pop();
Contract.Assert(b != null);
if (visitedBlocks.Contains(b))
var /*!*/ block = dfsStack.Pop();
Contract.Assert(block != null);
if (!visitedBlocks.Add(block))
{
multiPredBlocks.Add(b);
result.Add(block);
continue;
}

visitedBlocks.Add(b);
if (b.TransferCmd == null)
if (block.TransferCmd == null)
{
continue;
}

if (b.TransferCmd is ReturnCmd)
if (block.TransferCmd is ReturnCmd)
{
continue;
}

Contract.Assert(b.TransferCmd is GotoCmd);
GotoCmd gotoCmd = (GotoCmd) b.TransferCmd;
Contract.Assert(block.TransferCmd is GotoCmd);
var gotoCmd = (GotoCmd) block.TransferCmd;
if (gotoCmd.labelTargets == null)
{
continue;
}

foreach (Block /*!*/ succ in gotoCmd.labelTargets)
foreach (var /*!*/ succ in gotoCmd.labelTargets)
{
Contract.Assert(succ != null);
dfsStack.Push(succ);
}
}

return multiPredBlocks;
return result;
}

public override Implementation VisitImplementation(Implementation impl)
{
//Contract.Requires(impl != null);
Contract.Ensures(Contract.Result<Implementation>() != null);
//Console.WriteLine("Procedure {0}", impl.Name);
//Console.WriteLine("Initial number of blocks = {0}", impl.Blocks.Count);

HashSet<Block /*!*/> multiPredBlocks = ComputeMultiPredecessorBlocks(impl);
Contract.Assert(cce.NonNullElements(multiPredBlocks));
HashSet<Block /*!*/> visitedBlocks = new HashSet<Block /*!*/>();
HashSet<Block /*!*/> removedBlocks = new HashSet<Block /*!*/>();
Stack<Block /*!*/> dfsStack = new Stack<Block /*!*/>();
dfsStack.Push(impl.Blocks[0]);
while (dfsStack.Count > 0)
var newBlocks = CoalesceFromRootBlock(impl.Blocks);
impl.Blocks = newBlocks;
foreach (var block in impl.Blocks)
{
Block /*!*/
b = dfsStack.Pop();
Contract.Assert(b != null);
if (visitedBlocks.Contains(b))
if (block.TransferCmd is ReturnCmd)
{
continue;
}

visitedBlocks.Add(b);
if (b.TransferCmd == null)
var gotoCmd = (GotoCmd)block.TransferCmd;
gotoCmd.labelNames = new List<string>();
foreach (var successor in gotoCmd.labelTargets)
{
gotoCmd.labelNames.Add(successor.Label);
}
}
return impl;
}

public static List<Block> CoalesceFromRootBlock(List<Block> blocks)
{
if (!blocks.Any())
{
return blocks;
}
var multiPredecessorBlocks = ComputeMultiPredecessorBlocks(blocks[0]);
Contract.Assert(cce.NonNullElements(multiPredecessorBlocks));
var visitedBlocks = new HashSet<Block>();
var removedBlocks = new HashSet<Block>();
var toVisit = new Stack<Block>();
toVisit.Push(blocks[0]);
while (toVisit.Count > 0)
{
var block = toVisit.Pop();
Contract.Assert(block != null);
if (!visitedBlocks.Add(block))
{
continue;
}

if (b.TransferCmd is ReturnCmd)
if (block.TransferCmd == null)
{
continue;
}

Contract.Assert(b.TransferCmd is GotoCmd);
GotoCmd gotoCmd = (GotoCmd) b.TransferCmd;
if (block.TransferCmd is ReturnCmd)
{
continue;
}

Contract.Assert(block.TransferCmd is GotoCmd);
var gotoCmd = (GotoCmd) block.TransferCmd;
if (gotoCmd.labelTargets == null)
{
continue;
}

if (gotoCmd.labelTargets.Count == 1)
if (gotoCmd.labelTargets.Count != 1)
{
Block /*!*/
succ = cce.NonNull(gotoCmd.labelTargets[0]);
if (!multiPredBlocks.Contains(succ))
foreach (var aSuccessor in gotoCmd.labelTargets)
{
foreach (Cmd /*!*/ cmd in succ.Cmds)
{
Contract.Assert(cmd != null);
b.Cmds.Add(cmd);
}

b.TransferCmd = succ.TransferCmd;
if (!b.tok.IsValid && succ.tok.IsValid)
{
b.tok = succ.tok;
b.Label = succ.Label;
}

removedBlocks.Add(succ);
dfsStack.Push(b);
visitedBlocks.Remove(b);
continue;
Contract.Assert(aSuccessor != null);
toVisit.Push(aSuccessor);
}
continue;
}

foreach (Block /*!*/ succ in gotoCmd.labelTargets)
var successor = cce.NonNull(gotoCmd.labelTargets[0]);
if (multiPredecessorBlocks.Contains(successor))
{
Contract.Assert(succ != null);
dfsStack.Push(succ);
toVisit.Push(successor);
continue;
}
}

List<Block /*!*/> newBlocks = new List<Block /*!*/>();
foreach (Block /*!*/ b in impl.Blocks)
{
Contract.Assert(b != null);
if (visitedBlocks.Contains(b) && !removedBlocks.Contains(b))
block.Cmds.AddRange(successor.Cmds);
block.TransferCmd = successor.TransferCmd;
if (!block.tok.IsValid && successor.tok.IsValid)
{
newBlocks.Add(b);
block.tok = successor.tok;
block.Label = successor.Label;
}

removedBlocks.Add(successor);
toVisit.Push(block);
visitedBlocks.Remove(block);
}

impl.Blocks = newBlocks;
foreach (Block b in impl.Blocks)
var newBlocks = new List<Block>();
foreach (var block in blocks)
{
if (b.TransferCmd is ReturnCmd)
{
continue;
}

GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
gotoCmd.labelNames = new List<string>();
foreach (Block succ in gotoCmd.labelTargets)
Contract.Assert(block != null);
if (visitedBlocks.Contains(block) && !removedBlocks.Contains(block))
{
gotoCmd.labelNames.Add(succ.Label);
newBlocks.Add(block);
}
}

// Console.WriteLine("Final number of blocks = {0}", impl.Blocks.Count);
return impl;
return newBlocks;
}
}
2 changes: 1 addition & 1 deletion Source/Core/Analysis/LiveVariableAnalysis/GenKillWeight.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is this change? A change in line ending?


namespace Microsoft.Boogie;
Expand Down
14 changes: 0 additions & 14 deletions Source/Core/Analysis/LiveVariableAnalysis/InterProcGenKill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Microsoft.Boogie
{
// Interprocedural Gen/Kill Analysis
public class InterProcGenKill
{
private CoreOptions options;
Expand Down Expand Up @@ -554,19 +553,6 @@ public void Compute()
varsLiveAtEntry.Add(cfg.impl.Name, lv);
varsLiveSummary.Add(cfg.impl.Name, cfg.summary);
}

/*
foreach(Block/*!*/
/* b in mainImpl.Blocks){
Contract.Assert(b != null);
//Set<Variable!> lv = cfg.weightBefore[b].getLiveVars();
b.liveVarsBefore = procICFG[mainImpl.Name].liveVarsAfter[b];
//foreach(GlobalVariable/*!*/
/* v in program.GlobalVariables){Contract.Assert(v != null);
// b.liveVarsBefore.Add(v);
//}
}
*/
}

// Called when summaries have already been computed
Expand Down
7 changes: 4 additions & 3 deletions Source/ExecutionEngine/ExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public void CoalesceBlocks(Program program)
Options.OutputWriter.WriteLine("Coalescing blocks...");
}

Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
BlockCoalescer.CoalesceBlocks(program);
}
}

Expand All @@ -240,7 +240,7 @@ public void CollectModSets(Program program)

public void EliminateDeadVariables(Program program)
{
Microsoft.Boogie.UnusedVarEliminator.Eliminate(program);
UnusedVarEliminator.Eliminate(program);
}

public void PrintBplFile(string filename, Program program,
Expand Down Expand Up @@ -737,14 +737,15 @@ public async Task<IReadOnlyList<IVerificationTask>> GetVerificationTasks(Program
var writer = TextWriter.Null;
var vcGenerator = new VerificationConditionGenerator(processedProgram.Program, CheckerPool);


var run = new ImplementationRun(implementation, writer);
var collector = new VerificationResultCollector(Options);
vcGenerator.PrepareImplementation(run, collector, out _,
out var gotoCmdOrigins,
out var modelViewInfo);

ConditionGeneration.ResetPredecessors(run.Implementation.Blocks);
var splits = ManualSplitFinder.FocusAndSplit(Options, run, gotoCmdOrigins, vcGenerator).ToList();
var splits = ManualSplitFinder.FocusAndSplit(program, Options, run, gotoCmdOrigins, vcGenerator).ToList();
for (var index = 0; index < splits.Count; index++) {
var split = splits[index];
split.SplitIndex = index;
Expand Down
2 changes: 1 addition & 1 deletion Source/ExecutionEngine/VerificationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public VerificationTask(ExecutionEngine engine, ProcessedProgram processedProgra

public IVerificationTask FromSeed(int newSeed)
{
var split = new ManualSplit(Split.Options, Split.Blocks, Split.GotoCmdOrigins,
var split = new ManualSplit(Split.Options, () => Split.Blocks, Split.GotoCmdOrigins,
Split.parent, Split.Run, Split.Token, newSeed);
split.SplitIndex = Split.SplitIndex;
return new VerificationTask(engine, ProcessedProgram, split, modelViewInfo);
Expand Down
4 changes: 2 additions & 2 deletions Source/UnitTests/ExecutionEngineTests/ExecutionEngineTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ procedure Procedure(y: int)
var tasks = await engine.GetVerificationTasks(program);

// The first split is empty. Maybe it can be optimized away
Assert.AreEqual(5, tasks.Count);
Assert.AreEqual(4, tasks.Count);

var outcomes = new List<SolverOutcome> { SolverOutcome.Valid, SolverOutcome.Invalid, SolverOutcome.Valid, SolverOutcome.Invalid, SolverOutcome.Valid };
var outcomes = new List<SolverOutcome> { SolverOutcome.Invalid, SolverOutcome.Valid, SolverOutcome.Invalid, SolverOutcome.Valid };
for (var index = 0; index < outcomes.Count; index++)
{
var result0 = await tasks[index].TryRun()!.ToTask();
Expand Down
Loading
Loading