From 791adc9910560834c8159f892fad1b8acf0965dd Mon Sep 17 00:00:00 2001 From: Nadia Polikarpova Date: Sun, 16 Sep 2012 14:25:58 +0200 Subject: Added the new keyword (calc) to Util --- Util/Emacs/dafny-mode.el | 2 +- Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs | 3 ++- Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs | 1 + Util/latex/dafny.sty | 2 +- Util/vim/syntax/dafny.vim | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) (limited to 'Util') diff --git a/Util/Emacs/dafny-mode.el b/Util/Emacs/dafny-mode.el index e658bfe9..1e197644 100644 --- a/Util/Emacs/dafny-mode.el +++ b/Util/Emacs/dafny-mode.el @@ -38,7 +38,7 @@ )) . font-lock-builtin-face) `(,(dafny-regexp-opt '( "assert" "assume" "break" "choose" "then" "else" "if" "label" "return" "while" "print" "where" - "old" "forall" "exists" "new" "parallel" "in" "this" "fresh" + "old" "forall" "exists" "new" "parallel" "calc" "in" "this" "fresh" "match" "case" "false" "true" "null")) . font-lock-keyword-face) `(,(dafny-regexp-opt '("array" "array2" "array3" "bool" "multiset" "map" "nat" "int" "object" "set" "seq")) . font-lock-type-face) ) diff --git a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs index 81dd0dd1..8c3eee59 100644 --- a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs +++ b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs @@ -28,7 +28,7 @@ namespace Demo "in", "forall", "exists", "seq", "set", "map", "multiset", "array", "array2", "array3", "match", "case", - "fresh", "old", "choose", "where" + "fresh", "old", "choose", "where", "calc" ); StringLiteral s = new StringLiteral("String", "'", StringFlags.AllowsDoubledQuote); @@ -289,6 +289,7 @@ namespace Demo | "label" | "return" | "parallel" + | "calc" | "print" | "returns" | "requires" diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs index 5853f180..19f98ff7 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs +++ b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs @@ -231,6 +231,7 @@ namespace DafnyLanguage case "assume": case "bool": case "break": + case "calc": case "case": case "choose": case "class": diff --git a/Util/latex/dafny.sty b/Util/latex/dafny.sty index 81b04694..d60488d1 100644 --- a/Util/latex/dafny.sty +++ b/Util/latex/dafny.sty @@ -13,7 +13,7 @@ % expressions match,case,false,true,null,old,fresh,choose,this, % statements - assert,assume,print,new,if,then,else,while,invariant,break,label,return,parallel,where + assert,assume,print,new,if,then,else,while,invariant,break,label,return,parallel,where,calc }, literate=% {:}{$\colon$}1 diff --git a/Util/vim/syntax/dafny.vim b/Util/vim/syntax/dafny.vim index c61e5ebc..cc1c9d79 100644 --- a/Util/vim/syntax/dafny.vim +++ b/Util/vim/syntax/dafny.vim @@ -9,7 +9,7 @@ syntax keyword dafnyFunction function predicate copredicate method constructor syntax keyword dafnyTypeDef class datatype codatatype type module import opened as default syntax keyword dafnyConditional if then else match case syntax keyword dafnyRepeat while parallel -syntax keyword dafnyStatement assume assert return new print break label where +syntax keyword dafnyStatement assume assert return new print break label where calc syntax keyword dafnyKeyword var ghost returns null static this refines syntax keyword dafnyType bool nat int seq set multiset object array array2 array3 map syntax keyword dafnyLogic requires ensures modifies reads decreases invariant -- cgit v1.2.3 From 8cc9f82219a818ef54dda2c59b3a56d07114c3fb Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 21 Sep 2012 14:46:50 -0700 Subject: DafnyExtension: adding some missing keywords (for imports) --- Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Util') diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs index 19f98ff7..ec1514ae 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs +++ b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs @@ -227,6 +227,7 @@ namespace DafnyLanguage #region keywords case "allocated": case "array": + case "as": case "assert": case "assume": case "bool": @@ -250,7 +251,7 @@ namespace DafnyLanguage case "function": case "ghost": case "if": - case "imports": + case "import": case "in": case "int": case "invariant": @@ -265,6 +266,7 @@ namespace DafnyLanguage case "null": case "object": case "old": + case "opened": case "parallel": case "predicate": case "print": -- cgit v1.2.3 From 623a87c132abec61b5c74a6a00a7b162073a6a8d Mon Sep 17 00:00:00 2001 From: boehmes Date: Thu, 27 Sep 2012 17:13:42 +0200 Subject: Boogie: new syntax for integer division and modulus: use div and mod instead of / and % --- Binaries/DafnyPrelude.bpl | 12 ++-- Source/Core/AbsyExpr.cs | 4 +- Source/Core/BoogiePL.atg | 4 +- Source/Core/Parser.cs | 4 +- Source/Core/Scanner.cs | 82 ++++++++++------------ Source/Core/Util.cs | 4 +- Test/livevars/bla1.bpl | 2 +- Test/livevars/daytona_bug2_ioctl_example_1.bpl | 2 +- Test/livevars/daytona_bug2_ioctl_example_2.bpl | 2 +- Test/livevars/stack_overflow.bpl | 2 +- Test/prover/EQ_v2.Eval__v4.Eval_out.bpl | 4 +- Test/test0/Answer | 8 ++- Test/test0/BadLabels1.bpl | 2 +- Test/test0/PrettyPrint.bpl | 7 +- Test/test2/strings-no-where.bpl | 20 +++--- Test/test2/strings-where.bpl | 20 +++--- Util/Emacs/boogie-mode.el | 2 +- .../VS2010/Boogie/BoogieLanguageService/Grammar.cs | 7 +- Util/latex/boogie.sty | 2 +- Util/vim/syntax/boogie.vim | 2 +- 20 files changed, 98 insertions(+), 94 deletions(-) (limited to 'Util') diff --git a/Binaries/DafnyPrelude.bpl b/Binaries/DafnyPrelude.bpl index ca526173..53e8e86a 100644 --- a/Binaries/DafnyPrelude.bpl +++ b/Binaries/DafnyPrelude.bpl @@ -613,15 +613,15 @@ var $Tick: TickType; // -- Arithmetic ------------------------------------------------- // --------------------------------------------------------------- -// the connection between % and / -axiom (forall x:int, y:int :: {x % y} {x / y} x % y == x - x / y * y); +// the connection between mod and div +axiom (forall x:int, y:int :: {x mod y} {x div y} x mod y == x - x div y * y); // remainder is always Euclidean Modulus. -axiom (forall x:int, y:int :: {x % y} 0 < y ==> 0 <= x % y && x % y < y); -axiom (forall x:int, y:int :: {x % y} y < 0 ==> 0 <= x % y && x % y < -y); +axiom (forall x:int, y:int :: {x mod y} 0 < y ==> 0 <= x mod y && x mod y < y); +axiom (forall x:int, y:int :: {x mod y} y < 0 ==> 0 <= x mod y && x mod y < -y); -// the following axiom has some unfortunate matching, but it does state a property about % that +// the following axiom has some unfortunate matching, but it does state a property about mod that // is sometimes useful -axiom (forall a: int, b: int, d: int :: { a % d, b % d } 2 <= d && a % d == b % d && a < b ==> a + d <= b); +axiom (forall a: int, b: int, d: int :: { a mod d, b mod d } 2 <= d && a mod d == b mod d && a < b ==> a + d <= b); // --------------------------------------------------------------- diff --git a/Source/Core/AbsyExpr.cs b/Source/Core/AbsyExpr.cs index f2ed5790..d2b8506a 100644 --- a/Source/Core/AbsyExpr.cs +++ b/Source/Core/AbsyExpr.cs @@ -1214,9 +1214,9 @@ namespace Microsoft.Boogie { case Opcode.Mul: return "*"; case Opcode.Div: - return "/"; + return "div"; case Opcode.Mod: - return "%"; + return "mod"; case Opcode.Eq: return "=="; case Opcode.Neq: diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg index a2ad40f6..26b70bd3 100644 --- a/Source/Core/BoogiePL.atg +++ b/Source/Core/BoogiePL.atg @@ -1171,8 +1171,8 @@ Factor MulOp = (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) - | "/" (. x = t; op=BinaryOperator.Opcode.Div; .) - | "%" (. x = t; op=BinaryOperator.Opcode.Mod; .) + | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) + | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) ) . diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs index e95bccda..8638d9c3 100644 --- a/Source/Core/Parser.cs +++ b/Source/Core/Parser.cs @@ -2157,8 +2157,8 @@ public class Errors { case 68: s = "\"++\" expected"; break; case 69: s = "\"+\" expected"; break; case 70: s = "\"-\" expected"; break; - case 71: s = "\"/\" expected"; break; - case 72: s = "\"%\" expected"; break; + case 71: s = "\"div\" expected"; break; + case 72: s = "\"mod\" expected"; break; case 73: s = "\"!\" expected"; break; case 74: s = "\"\\u00ac\" expected"; break; case 75: s = "\"false\" expected"; break; diff --git a/Source/Core/Scanner.cs b/Source/Core/Scanner.cs index cfef86c7..b9f4ec42 100644 --- a/Source/Core/Scanner.cs +++ b/Source/Core/Scanner.cs @@ -262,36 +262,34 @@ public class Scanner { start[59] = 12; start[40] = 13; start[41] = 14; - start[58] = 49; + start[58] = 47; start[44] = 15; start[91] = 16; start[93] = 17; - start[60] = 50; - start[62] = 51; + start[60] = 48; + start[62] = 49; start[123] = 18; - start[125] = 52; - start[61] = 53; + start[125] = 50; + start[61] = 51; start[42] = 19; start[8660] = 22; start[8658] = 24; start[8656] = 25; start[38] = 26; start[8743] = 28; - start[124] = 54; + start[124] = 52; start[8744] = 30; - start[33] = 55; + start[33] = 53; start[8800] = 34; start[8804] = 35; start[8805] = 36; - start[43] = 56; + start[43] = 54; start[45] = 38; - start[47] = 39; - start[37] = 40; - start[172] = 41; - start[8704] = 44; - start[8707] = 45; - start[955] = 46; - start[8226] = 48; + start[172] = 39; + start[8704] = 42; + start[8707] = 43; + start[955] = 44; + start[8226] = 46; start[Buffer.EOF] = -1; } @@ -519,6 +517,8 @@ public class Scanner { case "havoc": t.kind = 46; break; case "call": t.kind = 48; break; case "forall": t.kind = 49; break; + case "div": t.kind = 71; break; + case "mod": t.kind = 72; break; case "false": t.kind = 75; break; case "true": t.kind = 76; break; case "old": t.kind = 77; break; @@ -658,68 +658,64 @@ public class Scanner { case 38: {t.kind = 70; break;} case 39: - {t.kind = 71; break;} - case 40: - {t.kind = 72; break;} - case 41: {t.kind = 74; break;} - case 42: + case 40: {t.kind = 78; break;} - case 43: + case 41: {t.kind = 79; break;} - case 44: + case 42: {t.kind = 81; break;} - case 45: + case 43: {t.kind = 83; break;} - case 46: + case 44: {t.kind = 85; break;} - case 47: + case 45: {t.kind = 86; break;} - case 48: + case 46: {t.kind = 87; break;} - case 49: + case 47: recEnd = pos; recKind = 10; if (ch == '=') {AddCh(); goto case 20;} - else if (ch == ':') {AddCh(); goto case 47;} + else if (ch == ':') {AddCh(); goto case 45;} else {t.kind = 10; break;} - case 50: + case 48: recEnd = pos; recKind = 17; - if (ch == '=') {AddCh(); goto case 57;} + if (ch == '=') {AddCh(); goto case 55;} else if (ch == ':') {AddCh(); goto case 33;} else {t.kind = 17; break;} - case 51: + case 49: recEnd = pos; recKind = 18; if (ch == '=') {AddCh(); goto case 31;} else {t.kind = 18; break;} - case 52: + case 50: recEnd = pos; recKind = 26; - if (ch == '|') {AddCh(); goto case 43;} + if (ch == '|') {AddCh(); goto case 41;} else {t.kind = 26; break;} - case 53: + case 51: recEnd = pos; recKind = 29; - if (ch == '=') {AddCh(); goto case 58;} + if (ch == '=') {AddCh(); goto case 56;} else {t.kind = 29; break;} - case 54: + case 52: if (ch == '|') {AddCh(); goto case 29;} - else if (ch == '{') {AddCh(); goto case 42;} + else if (ch == '{') {AddCh(); goto case 40;} else {goto case 0;} - case 55: + case 53: recEnd = pos; recKind = 73; if (ch == '=') {AddCh(); goto case 32;} else {t.kind = 73; break;} - case 56: + case 54: recEnd = pos; recKind = 69; if (ch == '+') {AddCh(); goto case 37;} else {t.kind = 69; break;} - case 57: + case 55: recEnd = pos; recKind = 61; - if (ch == '=') {AddCh(); goto case 59;} + if (ch == '=') {AddCh(); goto case 57;} else {t.kind = 61; break;} - case 58: + case 56: recEnd = pos; recKind = 60; if (ch == '>') {AddCh(); goto case 23;} else {t.kind = 60; break;} - case 59: + case 57: recEnd = pos; recKind = 54; if (ch == '>') {AddCh(); goto case 21;} else {t.kind = 54; break;} diff --git a/Source/Core/Util.cs b/Source/Core/Util.cs index a8e12f63..f8b8b82b 100644 --- a/Source/Core/Util.cs +++ b/Source/Core/Util.cs @@ -451,7 +451,7 @@ namespace Microsoft.Boogie { op = " && "; break; case Microsoft.Boogie.BinaryOperator.Opcode.Div: - op = " / "; + op = " div "; break; case Microsoft.Boogie.BinaryOperator.Opcode.Eq: op = " == "; @@ -475,7 +475,7 @@ namespace Microsoft.Boogie { op = " < "; break; case Microsoft.Boogie.BinaryOperator.Opcode.Mod: - op = " % "; + op = " mod "; break; case Microsoft.Boogie.BinaryOperator.Opcode.Mul: op = " * "; diff --git a/Test/livevars/bla1.bpl b/Test/livevars/bla1.bpl index 2854e5df..12ccc44a 100644 --- a/Test/livevars/bla1.bpl +++ b/Test/livevars/bla1.bpl @@ -471,7 +471,7 @@ function {:inline true} INT_NEQ(x:int, y:int) returns (bool) {x != y} function {:inline true} INT_ADD(x:int, y:int) returns (int) {x + y} function {:inline true} INT_SUB(x:int, y:int) returns (int) {x - y} function {:inline true} INT_MULT(x:int, y:int) returns (int) {x * y} -function {:inline true} INT_DIV(x:int, y:int) returns (int) {x / y} +function {:inline true} INT_DIV(x:int, y:int) returns (int) {x div y} function {:inline true} INT_LT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_ULT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_LEQ(x:int, y:int) returns (bool) {x <= y} diff --git a/Test/livevars/daytona_bug2_ioctl_example_1.bpl b/Test/livevars/daytona_bug2_ioctl_example_1.bpl index 1decba12..ae8ff08c 100644 --- a/Test/livevars/daytona_bug2_ioctl_example_1.bpl +++ b/Test/livevars/daytona_bug2_ioctl_example_1.bpl @@ -510,7 +510,7 @@ function {:inline true} INT_NEQ(x:int, y:int) returns (bool) {x != y} function {:inline true} INT_ADD(x:int, y:int) returns (int) {x + y} function {:inline true} INT_SUB(x:int, y:int) returns (int) {x - y} function {:inline true} INT_MULT(x:int, y:int) returns (int) {x * y} -function {:inline true} INT_DIV(x:int, y:int) returns (int) {x / y} +function {:inline true} INT_DIV(x:int, y:int) returns (int) {x div y} function {:inline true} INT_LT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_ULT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_LEQ(x:int, y:int) returns (bool) {x <= y} diff --git a/Test/livevars/daytona_bug2_ioctl_example_2.bpl b/Test/livevars/daytona_bug2_ioctl_example_2.bpl index 0b49364b..44e51827 100644 --- a/Test/livevars/daytona_bug2_ioctl_example_2.bpl +++ b/Test/livevars/daytona_bug2_ioctl_example_2.bpl @@ -521,7 +521,7 @@ function {:inline true} INT_NEQ(x:int, y:int) returns (bool) {x != y} function {:inline true} INT_ADD(x:int, y:int) returns (int) {x + y} function {:inline true} INT_SUB(x:int, y:int) returns (int) {x - y} function {:inline true} INT_MULT(x:int, y:int) returns (int) {x * y} -function {:inline true} INT_DIV(x:int, y:int) returns (int) {x / y} +function {:inline true} INT_DIV(x:int, y:int) returns (int) {x div y} function {:inline true} INT_LT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_ULT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_LEQ(x:int, y:int) returns (bool) {x <= y} diff --git a/Test/livevars/stack_overflow.bpl b/Test/livevars/stack_overflow.bpl index 242acd65..fae3e863 100644 --- a/Test/livevars/stack_overflow.bpl +++ b/Test/livevars/stack_overflow.bpl @@ -831,7 +831,7 @@ function {:inline true} INT_NEQ(x:int, y:int) returns (bool) {x != y} function {:inline true} INT_ADD(x:int, y:int) returns (int) {x + y} function {:inline true} INT_SUB(x:int, y:int) returns (int) {x - y} function {:inline true} INT_MULT(x:int, y:int) returns (int) {x * y} -function {:inline true} INT_DIV(x:int, y:int) returns (int) {x / y} +function {:inline true} INT_DIV(x:int, y:int) returns (int) {x div y} function {:inline true} INT_LT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_ULT(x:int, y:int) returns (bool) {x < y} function {:inline true} INT_LEQ(x:int, y:int) returns (bool) {x <= y} diff --git a/Test/prover/EQ_v2.Eval__v4.Eval_out.bpl b/Test/prover/EQ_v2.Eval__v4.Eval_out.bpl index e4da94f4..e53e00b4 100644 --- a/Test/prover/EQ_v2.Eval__v4.Eval_out.bpl +++ b/Test/prover/EQ_v2.Eval__v4.Eval_out.bpl @@ -382,7 +382,7 @@ axiom (forall x: int, y: int :: { v4.INT_SUB(x, y): int } v4.INT_SUB(x, y): int axiom (forall x: int, y: int :: { v4.INT_MULT(x, y): int } v4.INT_MULT(x, y): int == x * y); -axiom (forall x: int, y: int :: { v4.INT_DIV(x, y): int } v4.INT_DIV(x, y): int == x / y); +axiom (forall x: int, y: int :: { v4.INT_DIV(x, y): int } v4.INT_DIV(x, y): int == x div y); axiom (forall x: int, y: int :: { v4.INT_LT(x, y): bool } v4.INT_LT(x, y): bool <==> x < y); @@ -1173,7 +1173,7 @@ axiom (forall x: int, y: int :: { v4.INT_SUB(x, y): int } v4.INT_SUB(x, y): int axiom (forall x: int, y: int :: { v4.INT_MULT(x, y): int } v4.INT_MULT(x, y): int == x * y); -axiom (forall x: int, y: int :: { v4.INT_DIV(x, y): int } v4.INT_DIV(x, y): int == x / y); +axiom (forall x: int, y: int :: { v4.INT_DIV(x, y): int } v4.INT_DIV(x, y): int == x div y); axiom (forall x: int, y: int :: { v4.INT_LT(x, y): bool } v4.INT_LT(x, y): bool <==> x < y); diff --git a/Test/test0/Answer b/Test/test0/Answer index 51a139b7..d57e7647 100644 --- a/Test/test0/Answer +++ b/Test/test0/Answer @@ -48,9 +48,13 @@ axiom x * y * z == x * y * z; axiom x * y * z * x == x * y * z; -axiom x / y / z == x / (y / z); +axiom x div y div z == x div (y div z); -axiom x / y / (z / x) == x / y / z; +axiom x div y div (z div x) == x div y div z; + +axiom x + y mod z == y mod z + x; + +axiom (x + y) mod z == x mod z + y mod z; axiom x - y - z == x - (y - z); diff --git a/Test/test0/BadLabels1.bpl b/Test/test0/BadLabels1.bpl index 28fb47b8..c040ce26 100644 --- a/Test/test0/BadLabels1.bpl +++ b/Test/test0/BadLabels1.bpl @@ -28,7 +28,7 @@ procedure P1(y: int) { K: goto A; - if (y % 2 == 0) { + if (y mod 2 == 0) { goto L; M: } diff --git a/Test/test0/PrettyPrint.bpl b/Test/test0/PrettyPrint.bpl index a1f941d8..955faad8 100644 --- a/Test/test0/PrettyPrint.bpl +++ b/Test/test0/PrettyPrint.bpl @@ -11,8 +11,11 @@ axiom (x * y) + z == (x + y) * z; axiom x * y * z == (x * (y * z)); axiom (x * y) * (z * x) == (x * y) * z; -axiom x / y / z == (x / (y / z)); -axiom (x / y) / (z / x) == (x / y) / z; +axiom x div y div z == (x div (y div z)); +axiom (x div y) div (z div x) == (x div y) div z; + +axiom x + y mod z == ((y mod z) + x); +axiom (x + y) mod z == (x mod z) + (y mod z); axiom x - y - z == (x - (y - z)); axiom (x - y) - (z - x) == (x - y) - z; diff --git a/Test/test2/strings-no-where.bpl b/Test/test2/strings-no-where.bpl index ff723db2..c8ef88c8 100644 --- a/Test/test2/strings-no-where.bpl +++ b/Test/test2/strings-no-where.bpl @@ -330,23 +330,23 @@ function #shl(int, int) returns (int); function #shr(int, int) returns (int); -axiom (forall x: int, y: int :: { x % y } { x / y } x % y == x - x / y * y); +axiom (forall x: int, y: int :: { x mod y } { x div y } x mod y == x - x div y * y); -axiom (forall x: int, y: int :: { x % y } 0 <= x && 0 < y ==> 0 <= x % y && x % y < y); +axiom (forall x: int, y: int :: { x mod y } 0 <= x && 0 < y ==> 0 <= x mod y && x mod y < y); -axiom (forall x: int, y: int :: { x % y } 0 <= x && y < 0 ==> 0 <= x % y && x % y < 0 - y); +axiom (forall x: int, y: int :: { x mod y } 0 <= x && y < 0 ==> 0 <= x mod y && x mod y < 0 - y); -axiom (forall x: int, y: int :: { x % y } x <= 0 && 0 < y ==> 0 - y < x % y && x % y <= 0); +axiom (forall x: int, y: int :: { x mod y } x <= 0 && 0 < y ==> 0 - y < x mod y && x mod y <= 0); -axiom (forall x: int, y: int :: { x % y } x <= 0 && y < 0 ==> y < x % y && x % y <= 0); +axiom (forall x: int, y: int :: { x mod y } x <= 0 && y < 0 ==> y < x mod y && x mod y <= 0); -axiom (forall x: int, y: int :: { (x + y) % y } 0 <= x && 0 <= y ==> (x + y) % y == x % y); +axiom (forall x: int, y: int :: { (x + y) mod y } 0 <= x && 0 <= y ==> (x + y) mod y == x mod y); -axiom (forall x: int, y: int :: { (y + x) % y } 0 <= x && 0 <= y ==> (y + x) % y == x % y); +axiom (forall x: int, y: int :: { (y + x) mod y } 0 <= x && 0 <= y ==> (y + x) mod y == x mod y); -axiom (forall x: int, y: int :: { (x - y) % y } 0 <= x - y && 0 <= y ==> (x - y) % y == x % y); +axiom (forall x: int, y: int :: { (x - y) mod y } 0 <= x - y && 0 <= y ==> (x - y) mod y == x mod y); -axiom (forall a: int, b: int, d: int :: { a % d,b % d } 2 <= d && a % d == b % d && a < b ==> a + d <= b); +axiom (forall a: int, b: int, d: int :: { a mod d,b mod d } 2 <= d && a mod d == b mod d && a < b ==> a + d <= b); axiom (forall i: int :: { #shl(i, 0) } #shl(i, 0) == i); @@ -354,7 +354,7 @@ axiom (forall i: int, j: int :: 0 <= j ==> #shl(i, j + 1) == #shl(i, j) * 2); axiom (forall i: int :: { #shr(i, 0) } #shr(i, 0) == i); -axiom (forall i: int, j: int :: 0 <= j ==> #shr(i, j + 1) == #shr(i, j) / 2); +axiom (forall i: int, j: int :: 0 <= j ==> #shr(i, j + 1) == #shr(i, j) div 2); const unique $UnknownRef: ref; diff --git a/Test/test2/strings-where.bpl b/Test/test2/strings-where.bpl index da529b84..05e392cb 100644 --- a/Test/test2/strings-where.bpl +++ b/Test/test2/strings-where.bpl @@ -330,23 +330,23 @@ function #shl(int, int) returns (int); function #shr(int, int) returns (int); -axiom (forall x: int, y: int :: { x % y } { x / y } x % y == x - x / y * y); +axiom (forall x: int, y: int :: { x mod y } { x div y } x mod y == x - x div y * y); -axiom (forall x: int, y: int :: { x % y } 0 <= x && 0 < y ==> 0 <= x % y && x % y < y); +axiom (forall x: int, y: int :: { x mod y } 0 <= x && 0 < y ==> 0 <= x mod y && x mod y < y); -axiom (forall x: int, y: int :: { x % y } 0 <= x && y < 0 ==> 0 <= x % y && x % y < 0 - y); +axiom (forall x: int, y: int :: { x mod y } 0 <= x && y < 0 ==> 0 <= x mod y && x mod y < 0 - y); -axiom (forall x: int, y: int :: { x % y } x <= 0 && 0 < y ==> 0 - y < x % y && x % y <= 0); +axiom (forall x: int, y: int :: { x mod y } x <= 0 && 0 < y ==> 0 - y < x mod y && x mod y <= 0); -axiom (forall x: int, y: int :: { x % y } x <= 0 && y < 0 ==> y < x % y && x % y <= 0); +axiom (forall x: int, y: int :: { x mod y } x <= 0 && y < 0 ==> y < x mod y && x mod y <= 0); -axiom (forall x: int, y: int :: { (x + y) % y } 0 <= x && 0 <= y ==> (x + y) % y == x % y); +axiom (forall x: int, y: int :: { (x + y) mod y } 0 <= x && 0 <= y ==> (x + y) mod y == x mod y); -axiom (forall x: int, y: int :: { (y + x) % y } 0 <= x && 0 <= y ==> (y + x) % y == x % y); +axiom (forall x: int, y: int :: { (y + x) mod y } 0 <= x && 0 <= y ==> (y + x) mod y == x mod y); -axiom (forall x: int, y: int :: { (x - y) % y } 0 <= x - y && 0 <= y ==> (x - y) % y == x % y); +axiom (forall x: int, y: int :: { (x - y) mod y } 0 <= x - y && 0 <= y ==> (x - y) mod y == x mod y); -axiom (forall a: int, b: int, d: int :: { a % d,b % d } 2 <= d && a % d == b % d && a < b ==> a + d <= b); +axiom (forall a: int, b: int, d: int :: { a mod d,b mod d } 2 <= d && a mod d == b mod d && a < b ==> a + d <= b); axiom (forall i: int :: { #shl(i, 0) } #shl(i, 0) == i); @@ -354,7 +354,7 @@ axiom (forall i: int, j: int :: 0 <= j ==> #shl(i, j + 1) == #shl(i, j) * 2); axiom (forall i: int :: { #shr(i, 0) } #shr(i, 0) == i); -axiom (forall i: int, j: int :: 0 <= j ==> #shr(i, j + 1) == #shr(i, j) / 2); +axiom (forall i: int, j: int :: 0 <= j ==> #shr(i, j + 1) == #shr(i, j) div 2); const unique $UnknownRef: ref; diff --git a/Util/Emacs/boogie-mode.el b/Util/Emacs/boogie-mode.el index 5b60dcab..86721a74 100644 --- a/Util/Emacs/boogie-mode.el +++ b/Util/Emacs/boogie-mode.el @@ -36,7 +36,7 @@ )) . font-lock-builtin-face) `(,(boogie-regexp-opt '( "assert" "assume" "break" "call" "then" "else" "havoc" "if" "goto" "return" "while" - "old" "forall" "exists" "lambda" "cast" + "old" "forall" "exists" "lambda" "cast" "div" "mod" "false" "true")) . font-lock-keyword-face) `(,(boogie-regexp-opt '("bool" "int" "bv0" "bv1" "bv2" "bv3" "bv4" "bv5" "bv6" "bv7" "bv8" "bv9" diff --git a/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs b/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs index 02d14b93..4e38f654 100644 --- a/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs +++ b/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs @@ -23,13 +23,14 @@ namespace Demo "bv30", "bv31", "bv32", "bv64", "call", "complete", "const", + "div", "else", "ensures", "exists", "extends", "false", "forall", "free", "function", "goto", "havoc", "if", "implementation", "int", "invariant", "lambda", - "modifies", + "mod", "modifies", "old", "procedure", "requires", @@ -181,7 +182,7 @@ namespace Demo identList.Rule = MakePlusRule(identList, comma, ident); NewStmt.Rule = "new" + QualifiedName + GenericsPostfix.Q() + LParen + expressionList.Q() + RParen; NewArrStmt.Rule = "new" + QualifiedName + GenericsPostfix.Q() + LBracket + expressionList.Q() + RBracket; - BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "%" | "^" | "&" | "|" + BinOp.Rule = ToTerm("+") | "-" | "*" | "div" | "mod" | "^" | "&" | "|" | "&&" | "||" | "==" | "!=" | greater | less | ">=" | "<=" | "is" | "=" | "+=" | "-=" @@ -376,7 +377,7 @@ namespace Demo #region 5. Operators precedence RegisterOperators(1, "<==>"); RegisterOperators(2, "+", "-"); - RegisterOperators(3, "*", "/", "%", "!!"); + RegisterOperators(3, "*", "div", "mod", "!!"); RegisterOperators(4, Associativity.Right, "^"); RegisterOperators(5, "||"); RegisterOperators(6, "&&"); diff --git a/Util/latex/boogie.sty b/Util/latex/boogie.sty index 45eb050d..43336262 100644 --- a/Util/latex/boogie.sty +++ b/Util/latex/boogie.sty @@ -34,7 +34,7 @@ procedure,implementation, requires,modifies,ensures,free, % expressions - false,true,null,old,then, + false,true,null,old,then,div,mod, % statements assert,assume,havoc,call,if,else,while,invariant,break,return,goto, }, diff --git a/Util/vim/syntax/boogie.vim b/Util/vim/syntax/boogie.vim index 667a2b8c..673f967e 100644 --- a/Util/vim/syntax/boogie.vim +++ b/Util/vim/syntax/boogie.vim @@ -15,7 +15,7 @@ set cpo&vim " type syn keyword bplType bool int " repeat / condition / label -syn keyword bplExpr forall exists cast returns lambda +syn keyword bplExpr forall exists cast returns lambda div mod syn keyword bplStmt goto return while call else if assert assume havoc then syn keyword bplDecl axiom function procedure type requires ensures modifies unique const var free implementation invariant " user labels -- cgit v1.2.3 From 52c0262e9a4645625875f88dd8381e7d565c4443 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 27 Sep 2012 14:01:18 -0700 Subject: DafnyExtension: make it usable also in Visual Studio 2012 --- Util/VS2010/DafnyExtension/DafnyExtension.sln | 4 ++-- .../DafnyExtension/DafnyExtension/DafnyExtension.csproj | 14 +++++++++++++- .../DafnyExtension/source.extension.vsixmanifest | 3 +++ 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'Util') diff --git a/Util/VS2010/DafnyExtension/DafnyExtension.sln b/Util/VS2010/DafnyExtension/DafnyExtension.sln index e7391254..fd450cc8 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension.sln +++ b/Util/VS2010/DafnyExtension/DafnyExtension.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DafnyExtension", "DafnyExtension\DafnyExtension.csproj", "{6E9A5E14-0763-471C-A129-80A879D9E7BA}" EndProject Global diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj index 66370dec..2580c396 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj +++ b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -14,6 +15,12 @@ v4.0 512 false + 11.0 + + + + + 4.0 true @@ -158,8 +165,13 @@ + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + - + + cd diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest b/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest index d822fbfc..ef5c1cf5 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest +++ b/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest @@ -10,6 +10,9 @@ Pro + + Pro + -- cgit v1.2.3 From a9c6c8fcf205a13c759c6f09e69b01d3b144df94 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 28 Sep 2012 15:19:53 -0700 Subject: Dafny: removed div/mod axioms, since Boogie now interprets div/mod Dafny: included FloydCycleDetect again (which had been temporarily commented out) DafnyExtension: adjusted to Boogie's change in abstract-interpretation support --- Binaries/DafnyPrelude.bpl | 15 --------------- Test/dafny2/COST-verif-comp-2011-4-FloydCycleDetect.dfy | 9 --------- Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs | 3 --- 3 files changed, 27 deletions(-) (limited to 'Util') diff --git a/Binaries/DafnyPrelude.bpl b/Binaries/DafnyPrelude.bpl index 53e8e86a..5530f8a7 100644 --- a/Binaries/DafnyPrelude.bpl +++ b/Binaries/DafnyPrelude.bpl @@ -610,18 +610,3 @@ type TickType; var $Tick: TickType; // --------------------------------------------------------------- -// -- Arithmetic ------------------------------------------------- -// --------------------------------------------------------------- - -// the connection between mod and div -axiom (forall x:int, y:int :: {x mod y} {x div y} x mod y == x - x div y * y); - -// remainder is always Euclidean Modulus. -axiom (forall x:int, y:int :: {x mod y} 0 < y ==> 0 <= x mod y && x mod y < y); -axiom (forall x:int, y:int :: {x mod y} y < 0 ==> 0 <= x mod y && x mod y < -y); - -// the following axiom has some unfortunate matching, but it does state a property about mod that -// is sometimes useful -axiom (forall a: int, b: int, d: int :: { a mod d, b mod d } 2 <= d && a mod d == b mod d && a < b ==> a + d <= b); - -// --------------------------------------------------------------- diff --git a/Test/dafny2/COST-verif-comp-2011-4-FloydCycleDetect.dfy b/Test/dafny2/COST-verif-comp-2011-4-FloydCycleDetect.dfy index 3f68ee5d..774008b8 100644 --- a/Test/dafny2/COST-verif-comp-2011-4-FloydCycleDetect.dfy +++ b/Test/dafny2/COST-verif-comp-2011-4-FloydCycleDetect.dfy @@ -205,7 +205,6 @@ class Node { invariant forall k,l :: 0 <= k < l < steps ==> Nexxxt(k, S) != Nexxxt(l, S); decreases S - Visited; { -assume 2<2; // TEMPORARY HACK p, steps, Visited := p.next, steps + 1, Visited + {p}; } if (p == null) { @@ -219,7 +218,6 @@ assume 2<2; // TEMPORARY HACK invariant forall k :: 0 <= k < A ==> Nexxxt(k, S) != p; decreases steps - A; { -assume 2<2; // TEMPORARY HACK A := A + 1; } B := steps - A; @@ -228,13 +226,6 @@ assume 2<2; // TEMPORARY HACK } } -/** TEMPORARY - ghost method AnalyzeList_Aux(S: set, steps: int, p: Node) returns (A: int) - ensures 0 <= A < steps; - ensures forall k :: 0 <= k < A ==> Nexxxt(k, S) != p; - ensures Nexxxt(A, S) == p; -**/ - ghost method CrucialLemma(a: int, b: int, S: set) requires IsClosed(S); requires 0 <= a && 1 <= b; diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs index 9f22b887..c691d9da 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs +++ b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs @@ -231,9 +231,6 @@ namespace DafnyLanguage if (Bpl.CommandLineOptions.Clo.UseAbstractInterpretation) { if (Bpl.CommandLineOptions.Clo.Ai.J_Intervals || Bpl.CommandLineOptions.Clo.Ai.J_Trivial) { Microsoft.Boogie.AbstractInterpretation.NativeAbstractInterpretation.RunAbstractInterpretation(program); - } else if (Bpl.CommandLineOptions.Clo.Ai.AnySet) { - // run one of the old domains - Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program); } else { // use /infer:j as the default Bpl.CommandLineOptions.Clo.Ai.J_Intervals = true; -- cgit v1.2.3 From d3a315961bf6a7b83225f6311dcf40b0dbba6463 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 28 Sep 2012 16:12:27 -0700 Subject: Boogie: updated syntax highlighting ("real") --- Util/Emacs/boogie-mode.el | 2 +- Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs | 8 +++----- Util/latex/boogie.sty | 2 +- Util/vim/syntax/boogie.vim | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'Util') diff --git a/Util/Emacs/boogie-mode.el b/Util/Emacs/boogie-mode.el index 86721a74..5763d695 100644 --- a/Util/Emacs/boogie-mode.el +++ b/Util/Emacs/boogie-mode.el @@ -38,7 +38,7 @@ "assert" "assume" "break" "call" "then" "else" "havoc" "if" "goto" "return" "while" "old" "forall" "exists" "lambda" "cast" "div" "mod" "false" "true")) . font-lock-keyword-face) - `(,(boogie-regexp-opt '("bool" "int" + `(,(boogie-regexp-opt '("bool" "int" "real" "bv0" "bv1" "bv2" "bv3" "bv4" "bv5" "bv6" "bv7" "bv8" "bv9" "bv10" "bv11" "bv12" "bv13" "bv14" "bv15" "bv16" "bv17" "bv18" "bv19" "bv20" "bv21" "bv22" "bv23" "bv24" "bv25" "bv26" "bv27" "bv28" "bv29" diff --git a/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs b/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs index 4e38f654..fd7c561d 100644 --- a/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs +++ b/Util/VS2010/Boogie/BoogieLanguageService/Grammar.cs @@ -33,8 +33,7 @@ namespace Demo "mod", "modifies", "old", "procedure", - "requires", - "return", "returns", + "real", "requires", "return", "returns", "then", "true", "type", "unique", "var", @@ -271,8 +270,7 @@ namespace Demo "modifies" | "old" | "procedure" | - "requires" | - "return" | "returns" | + "real" | "requires" | "return" | "returns" | "then" | "true" | "type" | "unique" | "var" | @@ -323,7 +321,7 @@ namespace Demo ; typeDecl.Rule - = (ToTerm("int") | "bool" | ident) + = (ToTerm("int") | "bool" | "real" | ident) ; fieldDecl.Rule diff --git a/Util/latex/boogie.sty b/Util/latex/boogie.sty index 43336262..e67c61f4 100644 --- a/Util/latex/boogie.sty +++ b/Util/latex/boogie.sty @@ -19,7 +19,7 @@ \usepackage{listings} \lstdefinelanguage{boogie}{ - morekeywords={type,finite,bool,int,ref,% + morekeywords={type,bool,int,real,% bv0,bv1,bv2,bv3,bv4,bv5,bv6,bv7,bv8,bv9,% bv10,bv11,bv12,bv13,bv14,bv15,bv16,bv17,bv18,bv19,% bv20,bv21,bv22,bv23,bv24,bv25,bv26,bv27,bv28,bv29,% diff --git a/Util/vim/syntax/boogie.vim b/Util/vim/syntax/boogie.vim index 673f967e..6af66279 100644 --- a/Util/vim/syntax/boogie.vim +++ b/Util/vim/syntax/boogie.vim @@ -13,7 +13,7 @@ set cpo&vim " type -syn keyword bplType bool int +syn keyword bplType bool int real " repeat / condition / label syn keyword bplExpr forall exists cast returns lambda div mod syn keyword bplStmt goto return while call else if assert assume havoc then -- cgit v1.2.3 From 8d7686cd88736d117e37eb9bf9dd17404a294ff4 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 3 Oct 2012 12:32:19 -0700 Subject: bunch of refactorings - moved doomed and predication code into separate projects; for doomed there is a static dependency from BoogieDriver but for predication even that dependency has been eliminated - deleted Provers\Simplify and Provers\Z3 - removed Provers\Z3api from the solution - consolidated Core\GraphAlgorithms.cs VCGeneration\GraphAlgorithms.cs into Graph\Graph.cs --- Source/Boogie.sln | 81 +- Source/BoogieDriver/BoogieDriver.cs | 11 +- Source/BoogieDriver/BoogieDriver.csproj | 8 + Source/Core/Absy.cs | 2 +- Source/Core/CommandLineOptions.cs | 5 +- Source/Core/Core.csproj | 1 - Source/Core/DeadVarElim.cs | 4 +- Source/Core/GraphAlgorithms.cs | 244 ------ Source/Core/LoopUnroll.cs | 1 + Source/DafnyDriver/DafnyDriver.cs | 8 +- Source/Doomed/DoomCheck.cs | 401 +++++++++ Source/Doomed/DoomErrorHandler.cs | 86 ++ Source/Doomed/Doomed.csproj | 102 +++ Source/Doomed/DoomedLoopUnrolling.cs | 650 ++++++++++++++ Source/Doomed/DoomedStrategy.cs | 528 ++++++++++++ Source/Doomed/HasseDiagram.cs | 424 ++++++++++ Source/Doomed/VCDoomed.cs | 827 ++++++++++++++++++ Source/Graph/Graph.cs | 419 ++++++++- Source/Houdini/Houdini.cs | 2 +- Source/Predication/BlockPredicator.cs | 373 ++++++++ Source/Predication/Predication.csproj | 87 ++ Source/Predication/SmartBlockPredicator.cs | 528 ++++++++++++ Source/Predication/UniformityAnalyser.cs | 591 +++++++++++++ Source/Provers/Simplify/Let2ImpliesVisitor.cs | 236 ------ Source/Provers/Simplify/Prover.cs | 656 --------------- Source/Provers/Simplify/ProverInterface.cs | 868 ------------------- Source/Provers/Simplify/Simplify.csproj | 210 ----- Source/Provers/Simplify/cce.cs | 193 ----- Source/Provers/Z3/Inspector.cs | 162 ---- Source/Provers/Z3/Prover.cs | 937 --------------------- Source/Provers/Z3/ProverInterface.cs | 427 ---------- Source/Provers/Z3/TypeDeclCollector.cs | 398 --------- Source/Provers/Z3/Z3.csproj | 218 ----- Source/Provers/Z3/cce.cs | 193 ----- Source/VCGeneration/BlockPredicator.cs | 373 -------- Source/VCGeneration/ConditionGeneration.cs | 2 +- Source/VCGeneration/DoomCheck.cs | 401 --------- Source/VCGeneration/DoomErrorHandler.cs | 86 -- Source/VCGeneration/DoomedLoopUnrolling.cs | 650 -------------- Source/VCGeneration/DoomedStrategy.cs | 528 ------------ Source/VCGeneration/GraphAlgorithms.cs | 127 --- Source/VCGeneration/HasseDiagram.cs | 424 ---------- Source/VCGeneration/SmartBlockPredicator.cs | 528 ------------ Source/VCGeneration/StratifiedVC.cs | 2 +- Source/VCGeneration/UniformityAnalyser.cs | 556 ------------ Source/VCGeneration/VC.cs | 38 +- Source/VCGeneration/VCDoomed.cs | 827 ------------------ Source/VCGeneration/VCGeneration.csproj | 10 - .../DafnyExtension/DafnyExtension/DafnyDriver.cs | 6 +- 49 files changed, 5087 insertions(+), 9352 deletions(-) delete mode 100644 Source/Core/GraphAlgorithms.cs create mode 100644 Source/Doomed/DoomCheck.cs create mode 100644 Source/Doomed/DoomErrorHandler.cs create mode 100644 Source/Doomed/Doomed.csproj create mode 100644 Source/Doomed/DoomedLoopUnrolling.cs create mode 100644 Source/Doomed/DoomedStrategy.cs create mode 100644 Source/Doomed/HasseDiagram.cs create mode 100644 Source/Doomed/VCDoomed.cs create mode 100644 Source/Predication/BlockPredicator.cs create mode 100644 Source/Predication/Predication.csproj create mode 100644 Source/Predication/SmartBlockPredicator.cs create mode 100644 Source/Predication/UniformityAnalyser.cs delete mode 100644 Source/Provers/Simplify/Let2ImpliesVisitor.cs delete mode 100644 Source/Provers/Simplify/Prover.cs delete mode 100644 Source/Provers/Simplify/ProverInterface.cs delete mode 100644 Source/Provers/Simplify/Simplify.csproj delete mode 100644 Source/Provers/Simplify/cce.cs delete mode 100644 Source/Provers/Z3/Inspector.cs delete mode 100644 Source/Provers/Z3/Prover.cs delete mode 100644 Source/Provers/Z3/ProverInterface.cs delete mode 100644 Source/Provers/Z3/TypeDeclCollector.cs delete mode 100644 Source/Provers/Z3/Z3.csproj delete mode 100644 Source/Provers/Z3/cce.cs delete mode 100644 Source/VCGeneration/BlockPredicator.cs delete mode 100644 Source/VCGeneration/DoomCheck.cs delete mode 100644 Source/VCGeneration/DoomErrorHandler.cs delete mode 100644 Source/VCGeneration/DoomedLoopUnrolling.cs delete mode 100644 Source/VCGeneration/DoomedStrategy.cs delete mode 100644 Source/VCGeneration/GraphAlgorithms.cs delete mode 100644 Source/VCGeneration/HasseDiagram.cs delete mode 100644 Source/VCGeneration/SmartBlockPredicator.cs delete mode 100644 Source/VCGeneration/UniformityAnalyser.cs delete mode 100644 Source/VCGeneration/VCDoomed.cs (limited to 'Util') diff --git a/Source/Boogie.sln b/Source/Boogie.sln index 106a9b74..f3f068d7 100644 --- a/Source/Boogie.sln +++ b/Source/Boogie.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Provers", "Provers", "{B758C1E3-824A-439F-AA2F-0BA1143E8C8D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoogieDriver", "BoogieDriver\BoogieDriver.csproj", "{DAB6BAA4-7AF7-449F-96AB-F58F34D03A7A}" @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B230A69C-C466-4065-B9C1-84D80E76D802}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z3api", "Provers\Z3api\Z3api.csproj", "{966DD87B-A29D-4F3C-9406-F680A61DC0E0}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Graph", "Graph\Graph.csproj", "{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basetypes", "Basetypes\Basetypes.csproj", "{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}" @@ -31,6 +29,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParserHelper", "ParserHelpe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Houdini", "Houdini\Houdini.csproj", "{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Predication", "Predication\Predication.csproj", "{AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doomed", "Doomed\Doomed.csproj", "{884386A3-58E9-40BB-A273-B24976775553}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|.NET = Checked|.NET @@ -205,28 +207,6 @@ Global {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU {B230A69C-C466-4065-B9C1-84D80E76D802}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Checked|.NET.ActiveCfg = Checked|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Checked|Any CPU.ActiveCfg = Checked|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Checked|Any CPU.Build.0 = Checked|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Checked|Mixed Platforms.ActiveCfg = Checked|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Checked|x86.ActiveCfg = Checked|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Debug|.NET.ActiveCfg = Debug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Debug|x86.ActiveCfg = Debug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Release|.NET.ActiveCfg = Release|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Release|Any CPU.Build.0 = Release|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.Release|x86.ActiveCfg = Release|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|.NET.ActiveCfg = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|Any CPU.ActiveCfg = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|Any CPU.Build.0 = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU - {966DD87B-A29D-4F3C-9406-F680A61DC0E0}.z3apidebug|x86.Build.0 = z3apidebug|Any CPU {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|.NET.ActiveCfg = Checked|Any CPU {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.ActiveCfg = Checked|Any CPU {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}.Checked|Any CPU.Build.0 = Checked|Any CPU @@ -401,12 +381,59 @@ Global {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|Mixed Platforms.Build.0 = Debug|Any CPU {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.ActiveCfg = Release|Any CPU {CF41E903-78EB-43BA-A355-E5FEB5ECECD4}.z3apidebug|x86.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Checked|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|.NET.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Debug|x86.ActiveCfg = Debug|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.Release|x86.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44}.z3apidebug|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Checked|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|.NET.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Any CPU.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Debug|x86.ActiveCfg = Debug|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.Release|x86.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|.NET.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Any CPU.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.ActiveCfg = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|Mixed Platforms.Build.0 = Release|Any CPU + {884386A3-58E9-40BB-A273-B24976775553}.z3apidebug|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} - {966DD87B-A29D-4F3C-9406-F680A61DC0E0} = {B758C1E3-824A-439F-AA2F-0BA1143E8C8D} EndGlobalSection EndGlobal diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs index 75ba7372..402b5c68 100644 --- a/Source/BoogieDriver/BoogieDriver.cs +++ b/Source/BoogieDriver/BoogieDriver.cs @@ -594,15 +594,6 @@ namespace Microsoft.Boogie { program.UnrollLoops(CommandLineOptions.Clo.LoopUnrollCount); } - if (CommandLineOptions.Clo.DoPredication && CommandLineOptions.Clo.StratifiedInlining > 0) { - BlockPredicator.Predicate(program, false, false); - if (CommandLineOptions.Clo.PrintInstrumented) { - using (TokenTextWriter writer = new TokenTextWriter(Console.Out)) { - program.Emit(writer); - } - } - } - Dictionary> extractLoopMappingInfo = null; if (CommandLineOptions.Clo.ExtractLoops) { @@ -668,7 +659,7 @@ namespace Microsoft.Boogie { try { if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { vcgen = new DCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); - } else if(CommandLineOptions.Clo.StratifiedInlining > 0) { + } else if (CommandLineOptions.Clo.StratifiedInlining > 0) { vcgen = new StratifiedVCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); } else { vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); diff --git a/Source/BoogieDriver/BoogieDriver.csproj b/Source/BoogieDriver/BoogieDriver.csproj index 9edd2df7..36795a68 100644 --- a/Source/BoogieDriver/BoogieDriver.csproj +++ b/Source/BoogieDriver/BoogieDriver.csproj @@ -226,6 +226,10 @@ {B230A69C-C466-4065-B9C1-84D80E76D802} Core + + {884386a3-58e9-40bb-a273-b24976775553} + Doomed + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} Graph @@ -238,6 +242,10 @@ {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} ParserHelper + + {afaa5ce1-c41b-44f0-88f8-fd8a43826d44} + Predication + {9B163AA3-36BC-4AFB-88AB-79BC9E97E401} SMTLib diff --git a/Source/Core/Absy.cs b/Source/Core/Absy.cs index b64a9e5e..c8c052b7 100644 --- a/Source/Core/Absy.cs +++ b/Source/Core/Absy.cs @@ -77,7 +77,7 @@ namespace Microsoft.Boogie { using System.Collections.Generic; using System.Diagnostics.Contracts; using Microsoft.Boogie.AbstractInterpretation; - using Graphing; + using Microsoft.Boogie.GraphUtil; using Set = GSet; [ContractClass(typeof(AbsyContracts))] diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs index 8b567edd..4192259d 100644 --- a/Source/Core/CommandLineOptions.cs +++ b/Source/Core/CommandLineOptions.cs @@ -575,8 +575,6 @@ namespace Microsoft.Boogie { public string CoverageReporterPath = null; public Process coverageReporter = null; // used internally for debugging - public bool DoPredication = false; - public enum TypeEncoding { None, Predicates, @@ -1203,8 +1201,7 @@ namespace Microsoft.Boogie { ps.CheckBooleanFlag("useUnsatCoreForContractInfer", ref UseUnsatCoreForContractInfer) || ps.CheckBooleanFlag("printAssignment", ref PrintAssignment) || ps.CheckBooleanFlag("nonUniformUnfolding", ref NonUniformUnfolding) || - ps.CheckBooleanFlag("deterministicExtractLoops", ref DeterministicExtractLoops) || - ps.CheckBooleanFlag("predicate", ref DoPredication) + ps.CheckBooleanFlag("deterministicExtractLoops", ref DeterministicExtractLoops) ) { // one of the boolean flags matched return true; diff --git a/Source/Core/Core.csproj b/Source/Core/Core.csproj index 3a2f421a..49639822 100644 --- a/Source/Core/Core.csproj +++ b/Source/Core/Core.csproj @@ -155,7 +155,6 @@ - diff --git a/Source/Core/DeadVarElim.cs b/Source/Core/DeadVarElim.cs index 1376245a..5bf306b6 100644 --- a/Source/Core/DeadVarElim.cs +++ b/Source/Core/DeadVarElim.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Graphing; +using Microsoft.Boogie.GraphUtil; using PureCollections; using System.Diagnostics.Contracts; @@ -355,7 +355,7 @@ namespace Microsoft.Boogie { public static void ComputeLiveVariables(Implementation impl) { Contract.Requires(impl != null); Microsoft.Boogie.Helpers.ExtraTraceInformation("Starting live variable analysis"); - Graphing.Graph dag = new Graph(); + Graph dag = new Graph(); dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph foreach (Block b in impl.Blocks) { GotoCmd gtc = b.TransferCmd as GotoCmd; diff --git a/Source/Core/GraphAlgorithms.cs b/Source/Core/GraphAlgorithms.cs deleted file mode 100644 index a19cf96c..00000000 --- a/Source/Core/GraphAlgorithms.cs +++ /dev/null @@ -1,244 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System.Collections.Generic; -using System.Diagnostics.Contracts; - -namespace Microsoft.Boogie { - public delegate System.Collections.IEnumerable/**//*!*/ Adjacency(T/*!*/ node); - - - // An SCC is a set of nodes - public sealed class SCC : ICollection { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(nodesMap != null); - } - - private IDictionary/*!*/ nodesMap = new Dictionary(); - private ICollection/*!*/ nodes { - get { - return cce.NonNull(nodesMap.Keys); - } - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - System.Collections.IEnumerator/*!*/ System.Collections.IEnumerable.GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - - return ((System.Collections.IEnumerable)nodes).GetEnumerator(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IEnumerator/*!*/ IEnumerable.GetEnumerator() { - Contract.Ensures(Contract.Result>() != null); - - return ((IEnumerable)nodes).GetEnumerator(); - } - - public int Count { - get { - return nodes.Count; - } - } - public bool IsReadOnly { - get { - return nodesMap.IsReadOnly; - } - } - public void Add(Node item) { - nodesMap.Add(item, null); - } - public void Clear() { - nodesMap.Clear(); - } - [Pure] - public bool Contains(Node item) { - return nodesMap.ContainsKey(item); - } - public void CopyTo(Node[] array, int arrayIndex) { - //Contract.Requires(array != null); - nodes.CopyTo(array, arrayIndex); - } - public bool Remove(Node item) { - return nodesMap.Remove(item); - } - } - - public sealed class StronglyConnectedComponents : IEnumerable/*!*/> where Node : class { - private readonly IDictionary/*!*/ graph; - [ContractInvariantMethod] - void graphInvariantMethod() { - Contract.Invariant(Contract.ForAll(graph, entry => entry.Key != null)); - Contract.Invariant(preds != null); - Contract.Invariant(succs != null); - } - private readonly Adjacency/*!*/ preds; - private readonly Adjacency/*!*/ succs; - - private bool computed = false; - public bool Computed { - get { - return computed; - } - } - - [NotDelayed] - public StronglyConnectedComponents(System.Collections.IEnumerable/**/ graph, Adjacency preds, Adjacency succs) - : base() {//BASEMOVE DANGER - Contract.Requires(succs != null); - Contract.Requires(preds != null); - Contract.Requires(graph != null); - Contract.Ensures(!Computed); - IDictionary/*!*/ dict = new Dictionary(); - foreach (Node/*!*/ n in graph) { - Contract.Assert(n != null); - dict.Add(n, null); - } - - this.graph = dict; - this.preds = preds; - this.succs = succs; - //:base(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - System.Collections.IEnumerator/*!*/ System.Collections.IEnumerable.GetEnumerator() { - Contract.Ensures(Contract.Result() != null); - - return ((System.Collections.IEnumerable)sccs).GetEnumerator(); - } - - [Pure] - [GlobalAccess(false)] - [Escapes(true, false)] - IEnumerator/*!*/>/*!*/ IEnumerable/*!*/>.GetEnumerator() { - Contract.Ensures(Contract.Result>>() != null); - - Contract.Assume(Computed); - Contract.Assert(cce.NonNullElements((IEnumerable/*!*/>)sccs));//REVIEW - return ((IEnumerable/*!*/>)sccs).GetEnumerator(); - } - - private readonly IList/*!*/>/*!*/ sccs = new List/*!*/>(); - [ContractInvariantMethod] - void sccsInvariant() { - Contract.Invariant(cce.NonNullElements(sccs)); - } - - - public void Compute() { - Contract.Requires(!Computed); - Contract.Ensures(Computed); - // Compute post times on graph with edges reversed - this.dfsNext = this.preds; - foreach (Node/*!*/ n in cce.NonNull(graph.Keys)) { - Contract.Assert(n != null); - if (!seen.ContainsKey(n)) { - OrderNodes(n); - } - } - - // Clear seen - seen.Clear(); - - // Compute SCCs - this.dfsNext = this.succs; - while (postOrder.Count > 0) { - Node/*!*/ n = postOrder.Pop(); - Contract.Assert(n != null); - - if (!seen.ContainsKey(n)) { - SCC/*!*/ curr = new SCC(); - FindSCCs(n, curr); - sccs.Add(curr); - } - } - - // Clear seen - seen.Clear(); - - this.computed = true; - } - - private Adjacency/*?*/ dfsNext = null; - - private readonly IDictionary/*!*/ seen = new Dictionary(); - private readonly Stack/*!*/ postOrder = new Stack(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(seen != null); - Contract.Invariant(cce.NonNullElements(postOrder)); - } - - - // DFS to order nodes by post times - private void OrderNodes(Node node) { - Contract.Requires(node != null); - seen.Add(node, null); - - Contract.Assert(dfsNext != null); - System.Collections.IEnumerable/*!*/ nexts = dfsNext(node); - Contract.Assert(nexts != null); - foreach (Node/*!*/ n in nexts) { - Contract.Assert(n != null); - if (graph.ContainsKey(n) && !seen.ContainsKey(n)) { - OrderNodes(n); - } - } - - postOrder.Push(node); - } - - // DFS to compute SCCs - private void FindSCCs(Node node, SCC currSCC) { - Contract.Requires(currSCC != null); - Contract.Requires(node != null); - //modifies currSCC.*; - seen.Add(node, null); - currSCC.Add(node); - - Contract.Assert(dfsNext != null); - System.Collections.IEnumerable/*!*/ nexts = dfsNext(node); - Contract.Assert(nexts != null); - foreach (Node/*!*/ n in nexts) { - Contract.Assert(n != null); - if (graph.ContainsKey(n) && !seen.ContainsKey(n)) { - FindSCCs(n, currSCC); - } - } - } - - [Pure] - public override string ToString() { - Contract.Ensures(Contract.Result() != null); - string outStr = ""; - int i = 0; - - foreach (ICollection component in this) { - string/*!*/ tmp = System.String.Format("\nComponent #{0} = ", i++); - Contract.Assert(tmp != null); - outStr += tmp; - - bool firstInRow = true; - - foreach (Node b in component) { - string/*!*/ tmpComponent = System.String.Format("{0}{1}", firstInRow ? "" : ", ", b); - Contract.Assert(tmpComponent != null); - outStr += tmpComponent; - firstInRow = false; - } - } - return outStr; - } - - } -} diff --git a/Source/Core/LoopUnroll.cs b/Source/Core/LoopUnroll.cs index 3b61ad3e..580cbdc5 100644 --- a/Source/Core/LoopUnroll.cs +++ b/Source/Core/LoopUnroll.cs @@ -6,6 +6,7 @@ using System.Diagnostics.Contracts; using System.Collections.Generic; using Bpl = Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; namespace Microsoft.Boogie { public class LoopUnroll { diff --git a/Source/DafnyDriver/DafnyDriver.cs b/Source/DafnyDriver/DafnyDriver.cs index 39733c8e..80f78d16 100644 --- a/Source/DafnyDriver/DafnyDriver.cs +++ b/Source/DafnyDriver/DafnyDriver.cs @@ -571,13 +571,7 @@ namespace Microsoft.Dafny ConditionGeneration vcgen = null; try { - if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) - { - vcgen = new DCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); - } else - { - vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); - } + vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend); } catch (ProverException e) { diff --git a/Source/Doomed/DoomCheck.cs b/Source/Doomed/DoomCheck.cs new file mode 100644 index 00000000..1cbbeabf --- /dev/null +++ b/Source/Doomed/DoomCheck.cs @@ -0,0 +1,401 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC +{ + internal class Evc { + + public DoomErrorHandler ErrorHandler { + set { + m_ErrorHandler = value; + } + } + + [ContractInvariantMethod] +void ObjectInvariant() +{ + Contract.Invariant(m_Checker!=null); +} + + private Checker m_Checker; + private DoomErrorHandler m_ErrorHandler; + + [NotDelayed] + public Evc(Checker check) { + Contract.Requires(check != null); + m_Checker = check; + + } + + public void Initialize(VCExpr evc) { + Contract.Requires(evc != null); + m_Checker.PushVCExpr(evc); + } + + + public bool CheckReachvar(List lv,Dictionary finalreachvars, + int k, int l, bool usenew , out ProverInterface.Outcome outcome) { + Contract.Requires(lv != null); + + VCExpr vc = VCExpressionGenerator.False; + if (usenew ) + { + foreach (Variable v in lv) + { + + vc = m_Checker.VCExprGen.Or( + m_Checker.VCExprGen.Neq( + m_Checker.VCExprGen.Integer(BigNum.ZERO), + m_Checker.TheoremProver.Context.BoogieExprTranslator.LookupVariable(v)), + vc); + } + //Console.WriteLine("TPQuery k={0}, l={1}, |Sp|={2}", k, l, finalreachvars.Count); + + VCExpr vc21 = m_Checker.VCExprGen.Integer(BigNum.ZERO); // Ask: is the necessary or can we use the same instance term in two inequalities? + VCExpr vc22 = m_Checker.VCExprGen.Integer(BigNum.ZERO); + + foreach (KeyValuePair kvp in finalreachvars) + { + + vc21 = m_Checker.VCExprGen.Add(vc21, m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)); + vc22 = m_Checker.VCExprGen.Add(vc22, m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)); + } + + VCExpr post = m_Checker.VCExprGen.Gt(m_Checker.VCExprGen.Integer(BigNum.FromInt(l)), vc21); + + if (k != -1) + { + post = m_Checker.VCExprGen.Or( + post, m_Checker.VCExprGen.Gt(vc22, m_Checker.VCExprGen.Integer(BigNum.FromInt(k))) + ); + } + vc = (m_Checker.VCExprGen.Or(vc, (post) )); + + } + else + { + + foreach (Variable v in lv) + { + + vc = m_Checker.VCExprGen.Or( + m_Checker.VCExprGen.Eq( + m_Checker.VCExprGen.Integer(BigNum.ONE), + m_Checker.TheoremProver.Context.BoogieExprTranslator.LookupVariable(v)), + vc); + } + Contract.Assert(vc != null); + + // Add the desired outcome of the reachability variables + foreach (KeyValuePair kvp in finalreachvars) + { + vc = m_Checker.VCExprGen.Or( + m_Checker.VCExprGen.Neq( + m_Checker.VCExprGen.Integer(BigNum.FromInt(kvp.Value)), + m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)), + vc); + } + + } + + // Todo: Check if vc is trivial true or false + outcome = ProverInterface.Outcome.Undetermined; + Contract.Assert( m_ErrorHandler !=null); + m_Checker.BeginCheck(lv[0].Name, vc, m_ErrorHandler); + m_Checker.ProverDone.WaitOne(); + + try { + outcome = m_Checker.ReadOutcome(); + } catch (UnexpectedProverOutputException e) + { + if (CommandLineOptions.Clo.TraceVerify) { + Console.WriteLine("Prover is unable to check {0}! Reason:", lv[0].Name); + Console.WriteLine(e.ToString()); + } + return false; + } + return true; + } + } + + internal class DoomCheck { + + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(Label2Absy!=null); + Contract.Invariant(m_Check != null); + Contract.Invariant(m_Evc != null); + Contract.Invariant(m_Order != null); + } + + #region Attributes + public Hashtable Label2Absy; + public DoomErrorHandler ErrorHandler { + set { + m_ErrHandler = value; + m_Evc.ErrorHandler = value; + } + + get { + return m_ErrHandler; + } + } + + private DoomErrorHandler m_ErrHandler; + private Checker m_Check; + private DoomDetectionStrategy m_Order; + private Evc m_Evc; + #endregion + + public void __DEBUG_PrintStatistics() + { + Console.WriteLine("Checked/Total: Bl {0} / {1} EQ {2} / {3} {4} Tr {5} {6} / {7}", m_Order.__DEBUG_BlocksChecked, m_Order.__DEBUG_BlocksTotal, m_Order.__DEBUG_EQCChecked, m_Order.__DEBUG_EQCTotal, m_Order.__DEBUG_EQCLeaf, m_Order.__DEBUG_TracesChecked, m_Order.__DEBUG_InfeasibleTraces, m_Order.__DEBUG_TracesTotal); + } + + [NotDelayed] + public DoomCheck (Implementation passive_impl, Block unifiedExit, Checker check, List uncheckable, out int assertionCount) { + Contract.Requires(passive_impl != null); + Contract.Requires(check != null); + Contract.Requires(uncheckable != null); + m_Check = check; + + int replaceThisByCmdLineOption = CommandLineOptions.Clo.DoomStrategy ; + if (CommandLineOptions.Clo.DoomStrategy!=-1) Console.Write("Running experiments using {0} /", replaceThisByCmdLineOption); + switch (replaceThisByCmdLineOption) + { + default: + { + if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("Path Cover specialK Strategy"); + m_Order = new PathCoverStrategyK(passive_impl, unifiedExit, uncheckable); + break; + } + case 1: + { + if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("Path Cover L Strategy"); + m_Order = new PathCoverStrategy(passive_impl, unifiedExit, uncheckable); + break; + } + case 2: + { + if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("hasse strategy"); + m_Order = new HierachyStrategy(passive_impl, unifiedExit, uncheckable); + + break; + } + case 3: + { + if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("hasse+ce strategy"); + m_Order = new HierachyCEStrategy(passive_impl, unifiedExit, uncheckable); + break; + } + case 4: + { + if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("no strategy"); + m_Order = new NoStrategy(passive_impl, unifiedExit, uncheckable); + break; + } + + } + + Label2Absy = new Hashtable(); // This is only a dummy + m_Evc = new Evc(check); + Hashtable l2a = null; + VCExpr vce = this.GenerateEVC(passive_impl, out l2a, check, out assertionCount); + Contract.Assert(vce != null); + Contract.Assert( l2a!=null); + Label2Absy = l2a; + + m_Evc.Initialize(vce); + } + + + public void RespawnChecker(Implementation passive_impl, Checker check) + { + Contract.Requires(check != null); + m_Check = check; + Label2Absy = new Hashtable(); // This is only a dummy + m_Evc = new Evc(check); + Hashtable l2a = null; + int assertionCount; // compute and then ignore + VCExpr vce = this.GenerateEVC(passive_impl, out l2a, check, out assertionCount); + Contract.Assert(vce != null); + Contract.Assert(l2a != null); + Label2Absy = l2a; + + m_Evc.Initialize(vce); + } + + /* - Set b to the next block that needs to be checked. + - Returns false and set b to null if all blocks are checked. + - Has to be alternated with CheckLabel; might crash otherwise + */ + public bool GetNextBlock(out List lb) + { + return m_Order.GetNextBlock(out lb); + } + + public Stopwatch DEBUG_ProverTime = new Stopwatch(); + + /* - Checking a label means to ask the prover if |= ( rvar=false -> vc ) holds. + - outcome is set to Outcome.Invalid if the Block denoted by reachvar is doomed. + - returns false if the theorem prover throws an exception, otherwise true. + */ + public bool CheckLabel(List lv,Dictionary finalreachvars, out ProverInterface.Outcome outcome) { + Contract.Requires(lv != null); + outcome = ProverInterface.Outcome.Undetermined; + DEBUG_ProverTime.Reset(); + DEBUG_ProverTime.Start(); + if (m_Evc.CheckReachvar(lv,finalreachvars,m_Order.MaxBlocks,m_Order.MinBlocks,m_Order.HACK_NewCheck, out outcome) ) { + DEBUG_ProverTime.Stop(); + if (!m_Order.SetCurrentResult(lv, outcome, m_ErrHandler)) { + outcome = ProverInterface.Outcome.Undetermined; + } + return true; + } else { + DEBUG_ProverTime.Stop(); + Console.WriteLine(outcome); + m_Order.SetCurrentResult(lv, ProverInterface.Outcome.Undetermined, m_ErrHandler); + return false; + } + } + + public List!>!*/>> DoomedSequences { + get { + Contract.Ensures(Contract.ForAll(Contract.Result>>(), i=> cce.NonNullElements(i))); + + return m_Order.DetectedBlock; + } + } + + + #region Error Verification Condition Generation + /* + #region _TESTING_NEW_STUFF_ + CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Block; + //VCExpr wp = Wlp.Block(block, SuccCorrect, context); // Computes wp.S.true + + CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Doomed; + #endregion + + */ + + VCExpr GenerateEVC(Implementation impl, out Hashtable label2absy, Checker ch, out int assertionCount) { + Contract.Requires(impl != null); + Contract.Requires(ch != null); + Contract.Ensures(Contract.Result() != null); + + TypecheckingContext tc = new TypecheckingContext(null); + impl.Typecheck(tc); + label2absy = new Hashtable/**/(); + VCExpr vc; + switch (CommandLineOptions.Clo.vcVariety) { + case CommandLineOptions.VCVariety.Doomed: + vc = LetVC(cce.NonNull(impl.Blocks[0]), label2absy, ch.TheoremProver.Context, out assertionCount); + break; + + default: + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected enumeration value + } + return vc; + } + + public VCExpr LetVC(Block startBlock, + Hashtable/**/ label2absy, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(startBlock != null); + Contract.Requires(label2absy != null); + Contract.Requires(proverCtxt != null); + Contract.Ensures(Contract.Result() != null); + + Hashtable/**/ blockVariables = new Hashtable/**/(); + List bindings = new List(); + VCExpr startCorrect = LetVC(startBlock, label2absy, blockVariables, bindings, proverCtxt, out assertionCount); + if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { + return proverCtxt.ExprGen.Let(bindings, proverCtxt.ExprGen.Not(startCorrect) ); + } else { + return proverCtxt.ExprGen.Let(bindings, startCorrect ); + } + } + + VCExpr LetVC(Block block, + Hashtable/**/ label2absy, + Hashtable/**/ blockVariables, + List bindings, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(label2absy != null); + Contract.Requires(blockVariables != null); + Contract.Requires(proverCtxt != null); + Contract.Requires(cce.NonNullElements(bindings)); + Contract.Ensures(Contract.Result() != null); + + assertionCount = 0; + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + VCExprVar v = (VCExprVar)blockVariables[block]; + if (v == null) { + /* + * For block A (= block), generate: + * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct)) + * with the side effect of adding the let bindings to "bindings" for any + * successor not yet visited. + */ + VCExpr SuccCorrect; + GotoCmd gotocmd = block.TransferCmd as GotoCmd; + if (gotocmd == null) { + if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { + SuccCorrect = VCExpressionGenerator.False; + } else { + SuccCorrect = VCExpressionGenerator.True; + } + } else { + Contract.Assert( gotocmd.labelTargets != null); + List SuccCorrectVars = new List(gotocmd.labelTargets.Length); + foreach (Block successor in gotocmd.labelTargets) { + Contract.Assert(successor != null); + int ac; + VCExpr s = LetVC(successor, label2absy, blockVariables, bindings, proverCtxt, out ac); + assertionCount += ac; + SuccCorrectVars.Add(s); + } + SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars); + } + + VCContext context = new VCContext(label2absy, proverCtxt); + // m_Context = context; + + VCExpr vc = Wlp.Block(block, SuccCorrect, context); + assertionCount += context.AssertionCount; + v = gen.Variable(block.Label + "_correct", Microsoft.Boogie.Type.Bool); + + bindings.Add(gen.LetBinding(v, vc)); + blockVariables.Add(block, v); + } + return v; + } + + + #endregion + + } + +} diff --git a/Source/Doomed/DoomErrorHandler.cs b/Source/Doomed/DoomErrorHandler.cs new file mode 100644 index 00000000..33d8b68e --- /dev/null +++ b/Source/Doomed/DoomErrorHandler.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC +{ + internal class DoomErrorHandler : ProverInterface.ErrorHandler + { + + protected Hashtable label2Absy; + protected VerifierCallback callback; + private List m_CurrentTrace = new List(); + + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(label2Absy != null); + Contract.Invariant(callback != null); + Contract.Invariant(cce.NonNullElements(m_CurrentTrace)); + } + + + public DoomErrorHandler(Hashtable label2Absy, VerifierCallback callback) + { + Contract.Requires(label2Absy != null); + Contract.Requires(callback != null); + this.label2Absy = label2Absy; + this.callback = callback; + } + + public override Absy Label2Absy(string label) + { + //Contract.Requires(label != null); + Contract.Ensures(Contract.Result() != null); + + int id = int.Parse(label); + return cce.NonNull((Absy)label2Absy[id]); + } + + public override void OnProverWarning(string msg) + { + //Contract.Requires(msg != null); + this.callback.OnWarning(msg); + } + + + public List/*!>!*/ TraceNodes + { + get + { + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + return m_CurrentTrace; + } + } + + public override void OnModel(IList/*!>!*/ labels, Model model) + { + // TODO: it would be better to check which reachability variables are actually set to one! + List traceNodes = new List(); + List assertNodes = new List(); + foreach (string s in labels) + { + Contract.Assert(s != null); + Absy node = Label2Absy(s); + if (node is Block) + { + Block b = (Block)node; + traceNodes.Add(b); + //Console.Write("{0}, ", b.Label); + } + } + m_CurrentTrace.AddRange(traceNodes); + } + + } + +} \ No newline at end of file diff --git a/Source/Doomed/Doomed.csproj b/Source/Doomed/Doomed.csproj new file mode 100644 index 00000000..fb64b247 --- /dev/null +++ b/Source/Doomed/Doomed.csproj @@ -0,0 +1,102 @@ + + + + + Debug + AnyCPU + {884386A3-58E9-40BB-A273-B24976775553} + Library + Properties + Doomed + Doomed + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + InterimKey.snk + + + + + + + + + + + + + + + + + + + + + + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} + Basetypes + + + {accc0156-0921-43ed-8f67-ad8bdc8cde31} + CodeContractsExtender + + + {b230a69c-c466-4065-b9c1-84d80e76d802} + Core + + + {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} + Graph + + + {acef88d5-dadd-46da-bae1-2144d63f4c83} + Model + + + {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} + ParserHelper + + + {56ffdbca-7d14-43b8-a6ca-22a20e417ee1} + VCExpr + + + {e1f10180-c7b9-4147-b51f-fa1b701966dc} + VCGeneration + + + + + + + + \ No newline at end of file diff --git a/Source/Doomed/DoomedLoopUnrolling.cs b/Source/Doomed/DoomedLoopUnrolling.cs new file mode 100644 index 00000000..e65a570a --- /dev/null +++ b/Source/Doomed/DoomedLoopUnrolling.cs @@ -0,0 +1,650 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC +{ + #region Loop handeling for doomed code detection + + #region Loop Remover + internal class LoopRemover + { + GraphAnalyzer m_GraphAnalyzer; + + public LoopRemover(GraphAnalyzer ga) + { + m_GraphAnalyzer = ga; + } + + private void m_RemoveBackEdge(Loop l) + { + // first remove the backedges of the nested loops + foreach (Loop c in l.NestedLoops) m_RemoveBackEdge(c); + //Debugger.Break(); + GraphNode loopSkip = null; + foreach (GraphNode gn in l.Cutpoint.Suc) + { + if (l.LoopExitNodes.Contains(gn)) + { + loopSkip = gn; break; + } + } + if (loopSkip == null) + { // We didn't find a loop exit node. There must be a bug + Debugger.Break(); + } + foreach (GraphNode gn in l.Cutpoint.LoopingPred) + { + List newsuc = new List(); + foreach (GraphNode s in gn.Suc) + { + if (s == l.Cutpoint) newsuc.Add(loopSkip); + else newsuc.Add(s); + } + gn.Suc = newsuc; + } + } + + private void m_AbstractLoop(Loop l) + { + foreach (Loop c in l.NestedLoops) m_AbstractLoop(c); + m_HavocLoopBody(l); + m_RemoveBackEdge(l); + } + + public void AbstractLoopUnrolling() + { + foreach (Loop l in m_GraphAnalyzer.Graphloops) + { + m_MarkLoopExitUncheckable(l); + m_AbstractLoopUnrolling(l,null, "",true); + } + } + + private void m_HavocLoopBody(Loop l) + { + List loopblocks = new List(); + foreach (GraphNode g in l.LoopNodes) loopblocks.Add(g.Label); + HavocCmd hcmd = m_ComputHavocCmd(loopblocks, l.Cutpoint.Label.tok); + + //Add Havoc before and after the loop body + foreach (GraphNode g in l.Cutpoint.Suc) // before + { + if (l.LoopNodes.Contains(g)) m_AddHavocCmdToFront(g.Label, hcmd); + } + foreach (GraphNode g in l.Cutpoint.Pre) // and after + { + if (l.LoopNodes.Contains(g)) m_AddHavocCmdToFront(g.Label, hcmd); + } + } + + private void m_AddHavocCmdToFront(Block b, HavocCmd hcmd) + { + CmdSeq cs = new CmdSeq(); + cs.Add(hcmd); cs.AddRange(b.Cmds); + b.Cmds = cs; + } + + private HavocCmd m_ComputHavocCmd(List bl, IToken tok) + { + Contract.Requires(bl != null); + Contract.Requires(tok != null); + Contract.Ensures(Contract.Result() != null); + + VariableSeq varsToHavoc = new VariableSeq(); + foreach (Block b in bl) + { + Contract.Assert(b != null); + foreach (Cmd c in b.Cmds) + { + Contract.Assert(c != null); + c.AddAssignedVariables(varsToHavoc); + } + } + IdentifierExprSeq havocExprs = new IdentifierExprSeq(); + foreach (Variable v in varsToHavoc) + { + Contract.Assert(v != null); + IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v); + if (!havocExprs.Has(ie)) + havocExprs.Add(ie); + } + // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct + // the source location for this later on + return new HavocCmd(tok, havocExprs); + } + + private void m_AbstractLoopUnrolling(Loop l, Loop parent, string prefix, bool unfold) + { + //Debugger.Break(); + if (unfold) + { + + Loop first = new Loop(l, m_GraphAnalyzer,prefix+"FI_"); + Loop last = new Loop(l, m_GraphAnalyzer,prefix+"LA_"); + Loop abs = new Loop(l, m_GraphAnalyzer, prefix + "AB_"); + foreach (Loop c in first.NestedLoops) m_AbstractLoopUnrolling(c, first, prefix + "FI_", false); + foreach (Loop c in last.NestedLoops) m_AbstractLoopUnrolling(c, last, prefix + "LA_", false); + foreach (Loop c in abs.NestedLoops) m_AbstractLoopUnrolling(c, abs, prefix + "AB_", true); + + //Debugger.Break(); + + if (parent != null) + { + foreach (GraphNode gn in l.LoopNodes) + { + if (parent.LoopNodes.Contains(gn)) parent.LoopNodes.Remove(gn); + } + foreach (GraphNode gn in abs.LoopNodes) + { + if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); + } + foreach (GraphNode gn in first.LoopNodes) + { + if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); + } + foreach (GraphNode gn in last.LoopNodes) + { + if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); + } + } + + m_HavocLoopBody(abs); + List backupPre = new List(); + backupPre.AddRange(l.Cutpoint.Pre); + foreach (GraphNode pre in backupPre) + { + if (!l.Cutpoint.LoopingPred.Contains(pre)) + { + pre.RemoveEdgeTo(l.Cutpoint); + pre.RemoveEdgeTo(abs.Cutpoint); + pre.AddEdgeTo(first.Cutpoint); + } + } + + m_RemoveRegularLoopExit(last); + m_RemoveRegularLoopExit(abs); + + m_ReplaceBackEdge(first, abs.Cutpoint); + m_ReplaceBackEdge(abs, last.Cutpoint); + foreach (GraphNode gn in first.Cutpoint.Suc) + { + if (!first.LoopNodes.Contains(gn)) + { + m_ReplaceBackEdge(last, gn); + break; + } + } + + // Remove all remaining connections to the original loop + foreach (GraphNode gn in l.LoopExitNodes) + { + List tmp = new List(); + tmp.AddRange(gn.Pre); + foreach (GraphNode g in tmp) + { + if (l.LoopNodes.Contains(g)) + { + //Debugger.Break(); + g.RemoveEdgeTo(gn); + } + } + } + foreach (GraphNode gn in l.LoopNodes) + { + m_GraphAnalyzer.DeleteGraphNode(gn); + } + foreach (GraphNode gn in first.LoopNodes) + { + if (gn != first.Cutpoint && !m_GraphAnalyzer.UncheckableNodes.Contains(gn) ) + m_GraphAnalyzer.UncheckableNodes.Add(gn); + } + foreach (GraphNode gn in last.LoopNodes) + { + if (gn != last.Cutpoint && !m_GraphAnalyzer.UncheckableNodes.Contains(gn)) + m_GraphAnalyzer.UncheckableNodes.Add(gn); + } + MakeLoopExitUncheckable(last.LoopExitNodes); + } + else + { + foreach (Loop c in l.NestedLoops) m_AbstractLoopUnrolling(c, l, prefix, false); + m_AbstractLoop(l); + //MakeLoopExitUncheckable(l.LoopExitNodes); + } + } + + // the loop exit has to be marked uncheckable because otherwise + // while(true) would report unreachable code. + private void m_MarkLoopExitUncheckable(Loop l) + { + + foreach (GraphNode g in l.Cutpoint.Suc) + { + if (!l.LoopNodes.Contains(g)) + { + foreach (GraphNode g_ in m_MarkLoopExitUncheckable(g, l)) + { + if (!m_GraphAnalyzer.UncheckableNodes.Contains(g_)) + m_GraphAnalyzer.UncheckableNodes.Add(g_); + } + } + } + } + + private List m_MarkLoopExitUncheckable(GraphNode g, Loop l) + { + List ret = new List(); + + if (g.Pre.Count > 1) return ret; + ret.Add(g); + foreach (GraphNode gn in g.Suc) + { + ret.AddRange(m_MarkLoopExitUncheckable(gn, l)); + } + + return ret; + } + + // to avoid problems with unreachable code after while(true) {}, try to make the loopexit nodes uncheckable. + private void MakeLoopExitUncheckable(List le) + { + foreach (GraphNode gn in le) + { + if (gn.Suc.Count==1) m_GraphAnalyzer.UncheckableNodes.Add(gn); + } + } + + private void m_RemoveRegularLoopExit(Loop l) + { + List lg = new List(); + lg.AddRange( l.Cutpoint.Suc ); + foreach (GraphNode gn in lg) + { + if (l.LoopExitNodes.Contains(gn)) + { + l.Cutpoint.RemoveEdgeTo(gn); + l.LoopExitNodes.Remove(gn); + } + } + } + + private void m_ReplaceBackEdge(Loop l, GraphNode loopSkip) + { + + foreach (GraphNode gn in l.Cutpoint.LoopingPred) + { + List newsuc = new List(); + foreach (GraphNode s in gn.Suc) + { + if (s == l.Cutpoint) newsuc.Add(loopSkip); + else newsuc.Add(s); + } + gn.Suc = newsuc; + } + } + + + } + #endregion + + #region Graph Analyzer + internal class GraphAnalyzer + { + public List UncheckableNodes = new List(); + + public Dictionary GraphMap = new Dictionary(); + + public List Graphloops = null; + + public GraphAnalyzer(List blocks) + { + //ExitBlock = dedicatedExitBlock; + if (blocks.Count < 1) return; + foreach (Block b in blocks) GraphMap[b] = new GraphNode(b); + foreach (Block b in blocks) + { + foreach (Block pre in b.Predecessors) GraphMap[b].Pre.Add(GraphMap[pre]); + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc != null) + { + foreach (Block suc in gc.labelTargets) GraphMap[b].Suc.Add(GraphMap[suc]); + } + } + + + m_DetectCutPoints(GraphMap[blocks[0]]); + + //m_DetectCutPoints(GraphMap[blocks[0]], null, new List()); + Graphloops = m_CollectLoops(GraphMap[blocks[0]], null); + + } + + public List ToImplementation(out List uncheckables) + { + List blocks = new List(); + uncheckables = new List(); + + foreach (KeyValuePair kvp in GraphMap) + { + Block b = kvp.Key; + if (UncheckableNodes.Contains(GraphMap[b])) uncheckables.Add(b); + blocks.Add(b); + b.Predecessors = new BlockSeq(); + foreach (GraphNode p in kvp.Value.Pre) b.Predecessors.Add(p.Label); + if (kvp.Value.Suc.Count > 0) + { + BlockSeq bs = new BlockSeq(); + foreach (GraphNode s in kvp.Value.Suc) bs.Add(s.Label); + b.TransferCmd = new GotoCmd(b.tok, bs); + } + else + { + b.TransferCmd = new ReturnCmd(b.tok); + } + } + + return blocks; + } + + public GraphNode CloneGraphNode(GraphNode gn, string prefix) + { + CmdSeq cmds = new CmdSeq(gn.Label.Cmds); + + Block b = new Block(gn.Label.tok, prefix+gn.Label.Label, cmds, gn.Label.TransferCmd); + GraphNode clone = new GraphNode(b); + clone.IsCutpoint = gn.IsCutpoint; + clone.Suc.AddRange(gn.Suc); + clone.Pre.AddRange(gn.Pre); + clone.LoopingPred.AddRange(gn.LoopingPred); + GraphMap[b] = clone; + //if (gn.Label == ExitBlock) ExitBlock = b; + return clone; + } + + public void DeleteGraphNode(GraphNode gn) + { + List affected = new List(); + + foreach (KeyValuePair kvp in GraphMap) + { + if (kvp.Value == gn && !affected.Contains(kvp.Key)) affected.Add(kvp.Key); + } + foreach (Block b in affected) + { + GraphMap.Remove(b); + } + } +/* + private void m_DetectCutPoints(GraphNode gn, GraphNode pred, List visited ) + { + if (visited.Contains(gn) ) + { + if (pred != null && !gn.LoopingPred.Contains(pred)) gn.LoopingPred.Add(pred); + gn.IsCutpoint = true; + Console.WriteLine("Normal RootNode {0}", gn.Label.Label); + return; + } + else + { + List visited_ = new List(); + visited_.AddRange(visited); + visited_.Add(gn); + foreach (GraphNode next in gn.Suc) + { + m_DetectCutPoints(next,gn,visited_); + } + } + + } +*/ + + + private void m_DetectCutPoints(GraphNode gn) + { + List todo = new List(); + List done = new List(); + todo.Add(gn); + + GraphNode current = null; + todo[0].Index = 0; + + while (todo.Count > 0) + { + current = todo[0]; + todo.Remove(current); + + bool ready = true; + foreach (GraphNode p in current.Pre) + { + if (!done.Contains(p) ) + { + _loopbacktracking.Clear(); + if (!m_isLoop(current, p, todo, done)) + { + todo.Add(current); + ready = false; + break; + } + else + { + if (!current.LoopingPred.Contains(p)) current.LoopingPred.Add(p); + current.IsCutpoint = true; + } + } + } + if (!ready) continue; + done.Add(current); + foreach (GraphNode s in current.Suc) + { + if (!todo.Contains(s) && !done.Contains(s)) todo.Add(s); + } + } + + } + + List _loopbacktracking = new List(); + private bool m_isLoop(GraphNode loophead, GraphNode gn, List l1, List l2) + { + if (loophead == gn) return true; + if (l1.Contains(gn) || l2.Contains(gn) || _loopbacktracking.Contains(gn)) return false; + _loopbacktracking.Add(gn); + foreach (GraphNode p in gn.Pre) + { + if (m_isLoop(loophead, p, l1, l2)) return true; + } + return false; + } + + private List m_CollectLoops(GraphNode gn, Loop lastLoop) + { + List ret = new List(); + if (gn.Visited) return ret; + gn.Visited = true; + List loopingSucs = new List(); + if (gn.IsCutpoint) + { + Loop l = new Loop(gn); + if (lastLoop != null) + { + lastLoop.SucLoops.Add(l); + l.PreLoops.Add(lastLoop); + } + loopingSucs = l.LoopNodes; + lastLoop = l; + ret.Add(lastLoop); + } + foreach (GraphNode suc in gn.Suc) + { + if (!loopingSucs.Contains(suc)) ret.AddRange(m_CollectLoops(suc, lastLoop)); + } + //Debugger.Break(); + return ret; + } + } + #endregion + + #region GraphNodeStructure + internal class GraphNode + { + public int Index = -1; // Used for scc detection + public int LowLink = -1; // Used for scc detection + + public GraphNode(Block b) + { + Label = b; IsCutpoint = false; + } + public Block Label; + public List Pre = new List(); + public List Suc = new List(); + public bool IsCutpoint; + public bool Visited = false; + public List LoopingPred = new List(); + + public void AddEdgeTo(GraphNode other) + { + if (!this.Suc.Contains(other)) this.Suc.Add(other); + if (!other.Pre.Contains(this)) other.Pre.Add(this); + } + + public void RemoveEdgeTo(GraphNode other) + { + if (this.Suc.Contains(other)) this.Suc.Remove(other); + if (other.Pre.Contains(this)) other.Pre.Remove(this); + } + + } + #endregion + + #region LoopStructure + internal class Loop + { + public Loop(GraphNode cutpoint) + { + if (!cutpoint.IsCutpoint) + { + Debugger.Break(); + } + Cutpoint = cutpoint; + LoopNodes.Add(Cutpoint); + foreach (GraphNode gn in Cutpoint.LoopingPred) + { + CollectLoopBody(gn); + } + CollectLoopExitNodes(); + } + + // Copy Constructor + public Loop(Loop l, GraphAnalyzer ga, string prefix) + { + + Dictionary clonemap = new Dictionary(); + GraphNode clonecutpoint = null; + foreach (GraphNode gn in l.LoopNodes) + { + clonemap[gn] = ga.CloneGraphNode(gn, prefix); + if (gn == l.Cutpoint) clonecutpoint = clonemap[gn]; + } + + if (clonecutpoint == null) + { + Debugger.Break(); + return; + } + // Replace the pre and post nodes by the corresponding clone + foreach (GraphNode gn in l.LoopNodes) + { + List newl = new List(); + foreach (GraphNode g in clonemap[gn].Pre) + { + if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); + else newl.Add(g); + } + clonemap[gn].Pre = newl; + newl = new List(); + foreach (GraphNode g in clonemap[gn].Suc) + { + if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); + else newl.Add(g); + } + clonemap[gn].Suc = newl; + newl = new List(); + foreach (GraphNode g in clonemap[gn].LoopingPred) + { + if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); + else newl.Add(g); + } + clonemap[gn].LoopingPred = newl; + } + + foreach (GraphNode gn in l.Cutpoint.LoopingPred) + { + clonecutpoint.LoopingPred.Remove(gn); + clonecutpoint.LoopingPred.Add(clonemap[gn]); + } + + + + SucLoops.AddRange(l.SucLoops); + PreLoops.AddRange(l.PreLoops); + Cutpoint = clonecutpoint; + LoopNodes.Add(Cutpoint); + foreach (GraphNode gn in Cutpoint.LoopingPred) + { + CollectLoopBody(gn); + } + CollectLoopExitNodes(); + } + + private void CollectLoopBody(GraphNode gn) + { + if (gn == Cutpoint) return; + if (!LoopNodes.Contains(gn)) + { + if (gn.IsCutpoint) // nested loop found + { + Loop lo = new Loop(gn); + foreach (GraphNode lgn in lo.LoopNodes) + { + if (!LoopNodes.Contains(lgn)) LoopNodes.Add(lgn); + } + NestedLoops.Add(lo); + } + else + { + LoopNodes.Add(gn); + } + foreach (GraphNode pre in gn.Pre) if (!gn.LoopingPred.Contains(pre)) CollectLoopBody(pre); + } + } + + private void CollectLoopExitNodes() + { + foreach (GraphNode gn in LoopNodes) + { + foreach (GraphNode gn_ in gn.Suc) + { + if (!LoopNodes.Contains(gn_) && !LoopExitNodes.Contains(gn_)) LoopExitNodes.Add(gn_); + } + } + } + + public GraphNode Cutpoint; + public List LoopExitNodes = new List(); + public List NestedLoops = new List(); + public List SucLoops = new List(); + public List PreLoops = new List(); + public List LoopNodes = new List(); + } + #endregion + + #endregion +} \ No newline at end of file diff --git a/Source/Doomed/DoomedStrategy.cs b/Source/Doomed/DoomedStrategy.cs new file mode 100644 index 00000000..eb5716bb --- /dev/null +++ b/Source/Doomed/DoomedStrategy.cs @@ -0,0 +1,528 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC +{ + #region SuperClass for different doomed code detection strategies + abstract internal class DoomDetectionStrategy + { + public int __DEBUG_BlocksChecked = 0; + public int __DEBUG_BlocksTotal = 0; + public int __DEBUG_InfeasibleTraces = 0; + public int __DEBUG_TracesChecked = 0; + public int __DEBUG_TracesTotal = 0; + public int __DEBUG_EQCTotal = 0; + public int __DEBUG_EQCLeaf = 0; + public int __DEBUG_EQCChecked = 0; + + //Please use this one to toggle your Debug output + protected bool __DEBUGOUT = CommandLineOptions.Clo.DoomStrategy != -1; + + protected Implementation impl; + protected BlockHierachy m_BlockH = null; + + protected int m_MaxBranchingDepth = 0; + protected int m_MaxK = 0; + + protected Stopwatch sw = new Stopwatch(); + + + // This is the List with all detected doomed program points. This List is used by VCDoomed.cs to + // create an error message + public List/*!*/>/*!*/ DetectedBlock = new List/*!*/>(); + + private List __DEBUG_minelements = new List(); + + // There is no default constructor, because these parameters are needed for most subclasses + public DoomDetectionStrategy(Implementation imp, Block unifiedexit, List unreach) + { + m_BlockH = new BlockHierachy(imp, unifiedexit); + __DEBUG_EQCLeaf = m_BlockH.Leaves.Count; + + //foreach (BlockHierachyNode bhn in m_BlockH.Leaves) + //{ + // if (bhn.Content.Count > 0) __DEBUG_minelements.Add(bhn.Content[0]); + //} + //if (imp.Blocks.Count>0) m_GatherInfo(imp.Blocks[0], 0, 0,0); + + + if (__DEBUGOUT) + { + Console.WriteLine("MaBranchingDepth {0} MaxMinPP {1} ", m_MaxBranchingDepth, m_MaxK); + + Console.WriteLine("AvgLeaverPerPath {0} AvgPLen {1}", 0, 0); + } + + MaxBlocks = imp.Blocks.Count; + MinBlocks = imp.Blocks.Count; + HACK_NewCheck = false; + __DEBUG_BlocksTotal = imp.Blocks.Count; + } + + public int MaxBlocks, MinBlocks; + public bool HACK_NewCheck; + + // This method is called by the prover while it returns true. The prover checks for each + // List lb if + // |= !lb_1 /\ ... /\ !lb_n => wlp(Program, false) + // and passes the result to SetCurrentResult + abstract public bool GetNextBlock(out List passBlock); + + // This method is called to inform about the prover outcome for the previous GetNextBlock call. + abstract public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb); + + protected List m_GetErrorTraceFromCE(DoomErrorHandler cb) + { + BlockHierachyNode tn=null; + List errortrace = new List(); + foreach (Block b in cb.TraceNodes) + { + if (errortrace.Contains(b)) continue; + if (m_BlockH.BlockToHierachyMap.TryGetValue(b, out tn)) + { + foreach (Block b_ in tn.Unavoidable) + { + if (!errortrace.Contains(b_)) errortrace.Add(b_); + } + foreach (Block b_ in tn.Content) + { + if (!errortrace.Contains(b_)) errortrace.Add(b_); + } + } + } + return errortrace; + } + + private List __pathLength = new List(); + private List __leavespp = new List(); + protected void m_GatherInfo(Block b, int branchingdepth, int leavespp, int plen) + { + if (b.Predecessors.Length > 1) branchingdepth--; + + GotoCmd gc = b.TransferCmd as GotoCmd; + if (__DEBUG_minelements.Contains(b)) leavespp++; + plen++; + if (gc != null && gc.labelTargets.Length>0) + { + if (gc.labelTargets.Length > 1) branchingdepth++; + m_MaxBranchingDepth = (branchingdepth > m_MaxBranchingDepth) ? branchingdepth : m_MaxBranchingDepth; + foreach (Block s in gc.labelTargets) + { + m_GatherInfo(s, branchingdepth, leavespp,plen); + } + } + else + { + __pathLength.Add(plen); + __leavespp.Add(leavespp); + m_MaxK = (m_MaxK > leavespp) ? m_MaxK : leavespp; + } + } + + + + } + #endregion + + #region BruteForce Strategy + internal class NoStrategy : DoomDetectionStrategy + { + private List m_Blocks = new List(); + private int m_Current = 0; + + public NoStrategy(Implementation imp, Block unifiedexit, List unreach) + : base(imp, unifiedexit, unreach) + { + m_Blocks = imp.Blocks; + } + + override public bool GetNextBlock(out List lb) + { + if (m_Current < m_Blocks.Count) + { + lb = new List(); + lb.Add(m_Blocks[m_Current]); + m_Current++; + return true; + } + lb = null; + return false; + } + + // This method is called to inform about the prover outcome for the previous GetNextBlock call. + override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) + { + this.__DEBUG_BlocksChecked++; + // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) + if (outcome == ProverInterface.Outcome.Valid && m_Current <= m_Blocks.Count) + { + List lb = new List(); + lb.Add(m_Blocks[m_Current - 1]); + DetectedBlock.Add(lb); + } + return true; + } + } + #endregion + + #region Only check the minimal elements of the Hasse diagram + internal class HierachyStrategy : DoomDetectionStrategy + { + private List m_Blocks = new List(); + private List m_doomedBlocks = new List(); + private int m_Current = 0; + + public HierachyStrategy(Implementation imp, Block unifiedexit, List unreach) + : base(imp, unifiedexit, unreach) + { + foreach (BlockHierachyNode bhn in m_BlockH.Leaves) + { + if (bhn.Content.Count > 0) + { + m_Blocks.Add(bhn.Content[0]); + } + } + } + + override public bool GetNextBlock(out List lb) + { + sw.Start(); + if (m_Current < m_Blocks.Count) + { + lb = new List(); + lb.Add(m_Blocks[m_Current]); + m_Current++; + return true; + } + else + { + DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_doomedBlocks)); + } + lb = null; + return false; + } + + // This method is called to inform about the prover outcome for the previous GetNextBlock call. + override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) + { + this.__DEBUG_BlocksChecked++; + // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) + if (outcome == ProverInterface.Outcome.Valid && m_Current <= m_Blocks.Count) + { + m_doomedBlocks.Add(m_Blocks[m_Current - 1]); + } + if (__DEBUGOUT) Console.WriteLine("K := {0,3} , out {1,8}, time {2,12}", MaxBlocks, outcome, sw.ElapsedTicks); + sw.Stop(); + sw.Reset(); + + return true; + } + } + #endregion + + #region Only check the minimal elements of the Hasse diagram and use CEs + internal class HierachyCEStrategy : DoomDetectionStrategy + { + private List m_Blocks = new List(); + private List m_doomedBlocks = new List(); + private Block m_Current = null; + + public HierachyCEStrategy(Implementation imp, Block unifiedexit, List unreach) + : base(imp, unifiedexit, unreach) + { + foreach (BlockHierachyNode bhn in m_BlockH.Leaves) + { + if (bhn.Content.Count > 0) + { + m_Blocks.Add(bhn.Content[0]); + } + } + } + + override public bool GetNextBlock(out List lb) + { + m_Current = null; + if (m_Blocks.Count > 0) + { + m_Current = m_Blocks[0]; + m_Blocks.Remove(m_Current); + lb = new List(); + lb.Add(m_Current); + return true; + } + else + { + DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_doomedBlocks)); + } + lb = null; + return false; + } + + // This method is called to inform about the prover outcome for the previous GetNextBlock call. + override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) + { + this.__DEBUG_BlocksChecked++; + // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) + if (outcome == ProverInterface.Outcome.Valid && m_Current != null) + { + m_doomedBlocks.Add(m_Current); + } + else if (outcome == ProverInterface.Outcome.Invalid) + { + List errortrace = m_GetErrorTraceFromCE(cb); + foreach (Block b in errortrace) + { + if (m_Blocks.Contains(b)) + { + m_Blocks.Remove(b); + } + } + cb.TraceNodes.Clear(); + } + return true; + } + } + #endregion + + #region Path Cover Optimization with L + internal class PathCoverStrategy : DoomDetectionStrategy + { + List m_Uncheckedlocks = new List(); + List m_Ignore = new List(); + + Random m_Random = new Random(); + bool m_NoMoreMoves = false; + + private List m_foundBlock = new List(); + + public PathCoverStrategy(Implementation imp, Block unifiedexit, List unreach) + : base(imp, unifiedexit, unreach) + { + m_Ignore = unreach; + HACK_NewCheck = true; + impl = imp; + foreach (BlockHierachyNode bhn in m_BlockH.Leaves) + { + if (bhn.Content.Count > 0) + { + m_Uncheckedlocks.Add(bhn.Content[0]); + } + + } + m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); + MinBlocks = m_MaxK / 2 + (m_MaxK % 2 > 0 ? 1 : 0); + MaxBlocks = -1; + } + + override public bool GetNextBlock(out List lb) + { + sw.Start(); + + lb = new List(); + + if (m_Uncheckedlocks.Count == 0 || m_NoMoreMoves) + { + if (m_Uncheckedlocks.Count > 0) + { + DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_Uncheckedlocks)); + } + + return false; + } + + lb.AddRange(m_Uncheckedlocks); + + return true; + } + + override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) + { + this.__DEBUG_BlocksChecked++; + // Valid means infeasible... + int oldl = MinBlocks; + int oldsize = m_Uncheckedlocks.Count; + + + if (outcome == ProverInterface.Outcome.Valid) + { + this.__DEBUG_InfeasibleTraces++; + if (MinBlocks == 1) + { + m_NoMoreMoves = true; + } + else + { + MinBlocks = 1; + } + } + else if (outcome == ProverInterface.Outcome.Invalid) + { + this.__DEBUG_TracesChecked++; + + List errortrace = m_GetErrorTraceFromCE(cb); + foreach (Block b in errortrace) + { + if (m_Uncheckedlocks.Contains(b)) + { + m_Uncheckedlocks.Remove(b); + } + } + cb.TraceNodes.Clear(); + m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); + if (m_MaxK < 1) + { + m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); + } + MinBlocks = m_MaxK / 2 + (m_MaxK % 2 > 0 ? 1 : 0); + //if (MinBlocks > m_MaxK) MinBlocks = m_MaxK; + + } + else + { + m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); + } + if (__DEBUGOUT) + Console.WriteLine("K := {0,3}, L := {1,3}, deltaSp {2,3}, out {3,8}, time {4,8}", MaxBlocks, oldl, (oldsize - m_Uncheckedlocks.Count), outcome, sw.ElapsedTicks); + sw.Stop(); + sw.Reset(); + return true; + } + + + } + #endregion + + #region Path Cover Optimization with K + internal class PathCoverStrategyK : DoomDetectionStrategy + { + List m_Uncheckedlocks = new List(); + List m_Ignore = new List(); + + Random m_Random = new Random(); + bool m_NoMoreMoves = false; + + private List m_foundBlock = new List(); + + public PathCoverStrategyK(Implementation imp, Block unifiedexit, List unreach) + : base(imp, unifiedexit, unreach) + { + m_Ignore = unreach; + HACK_NewCheck = true; + impl = imp; + foreach (BlockHierachyNode bhn in m_BlockH.Leaves) + { + if (bhn.Content.Count > 0) + { + m_Uncheckedlocks.Add(bhn.Content[0]); + } + + } + + m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); + + MaxBlocks = m_Uncheckedlocks.Count; + if (m_MaxK < m_Uncheckedlocks.Count && m_MaxK > 0) + { + MaxBlocks = m_MaxK; + } + else if (m_MaxK >= m_Uncheckedlocks.Count) + { + MaxBlocks = m_Uncheckedlocks.Count; + } + else + { + MaxBlocks = 1; + } + //Console.WriteLine("InitK {0}, Max {1}", m_MaxK, MaxBlocks); + } + + override public bool GetNextBlock(out List lb) + { + sw.Start(); + + lb = new List(); + + if (m_Uncheckedlocks.Count == 0 || m_NoMoreMoves) + { + if (m_Uncheckedlocks.Count > 0) + { + DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_Uncheckedlocks)); + } + + return false; + } + + lb.AddRange(m_Uncheckedlocks); + + MaxBlocks = MaxBlocks > m_Uncheckedlocks.Count ? m_Uncheckedlocks.Count : MaxBlocks; + MinBlocks = MaxBlocks / 2 + (MaxBlocks % 2 > 0 ? 1 : 0); + return true; + } + + override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) + { + this.__DEBUG_BlocksChecked++; + // Valid means infeasible... + int oldk = MaxBlocks; + int oldl = MinBlocks; + int oldsize = m_Uncheckedlocks.Count; + + if (outcome == ProverInterface.Outcome.Valid) + { + this.__DEBUG_InfeasibleTraces++; + if (MaxBlocks == 1) + { + m_NoMoreMoves = true; + } + else + { + MaxBlocks /= 2; + } + } + else if (outcome == ProverInterface.Outcome.Invalid) + { + this.__DEBUG_TracesChecked++; + + List errortrace = m_GetErrorTraceFromCE(cb); + foreach (Block b in errortrace) + { + if (m_Uncheckedlocks.Contains(b)) + { + m_Uncheckedlocks.Remove(b); + } + } + cb.TraceNodes.Clear(); + + int k = m_BlockH.GetMaxK(m_Uncheckedlocks); + MaxBlocks = (k > MaxBlocks) ? MaxBlocks : k; + } + else + { + m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); + } + if (__DEBUGOUT) + Console.WriteLine("K := {0,3}, L := {1,3}, deltaSp {2,3}, out {3,8}, time {4,8}", oldk, oldl, (oldsize - m_Uncheckedlocks.Count), outcome, sw.ElapsedTicks); + sw.Stop(); + sw.Reset(); + return true; + } + + + } + #endregion + +} \ No newline at end of file diff --git a/Source/Doomed/HasseDiagram.cs b/Source/Doomed/HasseDiagram.cs new file mode 100644 index 00000000..b2ece2df --- /dev/null +++ b/Source/Doomed/HasseDiagram.cs @@ -0,0 +1,424 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC +{ + internal class BlockHierachyNode + { + public List Unavoidable; + public List Content = new List(); + public List Parents = new List(); + public List Children = new List(); + + public bool Checked, Doomed, DoubleChecked; + + public BlockHierachyNode(Block current, List unavoidable) + { + Checked = false; Doomed = false; DoubleChecked = false; + Unavoidable = unavoidable; + Content.Add(current); + } + + public static bool operator <(BlockHierachyNode left, BlockHierachyNode right) + { + return Compare(left,right)>0; + } + + public static bool operator >(BlockHierachyNode left, BlockHierachyNode right) + { + return Compare(left, right) < 0; + } + + // Compare the unavoidable blocks of two BlockHierachyNodes. + // returns 0 if sets have the same size, -1 if l2 has an element + // that is not in l1, otherwise the size of the intersection. + public static int Compare(BlockHierachyNode l1, BlockHierachyNode l2) + { + List tmp = new List(); + tmp.AddRange(l2.Unavoidable); + foreach (Block b in l1.Unavoidable) + { + if (tmp.Contains(b)) tmp.Remove(b); + else return -1; + } + return tmp.Count; + } + } + + internal class HasseDiagram + { + public readonly List Leaves = new List(); + public readonly List Roots = new List(); + + public HasseDiagram(List nodes) + { + Dictionary> largerElements = new Dictionary>(); + foreach (BlockHierachyNode left in nodes) + { + largerElements[left] = new List(); + foreach (BlockHierachyNode right in nodes) + { + if (left != right) + { + if (left < right) + { + largerElements[left].Add(right); + } + } + } + if (largerElements[left].Count == 0) Leaves.Add(left); + } + + List done = new List(); + List lastround = null; + + //Debugger.Break(); + + // Now that we have the leaves, build the Hasse diagram + while (done.Count < nodes.Count) + { + List maxelements = new List(); + maxelements.AddRange(nodes); + foreach (BlockHierachyNode bhn in nodes) + { + if (!done.Contains(bhn)) + { + foreach (BlockHierachyNode tmp in largerElements[bhn]) + { + if (maxelements.Contains(tmp)) maxelements.Remove(tmp); + } + } + else + { + maxelements.Remove(bhn); + } + } + + done.AddRange(maxelements); + + if (lastround != null) + { + foreach (BlockHierachyNode tmp in lastround) + { + foreach (BlockHierachyNode tmp2 in maxelements) + { + if (largerElements[tmp].Contains(tmp2)) + { + if (!tmp.Children.Contains(tmp2)) tmp.Children.Add(tmp2); + if (!tmp2.Parents.Contains(tmp)) tmp2.Parents.Add(tmp); + } + } + } + } + else + { + Roots.AddRange(maxelements); + } + lastround = maxelements; + } + } + + + } + + internal class BlockHierachy + { + public BlockHierachyNode RootNode = null; + readonly public Dictionary BlockToHierachyMap = new Dictionary(); + readonly public Dictionary> Dominators = new Dictionary>(); + readonly public Dictionary> PostDominators = new Dictionary>(); + readonly public List Leaves = new List(); + + private Implementation m_Impl; + + public BlockHierachy(Implementation impl, Block unifiedExit) + { + m_Impl = impl; + List blocks = impl.Blocks; + List tmp_hnodes = new List(); + Dictionary> unavoidable = new Dictionary>(); + + BfsTraverser(blocks[0], true, Dominators); + BfsTraverser(unifiedExit, false, PostDominators); + + foreach (Block b in blocks) + { + List l1 = Dominators[b]; + List l2 = PostDominators[b]; + unavoidable[b] = m_MergeLists(l1, l2); + + BlockHierachyNode bhn = new BlockHierachyNode(b, unavoidable[b]); + bool found = false; + foreach (KeyValuePair kvp in BlockToHierachyMap) + { + if (BlockHierachyNode.Compare(kvp.Value, bhn) == 0) // using the overloaded compare operator + { + kvp.Value.Content.AddRange(bhn.Content); + BlockToHierachyMap[b] = kvp.Value; + found = true; + break; + } + } + if (!found) + { + BlockToHierachyMap[b] = bhn; + tmp_hnodes.Add(bhn); + } + } + + HasseDiagram hd = new HasseDiagram(tmp_hnodes); + Leaves = hd.Leaves; + } + + public int GetMaxK(List blocks) + { + m_GetMaxK(blocks); + return (m_MaxK>0) ? m_MaxK : 1; + } + + private int m_MaxK = 0; + private void m_GetMaxK(List blocks) + { + m_MaxK = 0; + Dictionary kstore = new Dictionary(); + List todo = new List(); + List done = new List(); + todo.Add(m_Impl.Blocks[0]); + kstore[m_Impl.Blocks[0]] = 0; + int localmax; + Block current = null; + while (todo.Count > 0) + { + current = todo[0]; + todo.Remove(current); + bool ready = true; + localmax = 0; + if (current.Predecessors!=null) { + foreach (Block p in current.Predecessors) + { + if (!done.Contains(p)) + { + ready = false; break; + } + else localmax = (localmax > kstore[p]) ? localmax : kstore[p]; + } + } + if (!ready) + { + todo.Add(current); continue; + } + done.Add(current); + kstore[current] = (blocks.Contains(current)) ? localmax +1 : localmax; + + m_MaxK = (kstore[current] > m_MaxK) ? kstore[current] : m_MaxK; + + GotoCmd gc = current.TransferCmd as GotoCmd; + if (gc != null) + { + foreach (Block s in gc.labelTargets) + { + if (!todo.Contains(s)) todo.Add(s); + } + } + } + + } + + public List GetOtherDoomedBlocks(List doomedblocks) + { + List alsoDoomed = new List(); + List todo = new List(); + foreach (Block b in doomedblocks) + { + BlockToHierachyMap[b].Doomed = true; + todo.Add(BlockToHierachyMap[b]); + } + + while (todo.Count > 0) + { + BlockHierachyNode current = todo[0]; + todo.Remove(current); + if (!current.Doomed && current.Children.Count > 0) + { + bool childrenDoomed = true; + foreach (BlockHierachyNode c in current.Children) + { + if (!c.Doomed) { childrenDoomed = false; break; } + } + if (childrenDoomed) current.Doomed = true; + } + + if (current.Doomed) + { + foreach (BlockHierachyNode p in current.Parents) + { + if (!todo.Contains(p)) todo.Add(p); + } + foreach (Block b in current.Content) + { + if (!alsoDoomed.Contains(b)) alsoDoomed.Add(b); + } + } + } + + return alsoDoomed; + } + + public void Impl2Dot(string filename) + { + + Contract.Requires(filename != null); + List nodes = new List(); + List edges = new List(); + + string nodestyle = "[shape=box];"; + + List nl = new List(); + foreach (BlockHierachyNode h in BlockToHierachyMap.Values) if (!nl.Contains(h)) nl.Add(h); + + + foreach (BlockHierachyNode b in nl) + { + String l1 = ""; + foreach (Block bl in b.Content) l1 = String.Format("{0}_{1}", l1, bl.Label); + + Contract.Assert(b != null); + nodes.Add(string.Format("\"{0}\" {1}", l1, nodestyle)); + foreach (BlockHierachyNode b_ in b.Children) + { + + String l2 = ""; + foreach (Block bl in b_.Content) l2 = String.Format("{0}_{1}", l2, bl.Label); + edges.Add(String.Format("\"{0}\" -> \"{1}\";", l1, l2)); + } + + } + + using (StreamWriter sw = new StreamWriter(filename)) + { + sw.WriteLine(String.Format("digraph {0} {{", "DISCO")); + // foreach (string! s in nodes) { + // sw.WriteLine(s); + // } + foreach (string s in edges) + { + Contract.Assert(s != null); + sw.WriteLine(s); + } + sw.WriteLine("}}"); + sw.Close(); + } + } + + private void BfsTraverser(Block current, bool forward, Dictionary> unavoidableBlocks) + { + List todo = new List(); + List done = new List(); + unavoidableBlocks[current] = new List(); + //Debugger.Break(); + todo.Add(current); + while (todo.Count > 0) + { + current = todo[0]; + todo.Remove(current); + BlockSeq pre = m_Predecessors(current, forward); + bool ready = true; + if (pre != null) + { + foreach (Block bpre in pre) + { + if (!done.Contains(bpre)) + { + ready = false; + break; + } + } + } + if (!ready) + { + todo.Add(current); + continue; + } + done.Add(current); + unavoidableBlocks[current].Add(current); + + BlockSeq suc = m_Succecessors(current, forward); + if (suc == null) continue; + foreach (Block bsuc in suc) + { + if (unavoidableBlocks.ContainsKey(bsuc)) + { + unavoidableBlocks[bsuc] = m_IntersectLists(unavoidableBlocks[bsuc], unavoidableBlocks[current]); + } + else + { + todo.Add(bsuc); + unavoidableBlocks[bsuc] = new List(); + unavoidableBlocks[bsuc].AddRange(unavoidableBlocks[current]); + } + + } + } + + } + + private List m_MergeLists(List lb1, List lb2) + { + List ret = new List(); + ret.AddRange(lb1); + foreach (Block b in lb2) + { + if (!ret.Contains(b)) ret.Add(b); + } + return ret; + } + + private List m_IntersectLists(List lb1, List lb2) + { + List ret = new List(); + ret.AddRange(lb1); + foreach (Block b in lb2) + { + if (!lb1.Contains(b)) ret.Remove(b); + } + foreach (Block b in lb1) + { + if (ret.Contains(b) && !lb2.Contains(b)) ret.Remove(b); + } + return ret; + } + + private BlockSeq m_Predecessors(Block b, bool forward) + { + if (forward) return b.Predecessors; + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc != null) + { + return gc.labelTargets; + } + return null; + } + + private BlockSeq m_Succecessors(Block b, bool forward) + { + return m_Predecessors(b, !forward); + } + + + } + +} \ No newline at end of file diff --git a/Source/Doomed/VCDoomed.cs b/Source/Doomed/VCDoomed.cs new file mode 100644 index 00000000..fadb2ea7 --- /dev/null +++ b/Source/Doomed/VCDoomed.cs @@ -0,0 +1,827 @@ +//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC { + public partial class DCGen : ConditionGeneration { + private bool _print_time = CommandLineOptions.Clo.DoomStrategy!=-1; + #region Attributes + static private Dictionary/*!*/ m_BlockReachabilityMap; + Dictionary/*!*/ m_copiedBlocks = new Dictionary(); + const string reachvarsuffix = "__ivebeenthere"; + List/*!*/ m_doomedCmds = new List(); + [ContractInvariantMethod] + void ObjectInvariant() { + + } + + #endregion + + + /// + /// Constructor. Initializes the theorem prover. + /// + public DCGen(Program program, string/*?*/ logFilePath, bool appendLogFile) + : base(program) { + Contract.Requires(program != null); + + this.appendLogFile = appendLogFile; + this.logFilePath = logFilePath; + m_BlockReachabilityMap = new Dictionary(); + } + + /// + /// Debug method that prints a dot file of the + /// current set of blocks in impl to filename. + /// + private void Impl2Dot(Implementation impl, string filename) { + Contract.Requires(impl != null); + Contract.Requires(filename != null); + List nodes = new List(); + List edges = new List(); + + string nodestyle = "[shape=box];"; + + foreach (Block b in impl.Blocks) { + Contract.Assert(b != null); + nodes.Add(string.Format("\"{0}\" {1}", b.Label, nodestyle)); + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc != null) + { + Contract.Assert(gc.labelTargets != null); + foreach (Block b_ in gc.labelTargets) + { + Contract.Assert(b_ != null); + edges.Add(String.Format("\"{0}\" -> \"{1}\";", b.Label, b_.Label)); + } + } + + //foreach (Block b_ in b.Predecessors) + //{ + // edges.Add(String.Format("\"{0}\" -> \"{1}\";", b.Label, b_.Label)); + //} + } + + using (StreamWriter sw = new StreamWriter(filename)) { + sw.WriteLine(String.Format("digraph {0} {{", impl.Name)); + // foreach (string! s in nodes) { + // sw.WriteLine(s); + // } + foreach (string s in edges) { + Contract.Assert(s != null); + sw.WriteLine(s); + } + sw.WriteLine("}}"); + sw.Close(); + } + } + private const string _copyPrefix = "CPY__"; + + private List m_UncheckableBlocks = null; + + /// + /// MSchaef: + /// - remove loops and add reach variables + /// - make it a passive program + /// - compute the wlp for each block + /// - check if |= (reach=false) => wlp.S.false holds for each reach + /// + /// + public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) { + Contract.EnsuresOnThrow(true); + + Console.WriteLine(); + Console.WriteLine("Checking function {0}", impl.Name); + callback.OnProgress("doomdetector", 0, 0, 0); + + bool restartTP = CommandLineOptions.Clo.DoomRestartTP ; + + //Impl2Dot(impl, String.Format("c:/dot/{0}_orig.dot", impl.Name)); + + Transform4DoomedCheck(impl); + + //Impl2Dot(impl, String.Format("c:/dot/{0}_fin.dot", impl.Name)); + + Checker checker = FindCheckerFor(impl, 1000); + Contract.Assert(checker != null); + int assertionCount; + DoomCheck dc = new DoomCheck(impl, this.exitBlock, checker, m_UncheckableBlocks, out assertionCount); + CumulativeAssertionCount += assertionCount; + + //EmitImpl(impl, false); + + int _totalchecks = 0; + + ProverInterface.Outcome outcome; + dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); + + System.TimeSpan ts = new TimeSpan(); + + if (_print_time) Console.WriteLine("Total number of blocks {0}", impl.Blocks.Count); + + List lb; + List lv = new List(); + + while (dc.GetNextBlock(out lb)) + { + Contract.Assert(lb != null); + outcome = ProverInterface.Outcome.Undetermined; + + Variable v = null; + lv.Clear(); + + foreach (Block b_ in lb) + { + if (!m_BlockReachabilityMap.TryGetValue(b_, out v)) + { + // This should cause an error + continue; + } + //Console.Write("{0}, ",b_.Label); + lv.Add(v); + } + //Console.WriteLine(); + Dictionary finalreachvars = m_GetPostconditionVariables(impl.Blocks,lb); + if (lv.Count < 1) + { + + continue; + } + + Contract.Assert(lv != null); + _totalchecks++; + + + if (!dc.CheckLabel(lv,finalreachvars, out outcome)) { + return Outcome.Inconclusive; + } + ts += dc.DEBUG_ProverTime.Elapsed; + + if (restartTP) + { + checker.Close(); + checker = FindCheckerFor(impl, 1000); + dc.RespawnChecker(impl, checker); + dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); + } + + } + checker.Close(); + + if (_print_time) + { + Console.WriteLine("Number of Checkes / #Blocks: {0} of {1}", _totalchecks, impl.Blocks.Count); + dc.__DEBUG_PrintStatistics(); + Console.WriteLine("Total time for this method: {0}", ts.ToString()); + } + #region Try to produce a counter example (brute force) + if (dc.DoomedSequences.Count > 0) { + int counter = 0; + List _all = new List(); + foreach (List lb_ in dc.DoomedSequences) + { + foreach (Block b_ in lb_) + { + if (!_all.Contains(b_) && !m_UncheckableBlocks.Contains(b_)) + { + _all.Add(b_); counter++; + if (!_print_time) Console.WriteLine(b_.Label); + } + } + } + if (_all.Count > 0) + { + Console.WriteLine("#Dead Blocks found: {0}: ", counter); + return Outcome.Errors; + } + } + #endregion + + + return Outcome.Correct; + } + + private Dictionary m_GetPostconditionVariables(List allblock, List passBlock) + { + Dictionary r = new Dictionary(); + foreach (Block b in allblock) + { + Variable v; + if (m_BlockReachabilityMap.TryGetValue(b, out v)) + { + if (passBlock.Contains(b)) r[m_LastReachVarIncarnation[v]] = 1; + } + else + { + Console.WriteLine("there is no reachability variable for {0}", b.Label); + } + } + return r; + } + +#if false + #region Error message construction + private void SearchCounterexample(Implementation impl, DoomErrorHandler errh, VerifierCallback callback) { + Contract.Requires(impl != null); + Contract.Requires(errh != null); + Contract.Requires(callback != null); + Contract.Requires(errh.m_Reachvar != null); + //if (errh.m_Reachvar==null) { + // Contract.Assert(false);throw new cce.UnreachableException(); + //} + m_doomedCmds.Clear(); + + Dictionary cmdbackup = new Dictionary(); + + BruteForceCESearch(errh.m_Reachvar, impl, callback, cmdbackup, 0, impl.Blocks.Count / 2 - 1); + BruteForceCESearch(errh.m_Reachvar, impl, callback, cmdbackup, impl.Blocks.Count / 2, impl.Blocks.Count - 1); + + List causals = CollectCausalStatements(impl.Blocks[0]); + foreach (Cmd c in causals) { + Contract.Assert(c != null); + GenerateErrorMessage(c, causals); + } + + #region Undo all modifications + foreach (KeyValuePair kvp in cmdbackup) { + Contract.Assert(kvp.Key != null); + Contract.Assert(kvp.Value != null); + kvp.Key.Cmds = kvp.Value; + } + #endregion + } + + #region Causal Statement Tree + + private void GenerateErrorMessage(Cmd causalStatement, List causals) { + Contract.Requires(causalStatement != null); + Contract.Requires(cce.NonNullElements(causals)); + AssumeCmd uc = causalStatement as AssumeCmd; + AssertCmd ac = causalStatement as AssertCmd; + ConsoleColor col = Console.ForegroundColor; + + // Trivial case. Must be either assume or assert false + if (m_doomedCmds.Count == 1) { + Console.WriteLine("Found a trivial error:"); + if (uc != null) { + Console.Write("Trivial false assumption: "); + Console.Write("({0};{1}):", uc.tok.line, uc.tok.col); + } + if (ac != null) { + Console.Write("Trivial false assertion: "); + Console.Write("({0};{1}):", ac.tok.line, ac.tok.col); + } + causalStatement.Emit(new TokenTextWriter("", Console.Out, false), 0); + } else { + // Safety error + if (ac != null) { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Safety error:"); + Console.ForegroundColor = col; + Console.Write("This assertion is violated: "); + Console.Write("({0};{1}):", ac.tok.line, ac.tok.col); + ac.Emit(new TokenTextWriter("", Console.Out, false), 0); + } + if (uc != null) { + bool containsAssert = false; + foreach (Cmd c in m_doomedCmds) { + Contract.Assert(c != null); + if (causals.Contains(c)) { + continue; + } + AssertCmd asrt = c as AssertCmd; + if (asrt != null) { + containsAssert = true; + break; + } + } + // Plausibility error + if (containsAssert) { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("Plausibility error:"); + Console.ForegroundColor = col; + Console.Write("There is no legal exeuction passing: "); + Console.Write("({0};{1})", uc.tok.line, uc.tok.col); + uc.Emit(new TokenTextWriter("", Console.Out, false), 0); + } else { // Reachability error + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine("Reachability error:"); + Console.ForegroundColor = col; + Console.Write("No execution can reach: "); + Console.Write("({0};{1})", uc.tok.line, uc.tok.col); + uc.Emit(new TokenTextWriter("", Console.Out, false), 0); + } + + } + + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("...on any execution passing through:"); + foreach (Cmd c in m_doomedCmds) { + Contract.Assert(c != null); + if (causals.Contains(c)) { + continue; + } + Console.ForegroundColor = col; + Console.Write("In ({0};{1}): ", c.tok.line, c.tok.col); + Console.ForegroundColor = ConsoleColor.DarkYellow; + c.Emit(new TokenTextWriter("", Console.Out, false), 0); + } + Console.ForegroundColor = col; + Console.WriteLine("--"); + + } + } + + private List CollectCausalStatements(Block b) { + Contract.Requires(b != null); + Contract.Ensures(cce.NonNullElements(Contract.Result>())); + + Cmd lastCausal = null; + foreach (Cmd c in b.Cmds) { + Contract.Assert(c != null); + AssertCmd ac = c as AssertCmd; + AssumeCmd uc = c as AssumeCmd; + if (ac != null && !ContainsReachVariable(ac)) { + if (ac.Expr != Expr.True) { + lastCausal = c; + } + } else if (uc != null && !ContainsReachVariable(uc)) { + lastCausal = c; + } + } + + List causals = new List(); + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc != null && gc.labelTargets != null) { + List tmp; + //bool allcausal = true; + foreach (Block b_ in gc.labelTargets) { + Contract.Assert(b_ != null); + tmp = CollectCausalStatements(b_); + + foreach (Cmd cau in tmp) { + if (!causals.Contains(cau)) + causals.Add(cau); + } + } + //if (allcausal) + if (causals.Count > 0) + return causals; + } + if (lastCausal != null) + causals.Add(lastCausal); + return causals; + } + + #endregion + + bool BruteForceCESearch(Variable reachvar, Implementation impl, VerifierCallback callback, + Dictionary cmdbackup, int startidx, int endidx) { + Contract.Requires(reachvar != null); + Contract.Requires(impl != null); + Contract.Requires(callback != null); + Contract.Requires(cce.NonNullElements(cmdbackup)); + #region Modify implementation + for (int i = startidx; i <= endidx; i++) { + if (_copiedBlock.Contains(impl.Blocks[i])) + continue; + CmdSeq cs = new CmdSeq(); + cmdbackup.Add(impl.Blocks[i], impl.Blocks[i].Cmds); + foreach (Cmd c in impl.Blocks[i].Cmds) { + Contract.Assert(c != null); + if (ContainsReachVariable(c)) { + cs.Add(c); + continue; + } + AssertCmd ac = c as AssertCmd; + AssumeCmd uc = c as AssumeCmd; + if (ac != null) { + cs.Add(new AssertCmd(ac.tok, Expr.True)); + } else if (uc != null) { + cs.Add(new AssertCmd(uc.tok, Expr.True)); + } else { + cs.Add(c); + } + } + impl.Blocks[i].Cmds = cs; + } + #endregion + + ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined; + if (!ReCheckImpl(reachvar, impl, callback, out outcome)) { + UndoBlockModifications(impl, cmdbackup, startidx, endidx); + return false; + } + if (outcome == ProverInterface.Outcome.Valid) { + return true; + } else if (outcome == ProverInterface.Outcome.Invalid) { + UndoBlockModifications(impl, cmdbackup, startidx, endidx); + int mid = startidx + (endidx - startidx) / 2; + if (startidx >= endidx) { + // Now we found an interesting Block and we have to + // search for the interesting statements. + int cmdcount = impl.Blocks[endidx].Cmds.Length; + BruteForceCmd(impl.Blocks[endidx], 0, cmdcount / 2 - 1, reachvar, impl, callback); + BruteForceCmd(impl.Blocks[endidx], cmdcount / 2, cmdcount - 1, reachvar, impl, callback); + return true; + } else { + BruteForceCESearch(reachvar, impl, callback, cmdbackup, startidx, mid); + BruteForceCESearch(reachvar, impl, callback, cmdbackup, mid + 1, endidx); + return true; + } + } else { + UndoBlockModifications(impl, cmdbackup, startidx, endidx); + return false; + } + } + + bool BruteForceCmd(Block b, int startidx, int endidx, Variable reachvar, + Implementation impl, VerifierCallback callback) { + Contract.Requires(b != null); + Contract.Requires(reachvar != null); + Contract.Requires(impl != null); + Contract.Requires(callback != null); + #region Modify Cmds + CmdSeq backup = b.Cmds; + Contract.Assert(backup != null); + CmdSeq cs = new CmdSeq(); + for (int i = 0; i < startidx; i++) { + cs.Add(b.Cmds[i]); + } + for (int i = startidx; i <= endidx; i++) { + Cmd c = b.Cmds[i]; + if (ContainsReachVariable(c)) { + cs.Add(c); + continue; + } + cs.Add(new AssertCmd(c.tok, Expr.True)); + } + for (int i = endidx + 1; i < b.Cmds.Length; i++) { + cs.Add(b.Cmds[i]); + } + + b.Cmds = cs; + #endregion + + #region Recheck + ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined; + if (!ReCheckImpl(reachvar, impl, callback, out outcome)) { + b.Cmds = backup; + return false; + } + #endregion + + if (outcome == ProverInterface.Outcome.Valid) { + return true; + } else if (outcome == ProverInterface.Outcome.Invalid) { + b.Cmds = backup; + if (startidx >= endidx) { + if (!ContainsReachVariable(b.Cmds[endidx])) { + // Console.Write(" Witness ("); + // + // ConsoleColor col = Console.ForegroundColor; + // Console.ForegroundColor = ConsoleColor.White; + // Console.Write("{0};{1}", b.Cmds[endidx].tok.line, b.Cmds[endidx].tok.col ); + // Console.ForegroundColor = col; + // Console.Write("): "); + // Console.ForegroundColor = ConsoleColor.Yellow; + // b.Cmds[endidx].Emit(new TokenTextWriter("", Console.Out, false), 0); + // Console.ForegroundColor = col; + + m_doomedCmds.Add(b.Cmds[endidx]); + return true; + } else { + return false; + } + } else { + int mid = startidx + (endidx - startidx) / 2; + BruteForceCmd(b, startidx, mid, reachvar, impl, callback); + BruteForceCmd(b, mid + 1, endidx, reachvar, impl, callback); + return false; // This is pure random + } + } else { + b.Cmds = backup; + return false; + } + } + + void UndoBlockModifications(Implementation impl, Dictionary/*!*/ cmdbackup, + int startidx, int endidx) { + Contract.Requires(cce.NonNullElements(cmdbackup)); + Contract.Requires(impl != null); + for (int i = startidx; i <= endidx; i++) { + CmdSeq cs = null; + if (cmdbackup.TryGetValue(impl.Blocks[i], out cs)) { + Contract.Assert(cs != null); + impl.Blocks[i].Cmds = cs; + cmdbackup.Remove(impl.Blocks[i]); + } + } + } + + bool ReCheckImpl(Variable reachvar, Implementation impl, VerifierCallback callback, + out ProverInterface.Outcome outcome) { + Contract.Requires(reachvar != null); + Contract.Requires(impl != null); + Contract.Requires(callback != null); + Checker checker = FindCheckerFor(impl, 1000); + Contract.Assert(checker != null); + DoomCheck dc = new DoomCheck(impl, this.exitBlock, checker, m_UncheckableBlocks); + dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); + outcome = ProverInterface.Outcome.Undetermined; + List rv = new List(); + rv.Add(reachvar); + if (!dc.CheckLabel(rv,null, out outcome)) { + checker.Close(); + return false; + } + checker.Close(); + return true; + } + + + + bool ContainsReachVariable(Cmd c) { + Contract.Requires(c != null); + AssertCmd artc = c as AssertCmd; + AssumeCmd amec = c as AssumeCmd; + Expr e; + if (artc != null) { + e = artc.Expr; + } else if (amec != null) { + e = amec.Expr; + } else { + return false; + } + Set freevars = new Set(); + e.ComputeFreeVariables(freevars); + foreach (Variable v in freevars) { + Contract.Assert(v != null); + if (v.Name.Contains(reachvarsuffix)) + return true; + } + return false; + } +#endregion +#endif + + + Block exitBlock; + + #region Program Passification + private void GenerateHelperBlocks(Implementation impl) { + Contract.Requires(impl != null); + Hashtable gotoCmdOrigins = new Hashtable(); + exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins); + Contract.Assert(exitBlock != null); + + AddBlocksBetween(impl.Blocks); + + #region Insert pre- and post-conditions and where clauses as assume and assert statements + { + CmdSeq cc = new CmdSeq(); + // where clauses of global variables + foreach (Declaration d in program.TopLevelDeclarations) { + GlobalVariable gvar = d as GlobalVariable; + if (gvar != null && gvar.TypedIdent.WhereExpr != null) { + Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr); + cc.Add(c); + } + } + // where clauses of in- and out-parameters + cc.AddRange(GetParamWhereClauses(impl)); + // where clauses of local variables + foreach (Variable lvar in impl.LocVars) { + Contract.Assert(lvar != null); + if (lvar.TypedIdent.WhereExpr != null) { + Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr); + cc.Add(c); + } + } + + // add cc and the preconditions to new blocks preceding impl.Blocks[0] + InjectPreconditions(impl, cc); + + // append postconditions, starting in exitBlock and continuing into other blocks, if needed + exitBlock = InjectPostConditions(impl, exitBlock, gotoCmdOrigins); + } + #endregion + } + + + private Hashtable/*TransferCmd->ReturnCmd*/ PassifyProgram(Implementation impl, ModelViewInfo mvInfo) { + Contract.Requires(impl != null); + Contract.Requires(mvInfo != null); + Contract.Requires(this.exitBlock != null); + Contract.Ensures(Contract.Result() != null); + + CurrentLocalVariables = impl.LocVars; + return Convert2PassiveCmd(impl, mvInfo); + //return new Hashtable(); + } + + /// + /// Add additional variable to allow checking as described in the paper + /// "It's doomed; we can prove it" + /// + private CmdSeq GenerateReachabilityPredicates(Implementation impl) + { + Contract.Requires(impl != null); + + foreach (Block b in impl.Blocks) + { + Contract.Assert(b != null); + //if (b.Predecessors.Length==0) continue; + //if (b.Cmds.Length == 0 ) continue; + + Variable v_ = new LocalVariable(Token.NoToken, + new TypedIdent(b.tok, b.Label + reachvarsuffix, new BasicType(SimpleType.Int ))); + + impl.LocVars.Add(v_); + + m_BlockReachabilityMap[b] = v_; + + IdentifierExpr lhs = new IdentifierExpr(b.tok, v_); + Contract.Assert(lhs != null); + + impl.Proc.Modifies.Add(lhs); + + List lhsl = new List(); + lhsl.Add(new SimpleAssignLhs(Token.NoToken, lhs)); + List rhsl = new List(); + rhsl.Add(Expr.Literal(1) ); + + + CmdSeq cs = new CmdSeq(new AssignCmd(Token.NoToken, lhsl, rhsl)); + cs.AddRange(b.Cmds); + b.Cmds = cs; + + //checkBlocks.Add(new CheckableBlock(v_,b)); + } + + CmdSeq incReachVars = new CmdSeq(); + foreach (KeyValuePair kvp in m_BlockReachabilityMap) + { + IdentifierExpr lhs = new IdentifierExpr(Token.NoToken, kvp.Value); + impl.Proc.Modifies.Add(lhs); + incReachVars.Add(new AssumeCmd(Token.NoToken, Expr.Le(lhs, Expr.Literal(1)))); + } + + return incReachVars; + } + + #endregion + + #region Compute loop-free approximation + + // this might be redundant, but I didn't find a better place to get this information. + private Dictionary m_LastReachVarIncarnation = new Dictionary(); + + private void Transform4DoomedCheck(Implementation impl) + { + variable2SequenceNumber = new Hashtable/*Variable -> int*/(); + incarnationOriginMap = new Dictionary(); + if (impl.Blocks.Count < 1) return; + + impl.PruneUnreachableBlocks(); + AddBlocksBetween(impl.Blocks); + ResetPredecessors(impl.Blocks); + + GraphAnalyzer ga = new GraphAnalyzer(impl.Blocks); + LoopRemover lr = new LoopRemover(ga); + lr.AbstractLoopUnrolling(); + + impl.Blocks = ga.ToImplementation(out m_UncheckableBlocks); + ResetPredecessors(impl.Blocks); + + // Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks + List oldblocks = new List(); + oldblocks.AddRange(impl.Blocks); + GenerateHelperBlocks(impl); + #region Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks + foreach (Block b in impl.Blocks) + { + if (oldblocks.Contains(b)) continue; + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc != null) + { + bool allsuccUncheckable = true; + foreach (Block _b in gc.labelTargets) + { + if (!m_UncheckableBlocks.Contains(_b)) + { + allsuccUncheckable = false; break; + } + } + if (allsuccUncheckable && !m_UncheckableBlocks.Contains(b)) m_UncheckableBlocks.Add(b); + } + } + #endregion + + impl.Blocks = DeepCopyBlocks(impl.Blocks, m_UncheckableBlocks); + + m_BlockReachabilityMap = new Dictionary(); + CmdSeq cs = GenerateReachabilityPredicates(impl); + + //foreach (Block test in getTheFFinalBlock(impl.Blocks[0])) + //{ + // test.Cmds.AddRange(cs); + //} + + ResetPredecessors(impl.Blocks); + //EmitImpl(impl,false); + + Hashtable/*Variable->Expr*/ htbl = PassifyProgram(impl, new ModelViewInfo(program, impl)); + + // Collect the last incarnation of each reachability variable in the passive program + foreach (KeyValuePair kvp in m_BlockReachabilityMap) + { + if (htbl.ContainsKey(kvp.Value)) + { + m_LastReachVarIncarnation[kvp.Value] = (Expr)htbl[kvp.Value]; + } + } + } + + + List getTheFFinalBlock(Block b) + { + List lb = new List(); + GotoCmd gc = b.TransferCmd as GotoCmd; + if (gc == null) lb.Add(b); + else + { + foreach (Block s in gc.labelTargets) + { + foreach (Block r in getTheFFinalBlock(s)) if (!lb.Contains(r)) lb.Add(r); + } + } + return lb; + } + + + private List DeepCopyBlocks(List lb, List uncheckables) + { + List clones = new List(); + List uncheck_ = new List(); + Dictionary clonemap = new Dictionary(); + + foreach (Block b in lb) + { + Block clone = CloneBlock(b); + clones.Add(clone); + clonemap[b] = clone; + if (uncheckables.Contains(b)) uncheck_.Add(clone); + } + uncheckables.Clear(); + uncheckables.AddRange(uncheck_); + // update the successors and predecessors + foreach (Block b in lb) + { + BlockSeq newpreds = new BlockSeq(); + foreach (Block b_ in b.Predecessors) + { + newpreds.Add(clonemap[b_]); + } + clonemap[b].Predecessors = newpreds; + GotoCmd gc = b.TransferCmd as GotoCmd; + ReturnCmd rc = b.TransferCmd as ReturnCmd; + if (gc != null) + { + StringSeq lseq = new StringSeq(); + BlockSeq bseq = new BlockSeq(); + foreach (string s in gc.labelNames) lseq.Add(s); + foreach (Block b_ in gc.labelTargets) bseq.Add(clonemap[b_]); + GotoCmd tcmd = new GotoCmd(gc.tok, lseq, bseq); + clonemap[b].TransferCmd = tcmd; + } + else if (rc != null) + { + clonemap[b].TransferCmd = new ReturnCmd(rc.tok); + } + } + return clones; + } + + private Block CloneBlock(Block b) + { + Block clone = new Block(b.tok, b.Label, b.Cmds, b.TransferCmd); + if (this.exitBlock == b) this.exitBlock = clone; + return clone; + } + #endregion + } +} diff --git a/Source/Graph/Graph.cs b/Source/Graph/Graph.cs index 2d2eb90b..947a5882 100644 --- a/Source/Graph/Graph.cs +++ b/Source/Graph/Graph.cs @@ -3,11 +3,12 @@ // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- -using System; +using System; +using System.Linq; using System.Collections.Generic; using System.Text; // for StringBuilder using System.Diagnostics.Contracts; -namespace Graphing { +namespace Microsoft.Boogie.GraphUtil { internal static class Util { private static string/*!*/ ListToString(IEnumerable xs) { @@ -873,7 +874,419 @@ namespace Graphing { s.AppendLine("}"); return s.ToString(); } - } // end: class Graph + } // end: class Graph + + public static class GraphAlgorithms + { + + public static Graph Dual(this Graph g, Node dummySource) + { + var exits = g.Nodes.Where(n => g.Successors(n).Count() == 0).ToList(); + if (exits.Count == 0) + return null; + var dual = new Graph(new HashSet>(g.Edges.Select(e => new Tuple(e.Item2, e.Item1)))); + if (exits.Count == 1) + dual.AddSource(exits[0]); + else + { + dual.AddSource(dummySource); + foreach (var exit in exits) + dual.AddEdge(dummySource, exit); + } + return dual; + } + + public static List> LoopyTopSort(this Graph g) + { + Contract.Assert(g.Reducible); + + int n = g.Nodes.Count; + var nodeToNumber = new Dictionary(n); + var numberToNode = new Node[n]; + var allNodes = new List(); + int counter = 0; + foreach (Node node in g.Nodes) + { + numberToNode[counter] = node; + nodeToNumber[node] = counter; + allNodes.Add(counter); + counter++; + } + + var loops = new List[n]; + foreach (var h in g.Headers) + { + var loopNodes = new HashSet(); + foreach (var b in g.BackEdgeNodes(h)) + loopNodes.UnionWith(g.NaturalLoops(h, b)); + loops[nodeToNumber[h]] = + new List(loopNodes.Select(node => nodeToNumber[node])); + } + + var successors = new List[n]; + int[] incomingEdges = new int[n]; + + foreach (var e in g.Edges) + { + Contract.Assert(e.Item1 != null); + Contract.Assert(e.Item2 != null); + int source = nodeToNumber[e.Item1], target = nodeToNumber[e.Item2]; + if (loops[target] == null || !loops[target].Contains(source)) + { + if (successors[source] == null) + successors[source] = new List(); + successors[source].Add(target); + incomingEdges[target]++; + } + } + + var sortedNodes = new List>(); + + var regionStack = new Stack>>(); + regionStack.Push(new Tuple>(default(Node), allNodes)); + + while (regionStack.Count != 0) + { + int rootIndex = -1; + foreach (var i in regionStack.Peek().Item2) + { + if (incomingEdges[i] == 0) + { + rootIndex = i; + break; + } + } + if (rootIndex == -1) + { + var region = regionStack.Pop(); + if (regionStack.Count != 0) + sortedNodes.Add(new Tuple(region.Item1, true)); + continue; + } + incomingEdges[rootIndex] = -1; + sortedNodes.Add(new Tuple(numberToNode[rootIndex], false)); + if (successors[rootIndex] != null) + foreach (int s in successors[rootIndex]) + incomingEdges[s]--; + if (loops[rootIndex] != null) + regionStack.Push(new Tuple>(numberToNode[rootIndex], + loops[rootIndex])); + } + + return sortedNodes; + } + + // Algorithm from Jeanne Ferrante, Karl J. Ottenstein, Joe D. Warren, + // "The Program Dependence Graph and Its Use in Optimization" + public static Dictionary> ControlDependence(this Graph g) where Node : class, new() + { + Graph dual = g.Dual(new Node()); + DomRelation pdom = dual.DominatorMap; + var result = new Dictionary>(); + + var S = g.Edges.Where(e => !pdom.DominatedBy(e.Item1, e.Item2)); + foreach (var edge in S) + { + var L = pdom.LeastCommonAncestor(edge.Item1, edge.Item2); + var deps = new List(); + if (L == edge.Item1) + { + pdom.DominatedBy(edge.Item2, edge.Item1, deps); + deps.Add(edge.Item2); + deps.Add(edge.Item1); + } + else + { + pdom.DominatedBy(edge.Item2, L, deps); + deps.Add(edge.Item2); + } + if (result.ContainsKey(edge.Item1)) + { + result[edge.Item1].UnionWith(deps); + } + else + { + result[edge.Item1] = new HashSet(deps); + } + } + return result; + } + + } + + public delegate System.Collections.IEnumerable/**//*!*/ Adjacency(T/*!*/ node); + + + // An SCC is a set of nodes + public sealed class SCC : ICollection + { + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(nodesMap != null); + } + + private IDictionary/*!*/ nodesMap = new Dictionary(); + private ICollection/*!*/ nodes + { + get + { + return cce.NonNull(nodesMap.Keys); + } + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + System.Collections.IEnumerator/*!*/ System.Collections.IEnumerable.GetEnumerator() + { + Contract.Ensures(Contract.Result() != null); + + return ((System.Collections.IEnumerable)nodes).GetEnumerator(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IEnumerator/*!*/ IEnumerable.GetEnumerator() + { + Contract.Ensures(Contract.Result>() != null); + + return ((IEnumerable)nodes).GetEnumerator(); + } + + public int Count + { + get + { + return nodes.Count; + } + } + public bool IsReadOnly + { + get + { + return nodesMap.IsReadOnly; + } + } + public void Add(Node item) + { + nodesMap.Add(item, null); + } + public void Clear() + { + nodesMap.Clear(); + } + [Pure] + public bool Contains(Node item) + { + return nodesMap.ContainsKey(item); + } + public void CopyTo(Node[] array, int arrayIndex) + { + //Contract.Requires(array != null); + nodes.CopyTo(array, arrayIndex); + } + public bool Remove(Node item) + { + return nodesMap.Remove(item); + } + } + + public sealed class StronglyConnectedComponents : IEnumerable/*!*/> where Node : class + { + private readonly IDictionary/*!*/ graph; + [ContractInvariantMethod] + void graphInvariantMethod() + { + Contract.Invariant(Contract.ForAll(graph, entry => entry.Key != null)); + Contract.Invariant(preds != null); + Contract.Invariant(succs != null); + } + private readonly Adjacency/*!*/ preds; + private readonly Adjacency/*!*/ succs; + + private bool computed = false; + public bool Computed + { + get + { + return computed; + } + } + + [NotDelayed] + public StronglyConnectedComponents(System.Collections.IEnumerable/**/ graph, Adjacency preds, Adjacency succs) + : base() + {//BASEMOVE DANGER + Contract.Requires(succs != null); + Contract.Requires(preds != null); + Contract.Requires(graph != null); + Contract.Ensures(!Computed); + IDictionary/*!*/ dict = new Dictionary(); + foreach (Node/*!*/ n in graph) + { + Contract.Assert(n != null); + dict.Add(n, null); + } + + this.graph = dict; + this.preds = preds; + this.succs = succs; + //:base(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + System.Collections.IEnumerator/*!*/ System.Collections.IEnumerable.GetEnumerator() + { + Contract.Ensures(Contract.Result() != null); + + return ((System.Collections.IEnumerable)sccs).GetEnumerator(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IEnumerator/*!*/>/*!*/ IEnumerable/*!*/>.GetEnumerator() + { + Contract.Ensures(Contract.Result>>() != null); + + Contract.Assume(Computed); + Contract.Assert(cce.NonNullElements((IEnumerable/*!*/>)sccs));//REVIEW + return ((IEnumerable/*!*/>)sccs).GetEnumerator(); + } + + private readonly IList/*!*/>/*!*/ sccs = new List/*!*/>(); + [ContractInvariantMethod] + void sccsInvariant() + { + Contract.Invariant(cce.NonNullElements(sccs)); + } + + + public void Compute() + { + Contract.Requires(!Computed); + Contract.Ensures(Computed); + // Compute post times on graph with edges reversed + this.dfsNext = this.preds; + foreach (Node/*!*/ n in cce.NonNull(graph.Keys)) + { + Contract.Assert(n != null); + if (!seen.ContainsKey(n)) + { + OrderNodes(n); + } + } + + // Clear seen + seen.Clear(); + + // Compute SCCs + this.dfsNext = this.succs; + while (postOrder.Count > 0) + { + Node/*!*/ n = postOrder.Pop(); + Contract.Assert(n != null); + + if (!seen.ContainsKey(n)) + { + SCC/*!*/ curr = new SCC(); + FindSCCs(n, curr); + sccs.Add(curr); + } + } + + // Clear seen + seen.Clear(); + + this.computed = true; + } + + private Adjacency/*?*/ dfsNext = null; + + private readonly IDictionary/*!*/ seen = new Dictionary(); + private readonly Stack/*!*/ postOrder = new Stack(); + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(seen != null); + Contract.Invariant(cce.NonNullElements(postOrder)); + } + + + // DFS to order nodes by post times + private void OrderNodes(Node node) + { + Contract.Requires(node != null); + seen.Add(node, null); + + Contract.Assert(dfsNext != null); + System.Collections.IEnumerable/*!*/ nexts = dfsNext(node); + Contract.Assert(nexts != null); + foreach (Node/*!*/ n in nexts) + { + Contract.Assert(n != null); + if (graph.ContainsKey(n) && !seen.ContainsKey(n)) + { + OrderNodes(n); + } + } + + postOrder.Push(node); + } + + // DFS to compute SCCs + private void FindSCCs(Node node, SCC currSCC) + { + Contract.Requires(currSCC != null); + Contract.Requires(node != null); + //modifies currSCC.*; + seen.Add(node, null); + currSCC.Add(node); + + Contract.Assert(dfsNext != null); + System.Collections.IEnumerable/*!*/ nexts = dfsNext(node); + Contract.Assert(nexts != null); + foreach (Node/*!*/ n in nexts) + { + Contract.Assert(n != null); + if (graph.ContainsKey(n) && !seen.ContainsKey(n)) + { + FindSCCs(n, currSCC); + } + } + } + + [Pure] + public override string ToString() + { + Contract.Ensures(Contract.Result() != null); + string outStr = ""; + int i = 0; + + foreach (ICollection component in this) + { + string/*!*/ tmp = System.String.Format("\nComponent #{0} = ", i++); + Contract.Assert(tmp != null); + outStr += tmp; + + bool firstInRow = true; + + foreach (Node b in component) + { + string/*!*/ tmpComponent = System.String.Format("{0}{1}", firstInRow ? "" : ", ", b); + Contract.Assert(tmpComponent != null); + outStr += tmpComponent; + firstInRow = false; + } + } + return outStr; + } + + } public class GraphProgram { static void TestGraph(T/*!*/ source, params Tuple[] edges) { diff --git a/Source/Houdini/Houdini.cs b/Source/Houdini/Houdini.cs index f27cd410..5271a6a3 100644 --- a/Source/Houdini/Houdini.cs +++ b/Source/Houdini/Houdini.cs @@ -11,7 +11,7 @@ using Microsoft.Boogie.VCExprAST; using VC; using System.Collections; using System.IO; -using Graphing; +using Microsoft.Boogie.GraphUtil; namespace Microsoft.Boogie.Houdini { diff --git a/Source/Predication/BlockPredicator.cs b/Source/Predication/BlockPredicator.cs new file mode 100644 index 00000000..8419471e --- /dev/null +++ b/Source/Predication/BlockPredicator.cs @@ -0,0 +1,373 @@ +using Microsoft.Boogie.GraphUtil; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; + +namespace Microsoft.Boogie { + +public class BlockPredicator { + + Program prog; + Implementation impl; + Graph blockGraph; + + bool createCandidateInvariants = true; + bool useProcedurePredicates = true; + + Expr returnBlockId; + + LocalVariable curVar, pVar; + IdentifierExpr cur, p, fp; + Expr pExpr; + Dictionary havocVars = + new Dictionary(); + Dictionary blockIds = new Dictionary(); + HashSet doneBlocks = new HashSet(); + + BlockPredicator(Program p, Implementation i, bool cci, bool upp) { + prog = p; + impl = i; + createCandidateInvariants = cci; + useProcedurePredicates = upp; + } + + void PredicateCmd(List blocks, Block block, Cmd cmd, out Block nextBlock) { + if (!useProcedurePredicates && cmd is CallCmd) { + var trueBlock = new Block(); + blocks.Add(trueBlock); + trueBlock.Label = block.Label + ".call.true"; + trueBlock.Cmds.Add(new AssumeCmd(Token.NoToken, p)); + trueBlock.Cmds.Add(cmd); + + var falseBlock = new Block(); + blocks.Add(falseBlock); + falseBlock.Label = block.Label + ".call.false"; + falseBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(p))); + + var contBlock = new Block(); + blocks.Add(contBlock); + contBlock.Label = block.Label + ".call.cont"; + + block.TransferCmd = + new GotoCmd(Token.NoToken, new BlockSeq(trueBlock, falseBlock)); + trueBlock.TransferCmd = falseBlock.TransferCmd = + new GotoCmd(Token.NoToken, new BlockSeq(contBlock)); + nextBlock = contBlock; + } else { + PredicateCmd(block.Cmds, cmd); + nextBlock = block; + } + } + + void PredicateCmd(CmdSeq cmdSeq, Cmd cmd) { + if (cmd is AssignCmd) { + var aCmd = (AssignCmd)cmd; + cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss, + new List(aCmd.Lhss.Zip(aCmd.Rhss, (lhs, rhs) => + new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(p, rhs, lhs.AsExpr)))))); + } else if (cmd is AssertCmd) { + var aCmd = (AssertCmd)cmd; + if (cmdSeq.Last() is AssignCmd && + cmdSeq.Cast().SkipEnd(1).All(c => c is AssertCmd)) { + // This may be a loop invariant. Make sure it continues to appear as + // the first statement in the block. + var assign = cmdSeq.Last(); + cmdSeq.Truncate(cmdSeq.Length-1); + Expr newExpr = new EnabledReplacementVisitor(pExpr).VisitExpr(aCmd.Expr); + aCmd.Expr = QKeyValue.FindBoolAttribute(aCmd.Attributes, "do_not_predicate") ? newExpr : Expr.Imp(pExpr, newExpr); + cmdSeq.Add(aCmd); + // cmdSeq.Add(new AssertCmd(aCmd.tok, Expr.Imp(pExpr, aCmd.Expr))); + cmdSeq.Add(assign); + } else { + aCmd.Expr = Expr.Imp(p, aCmd.Expr); + cmdSeq.Add(aCmd); + // cmdSeq.Add(new AssertCmd(aCmd.tok, Expr.Imp(p, aCmd.Expr))); + } + } else if (cmd is AssumeCmd) { + var aCmd = (AssumeCmd)cmd; + cmdSeq.Add(new AssumeCmd(Token.NoToken, Expr.Imp(p, aCmd.Expr))); + } else if (cmd is HavocCmd) { + var hCmd = (HavocCmd)cmd; + foreach (IdentifierExpr v in hCmd.Vars) { + Microsoft.Boogie.Type type = v.Decl.TypedIdent.Type; + Contract.Assert(type != null); + + IdentifierExpr havocTempExpr; + if (havocVars.ContainsKey(type)) { + havocTempExpr = havocVars[type]; + } else { + var havocVar = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, + "_HAVOC_" + type.ToString(), type)); + impl.LocVars.Add(havocVar); + havocVars[type] = havocTempExpr = + new IdentifierExpr(Token.NoToken, havocVar); + } + cmdSeq.Add(new HavocCmd(Token.NoToken, + new IdentifierExprSeq(havocTempExpr))); + cmdSeq.Add(Cmd.SimpleAssign(Token.NoToken, v, + new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(p, havocTempExpr, v)))); + } + } else if (cmd is CallCmd) { + Debug.Assert(useProcedurePredicates); + var cCmd = (CallCmd)cmd; + cCmd.Ins.Insert(0, p); + cmdSeq.Add(cCmd); + } + else if (cmd is CommentCmd) { + // skip + } + else if (cmd is StateCmd) { + var sCmd = (StateCmd)cmd; + var newCmdSeq = new CmdSeq(); + foreach (Cmd c in sCmd.Cmds) + PredicateCmd(newCmdSeq, c); + sCmd.Cmds = newCmdSeq; + cmdSeq.Add(sCmd); + } + else { + Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); + } + } + + void PredicateTransferCmd(CmdSeq cmdSeq, TransferCmd cmd) { + if (cmd is GotoCmd) { + var gCmd = (GotoCmd)cmd; + var targets = new List( + gCmd.labelTargets.Cast().Select(b => blockIds[b])); + if (targets.Count == 1) { + PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, targets[0])); + } else { + PredicateCmd(cmdSeq, new HavocCmd(Token.NoToken, + new IdentifierExprSeq(cur))); + PredicateCmd(cmdSeq, new AssumeCmd(Token.NoToken, + targets.Select(t => (Expr)Expr.Eq(cur, t)).Aggregate(Expr.Or))); + } + + foreach (Block b in gCmd.labelTargets) { + if (blockGraph.Predecessors(b).Count() == 1) { + if (!doneBlocks.Contains(b)) { + var assumes = b.Cmds.Cast().TakeWhile(c => c is AssumeCmd); + if (assumes.Count() > 0) { + foreach (AssumeCmd aCmd in assumes) { + cmdSeq.Add(new AssumeCmd(Token.NoToken, + Expr.Imp(Expr.Eq(cur, blockIds[b]), + aCmd.Expr))); + } + b.Cmds = + new CmdSeq(b.Cmds.Cast().Skip(assumes.Count()).ToArray()); + } + } + } + } + } else if (cmd is ReturnCmd) { + PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, returnBlockId)); + } else { + Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); + } + } + + void PredicateImplementation() { + blockGraph = prog.ProcessLoops(impl); + var sortedBlocks = blockGraph.LoopyTopSort(); + + int blockId = 0; + foreach (var block in impl.Blocks) + blockIds[block] = Expr.Literal(blockId++); + returnBlockId = Expr.Literal(blockId++); + + curVar = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, "cur", + Microsoft.Boogie.Type.Int)); + impl.LocVars.Add(curVar); + cur = Expr.Ident(curVar); + + pVar = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, "p", + Microsoft.Boogie.Type.Bool)); + impl.LocVars.Add(pVar); + p = Expr.Ident(pVar); + + if (useProcedurePredicates) + fp = Expr.Ident(impl.InParams[0]); + + var newBlocks = new List(); + + Block entryBlock = new Block(); + entryBlock.Label = "entry"; + entryBlock.Cmds = new CmdSeq(Cmd.SimpleAssign(Token.NoToken, cur, + CreateIfFPThenElse(blockIds[sortedBlocks[0].Item1], + returnBlockId))); + newBlocks.Add(entryBlock); + + var prevBlock = entryBlock; + foreach (var n in sortedBlocks) { + if (n.Item2) { + var backedgeBlock = new Block(); + newBlocks.Add(backedgeBlock); + + backedgeBlock.Label = n.Item1.Label + ".backedge"; + backedgeBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, + Expr.Eq(cur, blockIds[n.Item1]), + new QKeyValue(Token.NoToken, "backedge", new List(), null))); + backedgeBlock.TransferCmd = new GotoCmd(Token.NoToken, + new BlockSeq(n.Item1)); + + var tailBlock = new Block(); + newBlocks.Add(tailBlock); + + tailBlock.Label = n.Item1.Label + ".tail"; + tailBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, + Expr.Neq(cur, blockIds[n.Item1]))); + + prevBlock.TransferCmd = new GotoCmd(Token.NoToken, + new BlockSeq(backedgeBlock, tailBlock)); + prevBlock = tailBlock; + } else { + var runBlock = n.Item1; + var oldCmdSeq = runBlock.Cmds; + runBlock.Cmds = new CmdSeq(); + newBlocks.Add(runBlock); + prevBlock.TransferCmd = new GotoCmd(Token.NoToken, + new BlockSeq(runBlock)); + + pExpr = Expr.Eq(cur, blockIds[runBlock]); + if (createCandidateInvariants && blockGraph.Headers.Contains(runBlock)) { + AddUniformCandidateInvariant(runBlock.Cmds, runBlock); + AddNonUniformCandidateInvariant(runBlock.Cmds, runBlock); + } + runBlock.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, p, pExpr)); + var transferCmd = runBlock.TransferCmd; + foreach (Cmd cmd in oldCmdSeq) + PredicateCmd(newBlocks, runBlock, cmd, out runBlock); + PredicateTransferCmd(runBlock.Cmds, transferCmd); + + prevBlock = runBlock; + doneBlocks.Add(runBlock); + } + } + + prevBlock.TransferCmd = new ReturnCmd(Token.NoToken); + impl.Blocks = newBlocks; + } + + private Expr CreateIfFPThenElse(Expr then, Expr eElse) { + if (useProcedurePredicates) { + return new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(fp, then, eElse)); + } else { + return then; + } + } + + private void AddUniformCandidateInvariant(CmdSeq cs, Block header) { + cs.Add(prog.CreateCandidateInvariant(Expr.Eq(cur, + CreateIfFPThenElse(blockIds[header], returnBlockId)), + "uniform loop")); + } + + private void AddNonUniformCandidateInvariant(CmdSeq cs, Block header) { + var loopNodes = new HashSet(); + foreach (var b in blockGraph.BackEdgeNodes(header)) + loopNodes.UnionWith(blockGraph.NaturalLoops(header, b)); + var exits = new HashSet(); + foreach (var ln in loopNodes) { + if (ln.TransferCmd is GotoCmd) { + var gCmd = (GotoCmd) ln.TransferCmd; + foreach (var exit in gCmd.labelTargets.Cast() + .Where(b => !loopNodes.Contains(b))) + exits.Add(blockIds[exit]); + } + if (ln.TransferCmd is ReturnCmd) + exits.Add(returnBlockId); + } + var curIsHeaderOrExit = exits.Aggregate((Expr)Expr.Eq(cur, blockIds[header]), + (e, exit) => Expr.Or(e, Expr.Eq(cur, exit))); + cs.Add(prog.CreateCandidateInvariant( + CreateIfFPThenElse(curIsHeaderOrExit, Expr.Eq(cur, returnBlockId)), + "non-uniform loop")); + } + + public static void Predicate(Program p, + bool createCandidateInvariants = true, + bool useProcedurePredicates = true) { + foreach (var decl in p.TopLevelDeclarations.ToList()) { + if (useProcedurePredicates && decl is DeclWithFormals && !(decl is Function)) { + var dwf = (DeclWithFormals)decl; + var fpVar = new Formal(Token.NoToken, + new TypedIdent(Token.NoToken, "_P", + Microsoft.Boogie.Type.Bool), + /*incoming=*/true); + dwf.InParams = new VariableSeq( + (new Variable[] {fpVar}.Concat(dwf.InParams.Cast())) + .ToArray()); + + if (dwf is Procedure) + { + var proc = (Procedure)dwf; + var newRequires = new RequiresSeq(); + foreach (Requires r in proc.Requires) + { + newRequires.Add(new Requires(r.Free, + new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(r.Condition))); + } + var newEnsures = new EnsuresSeq(); + foreach (Ensures e in proc.Ensures) + { + newEnsures.Add(new Ensures(e.Free, + new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(e.Condition))); + } + } + + } + + try { + var impl = decl as Implementation; + if (impl != null) + new BlockPredicator(p, impl, createCandidateInvariants, useProcedurePredicates).PredicateImplementation(); + } + catch (Program.IrreducibleLoopException) { } + } + } + + public static void Predicate(Program p, Implementation impl) { + try { + new BlockPredicator(p, impl, false, false).PredicateImplementation(); + } + catch (Program.IrreducibleLoopException) { } + } + +} + + +class EnabledReplacementVisitor : StandardVisitor +{ + private Expr pExpr; + + internal EnabledReplacementVisitor(Expr pExpr) + { + this.pExpr = pExpr; + } + + public override Expr VisitExpr(Expr node) + { + if (node is IdentifierExpr) + { + IdentifierExpr iExpr = node as IdentifierExpr; + if (iExpr.Decl is Constant && QKeyValue.FindBoolAttribute(iExpr.Decl.Attributes, "__enabled")) + { + return pExpr; + } + } + return base.VisitExpr(node); + } +} + +} diff --git a/Source/Predication/Predication.csproj b/Source/Predication/Predication.csproj new file mode 100644 index 00000000..d5ed2a9e --- /dev/null +++ b/Source/Predication/Predication.csproj @@ -0,0 +1,87 @@ + + + + + Debug + AnyCPU + {AFAA5CE1-C41B-44F0-88F8-FD8A43826D44} + Library + Properties + Predication + Predication + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + InterimKey.snk + + + + + + + + + + + + + + + + + + + {43dfad18-3e35-4558-9be2-caff6b5ba8a0} + Basetypes + + + {b230a69c-c466-4065-b9c1-84d80e76d802} + Core + + + {69a2b0b8-bcac-4101-ae7a-556fcc58c06e} + Graph + + + {fcd3ac7f-9dfd-46c8-ab1e-09f0b0f16dc5} + ParserHelper + + + {e1f10180-c7b9-4147-b51f-fa1b701966dc} + VCGeneration + + + + + + + + \ No newline at end of file diff --git a/Source/Predication/SmartBlockPredicator.cs b/Source/Predication/SmartBlockPredicator.cs new file mode 100644 index 00000000..9478595b --- /dev/null +++ b/Source/Predication/SmartBlockPredicator.cs @@ -0,0 +1,528 @@ +using Microsoft.Boogie.GraphUtil; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; + +namespace Microsoft.Boogie { + +public class SmartBlockPredicator { + + Program prog; + Implementation impl; + Graph blockGraph; + List> sortedBlocks; + + Func useProcedurePredicates; + + Dictionary predMap, defMap; + Dictionary> ownedMap; + Dictionary parentMap; + Dictionary partInfo; + + IdentifierExpr fp; + Dictionary havocVars = + new Dictionary(); + Dictionary blockIds = new Dictionary(); + HashSet doneBlocks = new HashSet(); + bool myUseProcedurePredicates; + UniformityAnalyser uni; + + SmartBlockPredicator(Program p, Implementation i, Func upp, UniformityAnalyser u) { + prog = p; + impl = i; + useProcedurePredicates = upp; + myUseProcedurePredicates = useProcedurePredicates(i.Proc); + uni = u; + } + + void PredicateCmd(Expr p, List blocks, Block block, Cmd cmd, out Block nextBlock) { + var cCmd = cmd as CallCmd; + if (cCmd != null && !useProcedurePredicates(cCmd.Proc)) { + if (p == null) { + block.Cmds.Add(cmd); + nextBlock = block; + return; + } + + var trueBlock = new Block(); + blocks.Add(trueBlock); + trueBlock.Label = block.Label + ".call.true"; + trueBlock.Cmds.Add(new AssumeCmd(Token.NoToken, p)); + trueBlock.Cmds.Add(cmd); + + var falseBlock = new Block(); + blocks.Add(falseBlock); + falseBlock.Label = block.Label + ".call.false"; + falseBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(p))); + + var contBlock = new Block(); + blocks.Add(contBlock); + contBlock.Label = block.Label + ".call.cont"; + + block.TransferCmd = + new GotoCmd(Token.NoToken, new BlockSeq(trueBlock, falseBlock)); + trueBlock.TransferCmd = falseBlock.TransferCmd = + new GotoCmd(Token.NoToken, new BlockSeq(contBlock)); + nextBlock = contBlock; + } else { + PredicateCmd(p, block.Cmds, cmd); + nextBlock = block; + } + } + + void PredicateCmd(Expr p, CmdSeq cmdSeq, Cmd cmd) { + if (cmd is CallCmd) { + var cCmd = (CallCmd)cmd; + Debug.Assert(useProcedurePredicates(cCmd.Proc)); + cCmd.Ins.Insert(0, p != null ? p : Expr.True); + cmdSeq.Add(cCmd); + } else if (p == null) { + cmdSeq.Add(cmd); + } else if (cmd is AssignCmd) { + var aCmd = (AssignCmd)cmd; + cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss, + new List(aCmd.Lhss.Zip(aCmd.Rhss, (lhs, rhs) => + new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(p, rhs, lhs.AsExpr)))))); + } else if (cmd is AssertCmd) { + var aCmd = (AssertCmd)cmd; + Expr newExpr = new EnabledReplacementVisitor(p).VisitExpr(aCmd.Expr); + aCmd.Expr = QKeyValue.FindBoolAttribute(aCmd.Attributes, "do_not_predicate") ? newExpr : Expr.Imp(p, newExpr); + cmdSeq.Add(aCmd); + } else if (cmd is AssumeCmd) { + var aCmd = (AssumeCmd)cmd; + cmdSeq.Add(new AssumeCmd(Token.NoToken, Expr.Imp(p, aCmd.Expr))); + } else if (cmd is HavocCmd) { + var hCmd = (HavocCmd)cmd; + foreach (IdentifierExpr v in hCmd.Vars) { + Microsoft.Boogie.Type type = v.Decl.TypedIdent.Type; + Contract.Assert(type != null); + + IdentifierExpr havocTempExpr; + if (havocVars.ContainsKey(type)) { + havocTempExpr = havocVars[type]; + } else { + var havocVar = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, + "_HAVOC_" + type.ToString(), type)); + impl.LocVars.Add(havocVar); + havocVars[type] = havocTempExpr = + new IdentifierExpr(Token.NoToken, havocVar); + } + cmdSeq.Add(new HavocCmd(Token.NoToken, + new IdentifierExprSeq(havocTempExpr))); + cmdSeq.Add(Cmd.SimpleAssign(Token.NoToken, v, + new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(p, havocTempExpr, v)))); + } + } else if (cmd is CommentCmd) { + // skip + } else if (cmd is StateCmd) { + var sCmd = (StateCmd)cmd; + var newCmdSeq = new CmdSeq(); + foreach (Cmd c in sCmd.Cmds) + PredicateCmd(p, newCmdSeq, c); + sCmd.Cmds = newCmdSeq; + cmdSeq.Add(sCmd); + } else { + Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); + } + } + + // hasPredicatedRegion is true iff the block or its targets are predicated + // (i.e. we enter, stay within or exit a predicated region). + void PredicateTransferCmd(Expr p, Block src, CmdSeq cmdSeq, TransferCmd cmd, out bool hasPredicatedRegion) { + hasPredicatedRegion = predMap.ContainsKey(src); + + if (cmd is GotoCmd) { + var gCmd = (GotoCmd)cmd; + + hasPredicatedRegion = hasPredicatedRegion || + gCmd.labelTargets.Cast().Any(b => predMap.ContainsKey(b)); + + if (gCmd.labelTargets.Length == 1) { + if (defMap.ContainsKey(gCmd.labelTargets[0])) + PredicateCmd(p, cmdSeq, + Cmd.SimpleAssign(Token.NoToken, + Expr.Ident(predMap[gCmd.labelTargets[0]]), Expr.True)); + } else { + Debug.Assert(gCmd.labelTargets.Length > 1); + Debug.Assert(gCmd.labelTargets.Cast().All(t => uni.IsUniform(impl.Name, t) || + partInfo.ContainsKey(t))); + foreach (Block target in gCmd.labelTargets) { + if (!partInfo.ContainsKey(target)) + continue; + + var part = partInfo[target]; + if (defMap.ContainsKey(part.realDest)) + PredicateCmd(p, cmdSeq, + Cmd.SimpleAssign(Token.NoToken, + Expr.Ident(predMap[part.realDest]), part.pred)); + var predsExitingLoop = new Dictionary>(); + foreach (Block exit in LoopsExited(src, target)) { + List predList; + if (!predsExitingLoop.ContainsKey(exit)) + predList = predsExitingLoop[exit] = new List(); + else + predList = predsExitingLoop[exit]; + predList.Add(part.pred); + } + foreach (var pred in predsExitingLoop) { + PredicateCmd(p, cmdSeq, + Cmd.SimpleAssign(Token.NoToken, + Expr.Ident(predMap[pred.Key]), + Expr.Not(pred.Value.Aggregate(Expr.Or)))); + } + } + } + } else if (cmd is ReturnCmd) { + // Blocks which end in a return will never share a predicate with a block + // which appears after it. Furthermore, such a block cannot be part of a + // loop. So it is safe to do nothing here. + } else { + Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); + } + } + + Variable FreshPredicate(ref int predCount) { + var pVar = new LocalVariable(Token.NoToken, + new TypedIdent(Token.NoToken, + "p" + predCount++, + Microsoft.Boogie.Type.Bool)); + impl.LocVars.Add(pVar); + return pVar; + } + + void AssignPredicates(Graph blockGraph, + DomRelation dom, + DomRelation pdom, + IEnumerator> i, + Variable headPredicate, + ref int predCount) { + var header = i.Current.Item1; + var regionPreds = new List>(); + var ownedPreds = new HashSet(); + ownedMap[header] = ownedPreds; + + if (headPredicate != null) { + predMap[header] = headPredicate; + defMap[header] = headPredicate; + regionPreds.Add(new Tuple(header, headPredicate)); + } + + while (i.MoveNext()) { + var block = i.Current; + if (uni != null && uni.IsUniform(impl.Name, block.Item1)) + continue; + if (block.Item2) { + if (block.Item1 == header) + return; + } else { + if (blockGraph.Headers.Contains(block.Item1)) { + parentMap[block.Item1] = header; + var loopPred = FreshPredicate(ref predCount); + ownedPreds.Add(loopPred); + AssignPredicates(blockGraph, dom, pdom, i, loopPred, ref predCount); + } else { + bool foundExisting = false; + foreach (var regionPred in regionPreds) { + if (dom.DominatedBy(block.Item1, regionPred.Item1) && + pdom.DominatedBy(regionPred.Item1, block.Item1)) { + predMap[block.Item1] = regionPred.Item2; + foundExisting = true; + break; + } + } + if (!foundExisting) { + var condPred = FreshPredicate(ref predCount); + predMap[block.Item1] = condPred; + defMap[block.Item1] = condPred; + ownedPreds.Add(condPred); + regionPreds.Add(new Tuple(block.Item1, condPred)); + } + } + } + } + } + + void AssignPredicates() { + DomRelation dom = blockGraph.DominatorMap; + + Graph dualGraph = blockGraph.Dual(new Block()); + DomRelation pdom = dualGraph.DominatorMap; + + var iter = sortedBlocks.GetEnumerator(); + if (!iter.MoveNext()) { + predMap = defMap = null; + ownedMap = null; + return; + } + + int predCount = 0; + predMap = new Dictionary(); + defMap = new Dictionary(); + ownedMap = new Dictionary>(); + parentMap = new Dictionary(); + AssignPredicates(blockGraph, dom, pdom, iter, + myUseProcedurePredicates ? impl.InParams[0] : null, + ref predCount); + } + + IEnumerable LoopsExited(Block src, Block dest) { + var i = sortedBlocks.GetEnumerator(); + while (i.MoveNext()) { + var b = i.Current; + if (b.Item1 == src) { + return LoopsExitedForwardEdge(dest, i); + } else if (b.Item1 == dest) { + return LoopsExitedBackEdge(src, i); + } + } + Debug.Assert(false); + return null; + } + + private IEnumerable LoopsExitedBackEdge(Block src, IEnumerator> i) { + var headsSeen = new HashSet(); + while (i.MoveNext()) { + var b = i.Current; + if (!b.Item2 && blockGraph.Headers.Contains(b.Item1)) + headsSeen.Add(b.Item1); + else if (b.Item2) + headsSeen.Remove(b.Item1); + if (b.Item1 == src) + return headsSeen; + } + Debug.Assert(false); + return null; + } + + private IEnumerable LoopsExitedForwardEdge(Block dest, IEnumerator> i) { + var headsSeen = new HashSet(); + while (i.MoveNext()) { + var b = i.Current; + if (b.Item1 == dest) + yield break; + else if (!b.Item2 && blockGraph.Headers.Contains(b.Item1)) + headsSeen.Add(b.Item1); + else if (b.Item2 && !headsSeen.Contains(b.Item1)) + yield return b.Item1; + } + Debug.Assert(false); + } + + class PartInfo { + public PartInfo(Expr p, Block r) { pred = p; realDest = r; } + public Expr pred; + public Block realDest; + } + + Dictionary BuildPartitionInfo() { + var partInfo = new Dictionary(); + foreach (var block in blockGraph.Nodes) { + if (uni.IsUniform(impl.Name, block)) + continue; + + var parts = block.Cmds.Cast().TakeWhile( + c => c is AssumeCmd && + QKeyValue.FindBoolAttribute(((AssumeCmd)c).Attributes, "partition")); + + Expr pred = null; + if (parts.Count() > 0) { + pred = parts.Select(a => ((AssumeCmd)a).Expr).Aggregate(Expr.And); + block.Cmds = + new CmdSeq(block.Cmds.Cast().Skip(parts.Count()).ToArray()); + } else { + continue; + } + + Block realDest = block; + if (block.Cmds.Length == 0) { + var gc = block.TransferCmd as GotoCmd; + if (gc != null && gc.labelTargets.Length == 1) + realDest = gc.labelTargets[0]; + } + partInfo[block] = new PartInfo(pred, realDest); + } + + return partInfo; + } + + void PredicateImplementation() { + blockGraph = prog.ProcessLoops(impl); + sortedBlocks = blockGraph.LoopyTopSort(); + + AssignPredicates(); + partInfo = BuildPartitionInfo(); + + if (myUseProcedurePredicates) + fp = Expr.Ident(impl.InParams[0]); + + var newBlocks = new List(); + Block prevBlock = null; + foreach (var n in sortedBlocks) { + if (predMap.ContainsKey(n.Item1)) { + var p = predMap[n.Item1]; + var pExpr = Expr.Ident(p); + + if (n.Item2) { + var backedgeBlock = new Block(); + newBlocks.Add(backedgeBlock); + + backedgeBlock.Label = n.Item1.Label + ".backedge"; + backedgeBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, pExpr, + new QKeyValue(Token.NoToken, "backedge", new List(), null))); + backedgeBlock.TransferCmd = new GotoCmd(Token.NoToken, + new BlockSeq(n.Item1)); + + var tailBlock = new Block(); + newBlocks.Add(tailBlock); + + tailBlock.Label = n.Item1.Label + ".tail"; + tailBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, + Expr.Not(pExpr))); + + if (uni != null && !uni.IsUniform(impl.Name, n.Item1)) { + uni.AddNonUniform(impl.Name, backedgeBlock); + uni.AddNonUniform(impl.Name, tailBlock); + } + + if (prevBlock != null) + prevBlock.TransferCmd = new GotoCmd(Token.NoToken, + new BlockSeq(backedgeBlock, tailBlock)); + prevBlock = tailBlock; + } else { + PredicateBlock(pExpr, n.Item1, newBlocks, ref prevBlock); + } + } else { + if (!n.Item2) { + PredicateBlock(null, n.Item1, newBlocks, ref prevBlock); + } + } + } + + if (prevBlock != null) + prevBlock.TransferCmd = new ReturnCmd(Token.NoToken); + + impl.Blocks = newBlocks; + } + + private void PredicateBlock(Expr pExpr, Block block, List newBlocks, ref Block prevBlock) { + var firstBlock = block; + + var oldCmdSeq = block.Cmds; + block.Cmds = new CmdSeq(); + newBlocks.Add(block); + if (prevBlock != null) { + prevBlock.TransferCmd = new GotoCmd(Token.NoToken, new BlockSeq(block)); + } + + if (parentMap.ContainsKey(block)) { + var parent = parentMap[block]; + if (predMap.ContainsKey(parent)) { + var parentPred = predMap[parent]; + if (parentPred != null) { + block.Cmds.Add(new AssertCmd(Token.NoToken, + pExpr != null ? (Expr)Expr.Imp(pExpr, Expr.Ident(parentPred)) + : Expr.Ident(parentPred))); + } + } + } + + var transferCmd = block.TransferCmd; + foreach (Cmd cmd in oldCmdSeq) + PredicateCmd(pExpr, newBlocks, block, cmd, out block); + + if (ownedMap.ContainsKey(firstBlock)) { + var owned = ownedMap[firstBlock]; + foreach (var v in owned) + block.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, Expr.Ident(v), Expr.False)); + } + + bool hasPredicatedRegion; + PredicateTransferCmd(pExpr, block, block.Cmds, transferCmd, out hasPredicatedRegion); + + if (hasPredicatedRegion) + prevBlock = block; + else + prevBlock = null; + + doneBlocks.Add(block); + } + + private Expr CreateIfFPThenElse(Expr then, Expr eElse) { + if (myUseProcedurePredicates) { + return new NAryExpr(Token.NoToken, + new IfThenElse(Token.NoToken), + new ExprSeq(fp, then, eElse)); + } else { + return then; + } + } + + public static void Predicate(Program p, + Func useProcedurePredicates = null, + UniformityAnalyser uni = null) { + useProcedurePredicates = useProcedurePredicates ?? (proc => false); + if (uni != null) { + var oldUPP = useProcedurePredicates; + useProcedurePredicates = proc => oldUPP(proc) && !uni.IsUniform(proc.Name); + } + + foreach (var decl in p.TopLevelDeclarations.ToList()) { + if (decl is Procedure || decl is Implementation) { + var proc = decl as Procedure; + Implementation impl = null; + if (proc == null) { + impl = (Implementation)decl; + proc = impl.Proc; + } + + bool upp = useProcedurePredicates(proc); + if (upp) { + var dwf = (DeclWithFormals)decl; + var fpVar = new Formal(Token.NoToken, + new TypedIdent(Token.NoToken, "_P", + Microsoft.Boogie.Type.Bool), + /*incoming=*/true); + dwf.InParams = new VariableSeq( + (new Variable[] {fpVar}.Concat(dwf.InParams.Cast())) + .ToArray()); + + if (impl == null) { + var newRequires = new RequiresSeq(); + foreach (Requires r in proc.Requires) { + newRequires.Add(new Requires(r.Free, + new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(r.Condition))); + } + var newEnsures = new EnsuresSeq(); + foreach (Ensures e in proc.Ensures) { + newEnsures.Add(new Ensures(e.Free, + new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(e.Condition))); + } + } + } + + if (impl != null) { + try { + new SmartBlockPredicator(p, impl, useProcedurePredicates, uni).PredicateImplementation(); + } catch (Program.IrreducibleLoopException) { } + } + } + } + } + + public static void Predicate(Program p, Implementation impl) { + try { + new SmartBlockPredicator(p, impl, proc => false, null).PredicateImplementation(); + } + catch (Program.IrreducibleLoopException) { } + } + +} + +} diff --git a/Source/Predication/UniformityAnalyser.cs b/Source/Predication/UniformityAnalyser.cs new file mode 100644 index 00000000..3408d88b --- /dev/null +++ b/Source/Predication/UniformityAnalyser.cs @@ -0,0 +1,591 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics; +using Microsoft.Boogie.GraphUtil; + +namespace Microsoft.Boogie +{ + + public class UniformityAnalyser + { + private Program prog; + + private bool doAnalysis, unstructured; + + private ISet entryPoints; + + private IEnumerable nonUniformVars; + + private bool ProcedureChanged; + + private Dictionary>> uniformityInfo; + + private Dictionary> nonUniformLoops; + + private Dictionary> nonUniformBlocks; + + private Dictionary> loopsWithNonuniformReturn; + + private Dictionary> inParameters; + + private Dictionary> outParameters; + + private List loopStack; + + private bool hitNonuniformReturn; + + /// + /// Simplifies the CFG of the given implementation impl by merging each + /// basic block with a single predecessor into that predecessor if the + /// predecessor has a single successor. If a uniformity analyser is + /// being used then block will only be merged if they are both uniform + /// or both non-uniform + /// + public static void MergeBlocksIntoPredecessors(Program prog, Implementation impl, UniformityAnalyser uni) + { + var blockGraph = prog.ProcessLoops(impl); + var predMap = new Dictionary(); + foreach (var block in blockGraph.Nodes) + { + try + { + var pred = blockGraph.Predecessors(block).Single(); + if (blockGraph.Successors(pred).Single() == block && + (uni == null || + (uni.IsUniform(impl.Name, pred) && uni.IsUniform(impl.Name, block)) || + (!uni.IsUniform(impl.Name, pred) && !uni.IsUniform(impl.Name, block)))) + { + Block predMapping; + while (predMap.TryGetValue(pred, out predMapping)) + pred = predMapping; + pred.Cmds.AddRange(block.Cmds); + pred.TransferCmd = block.TransferCmd; + impl.Blocks.Remove(block); + predMap[block] = pred; + } + // If Single throws an exception above (i.e. not exactly one pred/succ), skip this block. + } + catch (InvalidOperationException) { } + } + } + + public UniformityAnalyser(Program prog, bool doAnalysis, bool unstructured, ISet entryPoints, IEnumerable nonUniformVars) + { + this.prog = prog; + this.doAnalysis = doAnalysis; + this.unstructured = unstructured; + this.entryPoints = entryPoints; + this.nonUniformVars = nonUniformVars; + uniformityInfo = new Dictionary>>(); + nonUniformLoops = new Dictionary>(); + nonUniformBlocks = new Dictionary>(); + loopsWithNonuniformReturn = new Dictionary>(); + inParameters = new Dictionary>(); + outParameters = new Dictionary>(); + loopStack = new List(); + } + + public void Analyse() + { + var impls = prog.TopLevelDeclarations.OfType(); + + foreach (var Impl in impls) + { + bool uniformProcedure = doAnalysis || entryPoints.Contains(Impl); + + uniformityInfo.Add(Impl.Name, new KeyValuePair> + (uniformProcedure, new Dictionary ())); + + nonUniformLoops.Add(Impl.Name, new HashSet()); + loopsWithNonuniformReturn.Add(Impl.Name, new HashSet()); + + foreach (var v in nonUniformVars) + SetNonUniform(Impl.Name, v.Name); + + foreach (Variable v in Impl.LocVars) + { + if (doAnalysis) + { + SetUniform(Impl.Name, v.Name); + } + else + { + SetNonUniform(Impl.Name, v.Name); + } + } + + inParameters[Impl.Name] = new List(); + + foreach (Variable v in Impl.InParams) + { + inParameters[Impl.Name].Add(v.Name); + if (doAnalysis) + { + SetUniform(Impl.Name, v.Name); + } + else + { + SetNonUniform(Impl.Name, v.Name); + } + } + + outParameters[Impl.Name] = new List(); + foreach (Variable v in Impl.OutParams) + { + outParameters[Impl.Name].Add(v.Name); + if (doAnalysis) + { + SetUniform(Impl.Name, v.Name); + } + else + { + SetNonUniform(Impl.Name, v.Name); + } + } + + ProcedureChanged = true; + } + + if (doAnalysis) + { + while (ProcedureChanged) + { + ProcedureChanged = false; + + foreach (var Impl in impls) + { + hitNonuniformReturn = false; + Analyse(Impl, uniformityInfo[Impl.Name].Key); + } + } + } + + foreach (var Impl in impls) + { + if (!IsUniform (Impl.Name)) + { + List newIns = new List(); + newIns.Add("_P"); + foreach (string s in inParameters[Impl.Name]) + { + newIns.Add(s); + } + inParameters[Impl.Name] = newIns; + } + } + } + + private void Analyse(Implementation Impl, bool ControlFlowIsUniform) + { + if (unstructured) + { + if (!ControlFlowIsUniform) + { + nonUniformBlocks[Impl.Name] = new HashSet(Impl.Blocks); + + foreach (Variable v in Impl.LocVars) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + foreach (Variable v in Impl.InParams) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + foreach (Variable v in Impl.OutParams) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + return; + } + + Graph blockGraph = prog.ProcessLoops(Impl); + var ctrlDep = blockGraph.ControlDependence(); + + // Compute transitive closure of control dependence info. + bool changed; + do + { + changed = false; + foreach (var depEntry in ctrlDep) + { + var newDepSet = new HashSet(depEntry.Value); + foreach (var dep in depEntry.Value) + { + if (ctrlDep.ContainsKey(dep)) + newDepSet.UnionWith(ctrlDep[dep]); + } + if (newDepSet.Count != depEntry.Value.Count) + { + depEntry.Value.UnionWith(newDepSet); + changed = true; + } + } + } while (changed); + + var nonUniformBlockSet = new HashSet(); + nonUniformBlocks[Impl.Name] = nonUniformBlockSet; + + do { + changed = false; + foreach (var block in Impl.Blocks) { + bool uniform = !nonUniformBlockSet.Contains(block); + bool newUniform = Analyse(Impl, block.Cmds, uniform); + if (uniform && !newUniform) { + changed = true; + nonUniformBlockSet.Add(block); + Block pred = blockGraph.Predecessors(block).Single(); + if (ctrlDep.ContainsKey(pred)) + nonUniformBlockSet.UnionWith(ctrlDep[pred]); + } + } + } while (changed); + } + else + { + Analyse(Impl, Impl.StructuredStmts, ControlFlowIsUniform); + } + } + + + private void Analyse(Implementation impl, StmtList stmtList, bool ControlFlowIsUniform) + { + ControlFlowIsUniform &= !hitNonuniformReturn; + foreach (BigBlock bb in stmtList.BigBlocks) + { + Analyse(impl, bb, ControlFlowIsUniform); + } + } + + private Implementation GetImplementation(string procedureName) + { + foreach (Declaration D in prog.TopLevelDeclarations) + { + if (D is Implementation && ((D as Implementation).Name == procedureName)) + { + return D as Implementation; + } + } + return null; + } + + private void Analyse(Implementation impl, BigBlock bb, bool ControlFlowIsUniform) + { + ControlFlowIsUniform &= !hitNonuniformReturn; + Analyse(impl, bb.simpleCmds, ControlFlowIsUniform); + + if (bb.ec is WhileCmd) + { + WhileCmd wc = bb.ec as WhileCmd; + loopStack.Add(wc); + Analyse(impl, wc.Body, ControlFlowIsUniform && IsUniform(impl.Name, wc.Guard) && + !nonUniformLoops[impl.Name].Contains(GetLoopId(wc))); + loopStack.RemoveAt(loopStack.Count - 1); + } + else if (bb.ec is IfCmd) + { + IfCmd ifCmd = bb.ec as IfCmd; + Analyse(impl, ifCmd.thn, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard)); + if (ifCmd.elseBlock != null) + { + Analyse(impl, ifCmd.elseBlock, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard)); + } + Debug.Assert(ifCmd.elseIf == null); + } + else if (bb.ec is BreakCmd) + { + if (!ControlFlowIsUniform && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[loopStack.Count - 1]))) + { + SetNonUniform(impl.Name, loopStack[loopStack.Count - 1]); + } + } + + if (bb.tc is ReturnCmd && !ControlFlowIsUniform) + { + hitNonuniformReturn = true; + if (loopStack.Count > 0 && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[0]))) + { + SetNonUniform(impl.Name, loopStack[0]); + loopsWithNonuniformReturn[impl.Name].Add(GetLoopId(loopStack[0])); + } + } + + + } + + private bool Analyse(Implementation impl, CmdSeq cmdSeq, bool ControlFlowIsUniform) + { + foreach (Cmd c in cmdSeq) + { + if (c is AssignCmd) + { + AssignCmd assignCmd = c as AssignCmd; + foreach (var a in assignCmd.Lhss.Zip(assignCmd.Rhss)) + { + + if (a.Item1 is SimpleAssignLhs) + { + SimpleAssignLhs lhs = a.Item1 as SimpleAssignLhs; + Expr rhs = a.Item2; + if (IsUniform(impl.Name, lhs.AssignedVariable.Name) && + (!ControlFlowIsUniform || !IsUniform(impl.Name, rhs))) + { + SetNonUniform(impl.Name, lhs.AssignedVariable.Name); + } + + } + } + } + else if (c is HavocCmd) + { + HavocCmd havocCmd = c as HavocCmd; + foreach(IdentifierExpr ie in havocCmd.Vars) + { + if(IsUniform(impl.Name, ie.Decl.Name)) { + SetNonUniform(impl.Name, ie.Decl.Name); + } + } + } + else if (c is CallCmd) + { + CallCmd callCmd = c as CallCmd; + Implementation CalleeImplementation = GetImplementation(callCmd.callee); + + if (CalleeImplementation != null) + { + + if (!ControlFlowIsUniform) + { + if (IsUniform(callCmd.callee)) + { + SetNonUniform(callCmd.callee); + } + } + for (int i = 0; i < CalleeImplementation.InParams.Length; i++) + { + if (IsUniform(callCmd.callee, CalleeImplementation.InParams[i].Name) + && !IsUniform(impl.Name, callCmd.Ins[i])) + { + SetNonUniform(callCmd.callee, CalleeImplementation.InParams[i].Name); + } + } + + for (int i = 0; i < CalleeImplementation.OutParams.Length; i++) + { + if (IsUniform(impl.Name, callCmd.Outs[i].Name) + && !IsUniform(callCmd.callee, CalleeImplementation.OutParams[i].Name)) + { + SetNonUniform(impl.Name, callCmd.Outs[i].Name); + } + } + + } + } + else if (c is AssumeCmd) + { + var ac = (AssumeCmd)c; + if (ControlFlowIsUniform && QKeyValue.FindBoolAttribute(ac.Attributes, "partition") && + !IsUniform(impl.Name, ac.Expr)) + { + ControlFlowIsUniform = false; + } + } + } + + return ControlFlowIsUniform; + } + + private int GetLoopId(WhileCmd wc) + { + AssertCmd inv = wc.Invariants[0] as AssertCmd; + Debug.Assert(inv.Attributes.Key.Contains("loophead_")); + return Convert.ToInt32(inv.Attributes.Key.Substring("loophead_".Length)); + } + + private void SetNonUniform(string procedureName) + { + uniformityInfo[procedureName] = new KeyValuePair> + (false, uniformityInfo[procedureName].Value); + RecordProcedureChanged(); + } + + private void SetNonUniform(string procedureName, WhileCmd wc) + { + nonUniformLoops[procedureName].Add(GetLoopId(wc)); + RecordProcedureChanged(); + } + + public bool IsUniform(string procedureName) + { + if (!uniformityInfo.ContainsKey(procedureName)) + { + return false; + } + return uniformityInfo[procedureName].Key; + } + + public bool IsUniform(string procedureName, Block b) + { + if (!nonUniformBlocks.ContainsKey(procedureName)) + { + return false; + } + return !nonUniformBlocks[procedureName].Contains(b); + } + + class UniformExpressionAnalysisVisitor : StandardVisitor { + + private bool isUniform = true; + private Dictionary uniformityInfo; + + public UniformExpressionAnalysisVisitor(Dictionary uniformityInfo) { + this.uniformityInfo = uniformityInfo; + } + + public override Variable VisitVariable(Variable v) { + if (!uniformityInfo.ContainsKey(v.Name)) { + isUniform = isUniform && (v is Constant); + } else if (!uniformityInfo[v.Name]) { + isUniform = false; + } + + return v; + } + + internal bool IsUniform() { + return isUniform; + } + } + + public bool IsUniform(string procedureName, Expr expr) + { + UniformExpressionAnalysisVisitor visitor = new UniformExpressionAnalysisVisitor(uniformityInfo[procedureName].Value); + visitor.VisitExpr(expr); + return visitor.IsUniform(); + } + + public bool IsUniform(string procedureName, string v) + { + if (!uniformityInfo.ContainsKey(procedureName)) + { + return false; + } + + if (!uniformityInfo[procedureName].Value.ContainsKey(v)) + { + return false; + } + return uniformityInfo[procedureName].Value[v]; + } + + private void SetUniform(string procedureName, string v) + { + uniformityInfo[procedureName].Value[v] = true; + RecordProcedureChanged(); + } + + private void RecordProcedureChanged() + { + ProcedureChanged = true; + } + + private void SetNonUniform(string procedureName, string v) + { + uniformityInfo[procedureName].Value[v] = false; + RecordProcedureChanged(); + } + + public void dump() + { + foreach (string p in uniformityInfo.Keys) + { + Console.WriteLine("Procedure " + p + ": " + + (uniformityInfo[p].Key ? "uniform" : "nonuniform")); + foreach (string v in uniformityInfo[p].Value.Keys) + { + Console.WriteLine(" " + v + ": " + + (uniformityInfo[p].Value[v] ? "uniform" : "nonuniform")); + } + Console.Write("Ins ["); + for (int i = 0; i < inParameters[p].Count; i++) + { + Console.Write((i == 0 ? "" : ", ") + inParameters[p][i]); + } + Console.WriteLine("]"); + Console.Write("Outs ["); + for (int i = 0; i < outParameters[p].Count; i++) + { + Console.Write((i == 0 ? "" : ", ") + outParameters[p][i]); + } + Console.WriteLine("]"); + Console.Write("Non-uniform loops:"); + foreach (int l in nonUniformLoops[p]) + { + Console.Write(" " + l); + } + Console.WriteLine(); + Console.Write("Non-uniform blocks:"); + foreach (Block b in nonUniformBlocks[p]) + { + Console.Write(" " + b.Label); + } + Console.WriteLine(); + } + } + + + public string GetInParameter(string procName, int i) + { + return inParameters[procName][i]; + } + + public string GetOutParameter(string procName, int i) + { + return outParameters[procName][i]; + } + + + public bool knowsOf(string p) + { + return uniformityInfo.ContainsKey(p); + } + + public void AddNonUniform(string proc, string v) + { + if (uniformityInfo.ContainsKey(proc)) + { + Debug.Assert(!uniformityInfo[proc].Value.ContainsKey(v)); + uniformityInfo[proc].Value[v] = false; + } + } + + public void AddNonUniform(string proc, Block b) { + if (nonUniformBlocks.ContainsKey(proc)) { + Debug.Assert(!nonUniformBlocks[proc].Contains(b)); + nonUniformBlocks[proc].Add(b); + } + } + + public bool IsUniform(string proc, WhileCmd wc) + { + if (unstructured) + return false; + + return !nonUniformLoops[proc].Contains(GetLoopId(wc)); + } + + public bool HasNonuniformReturn(string proc, WhileCmd whileCmd) + { + return loopsWithNonuniformReturn[proc].Contains(GetLoopId(whileCmd)); + } + } + +} diff --git a/Source/Provers/Simplify/Let2ImpliesVisitor.cs b/Source/Provers/Simplify/Let2ImpliesVisitor.cs deleted file mode 100644 index 9b8328d1..00000000 --- a/Source/Provers/Simplify/Let2ImpliesVisitor.cs +++ /dev/null @@ -1,236 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.VCExprAST; - -namespace Microsoft.Boogie.Simplify -{ - // Simplify does not understand the LET operator, so we have to replace - // it with implications (previously, this was done in the VCExprGenerator), or - // we have to apply the let as a substitution (in the case of terms) - - // This visitor expects that let-bindings are sorted, so that bound - // variables only occur after their declaration - - public class Let2ImpliesMutator : SubstitutingVCExprVisitor { - - public Let2ImpliesMutator(VCExpressionGenerator gen) :base(gen) { - Contract.Requires(gen!=null); - this.keepLetFormula = this.keepLetTerm = false; - } - - public Let2ImpliesMutator(VCExpressionGenerator gen, bool keepLetTerm, bool keepLetFormula):base(gen) { - Contract.Requires(gen!=null); - - this.keepLetTerm = keepLetTerm; - this.keepLetFormula = keepLetFormula; - } - - readonly bool keepLetTerm; - readonly bool keepLetFormula; - - public VCExpr Mutate(VCExpr expr) { - Contract.Requires(expr != null); - Contract.Ensures(Contract.Result() != null); - - return Mutate(expr, new VCExprSubstitution ()); - } - - //////////////////////////////////////////////////////////////////////////// - - private int polarity = 1; // 1 for positive, -1 for negative, 0 for both - - // we also track which variables occur in positive, negative, or - // in both positions (to decide whether implications or equations - // have to be used to define such a variable) - private enum OccurrenceTypes { None, Pos, Neg, PosNeg }; - private OccurrenceTypes Union(OccurrenceTypes o1, OccurrenceTypes o2) { - switch(o1) { - case OccurrenceTypes.None: return o2; - case OccurrenceTypes.Pos: - switch(o2) { - case OccurrenceTypes.None: - case OccurrenceTypes.Pos: - return OccurrenceTypes.Pos; - default: - return OccurrenceTypes.PosNeg; - } - case OccurrenceTypes.Neg: - switch(o2) { - case OccurrenceTypes.None: - case OccurrenceTypes.Neg: - return OccurrenceTypes.Neg; - default: - return OccurrenceTypes.PosNeg; - } - default: - return OccurrenceTypes.PosNeg; - } - } - - private IDictionary/*!*/ VarOccurrences = - new Dictionary(); - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(VarOccurrences != null); -} - - //////////////////////////////////////////////////////////////////////////// - - public override VCExpr Visit(VCExprVar node, - VCExprSubstitution substitution) { - Contract.Requires(node!= null); - Contract.Requires(substitution != null); - Contract.Ensures(Contract.Result() != null); - - VCExpr res = base.Visit(node, substitution); - Contract.Assert(res!=null); - - VCExprVar resAsVar = res as VCExprVar; - if (resAsVar != null) { - OccurrenceTypes occ; - if (polarity > 0) - occ = OccurrenceTypes.Pos; - else if (polarity < 0) - occ = OccurrenceTypes.Neg; - else - occ = OccurrenceTypes.PosNeg; - - OccurrenceTypes oldOcc; - if (VarOccurrences.TryGetValue(resAsVar, out oldOcc)) - occ = Union(occ, oldOcc); - VarOccurrences[resAsVar] = occ; - } - - return res; - } - - public override VCExpr Visit(VCExprNAry node, - VCExprSubstitution substitution) { - Contract.Requires(node != null); - Contract.Requires(substitution != null); - Contract.Ensures(Contract.Result() != null); - - // track the polarity to ensure that no implications are introduced - // in negative positions - // UGLY: the code for tracking polarities should be factored out - // (similar code is used in the TypeEraser) - - VCExpr res; - if (node.Op.Equals(VCExpressionGenerator.NotOp)) { - polarity = -polarity; - res = base.Visit(node, substitution); - polarity = -polarity; - } else if (node.Op.Equals(VCExpressionGenerator.ImpliesOp)) { - polarity = -polarity; - VCExpr newArg0 = Mutate(node[0], substitution); - Contract.Assert(newArg0 != null); - polarity = -polarity; - VCExpr newArg1 = Mutate(node[1], substitution); - Contract.Assert(newArg1 != null); - - res = Gen.Implies(newArg0, newArg1); - } else if (!node.Op.Equals(VCExpressionGenerator.AndOp) && - !node.Op.Equals(VCExpressionGenerator.OrOp) && - !(node.Op is VCExprLabelOp)) { - // standard is to set the polarity to 0 (fits most operators) - int oldPolarity = polarity; - polarity = 0; - res = base.Visit(node, substitution); - polarity = oldPolarity; - } else { - res = base.Visit(node, substitution); - } - - return res; - } - - public override VCExpr Visit(VCExprLet originalNode, - VCExprSubstitution substitution) { - Contract.Requires(originalNode != null); - Contract.Requires(substitution != null); - Contract.Ensures(Contract.Result() != null); - - // first sort the bindings to be able to apply substitutions - LetBindingSorter letSorter = new LetBindingSorter (Gen); - Contract.Assert(letSorter != null); - VCExpr newNode = letSorter.Mutate(originalNode, true); - Contract.Assert(newNode != null); - VCExprLet node = newNode as VCExprLet; - - if (node == null) - // it can happen that the complete let-expressions gets eliminated by the - // sorter, which also checks whether let-bindings are actually used - return newNode; - - substitution.PushScope(); try { - - // the bindings that remain and that are later handled using an implication - List bindings = new List (); - List keepBindings = new List (); - - foreach (VCExprLetBinding binding in node) { - Contract.Assert(binding != null); - // in all cases we apply the substitution up to this point - // to the bound formula - VCExpr newE = Mutate(binding.E, substitution); - Contract.Assert(newE != null); - if (binding.V.Type.IsBool) { - // a bound formula is handled using an implication; we introduce - // a fresh variable to avoid clashes - Contract.Assert( polarity > 0); - - if (keepLetFormula) { - keepBindings.Add(Gen.LetBinding(binding.V, newE)); - - } else { - VCExprVar newVar = Gen.Variable(binding.V.Name, Type.Bool); - Contract.Assert(newVar != null); - substitution[binding.V] = newVar; - - bindings.Add(Gen.LetBinding(newVar, newE)); - } - } else { - if (keepLetTerm) { - keepBindings.Add(Gen.LetBinding(binding.V, newE)); - } else { - // a bound term is substituted - substitution[binding.V] = newE; - } - } - } - - VCExpr newBody = Mutate(node.Body, substitution); - Contract.Assert(newBody != null); - if (keepBindings.Count > 0) { - newBody = Gen.Let(keepBindings, newBody); - } - - // Depending on the places where the variable occurs, we would - // have to introduce implications or equations to define the - // bound variables. For the time being, we just assert that all - // occurrences are positive - foreach (VCExprLetBinding b in bindings) { - Contract.Assert(b != null); - OccurrenceTypes occ; - if (VarOccurrences.TryGetValue(b.V, out occ)) - Contract.Assert( occ == OccurrenceTypes.None || occ == OccurrenceTypes.Pos); - } - - return Gen.ImpliesSimp(Gen.AsImplications(bindings), newBody); - - } finally { - substitution.PopScope(); - } - } - } - -} \ No newline at end of file diff --git a/Source/Provers/Simplify/Prover.cs b/Source/Provers/Simplify/Prover.cs deleted file mode 100644 index 3faa18e1..00000000 --- a/Source/Provers/Simplify/Prover.cs +++ /dev/null @@ -1,656 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.IO; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Collections; -using System.Collections.Generic; -//using util; -using Microsoft.Boogie; - -// Simplified interface to an external prover like Simplify or the z3 process, taken from Bird. -namespace Microsoft.Boogie.Simplify { - /// - /// An interface to Simplify theorem prover. - /// - /// - [ContractClass(typeof(ProverProcessContracts))] - public abstract class ProverProcess { - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(simplify != null); - Contract.Invariant(fromSimplify != null); - Contract.Invariant(toSimplify != null); - Contract.Invariant(fromStdError != null); - } - - [Rep] - protected readonly Process simplify; - - [Rep] - readonly TextReader fromSimplify; - [Rep] - readonly TextWriter toSimplify; - [Rep] - readonly TextReader fromStdError; - - protected bool readTimedOut; - - int nFormulasChecked = 0; - public int NumFormulasChecked { - get { - return nFormulasChecked; - } - } - - // Note: In the Everett build (.NET framework < 2.0), Process.PeakVirtualMemorySize64 - // is not defined, but rather a version that returns an 'int' rather than a 'long'. - public long PeakVirtualMemorySize { - [NoDefaultContract] - get - //modifies this.*; - { - Contract.Requires(cce.IsPeerConsistent(this)); - try { - cce.BeginExpose(this); - simplify.Refresh(); -#if WHIDBEY - return simplify.PeakVirtualMemorySize64; -#else - return simplify.PeakPagedMemorySize64; -#endif - } finally { - cce.EndExpose(); - } - } - } - - public bool HasExited { - get { - return simplify.HasExited; - } - } - - public ProverProcess(ProcessStartInfo psi, string proverPath) { // throws ProverException - Contract.Requires(psi != null); - Contract.Requires(proverPath != null); - try { - Process simplify = Process.Start(psi); - this.simplify = simplify; - fromSimplify = simplify.StandardOutput; - toSimplify = simplify.StandardInput; - fromStdError = simplify.StandardError; - } catch (System.ComponentModel.Win32Exception e) { - throw new ProverException(string.Format("Unable to start the process {0}: {1}", proverPath, e.Message)); - } - // base(); - } - - public abstract string OptionComments(); - - //[Pure(false)] - public virtual IEnumerable!*/> ParameterSettings { - get { - yield break; - } - } - - public void Close() - //modifies this.*; - { - cce.BeginExpose(this); - { - toSimplify.Flush(); - if (this.simplify != null) { - if (!simplify.HasExited) { - this.Kill(); - } - simplify.Close(); - } - } - cce.EndExpose(); - } - - [NoDefaultContract] // this method assumes nothing about the object, other than that it has been constructed (which means simplify!=null) - [Verify(false)] // The call simplify.Kill will require simplify.IsPeerConsistent, but since we don't know the state of "this" and "simplify", we cannot afford the run-time check that an assume statement here would impose - public void Kill() { - try { - if (CommandLineOptions.Clo.ProverShutdownLimit > 0) { - toSimplify.Close(); - for (int i = 0; !simplify.HasExited && i <= CommandLineOptions.Clo.ProverShutdownLimit * 1000; i += 100) { - System.Threading.Thread.Sleep(100); - } - } - if (!simplify.HasExited) { - simplify.Kill(); - } - } catch (InvalidOperationException) { /* already exited */ - } catch (System.ComponentModel.Win32Exception) { /* already exiting */ - } - } - - public virtual void AddAxioms(string s) - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.Requires(s != null); - Contract.EnsuresOnThrow(true); - cce.BeginExpose(this); - toSimplify.Write("(BG_PUSH "); - toSimplify.Write(s); - toSimplify.WriteLine(")"); - cce.EndExpose(); - } - - public virtual void Feed(string s, int statementCount) - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.Requires(s != null); - Contract.EnsuresOnThrow(true); - cce.BeginExpose(this); - { - toSimplify.Write(s); - } - cce.EndExpose(); - } - - public virtual void PopAxioms() - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.EnsuresOnThrow(true); - cce.BeginExpose(this); - { - toSimplify.WriteLine("(BG_POP)"); - } - cce.EndExpose(); - } - - public void ToFlush() - //modifies this.*; - { - cce.BeginExpose(this); - { - toSimplify.Flush(); - } - cce.EndExpose(); - } - - public enum ProverOutcome { - Valid, - NotValid, - TimeOut, - OutOfMemory, - Inconclusive - } - - /// - /// Passes the formula to Simplify. - /// - public void BeginCheck(string descriptiveName, string formula) - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.Requires(descriptiveName != null); - Contract.Requires(formula != null); - DoBeginCheck(descriptiveName, formula); - nFormulasChecked++; - } - - /// - /// Reports the outcome of formula checking. If the outcome is Invalid, - /// then the "handler" is invoked with each counterexample. - /// - public abstract ProverOutcome CheckOutcome(Microsoft.Boogie.ProverInterface.ErrorHandler handler); - //modifies this.**; - //modifies Console.Out.*, Console.Error.*; - //modifies handler.*; - - protected abstract void DoBeginCheck(string descriptiveName, string formula); - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - - /// - /// Returns an array of the labels in "labels", with "|" brackets (if any) - /// stripped off. - /// Assumes that every label begins with "|+" or "|@", or just "+" or "@", - /// and ends with "|" if it started with one, and that these "|" brackets are - /// the only "|"s in "labels". - /// - protected static List!*/> ParseLabels(string labels) { - Contract.Requires(labels != null); - Contract.Ensures(Contract.Result>() != null); - - List list = new List(); - int j = 0; - while (true) - // invariant: j is the number of characters of "labels" consumed so far - // invariant: an even number of '|' characters remain in "labels" - { - cce.LoopInvariant(0 <= j && j <= labels.Length); - j = labels.IndexOfAny(new char[] { '|', '+', '@' }, j); - if (j < 0) { - // no more labels - return list; - } - char ch = labels[j]; - if (ch == '|') { - j++; // skip the '|' - Contract.Assume(j < labels.Length); // there should now be a '+' or '@' - ch = labels[j]; - } - Contract.Assume(ch == '+' || ch == '@'); - j++; // skip the '+' or '@' - int k = labels.IndexOfAny(new char[] { '|', ' ', ')' }, j); - Contract.Assume(j + 2 <= k); - string s = labels.Substring(j, k - j); - list.Add(s); - j = k + 1; - } - } - - [Rep] - char[] expectBuffer = null; - - /// - /// Expects s[0]==ch and the next s.Length-1 characters of the input to be s[1,..] - /// If not, more characters may be read from "fromSimplify" to provide additional context - /// for the UnexpectedProverOutputException exception that will be thrown. - /// - protected void Expect(int ch, string s) - //modifies this.*; - { - Contract.Requires(s != null); - Contract.Requires(1 <= s.Length); - Contract.EnsuresOnThrow(true); - if (ch == -1) { - // a return of -1 from FromReadChar means that there is no StdOutput - // to treat this we can return the error message we get from Z3 on StdError and then - // declare this case to be inconclusive - string str = FromStdErrorAll(); - if (str == "") { - throw new ProverDiedException(); - } else { - throw new UnexpectedProverOutputException("Expected \"" + s + "\", found:\r\n<<>>\r\n" + str + "<<>>"); - } - } - - string badInputPrefix; - if (ch != s[0]) { - badInputPrefix = Char.ToString((char)ch); - } else { - int len = s.Length - 1; - if (expectBuffer == null || expectBuffer.Length < len) { - cce.BeginExpose(this); - { - expectBuffer = new char[len]; - } - cce.EndExpose(); - } - try { - string s0; - cce.BeginExpose(this); - { - fromSimplify.ReadBlock(expectBuffer, 0, len); - s0 = new string(expectBuffer, 0, len); - } - cce.EndExpose(); - string s1 = s.Substring(1, len); - if (s0.CompareTo(s1) == 0) { - badInputPrefix = null; // no error - } else { - badInputPrefix = (char)ch + s0; - } - } catch (IOException) { - throw new UnexpectedProverOutputException("Expected \"" + s + "\", encountered IO exception."); - } - } - - if (badInputPrefix != null) { - // Read the rest of the available input, without blocking! - // Despite the confusing documentation for the Read method, it seems - // that Read does block. It if didn't, I would have written: - // string remaining = ""; - // char[] buf = new char[1024]; - // while (true) { - // int len = fromSimplify.Read(buf, 0, buf.Length); - // remaining += new String(buf, 0, len); - // if (len != buf.Length) { - // break; - // } - // } - // But instead, I'll just hope that one line of input is available and read - // it. - string remaining = fromSimplify.ReadLine() + "\r\n"; - throw new UnexpectedProverOutputException("Expected \"" + s + "\", found:\r\n<<>>\r\n" + badInputPrefix + remaining + "<<>>"); - } - } - - protected int FromReadChar() - //modifies this.*; - { - try { - cce.BeginExpose(this); - return fromSimplify.Read(); - } finally { - cce.EndExpose(); - } - } - - private void KillProver(object state) { - cce.BeginExpose(this); - { - this.readTimedOut = true; - simplify.Kill(); - } - cce.EndExpose(); - } - - protected int FromReadChar(int timeout) - //modifies this.*; - { - Contract.Requires(-1 <= timeout); - try { - cce.BeginExpose(this); - this.readTimedOut = false; - System.Threading.Timer t = new System.Threading.Timer(this.KillProver, null, timeout, System.Threading.Timeout.Infinite); - int ch = fromSimplify.Read(); - t.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); - t.Dispose(); - return ch; - } finally { - cce.EndExpose(); - } - } - - protected string FromReadLine() - //modifies this.*; - { - Contract.Ensures(Contract.Result() != null); - try { - cce.BeginExpose(this); - string s = fromSimplify.ReadLine(); - if (s == null) { - // this is what ReadLine returns if all characters have been read - s = ""; - } - return s; - } finally { - cce.EndExpose(); - } - } - - protected string FromStdErrorAll() - //modifies this.*; - { - Contract.Ensures(Contract.Result() != null); - - try { - cce.BeginExpose(this); - if (fromStdError != null) { - string s = fromStdError.ReadToEnd(); - if (s == null) { - // this is what ReadLine returns if all characters have been read - s = ""; - } - return s; - } else { - // there is no StdErrorReader available - return ""; - } - } finally { - cce.EndExpose(); - } - } - - protected void ToWriteLine(string s) - //modifies this.*; - { - Contract.Requires(s != null); - cce.BeginExpose(this); - { - toSimplify.WriteLine(s); - } - cce.EndExpose(); - } - } - [ContractClassFor(typeof(ProverProcess))] - public abstract class ProverProcessContracts : ProverProcess { - private ProverProcessContracts() : base(null, null) { } - public override string OptionComments() { - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - - public override ProverProcess.ProverOutcome CheckOutcome(ProverInterface.ErrorHandler handler) { - Contract.Requires(handler != null); - throw new NotImplementedException(); - } - - protected override void DoBeginCheck(string descriptiveName, string formula) { - Contract.Requires(descriptiveName != null); - Contract.Requires(formula != null); - throw new NotImplementedException(); - } - } - // derived by Z3ProverProcess - public class SimplifyProverProcess : ProverProcess { - public SimplifyProverProcess(string proverPath, bool dummy) :base(getPSI(proverPath),proverPath) { - Contract.Requires(proverPath != null); - // throws ProverException - } - private static ProcessStartInfo getPSI(string proverPath){ProcessStartInfo psi = new ProcessStartInfo(proverPath, "-labelsonly"); - psi.CreateNoWindow = true; - psi.UseShellExecute = false; - psi.RedirectStandardInput = true; - psi.RedirectStandardOutput = true; - psi.RedirectStandardError = true; - Contract.Assume(psi.EnvironmentVariables != null); // by inspecting the code through Reflector; the documentation says this property is "null by default", whatever that means --KRML - if (0 <= CommandLineOptions.Clo.ProverKillTime) { - psi.EnvironmentVariables["PROVER_KILL_TIME"] = CommandLineOptions.Clo.ProverKillTime.ToString(); - } - if (0 <= CommandLineOptions.Clo.SimplifyProverMatchDepth) { - psi.EnvironmentVariables["PROVER_MATCH_DEPTH"] = CommandLineOptions.Clo.SimplifyProverMatchDepth.ToString(); - } - if (0 <= CommandLineOptions.Clo.ProverCCLimit) { - psi.EnvironmentVariables["PROVER_CC_LIMIT"] = CommandLineOptions.Clo.ProverCCLimit.ToString(); - } - return psi; - } - - - public override string OptionComments() { - Contract.Ensures(Contract.Result() != null); - - // would we want the timeout stuff here? - return ""; - } - - [NotDelayed] - // TODO it complains about things not beeing peer consistent upon call to EatPrompt() - // not sure what is it about... --micmo - [Verify(false)] - public SimplifyProverProcess(string proverPath):base(getPSI(proverPath),proverPath) - //modifies Console.Out.*, Console.Error.*; - { - Contract.Requires(proverPath != null); - Contract.EnsuresOnThrow(true); - EatPrompt(); - } - - private void EatPrompt() - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.EnsuresOnThrow(true); - // skips text matching the regular expression: (white space)* ">\t" - ToFlush(); - - int ch = 0; - do { - ch = FromReadChar(); - } while (Char.IsWhiteSpace((char)ch)); - - while (ch == 'W') { - ch = ConsumeWarnings(ch, null); - } - - Expect(ch, ">\t"); - } - - public override void AddAxioms(string s) { - //Contract.Requires(s != null); - Contract.EnsuresOnThrow(true); - //ToWriteLine("(PROMPT_OFF)"); - base.AddAxioms(s); - //ToWriteLine("(PROMPT_ON)"); - EatPrompt(); - } - - public override void Feed(string s, int statementCount) { - //Contract.Requires(s != null); - Contract.EnsuresOnThrow(true); - //ToWriteLine("(PROMPT_OFF)"); - base.Feed(s, statementCount); - //ToWriteLine("(PROMPT_ON)"); - for (int i = 0; i < statementCount; i++) { - EatPrompt(); - } - } - - public override void PopAxioms() { - Contract.EnsuresOnThrow(true); - base.PopAxioms(); - EatPrompt(); - } - - protected override void DoBeginCheck(string descriptiveName, string formula) { - //Contract.Requires(descriptiveName != null); - //Contract.Requires(formula != null); - //simplify.Refresh(); - //this.Comment("@@@@ Virtual Memory: " + simplify.PeakVirtualMemorySize64); - //this.Comment("@@@@ Working Set: " + simplify.PeakWorkingSet64); - //this.Comment("@@@@ Paged Memory: " + simplify.PeakPagedMemorySize64); - - ToWriteLine(formula); - ToFlush(); - } - - public override ProverOutcome CheckOutcome(Microsoft.Boogie.ProverInterface.ErrorHandler handler) { - //Contract.Requires(handler != null); - Contract.EnsuresOnThrow(true); - ProverOutcome outcome; - - if (this.simplify == null) { - return ProverOutcome.Inconclusive; - } - - int ch = FromReadChar(); - while (ch == 'W') { - ch = ConsumeWarnings(ch, handler); - } - if (ch == 'E') { - Expect(ch, "Exceeded PROVER_KILL_TIME -- discontinuing search for counterexamples."); - FromReadLine(); - ch = FromReadChar(); - if (ch == '\n') { - ch = FromReadChar(); - } - Expect(ch, " labels:"); - FromReadLine(); - ch = FromReadChar(); - ch = FromReadChar(); - ch = FromReadChar(); - FromReadLine(); - ch = FromReadChar(); - ch = FromReadChar(); - ch = FromReadChar(); - return ProverOutcome.TimeOut; - } - if ('0' <= ch && ch <= '9') { - // Valid! - do { - ch = FromReadChar(); - } while ('0' <= ch && ch <= '9'); - Expect(ch, ": Valid."); - outcome = ProverOutcome.Valid; - ToWriteLine(String.Format("; FORMULA {0} IS VALID!", NumFormulasChecked + 1 /*Simplify starts at 1*/)); - } else { - // now we expect one or more counterexample contexts, each proving a list of labels - do { - List labels = ReadLabels(ch); - handler.OnModel(labels, null); - ch = FromReadChar(); - } while (ch == 'C'); - // now we expect ": Invalid" where is some number - while ('0' <= ch && ch <= '9') { - ch = FromReadChar(); - } - Expect(ch, ": Invalid."); - outcome = ProverOutcome.NotValid; - ToWriteLine(String.Format("; FORMULA {0} IS INVALID", NumFormulasChecked + 1 /*Simplify starts at 1*/)); - } - - EatPrompt(); - return outcome; - } - - List!*/> ReadLabels(int ch) - //modifies this.*; - { - Contract.Ensures(Contract.Result>() != null); - - Contract.EnsuresOnThrow(true); - Expect(ch, "Counterexample:\n"); // FIX! ? Is there a problem with \r\n here? - ch = FromReadChar(); - List theLabels; - if (ch == ' ') { - // there are labels - Expect(ch, " labels: "); - string labels = FromReadLine(); // reads "(A B C ...)\n" - theLabels = ParseLabels(labels); - ch = FromReadChar(); - } else { - theLabels = new List(); - } - Expect(ch, "\n"); // empty line - - return theLabels; - } - - int ConsumeWarnings(int ch, Microsoft.Boogie.ProverInterface.ErrorHandler handler) - //modifies this.*; - //modifies Console.Out.*, Console.Error.*; - { - Contract.Requires(ch == 'W'); - Contract.EnsuresOnThrow(true); - Expect(ch, "Warning: "); - string w = FromReadLine(); - if (w.StartsWith("triggerless quantifier body")) { - FromReadLine(); // blank line - w = "triggerless quantifier body: " + FromReadLine(); // expression (body) - FromReadLine(); // blank line - FromReadLine(); // "with X pattern variable(s)... - FromReadLine(); // blank line - FromReadLine(); // expression (entire quantifier) - } - - if (handler != null) - handler.OnProverWarning(w); - - ch = FromReadChar(); - if (ch == '\n') { - // make up for a poorly designed ReadLine routine (only the first - // character of the DOS end-of-line sequence "\r\n" is read) - ch = FromReadChar(); - } - return ch; - } - } - -} \ No newline at end of file diff --git a/Source/Provers/Simplify/ProverInterface.cs b/Source/Provers/Simplify/ProverInterface.cs deleted file mode 100644 index 4584b2e7..00000000 --- a/Source/Provers/Simplify/ProverInterface.cs +++ /dev/null @@ -1,868 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Threading; -using System.IO; -using System.Text; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.AbstractInterpretation; -using Microsoft.Boogie.Simplify; -using Microsoft.Boogie.VCExprAST; -using Microsoft.Boogie.TypeErasure; -using System.Text.RegularExpressions; - -namespace Microsoft.Boogie.Simplify { - public abstract class LogProverInterface : ProverInterface { - [NotDelayed] - protected LogProverInterface(ProverOptions options, - string openComment, string closeComment, - string openActivity, string closeActivity, - VCExpressionGenerator gen) { - Contract.Requires(options != null); - Contract.Requires(openComment != null); - Contract.Requires(closeComment != null); - Contract.Requires(openActivity != null); - Contract.Requires(closeActivity != null); - Contract.Requires(gen != null); - Contract.Ensures(this.gen == gen); - if (options.SeparateLogFiles) { - this.commonPrefix = new List(); - } else { - this.logFileWriter = options.OpenLog(null); - } - this.openCommentString = openComment; - this.closeCommentString = closeComment; - this.openActivityString = openActivity; - this.closeActivityString = closeActivity; - this.gen = gen; - this.options = options; - - if (CommandLineOptions.Clo.ShowEnv != CommandLineOptions.ShowEnvironment.Never) { - // Emit version comment in the log - LogCommonComment(CommandLineOptions.Clo.Version); - LogCommonComment(CommandLineOptions.Clo.Environment); - } - } - - [StrictReadonly] - [Additive] - protected readonly VCExpressionGenerator gen; - - private TextWriter/*?*/ logFileWriter; - [StrictReadonly] - private readonly string openCommentString; - [StrictReadonly] - private readonly string closeCommentString; - [StrictReadonly] - private readonly string openActivityString; - [StrictReadonly] - private readonly string closeActivityString; - [StrictReadonly] - protected readonly ProverOptions options; - [StrictReadonly] - private readonly List/*?*/ commonPrefix; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(openCommentString != null); - Contract.Invariant(closeCommentString != null); - Contract.Invariant(openActivityString != null); - Contract.Invariant(closeActivityString != null); - Contract.Invariant(options != null); - Contract.Invariant(commonPrefix == null || cce.NonNullElements(commonPrefix)); - } - - - public void LogActivity(string s) { - Contract.Requires(s != null); - LogActivity(s, false); - } - - public void LogCommon(string s) { - Contract.Requires(s != null); - LogActivity(s, true); - } - - private void LogActivity(string s, bool common) { - Contract.Requires(s != null); - Contract.Assume(common || !options.SeparateLogFiles || logFileWriter != null); - if (logFileWriter != null) { - logFileWriter.Write(openActivityString); - logFileWriter.Write(s); - logFileWriter.WriteLine(closeActivityString); - logFileWriter.Flush(); - } - if (common && commonPrefix != null) { - commonPrefix.Add(openActivityString + s + closeActivityString); - } - } - - /// - /// Write "comment" to logfile, if any, formatted as a comment for the theorem prover at hand. - /// Assumes that "comment" does not contain any characters that would prematurely terminate - /// the comment (like, perhaps, a newline or "*/"). - /// - public override void LogComment(string comment) { - //Contract.Requires(comment != null); - LogComment(comment, false); - } - - public void LogCommonComment(string comment) { - Contract.Requires(comment != null); - LogComment(comment, true); - } - - private void LogComment(string comment, bool common) { - Contract.Requires(comment != null); - Contract.Assume(common || !options.SeparateLogFiles || logFileWriter != null); - if (logFileWriter != null) { - logFileWriter.Write(openCommentString); - logFileWriter.Write(comment); - logFileWriter.WriteLine(closeCommentString); - logFileWriter.Flush(); - } - if (common && commonPrefix != null) { - commonPrefix.Add(openCommentString + comment + closeCommentString); - } - } - - public virtual void NewProblem(string descName) { - Contract.Requires(descName != null); - if (commonPrefix != null) { - if (logFileWriter != null) { - logFileWriter.Close(); - } - logFileWriter = options.OpenLog(descName); - if (logFileWriter != null) { - foreach (string s in commonPrefix) { - Contract.Assert(s != null); - logFileWriter.WriteLine(s); - } - } - } - LogComment("Proof obligation: " + descName); - } - - public override void Close() { - if (logFileWriter != null) { - logFileWriter.Close(); - logFileWriter = null; - } - } - - public override VCExpressionGenerator VCExprGen { - get { - Contract.Ensures(Contract.Result() != null); - return this.gen; - } - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - [ContractClass(typeof(ProcessTheoremProverContracts))] - public abstract class ProcessTheoremProver : LogProverInterface { - private static string _proverPath; - - protected AxiomVCExprTranslator vcExprTranslator { - get { - Contract.Ensures(Contract.Result() != null); - - return cce.NonNull((AxiomVCExprTranslator)ctx.exprTranslator); - } - } - - protected abstract AxiomVCExprTranslator SpawnVCExprTranslator(ProverOptions p); - - // Return the number of axioms pushed to the theorem prover - protected int FeedNewAxiomsDecls2Prover() { - Contract.EnsuresOnThrow(true); - if (thmProver == null) - return 0; - int ret = 0; - foreach (string s in vcExprTranslator.NewTypeDecls) { - Contract.Assert(s != null); - LogCommon(s); - thmProver.Feed(s, 0); - } - foreach (string s in vcExprTranslator.NewAxioms) { - Contract.Assert(s != null); - LogBgPush(s); - thmProver.AddAxioms(s); - ret++; - } - return ret; - } - - protected static string CodebaseString() { - Contract.Ensures(Contract.Result() != null); - - return Path.GetDirectoryName(cce.NonNull(System.Reflection.Assembly.GetExecutingAssembly().Location)); - } - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNullDictionaryAndValues(BackgroundPredicates)); - Contract.Invariant(BackgroundPredFilename != null); - Contract.Invariant(ctx != null); - } - - private static IDictionary!*/> BackgroundPredicates = - new Dictionary(); - - protected static string GetBackgroundPredicate(string filename) { - Contract.Requires(filename != null); - Contract.Ensures(Contract.Result() != null); - - string res; - if (!BackgroundPredicates.TryGetValue(filename, out res)) { - // do we have to lock/synchronise anything? - string univBackPredPath = Path.Combine(CodebaseString(), filename); - using (StreamReader reader = new System.IO.StreamReader(univBackPredPath)) { - res = reader.ReadToEnd(); - } - BackgroundPredicates.Add(filename, res); - } - return cce.NonNull(res); - } - - static void InitializeGlobalInformation(string proverExe) - // throws ProverException, System.IO.FileNotFoundException; - { - Contract.Requires(proverExe != null); - Contract.Ensures(_proverPath != null); - - if (CommandLineOptions.Clo.Z3ExecutablePath != null) { - _proverPath = CommandLineOptions.Clo.Z3ExecutablePath; - } - - if (_proverPath == null) { - // Initialize '_proverPath' - _proverPath = Path.Combine(CodebaseString(), proverExe); - string firstTry = _proverPath; - - if (File.Exists(firstTry)) - return; - - string programFiles = Environment.GetEnvironmentVariable("ProgramFiles"); - Contract.Assert(programFiles != null); - string programFilesX86 = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); - if (programFiles.Equals(programFilesX86)) { - // If both %ProgramFiles% and %ProgramFiles(x86)% point to "ProgramFiles (x86)", use %ProgramW6432% instead. - programFiles = Environment.GetEnvironmentVariable("ProgramW6432"); - } - - - List z3Dirs = new List(); - if (Directory.Exists(programFiles + @"\Microsoft Research\")) { - string msrDir = programFiles + @"\Microsoft Research\"; - z3Dirs.AddRange(Directory.GetDirectories(msrDir, "Z3-*")); - } - if (Directory.Exists(programFilesX86 + @"\Microsoft Research\")) { - string msrDir = programFilesX86 + @"\Microsoft Research\"; - z3Dirs.AddRange(Directory.GetDirectories(msrDir, "Z3-*")); - } - - // Look for the most recent version of Z3. - int minor = 0, major = 0; - string winner = null; - Regex r = new Regex(@"^Z3-(\d+)\.(\d+)$"); - foreach (string d in z3Dirs) { - string name = new DirectoryInfo(d).Name; - foreach (Match m in r.Matches(name)) { - int ma, mi; - ma = int.Parse(m.Groups[1].ToString()); - mi = int.Parse(m.Groups[2].ToString()); - if (major < ma || (major == ma && minor < mi)) { - major = ma; - minor = mi; - winner = d; - } - } - } - - if (major == 0 && minor == 0) { - throw new ProverException("Cannot find executable: " + firstTry); - } - Contract.Assert(winner != null); - - _proverPath = Path.Combine(Path.Combine(winner, "bin"), proverExe); - if (!File.Exists(_proverPath)) { - throw new ProverException("Cannot find prover: " + _proverPath); - } - - if (CommandLineOptions.Clo.Trace) { - Console.WriteLine("[TRACE] Using prover: " + _proverPath); - } - } - } - - [Rep] - protected internal ProverProcess thmProver; - bool currentProverHasBeenABadBoy = false; - // invariant currentProverHasBeenABadBoy ==> thmProver != null; - protected int restarts = 0; - protected DeclFreeProverContext ctx; - protected string BackgroundPredFilename; - protected ConsoleCancelEventHandler cancelEvent; - - [NotDelayed] - public ProcessTheoremProver(ProverOptions options, VCExpressionGenerator gen, DeclFreeProverContext ctx, - string proverExe, string backgroundPred) - : base(options, "; ", "", "", "", gen) { - Contract.Requires(options != null); - Contract.Requires(gen != null); - Contract.Requires(ctx != null); - Contract.Requires(proverExe != null); - Contract.Requires(backgroundPred != null); - Contract.EnsuresOnThrow(true); - BackgroundPredFilename = backgroundPred; - InitializeGlobalInformation(proverExe); - this.ctx = ctx; - - - // ensure that a VCExprTranslator is available - // if none exists so far, we have to create a new one - // from scratch and feed the axioms to it - if (ctx.exprTranslator == null) { - AxiomVCExprTranslator tl = SpawnVCExprTranslator(options); - ctx.exprTranslator = tl; - tl.AddAxiom(tl.translate(ctx.Axioms, -1)); - // we clear the lists with new axioms and declarations; - // they are not needed at this point - List x = tl.NewAxioms; - //x = x; // make the compiler happy: somebody uses the value of x - x = tl.NewTypeDecls; - } - } - - /// - /// MSchaef: Allows to Push a VCExpression as Axiom on the prover stack (beta) - /// - public override void PushVCExpression(VCExpr vc) { - //Contract.Requires(vc != null); - vcExprTranslator.AddAxiom(vcExprTranslator.translate(vc, 1)); - } - - public override string VCExpressionToString(VCExpr vc) { - //Contract.Requires(vc != null); - Contract.Ensures(Contract.Result() != null); - - return vcExprTranslator.translate(vc, 1); - } - - // Number of axioms pushed since the last call to Check - public override int NumAxiomsPushed() { - return vcExprTranslator.NewAxiomsCount; - } - - // Feed the axioms pushed since the last call to Check to the theorem prover - public override int FlushAxiomsToTheoremProver() { - Contract.EnsuresOnThrow(true); - return FeedNewAxiomsDecls2Prover(); - } - - public override void Pop() { - Contract.EnsuresOnThrow(true); - Contract.Assert(thmProver != null); - LogCommon("(BG_POP)"); - thmProver.PopAxioms(); - } - - [NoDefaultContract] // important, since we have no idea what state the object might be in when this handler is invoked - void ControlCHandler(object o, ConsoleCancelEventArgs a) { - if (thmProver != null) { - thmProver.Kill(); - } - } - - public override void Close() { - if (cancelEvent != null) { - Console.CancelKeyPress -= cancelEvent; - cancelEvent = null; - } - if (thmProver != null) { - cce.BeginExpose(this); - { - thmProver.Close(); - thmProver = null; - currentProverHasBeenABadBoy = false; - } - cce.EndExpose(); - } - base.Close(); - } - - private UnexpectedProverOutputException proverException; - - public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) { - //Contract.Requires(descriptiveName != null); - //Contract.Requires(vc != null); - //Contract.Requires(handler != null); - this.NewProblem(descriptiveName); - this.proverException = null; - - try { - this.ResurrectProver(); - - string vcString = vcExprTranslator.translate(vc, 1); - - Helpers.ExtraTraceInformation("Sending data to theorem prover"); - - int num_axioms_pushed = - FeedNewAxiomsDecls2Prover(); - - LogActivity(vcString); - - Contract.Assert(thmProver != null); - thmProver.BeginCheck(descriptiveName, vcString); - - if (CommandLineOptions.Clo.StratifiedInlining > 0) { - // Pop all the axioms that were pushed by FeedNewAxiomsDecls2Prover - for (int i = 0; i < num_axioms_pushed; i++) { - LogBgPop(); - thmProver.PopAxioms(); - } - } - - if (CommandLineOptions.Clo.RestartProverPerVC) { - LogComment("Will restart the prover due to /restartProver option"); - currentProverHasBeenABadBoy = true; - } - } catch (UnexpectedProverOutputException e) { - proverException = e; - } - } - - public override Outcome CheckOutcome(ErrorHandler handler) { - //Contract.Requires(handler != null); - Contract.EnsuresOnThrow(true); - - if (this.thmProver == null) { - return Outcome.Undetermined; - } - - if (proverException == null) { - try { - ProverProcess.ProverOutcome result = thmProver.CheckOutcome(handler); - - if (options.ForceLogStatus) { - switch (result) { - case ProverProcess.ProverOutcome.Valid: - LogActivity("DBG_WAS_VALID"); - break; - case ProverProcess.ProverOutcome.NotValid: - LogActivity("DBG_WAS_INVALID"); - break; - } - } - - switch (result) { - case ProverProcess.ProverOutcome.Valid: - return Outcome.Valid; - case ProverProcess.ProverOutcome.TimeOut: - return Outcome.TimeOut; - case ProverProcess.ProverOutcome.OutOfMemory: - return Outcome.OutOfMemory; - case ProverProcess.ProverOutcome.Inconclusive: - return Outcome.Undetermined; - case ProverProcess.ProverOutcome.NotValid: - return Outcome.Invalid; - } - } catch (UnexpectedProverOutputException e) { - proverException = e; - } - } - - Contract.Assume(proverException != null); - LogComment("***** Unexpected prover output"); - cce.BeginExpose(this); - { - currentProverHasBeenABadBoy = true; // this will cause the next resurrect to restart the prover - } - cce.EndExpose(); - throw proverException; - } - - protected virtual void ResurrectProver() { - Contract.EnsuresOnThrow(true); - cce.BeginExpose(this); - { - if (thmProver != null) { - if (thmProver.HasExited) { - DateTime now = DateTime.Now; - LogComment("***** Prover Crashed at or before " + now.ToString("G")); - - } else if (CommandLineOptions.Clo.MaxProverMemory > 0 && - thmProver.NumFormulasChecked > CommandLineOptions.Clo.MinNumOfProverCalls && - thmProver.PeakVirtualMemorySize > CommandLineOptions.Clo.MaxProverMemory) { - LogComment("***** Exceeded memory limit. Peak memory usage so far: " + - thmProver.PeakVirtualMemorySize / CommandLineOptions.Megabyte + "MB"); - - } else if (!currentProverHasBeenABadBoy) { - // prover is ready to go - return; - } - - thmProver.Close(); - thmProver = null; - currentProverHasBeenABadBoy = false; - restarts++; - - if (CommandLineOptions.Clo.StratifiedInlining > 0) - { - Console.WriteLine("Warning: restarting theorem prover. Context could be lost"); - } - } - - FireUpNewProver(); - } - cce.EndExpose(); - } - - protected abstract ProverProcess CreateProverProcess(string proverPath); - - public void LogBgPush(string s) { - Contract.Requires(s != null); - LogCommon("(BG_PUSH "); - LogCommon(s); - LogCommon(")"); - } - - public void LogBgPop() { - LogCommon("(BG_POP)"); - } - - [NoDefaultContract] - private void FireUpNewProver() - { - Contract.Requires( cce.IsExposed(this)); - Contract.Requires( thmProver == null); - Contract.EnsuresOnThrow(true); - - if (cancelEvent == null && CommandLineOptions.Clo.RunningBoogieFromCommandLine) { - cancelEvent = new ConsoleCancelEventHandler(ControlCHandler); - Console.CancelKeyPress += cancelEvent; - } - thmProver = CreateProverProcess(_proverPath); - if (restarts == 0) { - foreach (string s in thmProver.OptionComments().Split('\n')) {Contract.Assert(s != null); - LogCommonComment(s); - } - foreach (string parmsetting in thmProver.ParameterSettings) {Contract.Assert(parmsetting != null); - LogCommon(parmsetting); - } - } - foreach (string parmsetting in thmProver.ParameterSettings) {Contract.Assert(parmsetting != null); - thmProver.Feed(parmsetting, 0); - } - thmProver.Feed(GetBackgroundPredicate(BackgroundPredFilename), 3); - - if (restarts == 0) { - // log the stuff before feeding it into the prover, so when it dies - // and takes Boogie with it, we know what happened - LogCommon(GetBackgroundPredicate(BackgroundPredFilename)); - - foreach (string s in vcExprTranslator.AllTypeDecls){Contract.Assert(s != null); - LogCommon(s);} - foreach (string s in vcExprTranslator.AllAxioms){Contract.Assert(s != null); - LogBgPush(s);} - - LogCommonComment("Initialized all axioms."); - } - - foreach (string s in vcExprTranslator.AllTypeDecls){Contract.Assert(s != null); - thmProver.Feed(s, 0);} - foreach (string s in vcExprTranslator.AllAxioms){Contract.Assert(s != null); - thmProver.AddAxioms(s);} - - // we have sent everything to the prover and can clear the lists with - // new axioms and declarations - List x = vcExprTranslator.NewAxioms; - //x = x; // make the compiler happy: somebody uses the value of x - x = vcExprTranslator.NewTypeDecls; - } - - public override ProverContext Context { - get { - Contract.Ensures(Contract.Result() != null); - return this.ctx; - } - } - } - [ContractClassFor(typeof(ProcessTheoremProver))] - public abstract class ProcessTheoremProverContracts :ProcessTheoremProver{ - protected override AxiomVCExprTranslator SpawnVCExprTranslator(ProverOptions p) { - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - - } - protected override ProverProcess CreateProverProcess(string proverPath) { - Contract.Requires(proverPath != null); - Contract.Ensures(Contract.Result() != null); - throw new NotImplementedException(); - } - [NotDelayed] - public ProcessTheoremProverContracts(ProverOptions options, VCExpressionGenerator gen, DeclFreeProverContext ctx, - string proverExe, string backgroundPred):base(options,gen,ctx,proverExe,backgroundPred) - {throw new NotImplementedException();} - } - - public class SimplifyTheoremProver : ProcessTheoremProver { - [NotDelayed] - public SimplifyTheoremProver(ProverOptions options, VCExpressionGenerator gen, DeclFreeProverContext ctx) - : base(options, gen, ctx, "simplify.exe", "UnivBackPred2.sx") { - Contract.EnsuresOnThrow(true); - } - - protected override ProverProcess CreateProverProcess(string proverPath) { - //Contract.Requires(proverPath != null); - Contract.Ensures(Contract.Result() != null); - - return new SimplifyProverProcess(proverPath); - } - - protected override AxiomVCExprTranslator SpawnVCExprTranslator(ProverOptions opts) { - //Contract.Requires(opts!=null); - Contract.Ensures(Contract.Result() != null); - - return new SimplifyVCExprTranslator(gen); - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - - public abstract class AxiomVCExprTranslator : VCExprTranslator { - protected AxiomVCExprTranslator() { - AllAxioms = new List (); - NewAxiomsAttr = new List (); - AllTypeDecls = new List (); - NewTypeDeclsAttr = new List (); - } - - protected AxiomVCExprTranslator(AxiomVCExprTranslator tl) { - Contract.Requires(tl != null); - AllAxioms = new List(tl.AllAxioms); - NewAxiomsAttr = new List(tl.NewAxiomsAttr); - AllTypeDecls = new List(tl.AllTypeDecls); - NewTypeDeclsAttr = new List(tl.NewTypeDeclsAttr); - } - - // we store all typing-related axioms that have been sent to the prover - // so that the prover can be re-initialised in case it dies - public readonly List!*/> AllAxioms; - private List!*/> NewAxiomsAttr; - - // The length of the list NewAxiomsAttr - public int NewAxiomsCount { - get { - return NewAxiomsAttr.Count; - } - } - - public List!*/> NewAxioms { - get { - Contract.Ensures(Contract.Result>() != null); - - List!*/> res = NewAxiomsAttr; - NewAxiomsAttr = new List(); - return res; - } - } - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(AllAxioms != null); - Contract.Invariant(NewAxiomsAttr != null); - Contract.Invariant(AllTypeDecls != null); - Contract.Invariant(NewTypeDeclsAttr != null); - } - - - // similarly, a list of declarations that have been sent to the prover - public readonly List!*/> AllTypeDecls; - private List!*/> NewTypeDeclsAttr; - - public List/*!>!*/ NewTypeDecls { - get { - List!*/> res = NewTypeDeclsAttr; - NewTypeDeclsAttr = new List(); - return res; - } - } - - public void AddAxiom(string axiom) { - Contract.Requires(axiom != null); - AllAxioms.Add(axiom); - NewAxiomsAttr.Add(axiom); - } - - public void AddTypeDecl(string typeDecl) { - Contract.Requires(typeDecl != null); - AllTypeDecls.Add(typeDecl); - NewTypeDeclsAttr.Add(typeDecl); - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - - public class SimplifyVCExprTranslator : AxiomVCExprTranslator { - public SimplifyVCExprTranslator(VCExpressionGenerator gen) { - Contract.Requires(gen != null); - Gen = gen; - TypeAxiomBuilder axBuilder; - switch (CommandLineOptions.Clo.TypeEncodingMethod) { - case CommandLineOptions.TypeEncoding.Arguments: - axBuilder = new TypeAxiomBuilderArguments(gen); - break; - default: - axBuilder = new TypeAxiomBuilderPremisses(gen); - break; - } - axBuilder.Setup(); - AxBuilder = axBuilder; - Namer = new UniqueNamer(); - LitAbstracter = new BigLiteralAbstracter(gen); - } - - private SimplifyVCExprTranslator(SimplifyVCExprTranslator tl) - : base(tl) { - Contract.Requires(tl != null); - Gen = tl.Gen; - AxBuilder = (TypeAxiomBuilder)tl.AxBuilder.Clone(); - Namer = (UniqueNamer)tl.Namer.Clone(); - LitAbstracter = (BigLiteralAbstracter)tl.LitAbstracter.Clone(); - } - - public override Object Clone() { - Contract.Ensures(Contract.Result() != null); - - return new SimplifyVCExprTranslator(this); - } - - private readonly VCExpressionGenerator Gen; - private readonly TypeAxiomBuilder AxBuilder; - private readonly UniqueNamer Namer; - private readonly BigLiteralAbstracter LitAbstracter; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Gen != null); - Contract.Invariant(AxBuilder != null); - Contract.Invariant(Namer != null); - Contract.Invariant(LitAbstracter != null); - } - - - public override string Lookup(VCExprVar var) { - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - - VCExprVar v = AxBuilder.TryTyped2Untyped(var); - if (v != null) { - var = v; - } - return Namer.Lookup(var); - } - - public override string translate(VCExpr expr, int polarity) { - //Contract.Requires(expr != null); - Contract.Ensures(Contract.Result() != null); - - Let2ImpliesMutator letImplier = new Let2ImpliesMutator(Gen); - Contract.Assert(letImplier != null); - - // handle the types in the VCExpr - TypeEraser eraser; - switch (CommandLineOptions.Clo.TypeEncodingMethod) { - case CommandLineOptions.TypeEncoding.Arguments: - eraser = new TypeEraserArguments((TypeAxiomBuilderArguments)AxBuilder, Gen); - break; - case CommandLineOptions.TypeEncoding.Monomorphic: - eraser = null; - break; - default: - eraser = new TypeEraserPremisses((TypeAxiomBuilderPremisses)AxBuilder, Gen); - break; - } - VCExpr exprWithoutTypes = eraser != null ? eraser.Erase(expr, polarity) : expr; - Contract.Assert(exprWithoutTypes != null); - - TermFormulaFlattener flattener = new TermFormulaFlattener(Gen); - Contract.Assert(flattener != null); - VCExpr exprWithLet = flattener.Flatten(exprWithoutTypes); - Contract.Assert(exprWithLet != null); - VCExpr exprWithoutLet = letImplier.Mutate(exprWithLet); - Contract.Assert(exprWithoutLet != null); - - // big integer literals - VCExpr exprWithoutBigLits = LitAbstracter.Abstract(exprWithoutLet); - Contract.Assert(exprWithoutBigLits != null); - AddAxiom(SimplifyLikeExprLineariser.ToSimplifyString(LitAbstracter.GetNewAxioms(), - Namer)); - - // type axioms - VCExpr axiomsWithLet = flattener.Flatten(AxBuilder.GetNewAxioms()); - Contract.Assert(axiomsWithLet != null); - VCExpr axiomsWithoutLet = letImplier.Mutate(axiomsWithLet); - Contract.Assert(axiomsWithoutLet != null); - - AddAxiom(SimplifyLikeExprLineariser.ToSimplifyString(axiomsWithoutLet, Namer)); - return SimplifyLikeExprLineariser.ToSimplifyString(exprWithoutBigLits, Namer); - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - - public class Factory : ProverFactory { - public override object SpawnProver(ProverOptions options, object ctxt) { - //Contract.Requires(options != null); - //Contract.Requires(ctxt != null); - Contract.Ensures(Contract.Result() != null); - - return new SimplifyTheoremProver(options, - cce.NonNull((DeclFreeProverContext)ctxt).ExprGen, - cce.NonNull((DeclFreeProverContext)ctxt)); - } - - public override object NewProverContext(ProverOptions options) { - //Contract.Requires(options != null); - Contract.Ensures(Contract.Result() != null); - - if (CommandLineOptions.Clo.BracketIdsInVC < 0) { - CommandLineOptions.Clo.BracketIdsInVC = 1; - } - VCExpressionGenerator gen = new VCExpressionGenerator(); - Contract.Assert(gen != null); - List/*!>!*/ proverCommands = new List (); - Contract.Assert(cce.NonNullElements(proverCommands)); - proverCommands.Add("simplify"); - return new DeclFreeProverContext(gen, new VCGenerationOptions(proverCommands)); - } - - public override CommandLineOptions.VCVariety DefaultVCVariety { - get { - return CommandLineOptions.VCVariety.BlockNested; - } - } - - // needed to make test7 pass - public override bool SupportsDags { - get { - return true; - } - } - } -} diff --git a/Source/Provers/Simplify/Simplify.csproj b/Source/Provers/Simplify/Simplify.csproj deleted file mode 100644 index 81d2f90a..00000000 --- a/Source/Provers/Simplify/Simplify.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {FEE9F01B-9722-4A76-A24B-72A4016DFA8E} - Library - Properties - Microsoft.Boogie.Simplify - Provers.Simplify - v4.0 - 512 - 1 - true - ..\..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for Simplify.ruleset - true - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\Provers.Simplify.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - - - - - - - - - - - - - - - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - AIFramework - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} - Graph - - - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} - VCExpr - - - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - VCGeneration - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file diff --git a/Source/Provers/Simplify/cce.cs b/Source/Provers/Simplify/cce.cs deleted file mode 100644 index ef594484..00000000 --- a/Source/Provers/Simplify/cce.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { -} \ No newline at end of file diff --git a/Source/Provers/Z3/Inspector.cs b/Source/Provers/Z3/Inspector.cs deleted file mode 100644 index c9bdfa31..00000000 --- a/Source/Provers/Z3/Inspector.cs +++ /dev/null @@ -1,162 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -//using util; -using Microsoft.Boogie; -using Microsoft.Boogie.Simplify; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace Microsoft.Boogie.Z3 -{ - internal class FindLabelsVisitor : TraversingVCExprVisitor { - public HashSet/*!*/ Labels = new HashSet(); - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(cce.NonNull(Labels)); - } - - - public static HashSet/*!*/ FindLabels(VCExpr/*!*/ expr) { - Contract.Requires(expr != null); - Contract.Ensures(cce.NonNull(Contract.Result/*!*/>())); - - FindLabelsVisitor visitor = new FindLabelsVisitor(); - visitor.Traverse(expr, true); - return visitor.Labels; - } - - protected override bool StandardResult(VCExpr node, bool arg) { - //Contract.Requires(node!=null); - VCExprNAry nary = node as VCExprNAry; - if (nary != null) { - VCExprLabelOp lab = nary.Op as VCExprLabelOp; - if (lab != null) { - Labels.Add(lab.label); - } - } - return true; - } - } - - internal class Inspector { - [Rep] protected readonly Process inspector; - [Rep] readonly TextReader fromInspector; - [Rep] readonly TextWriter toInspector; - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(inspector!=null); - Contract.Invariant(fromInspector!=null); - Contract.Invariant(toInspector != null); - } - - - public Inspector(Z3InstanceOptions opts) - { - Contract.Requires(opts != null); - ProcessStartInfo psi = new ProcessStartInfo(opts.Inspector); - Contract.Assert(psi!=null); - psi.CreateNoWindow = true; - psi.UseShellExecute = false; - psi.RedirectStandardInput = true; - psi.RedirectStandardOutput = true; - psi.RedirectStandardError = false; - - try - { - Process inspector = Process.Start(psi); - this.inspector = inspector; - fromInspector = inspector.StandardOutput; - toInspector = inspector.StandardInput; - } - catch (System.ComponentModel.Win32Exception e) - { - throw new Exception(string.Format("Unable to start the inspector process {0}: {1}", opts.Inspector, e.Message)); - } - } - - public void NewProver() - { - } - - public void NewProblem(string descriptiveName, VCExpr vc, ProverInterface.ErrorHandler handler) - { - Contract.Requires(descriptiveName != null); - Contract.Requires(vc != null); - Contract.Requires(handler != null); - HashSet/*!*/ labels = FindLabelsVisitor.FindLabels(vc); - Contract.Assert(labels!=null); - toInspector.WriteLine("PROBLEM " + descriptiveName); - toInspector.WriteLine("TOKEN BEGIN"); - foreach (string lab in labels) { - Contract.Assert(lab!=null); - string no = lab.Substring(1); - Absy absy = handler.Label2Absy(no); - - IToken tok = absy.tok; - AssertCmd assrt = absy as AssertCmd; - Block blk = absy as Block; - string val = tok.val; // might require computation, so cache it - if (val == "foo" || tok.filename == null) continue; // no token - - toInspector.Write("TOKEN "); - toInspector.Write(lab); - toInspector.Write(" "); - - if (assrt != null) { - toInspector.Write("ASSERT"); - string errData = assrt.ErrorData as string; - if (errData != null) { - val = errData; - } else if (assrt.ErrorMessage != null) { - val = assrt.ErrorMessage; - } - } else if (blk != null) { - toInspector.Write("BLOCK "); - toInspector.Write(blk.Label); - } else { - Contract.Assume( false); - } - if (val == null || val == "assert" || val == "ensures") { val = ""; } - - if (absy is LoopInitAssertCmd) { - val += " (loop entry)"; - } else if (absy is LoopInvMaintainedAssertCmd) { - val += " (loop body)"; - } else if (val.IndexOf("#VCCERR") >= 0) { - // skip further transformations - } else if (absy is AssertRequiresCmd) { - AssertRequiresCmd req = (AssertRequiresCmd)absy; - IToken t2 = req.Requires.tok; - string tval = t2.val; - if (tval == "requires") - tval = string.Format("{0}({1},{2}))", t2.filename, t2.line, t2.col); - string call = ""; - if (val != "call") call = " in call to " + val; - val = string.Format("precondition {0}{1}", tval, call); - } - - val = val.Replace("\r", "").Replace("\n", " "); - - toInspector.WriteLine(string.Format(" {0} {1} :@:{2}:@:{3}", tok.line, tok.col, tok.filename, val)); - } - toInspector.WriteLine("TOKEN END"); - } - - public void StatsLine(string line) - { - Contract.Requires(line != null); - toInspector.WriteLine(line); - toInspector.Flush(); - } - } -} diff --git a/Source/Provers/Z3/Prover.cs b/Source/Provers/Z3/Prover.cs deleted file mode 100644 index 6a066f1f..00000000 --- a/Source/Provers/Z3/Prover.cs +++ /dev/null @@ -1,937 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -// #define RECENT_Z3 // 2.20 or newer - -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using util; -using Microsoft.Boogie; -using Microsoft.Boogie.Simplify; -using Microsoft.Basetypes; - -// Simplified interface to an external prover like Simplify or the z3 process, taken from Bird. -namespace Microsoft.Boogie.Z3 -{ - internal class Z3ProverProcess : ProverProcess - { - [Peer] - private Z3InstanceOptions opts; - [Peer] - private readonly Inspector/*?*/ inspector; - private readonly bool expectingModel = false; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(opts != null); - Contract.Invariant(cce.NonNullElements(parameterSettings)); - } - - class OptionValue - { - public readonly string Option; - public readonly string Value; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Option != null); - Contract.Invariant(Value != null); - } - - public OptionValue(string option, string value) { Contract.Requires(option != null); Contract.Requires(value != null); Option = option; Value = value; } - } - - static void AddOption(List parms, string option, string value) - //modifies parms.*; TODO: - { - Contract.Requires(option != null); - Contract.Requires(value != null); - Contract.Requires(cce.NonNullElements(parms)); - OptionValue ov = new OptionValue(option, value); - cce.Owner.AssignSame(ov, cce.Owner.ElementProxy(parms)); - parms.Add(ov); - } - - private List!*/> parameterSettings; - - static void AppendCmdLineOption(StringBuilder cmdLineBldr, string name, object value) { - cmdLineBldr.Append(' ').Append(OptionChar()).Append(name).Append(':').Append(value); - } - - static void AppendCmdLineOption(StringBuilder cmdLineBldr, string name) { - cmdLineBldr.Append(' ').Append(OptionChar()).Append(name); - } - - static bool ExpectingModel() - { - return CommandLineOptions.Clo.PrintErrorModel >= 1 || - CommandLineOptions.Clo.EnhancedErrorMessages == 1 || - CommandLineOptions.Clo.ModelViewFile != null || - CommandLineOptions.Clo.ContractInfer || - CommandLineOptions.Clo.LazyInlining > 0 || - CommandLineOptions.Clo.StratifiedInlining > 0; - } - - static string/*!*/ CreateCommandLineArgsForOptions(Z3InstanceOptions opts) - { - StringBuilder cmdLineArgsBldr = new StringBuilder(); - AppendCmdLineOption(cmdLineArgsBldr, "si"); - - if (CommandLineOptions.Clo.z3AtFlag) - AppendCmdLineOption(cmdLineArgsBldr, "@"); - - if (0 <= CommandLineOptions.Clo.ProverCCLimit) - AppendCmdLineOption(cmdLineArgsBldr, "cex", CommandLineOptions.Clo.ProverCCLimit); - - if (0 <= opts.Timeout) - AppendCmdLineOption(cmdLineArgsBldr, "t", opts.Timeout); - - if (ExpectingModel()) - AppendCmdLineOption(cmdLineArgsBldr, "m"); - - foreach (string opt in CommandLineOptions.Clo.Z3Options) { - Contract.Assert(opt != null); - cmdLineArgsBldr.Append(" \"").Append(opt).Append('\"'); - } - - return cmdLineArgsBldr.ToString(); - } - - static List/*!*/ CreateParameterListForOptions(Z3InstanceOptions opts, Inspector inspector) - { - List/*!*/ result = new List(); - - AddOption(result, "MODEL_PARTIAL", "true"); - - AddOption(result, "MODEL_HIDE_UNUSED_PARTITIONS", "false"); - AddOption(result, "MODEL_V1", "true"); - AddOption(result, "ASYNC_COMMANDS", "false"); - -#if RECENT_Z3 - AddOption(result, "AUTO_CONFIG", "false"); - AddOption(result, "MBQI", "false"); -#else - AddOption(result, "MODEL_VALUE_COMPLETION", "false"); -#endif - - if (!opts.OptimizeForBv) { - // Phase selection means to always try the negative literal polarity first, seems to be good for Boogie. - // The restart parameters change the restart behavior to match Z3 v1, which also seems to be good. - AddOption(result, "PHASE_SELECTION", "0"); - AddOption(result, "RESTART_STRATEGY", "0"); - AddOption(result, "RESTART_FACTOR", "|1.5|"); - - // Make the integer model more diverse by default, speeds up some benchmarks a lot. - AddOption(result, "ARITH_RANDOM_INITIAL_VALUE", "true"); - - // The left-to-right structural case-splitting strategy. -#if !RECENT_Z3 - AddOption(result, "SORT_AND_OR", "false"); -#endif - AddOption(result, "CASE_SPLIT", "3"); - - // In addition delay adding unit conflicts. - AddOption(result, "DELAY_UNITS", "true"); - AddOption(result, "DELAY_UNITS_THRESHOLD", "16"); - } - - // This is used by VCC, but could be also useful for others, if sk_hack(foo(x)) is included as trigger, - // the foo(x0) will be activated for e-matching when x is skolemized to x0. - AddOption(result, "NNF_SK_HACK", "true"); - - // More or less like MAM=0. - AddOption(result, "QI_EAGER_THRESHOLD", "100"); - // Complex proof attempts in VCC (and likely elsewhere) require matching depth of 20 or more. - - // the following will make the :weight option more usable - AddOption(result, "QI_COST", "|\"(+ weight generation)\"|"); - - if (opts.Inspector != null) - AddOption(result, "PROGRESS_SAMPLING_FREQ", "100"); - - AddOption(result, "TYPE_CHECK", "true"); - AddOption(result, "BV_REFLECT", "true"); - - foreach (string opt in CommandLineOptions.Clo.Z3Options) { - Contract.Assert(opt != null); - int eq = opt.IndexOf("="); - // we add them both to command line and the input file: - // - allow for overriding default options - // - some options (like TRACE) work only from command line - // Also options with spaces do not work with (SETPARAMETER ...) - if (eq > 0 && opt.IndexOf(" ") < 0 && 'A' <= opt[0] && opt[0] <= 'Z') { - AddOption(result, opt.Substring(0, eq), opt.Substring(eq + 1)); - } - } - - return result; - } - - //[NotDelayed] - [Captured] - public Z3ProverProcess(Z3InstanceOptions opts, Inspector inspector) - : base(ComputeProcessStartInfo(opts), opts.ExeName) { // throws ProverException - Contract.Requires(opts != null); - Contract.Requires(inspector == null || cce.Owner.Same(opts, inspector)); - this.parameterSettings = CreateParameterListForOptions(opts, inspector); - cce.Owner.AssignSame(this, opts); - this.opts = opts; - this.inspector = inspector; - this.expectingModel = ExpectingModel(); - } - - private static ProcessStartInfo ComputeProcessStartInfo(Z3InstanceOptions opts) - { - return new ProcessStartInfo(opts.ExeName, CreateCommandLineArgsForOptions(opts)) - { - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardInput = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - } - - public override string OptionComments() { - Contract.Ensures(Contract.Result() != null); - - StringBuilder sb = new StringBuilder(); - sb.AppendFormat("Z3 command line: {0} {1}\nUser supplied Z3 options:", - opts.ExeName, this.simplify.StartInfo.Arguments); - Contract.Assume(cce.IsPeerConsistent(CommandLineOptions.Clo)); - foreach (string opt in CommandLineOptions.Clo.Z3Options) { - Contract.Assert(opt != null); - sb.Append(" ").Append(opt); - } - sb.AppendFormat("\nProver options: {0}\n", opts.ToString()); - return sb.ToString(); - } - - //[Pure(false)] - public override IEnumerable!*/> ParameterSettings { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - foreach (OptionValue opt in parameterSettings) { - yield return "(SETPARAMETER " + opt.Option + " " + opt.Value + ")"; - } - } - } - - // z3 uses different magic characters for options on linux/unix and on windows - private static string OptionChar() { - Contract.Ensures(Contract.Result() != null); - - Contract.Assume(Environment.OSVersion != null); - switch (Environment.OSVersion.Platform) { - case PlatformID.Unix: - return "-"; - default: - return "/"; - } - } - - protected override void DoBeginCheck(string descriptiveName, string formula) { - //Contract.Requires(descriptiveName != null); - //Contract.Requires(formula != null); - ToWriteLine(formula); - ToWriteLine(String.Format("; END OF FORMULA {0} - {1}", NumFormulasChecked.ToString(), descriptiveName)); - ToFlush(); - } - - protected int TimedFromReadChar() { - if (opts.Timeout > 0) - return FromReadChar((opts.Timeout + 1) * 1000); - else - return FromReadChar(); - } - - private void Trace(string msg) { - Contract.Requires(msg != null); - Console.WriteLine("Z3: " + msg); - } - - public override ProverOutcome CheckOutcome(Microsoft.Boogie.ProverInterface.ErrorHandler handler) { - //Contract.Requires(handler != null); - Contract.EnsuresOnThrow(true); - //ProverOutcome outcome; - bool isInvalid = false; - - if (this.simplify == null) { - return ProverOutcome.Inconclusive; - } - - - while (true) { - int ch = TimedFromReadChar(); - if (ch == -1 && this.readTimedOut) { - handler.OnResourceExceeded("timeout (forced)"); - return ProverOutcome.TimeOut; - } - - if (ch == -1) - throw new UnexpectedProverOutputException("z3 crashed and produced no output"); - - string line = new string((char)ch, 1) + FromReadLine(); - - if (line.StartsWith("STATS ")) { - if (inspector != null) { - inspector.StatsLine(line); - } - continue; - } - - if (opts.Verbosity > 2) { - Trace("INPUT: " + line); - } - - if (line.StartsWith("WARNING: Out of allocated virtual memory.")) { - handler.OnResourceExceeded("memory"); - return ProverOutcome.OutOfMemory; - } - - - if (line.StartsWith("WARNING: ")) { - string w = line.Substring(9); - handler.OnProverWarning(w); - continue; - } - - if (line.ToUpper().StartsWith("ERROR")) { - Console.WriteLine("Z3 returns the following error:"); - Console.WriteLine(" " + line); - return ProverOutcome.Inconclusive; - } - - int beg = 0; - while (beg < line.Length && '0' <= line[beg] && line[beg] <= '9') { - cce.LoopInvariant(beg <= line.Length); - beg++; - } - - if (beg > 0 && line.Substring(beg).StartsWith(": ")) { - string status = line.Substring(beg + 2); - - if (status.StartsWith("Valid")) { - return ProverOutcome.Valid; - } - - if (status.StartsWith("Timeout")) { - handler.OnResourceExceeded("timeout"); - return ProverOutcome.TimeOut; - } - - if (status.StartsWith("Inconclusive")) { - return ProverOutcome.Inconclusive; - } - - if (status.StartsWith("Memout")) { - handler.OnResourceExceeded("memory"); - return ProverOutcome.OutOfMemory; - } - - if (status.StartsWith("Invalid")) { - isInvalid = true; - continue; - } - } - - if (isInvalid && line == ".") { - return ProverOutcome.NotValid; - } - - if (isInvalid && line.StartsWith("labels: (")) { - List/*!*/ l = ParseLabels(line); - Contract.Assert(cce.NonNullElements(l)); - Z3ErrorModel errModel = null; - if (expectingModel) { - if (opts.Verbosity > 2) { - Trace("waiting for model"); - } - line = FromReadLine(); - if (line.StartsWith("partitions:")) { - line = ParseModel(out errModel); - if (opts.Verbosity > 2) { - Trace("model parsed, final line " + line); - } - // Z3 always ends the model with END_OF_MODEL, not with labels: or . - Contract.Assume(line == "END_OF_MODEL"); - } else { - throw new UnexpectedProverOutputException(string.Format("evil input from z3 (expecting partitions): '{0}'", line)); - } - } - handler.OnModel(l, errModel); - continue; - } - - throw new UnexpectedProverOutputException(string.Format("evil input from z3: '{0}'", line)); - } - } - - /* ---------------------------------------------------------------------------- - BNF Grammar to parse Z3 output, including the model generated when using the /m /si switch: - - Output ::= VC* - VC ::= number ": " "Valid." | number ": " "Inconclusive" | VCI - VCI ::= number ": " "Invalid" - ("labels: " "(" ID* ")" - [MODEL] "END_OF_MODEL")+ - "." - MODEL ::= MBOOL MFUNC - MBOOL ::= "boolean assignment:" - "partitions:" - MAPPING* - MAPPING ::= ZID ["{" ID+"}"] ["->" "(" (number | false | true | BITVECTOR) ")"] - BITVECTOR ::= ulong ":bv" int - MFUNC ::= "function interpretations:" - F* - F ::= Id "->" "{" - MAPLET* - "else" "->" ZID - "}" - MAPLET ::= ZID* "->" ZID - - -----------------------------------------------------------------------------*/ - private string ParseModel(out Z3ErrorModel errModel) - //modifies this.*; - //throws UnexpectedProverOutputException; - { - Contract.Ensures(Contract.Result() == "." || Contract.Result().StartsWith("labels: (") || Contract.Result() == "END_OF_MODEL"); - Contract.Ensures(Contract.Result() != null); - Contract.EnsuresOnThrow(true); - - //Format in the grammar: - // ZID ["{" ID+"}"] ["->" "(" (number | false | true) ")"] - // storing the model: - // map each ID (a string) to the corresping ZID (an integer) in a dictionary: - Dictionary identifierToPartition = new Dictionary(); - // map each ZID to the set (in list form) of IDs belonging to it (possibly empty): - List> partitionToIdentifiers = new List>(); - // map each ZID to the number or boolean given, if any: - List partitionToValue = new List(); - // map each value (number or boolean) to the ZID, reverse map of partitionToValue - Dictionary valueToPartition = new Dictionary(); - cce.Owner.AssignSame(cce.Owner.ElementProxy(partitionToValue), cce.Owner.ElementProxy(valueToPartition)); - - int ch; - - // read the MAPPING - for (int zID = 0; true; zID++) { - ch = FromReadChar(); - if (ch == 'f') { - break; - } - ParseModelMapping(zID, identifierToPartition, partitionToIdentifiers, partitionToValue, valueToPartition); - }// end MAPPING - - // add the fake partition for the 'else -> #undefined' clause - List emptyList = new List(); - cce.Owner.AssignSame(emptyList, cce.Owner.ElementProxy(partitionToIdentifiers)); - partitionToIdentifiers.Add(emptyList); - partitionToValue.Add(null); - - // continue in ParseModelFunctions, which breaks up this long method and enables its verification - return ParseModelFunctions(ch, out errModel, identifierToPartition, partitionToIdentifiers, partitionToValue, valueToPartition); - } - - private void ParseModelMapping(int zID, - Dictionary/*!*/ identifierToPartition, - List>/*!*/ partitionToIdentifiers, - List/*!*/ partitionToValue, - Dictionary/*!*/ valueToPartition) - //modifies this.*, identifierToPartition.*, partitionToIdentifiers.*, partitionToValue.*, valueToPartition.*; - { - Contract.Requires(partitionToValue != null); - Contract.Requires(valueToPartition != null); - Contract.Requires(identifierToPartition != null); - Contract.Requires(cce.NonNullElements(partitionToIdentifiers)); - Contract.Requires(cce.Owner.Same(cce.Owner.ElementProxy(partitionToValue), cce.Owner.ElementProxy(valueToPartition))); - string s = FromReadLine(); - { - // sanity check - int pos = s.IndexOf(' '); - string n = s; - int k; - if (pos >= 0) { - n = s.Substring(0, pos); - } - if (!(int.TryParse(n, out k) && zID == k)) { - System.Console.WriteLine("mismatch: {0}!={1} '{2}'", zID, k, s); - Contract.Assume(false); - } - } - - int j = ParseModelZidAndIdentifiers(zID, s, identifierToPartition, partitionToIdentifiers); - - j = s.IndexOf(" -> ", j); - if (0 <= j) { - j += 4; - } - Contract.Assume(j == -1 || j < s.Length); // if ' -> ' is present, then more should remain of the line - if (j == -1) { - // no "-> " found, end of this line, store that there is no value: - partitionToValue.Add(null); - int idForNull; - if (identifierToPartition.TryGetValue("nullObject", out idForNull) && idForNull == zID) { - Contract.Assume(!valueToPartition.ContainsKey("nullObject")); // a RHS value should occur only once in the Z3 output - valueToPartition.Add("nullObject", zID); - // In this case partitionToValue (as the reverse of valueToPartition) should include - // a map from zID -> "nullObject", but doing that breaks printing out the model as - // it is printed out by Z3. Also, that information is not required, valueToPartition - // works well enough by itself. - } - - } else if (s[j] == 't'/*rue*/) { - partitionToValue.Add(true); - object boxedTrue = true; - Contract.Assume(!valueToPartition.ContainsKey(boxedTrue)); // a RHS value should occur only once in the Z3 output - valueToPartition.Add(boxedTrue, zID); - } else if (s[j] == 'f'/*alse*/) { - object boxedFalse = false; - cce.Owner.AssignSame(boxedFalse, cce.Owner.ElementProxy(partitionToValue)); - partitionToValue.Add(boxedFalse); - Contract.Assume(!valueToPartition.ContainsKey(boxedFalse)); // a RHS value should occur only once in the Z3 output - valueToPartition.Add(boxedFalse, zID); - } else if (s[j] == 'v') { - // -> val!..., i.e. no value - partitionToValue.Add(null); - } else if (s[j] == '{') { - // array - List/*!*/> arrayModel = new List/*!*/>(); - Contract.Assert(Contract.ForAll(arrayModel, a => a != null)); - string array = s.Substring(j + 1); - int index1, index2; - string from, to; - List tuple = new List(); - while (0 <= array.IndexOf(';')) { - index1 = array.IndexOf('*') + 1; - index2 = array.IndexOf(' '); - from = array.Substring(index1, index2 - index1); - tuple.Add(int.Parse(from)); - array = array.Substring(index2); - index1 = array.IndexOf('*') + 1; - index2 = array.IndexOf(';'); - to = array.Substring(index1, index2 - index1); - array = array.Substring(index2 + 2); - tuple.Add(int.Parse(to)); - arrayModel.Add(tuple); - tuple = new List(); - } - Contract.Assert(array.StartsWith("else ->")); - index1 = array.IndexOf('*') + 1; - index2 = array.IndexOf('}'); - to = array.Substring(index1, index2 - index1); - tuple.Add(int.Parse(to)); - arrayModel.Add(tuple); - partitionToValue.Add(arrayModel); - } else { - string numberOrBv = s.Substring(j); - // make number an int, then store it: - BigNum bvVal; - int bvSize; - string number, type; - - int l = numberOrBv.IndexOf(':', 0); - if (0 <= l) { - number = numberOrBv.Substring(0, l); - type = numberOrBv.Substring(l + 1); - } else { - l = numberOrBv.IndexOf('[', 0); - if (0 <= l) { - number = numberOrBv.Substring(2, l - 2); - int closingBracePosition = numberOrBv.IndexOf(']', l); - if (l < closingBracePosition) - type = "bv" + numberOrBv.Substring(l + 1, closingBracePosition - l - 1); - else type = "int"; - } else { - number = numberOrBv; - type = "int"; - } - } - - if (type == "int") { - object boxedN = BigNum.FromString(number); - Contract.Assume(cce.Owner.None(boxedN)); - cce.Owner.AssignSame(boxedN, cce.Owner.ElementProxy(partitionToValue)); - partitionToValue.Add(boxedN); - Contract.Assume(!valueToPartition.ContainsKey(boxedN)); // a RHS value should occur only once in the Z3 output - valueToPartition.Add(boxedN, zID); - } else if (type.StartsWith("bv") && BigNum.TryParse(number, out bvVal) && int.TryParse(type.Substring(2), out bvSize)) { - BvConst bitV = new BvConst(bvVal, bvSize); - cce.Owner.AssignSame(bitV, cce.Owner.ElementProxy(partitionToValue)); - partitionToValue.Add(bitV); - Contract.Assume(!valueToPartition.ContainsKey(bitV)); // a RHS value should occur only once in the Z3 output - valueToPartition.Add(bitV, zID); - } else { - System.Console.WriteLine("cannot parse type: '{0}':'{1}'", number, type); - Contract.Assume(false); - } - - } - } - - private static int ParseModelZidAndIdentifiers(int zID, string s, - Dictionary/*!*/ identifierToPartition, - List>/*!*/ partitionToIdentifiers) - //modifies identifierToPartition.*, partitionToIdentifiers.*; - { - Contract.Requires(identifierToPartition != null && cce.NonNullElements(identifierToPartition.Keys)); - Contract.Requires(partitionToIdentifiers != null && Contract.ForAll(partitionToIdentifiers, identifier => cce.NonNullElements(identifier))); - Contract.Requires(s != null); - Contract.Ensures(0 <= Contract.Result() && Contract.Result() <= s.Length); - - List identifiers = new List(); - int arrowIndex = s.IndexOf('>'); - Contract.Assert(0 < arrowIndex); - int j = s.IndexOf('{', 0) + 1; // skip the '{', if present, and set j to 0 otherwise - if (1 <= j && j < arrowIndex) { - // There is a list of ID's. - Contract.Assume(j < s.Length); // there should be more characters; the ending '}', for one - //ID* - while (true) { - cce.LoopInvariant(cce.IsPeerConsistent(identifiers) && cce.IsPeerConsistent(identifierToPartition) && cce.IsPeerConsistent(partitionToIdentifiers)); - cce.LoopInvariant(0 <= j && j < s.Length); - int k = s.IndexOfAny(new char[] { ' ', '}' }, j); - Contract.Assume(j <= k); - string id = s.Substring(j, k - j); - j = k + 1; - Contract.Assume(!identifierToPartition.ContainsKey(id)); // an ID is listed only once in this list, and an ID can only belong to one ZID equivalence class - identifierToPartition.Add(id, zID); - identifiers.Add(id); - if (s[k] == '}') { - // end of reading ID* - break; - } - Contract.Assume(j < s.Length); // there should be more characters; the ending '}', for one - }//end ID* - } else { - j = 0; - } - cce.Owner.AssignSame(identifiers, cce.Owner.ElementProxy(partitionToIdentifiers)); - partitionToIdentifiers.Add(identifiers); - return j; - } - - private string ParseModelFunctions(int ch, out Z3ErrorModel errModel, - Dictionary/*!*/ identifierToPartition, - List>/*!*/ partitionToIdentifiers, - List/*!*/ partitionToValue, - Dictionary/*!*/ valueToPartition - ) - //modifies this.*; - { - Contract.Requires(identifierToPartition != null && cce.NonNullElements(identifierToPartition.Keys)); - Contract.Requires(partitionToIdentifiers != null && Contract.ForAll(partitionToIdentifiers, identifier => cce.NonNullElements(identifier))); - Contract.Requires(partitionToValue != null); - Contract.Requires(valueToPartition != null); - Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result() == "." || Contract.Result().StartsWith("labels: (") || Contract.Result() == "END_OF_MODEL"); - Contract.EnsuresOnThrow(true); - // read the function F - Expect(ch, "function interpretations:"); - FromReadLine(); - - // mapping of function names to function definitions - Dictionary>/*!*/> definedFunctions = new Dictionary>/*!*/>(); - // function definition given as list of 'pointwise definitions' in the form of the arguments and result - // the last element here will always be a list with just one entry which corresponds to the else case - List> functionDefinition = new List>(); - // list of arguments, followed by the result, the last element of this list is always the result - List argumentsAndResult = new List(); - - // read F - while (true) { - functionDefinition = new List>(); - string s = FromReadLine(); - // end of F, "END_OF_MODEL" ends model, '.' ends whole VC, 'l' starts a new set of labels and model - // whenever there is a model this will end with "END_OF_MODEL", the other cases can only - // happen when there is no model printed! - if (s == "." || s.StartsWith("labels: (") || s == "END_OF_MODEL") { - errModel = new Z3ErrorModel(identifierToPartition, partitionToIdentifiers, partitionToValue, valueToPartition, definedFunctions); - return s; - } - int j = s.IndexOf(' ', 0); - Contract.Assume(0 <= j); - string id = s.Substring(0, j); - // id is stored into definedFunctions once the function definition for it has - // been completely parsed. - - if (s.IndexOf("-> {") < 0) { - // This function was a macro and we are not parsing its definition currently. - // Just move on to the next function. - while (true) { - s = FromReadLine(); - if (0 <= s.IndexOf("{" + id + "}")) - break; - } - continue; - } - - // just ignore the "-> {" by dropping string s - string zIDstring; - - // MAPLET - while (true) { - argumentsAndResult = new List(); - // remove the 2 spaces that are here - FromReadChar(); - FromReadChar(); - s = FromReadLine(); - if (s.StartsWith("else ->")) break; - j = 0; - - //ZID* - while (true) { - cce.LoopInvariant(0 <= j && j <= s.Length); - - j = s.IndexOfAny(new Char[] { '*', '-' }, j); - // true because this always ends with a "->": - Contract.Assume(0 <= j); - - // reading -> means end of ZID* - if (s[j] == '-'/*>*/) break; - - // start reading the ZID* with the number, not the * - j = j + 1; - // by input string format: - Contract.Assume(j < s.Length); - int k = s.IndexOf(' ', j); - // by input string format: - Contract.Assume(j <= k); - zIDstring = s.Substring(j, k - j); - // add the arguments - argumentsAndResult.Add(int.Parse(zIDstring)); - j = k; - }// end ZID* - - // j is the beginning of "-> *", we want the first character after this - j = j + 4; - // by input string format: - Contract.Assume(j <= s.Length); - zIDstring = s.Substring(j); - // add the result - argumentsAndResult.Add(int.Parse(zIDstring)); - // add the input line as another 'pointwise defined' element to the functions definition - functionDefinition.Add(argumentsAndResult); - }// end MAPLET - - // this is the 'else -> #unspecified' case - // by input string format: - Contract.Assume(s.IndexOf("#unspec") >= 0); - // this stores the else line as another argumentsAndResult list - argumentsAndResult = new List(); - argumentsAndResult.Add(partitionToIdentifiers.Count - 1); // use the fake partition we have created before - // which is then added to the function definition, which is now complete - cce.Owner.AssignSame(argumentsAndResult, cce.Owner.ElementProxy(functionDefinition)); - functionDefinition.Add(argumentsAndResult); - - /* - // this is the 'else -> *' case, that string is already in s - j = s.IndexOf('*', 0) + 1; - // by input string format: - assume 0 < j && j < s.Length; - zIDstring = s.Substring(j); - // this stores the else line as another argumentsAndResult list - argumentsAndResult = new List(); - argumentsAndResult.Add(int.Parse(zIDstring)); - // which is then added to the function definition, which is now complete - functionDefinition.Add(argumentsAndResult); */ - - // and therefore added to the map of defined functions, together with the name 'id' - // which had been extracted before - Contract.Assume(!definedFunctions.ContainsKey(id)); // each function name in the model is listed only once - definedFunctions.Add(id, functionDefinition); - - // read the line with "}" - ch = FromReadChar(); - Expect(ch, "}"); - FromReadLine(); - }// end F - } - - } - - - public class Z3ErrorModel : ErrorModel - { - public Z3ErrorModel(Dictionary/*!*/ identifierToPartition, - List>/*!*/ partitionToIdentifiers, - List/*!*/ partitionToValue, - Dictionary/*!*/ valueToPartition, - Dictionary>/*!*/>/*!*/ definedFunctions) - : base(identifierToPartition, partitionToIdentifiers, partitionToValue, valueToPartition, definedFunctions) { - Contract.Requires(identifierToPartition != null && cce.NonNullElements(identifierToPartition.Keys)); - Contract.Requires(partitionToIdentifiers != null && Contract.ForAll(partitionToIdentifiers, x => cce.NonNullElements(x))); - Contract.Requires(partitionToValue != null); - Contract.Requires(valueToPartition != null); - Contract.Requires(definedFunctions != null && cce.NonNullElements(definedFunctions.Keys) && cce.NonNullElements(definedFunctions.Values)); - - this.partitionNames = new string/*?*/[partitionToIdentifiers.Count]; - this.prevPartitionNames = new string/*?*/[partitionToIdentifiers.Count]; - } - - private string/*?*/[]/*!*/ partitionNames; - private string/*?*/[]/*!*/ prevPartitionNames; - - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(partitionNames != null); - Contract.Invariant(prevPartitionNames != null); - } - - - private void SetNames() { - int len = partitionToIdentifiers.Count; - for (int i = 0; i < 3; ++i) { // let the names stabilize a bit - prevPartitionNames = partitionNames; - partitionNames = new string[len]; - for (int pos = 0; pos < len; ++pos) - GetPartitionName(pos); - } - } - - private int NameBadness(string name) { - Contract.Requires(name != null); - int badness = name.Length; - if (name.StartsWith("call") && name.IndexOf("formal@") > 0) - badness += 1000; - if (name.IndexOf("(") > 0) - badness += 500; - return badness; - } - - private string GetPartitionName(int pos) { - Contract.Ensures(Contract.Result() != null); - - string name = partitionNames[pos]; - if (name != null) { - return name; - } - - object tmp = partitionToValue[pos]; - if (tmp != null) { - partitionNames[pos] = tmp is BvConst ? ((BvConst)tmp).ToReadableString() : tmp.ToString(); - } else { - List/*!*/ possible_names = new List(); - List pti = partitionToIdentifiers[pos]; - Contract.Assert(cce.NonNullElements(pti)); - - // make sure we're not called recursively - string prevName = prevPartitionNames[pos]; - if (prevName == null) prevName = "*" + pos; - partitionNames[pos] = prevName; - - if (pti != null && pti.Count > 0) { - // add identifiers - foreach (string n in pti) { - Contract.Assert(n != null); - possible_names.Add(n); - } - } - - // Then also look for functions, - // and then collect possible functional definitions - foreach (KeyValuePair>/*!*/> kv in definedFunctions) { - Contract.Assert(kv.Key != null); - Contract.Assert(kv.Value != null); - foreach (List parms in kv.Value) { - if (parms.Count > 1 && parms[parms.Count - 1] == pos) { - string s = kv.Key + "("; - for (int i = 0; i < parms.Count - 1; ++i) { - if (i != 0) s += ", "; - s += GetPartitionName(parms[i]); - } - s += ")"; - possible_names.Add(s); - } - } - } - - // choose the shortest possible name - if (possible_names.Count > 0) { - string best = possible_names[0]; - foreach (string s in possible_names) { - Contract.Assert(s != null); - if (NameBadness(s) < NameBadness(best)) best = s; - } - if (best.Length < 120) - partitionNames[pos] = best; - } - } - - return cce.NonNull(partitionNames[pos]); - } - - private void PrintReadableModel(TextWriter writer) { - Contract.Requires(writer != null); - writer.WriteLine("Z3 error model: "); - SetNames(); - writer.WriteLine("partitions:"); - Contract.Assert(partitionToIdentifiers.Count == partitionToValue.Count); - for (int i = 0; i < partitionToIdentifiers.Count; i++) { - writer.Write("{0,5}: {1} ", "*" + i, GetPartitionName(i)); - List pti = partitionToIdentifiers[i]; - Contract.Assert(cce.NonNullElements(pti)); - if (pti != null && (pti.Count > 1 || (pti.Count == 1 && partitionToValue[i] != null))) { - writer.Write("{"); - for (int k = 0; k < pti.Count - 1; k++) { - writer.Write(pti[k] + " "); - } - //extra work to make sure no " " is at the end of the list of identifiers - if (pti.Count != 0) { - writer.Write(pti[pti.Count - 1]); - } - writer.Write("}"); - } - writer.WriteLine(); - } - - writer.WriteLine(); - writer.WriteLine("function interpretations:"); - List funNames = new List(definedFunctions.Keys); - funNames.Sort(); - foreach (string name in funNames) { - Contract.Assert(name != null); - if (definedFunctions[name].Count == 1) continue; // skip functions with only the else-> clause - foreach (List parms in definedFunctions[name]) { - Contract.Assert(parms != null); - string s = name + "("; - if (parms.Count == 1) { - continue; - // s += "*"; - } else { - for (int i = 0; i < parms.Count - 1; ++i) { - if (i != 0) s += ", "; - s += GetPartitionName(parms[i]); - } - } - s += ")"; - string res = GetPartitionName(parms[parms.Count - 1]); - if (res == s) - res = "*" + parms[parms.Count - 1] + " (SELF)"; - writer.WriteLine("{0} = {1}", s, res); - } - writer.WriteLine(); - } - writer.WriteLine("The end."); - writer.WriteLine(); - } - - public override void Print(TextWriter writer) { - //Contract.Requires(writer != null); - if (CommandLineOptions.Clo.PrintErrorModel == 4) { - PrintReadableModel(writer); - } else { - base.Print(writer); - } - } - } -} - - diff --git a/Source/Provers/Z3/ProverInterface.cs b/Source/Provers/Z3/ProverInterface.cs deleted file mode 100644 index 3718372b..00000000 --- a/Source/Provers/Z3/ProverInterface.cs +++ /dev/null @@ -1,427 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -//using System.Collections; -using System.Collections.Generic; -using System.Threading; -//using System.IO; -using System.Text; -//using ExternalProver; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.AbstractInterpretation; -using Microsoft.Boogie; -using Microsoft.Boogie.VCExprAST; -using Microsoft.Boogie.Clustering; -using Microsoft.Boogie.TypeErasure; -using Microsoft.Boogie.Z3; -using Microsoft.Boogie.Simplify; - -namespace Microsoft.Boogie.Z3 -{ - public class Z3ProcessTheoremProver : ProcessTheoremProver - { - private Z3InstanceOptions opts; - private Inspector inspector; - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(opts!=null); -} - - - [NotDelayed] - public Z3ProcessTheoremProver(VCExpressionGenerator gen, - DeclFreeProverContext ctx, Z3InstanceOptions opts):base(opts, gen, ctx, opts.ExeName, "TypedUnivBackPred2.sx") - { - Contract.Requires(gen != null); - Contract.Requires(ctx != null); - Contract.Requires(opts != null); - Contract.EnsuresOnThrow(true); - this.opts = opts; - - } - - private void FireUpInspector() - { - if (inspector == null && opts.Inspector != null) { - inspector = new Inspector(opts); - } - } - - protected override Microsoft.Boogie.Simplify.ProverProcess CreateProverProcess(string proverPath) { - //Contract.Requires(proverPath!= null); - Contract.Ensures(Contract.Result() != null); - - - opts.ExeName = proverPath; - FireUpInspector(); - if (inspector != null) { - inspector.NewProver(); - } - return new Z3ProverProcess(opts, inspector); - } - - protected override AxiomVCExprTranslator SpawnVCExprTranslator(ProverOptions opts) { - //Contract.Requires(opts != null); - Contract.Ensures(Contract.Result() != null); - - return new Z3VCExprTranslator(gen, (Z3InstanceOptions) opts); - } - - public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) - { - //Contract.Requires(descriptiveName != null); - //Contract.Requires(vc != null); - //Contract.Requires(handler != null); - FireUpInspector(); - if (inspector != null) { - inspector.NewProblem(descriptiveName, vc, handler); - } - base.BeginCheck(descriptiveName, vc, handler); - } - } - - public class Z3InstanceOptions : ProverOptions - { - public int Timeout { get { return TimeLimit / 1000; } } - public int Lets { - get - { - Contract.Ensures(0 <= Contract.Result() && Contract.Result() < 4); - return CommandLineOptions.Clo.Z3lets; - } - } - public bool DistZ3 = false; - public string ExeName = "z3.exe"; - public bool InverseImplies = false; - public string Inspector = null; - public bool OptimizeForBv = false; - - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(ExeName!=null); - } - - protected override bool Parse(string opt) - { - //Contract.Requires(opt!=null); - return ParseBool(opt, "REVERSE_IMPLIES", ref InverseImplies) || - ParseString(opt, "INSPECTOR", ref Inspector) || - ParseBool(opt, "DIST", ref DistZ3) || - ParseBool(opt, "OPTIMIZE_FOR_BV", ref OptimizeForBv) || - base.Parse(opt); - } - - public override void PostParse() - { - base.PostParse(); - - if (DistZ3) { - ExeName = "z3-dist.exe"; - CommandLineOptions.Clo.RestartProverPerVC = true; - } - } - - public override string Help - { - get - { - return -@" -Z3-specific options: -~~~~~~~~~~~~~~~~~~~~ -INSPECTOR= Use the specified Z3Inspector binary. -OPTIMIZE_FOR_BV= Optimize Z3 options for bitvector reasoning, and not quantifier instantiation. Defaults to false. - -Obscure options: -~~~~~~~~~~~~~~~~ -DIST= Use z3-dist.exe binary. -REVERSE_IMPLIES= Encode P==>Q as Q||!P. - -" + base.Help; - // DIST requires non-public binaries - } - } - } - - public class Z3LineariserOptions : LineariserOptions { - private readonly Z3InstanceOptions opts; - - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(opts!=null); - } - - - public Z3LineariserOptions(bool asTerm, Z3InstanceOptions opts, List!*/> letVariables):base(asTerm) { - Contract.Requires(opts != null); - Contract.Requires(cce.NonNullElements(letVariables)); - - this.opts = opts; - this.LetVariablesAttr = letVariables; - } - - public override bool UseWeights { get { - return true; - } } - - public override bool UseTypes { get { - return true; - } } - - public override bool QuantifierIds { get { - return true; - } } - - public override bool InverseImplies { get { - return opts.InverseImplies; - } } - - public override LineariserOptions SetAsTerm(bool newVal) { - Contract.Ensures(Contract.Result() != null); - - if (newVal == AsTerm) - return this; - return new Z3LineariserOptions(newVal, opts, LetVariables); - } - - // variables representing formulas in let-bindings have to be - // printed in a different way than other variables - private readonly List!*/> LetVariablesAttr; - public override List!*/> LetVariables { get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - return LetVariablesAttr; - } } - - public override LineariserOptions AddLetVariable(VCExprVar furtherVar) { - //Contract.Requires(furtherVar != null); - Contract.Ensures(Contract.Result() != null); - - List!*/> allVars = new List(); - allVars.AddRange(LetVariables); - allVars.Add(furtherVar); - return new Z3LineariserOptions(AsTerm, opts, allVars); - } - - public override LineariserOptions AddLetVariables(List!*/> furtherVars) { - //Contract.Requires(furtherVars != null); - Contract.Ensures(Contract.Result() != null); - - List!*/> allVars = new List (); - allVars.AddRange(LetVariables); - allVars.AddRange(furtherVars); - return new Z3LineariserOptions(AsTerm, opts, allVars); - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - - public class Z3VCExprTranslator : AxiomVCExprTranslator { - public Z3VCExprTranslator(VCExpressionGenerator gen, Z3InstanceOptions opts) { - Contract.Requires(gen != null); - Contract.Requires(opts != null); - Gen = gen; - Opts = opts; - TypeAxiomBuilder axBuilder; - switch (CommandLineOptions.Clo.TypeEncodingMethod) { - case CommandLineOptions.TypeEncoding.Arguments: - axBuilder = new TypeAxiomBuilderArguments (gen); - break; - default: - axBuilder = new TypeAxiomBuilderPremisses (gen); - break; - } - axBuilder.Setup(); - AxBuilder = axBuilder; - UniqueNamer namer = new UniqueNamer (); - Namer = namer; - this.DeclCollector = - new TypeDeclCollector (namer, true); - } - - private Z3VCExprTranslator(Z3VCExprTranslator tl) :base(tl){ - Contract.Requires(tl!=null); - Gen = tl.Gen; - Opts = tl.Opts; // we assume that the options have not changed - AxBuilder = (TypeAxiomBuilder)tl.AxBuilder.Clone(); - UniqueNamer namer = (UniqueNamer)tl.Namer.Clone(); - Namer = namer; - DeclCollector = new TypeDeclCollector (namer, tl.DeclCollector); - } - - public override Object Clone() { - Contract.Ensures(Contract.Result() != null); - - return new Z3VCExprTranslator(this); - } - - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(Opts!=null); - Contract.Invariant(Gen != null); - Contract.Invariant(AxBuilder != null); - Contract.Invariant(Namer != null); - Contract.Invariant(DeclCollector != null); - } - - private readonly Z3InstanceOptions Opts; - private readonly VCExpressionGenerator Gen; - private readonly TypeAxiomBuilder AxBuilder; - private readonly UniqueNamer Namer; - private readonly TypeDeclCollector DeclCollector; - - public override string Lookup(VCExprVar var) - { - //Contract.Requires(var != null); - Contract.Ensures(Contract.Result() != null); - - VCExprVar v = AxBuilder.TryTyped2Untyped(var); - if (v != null) { - var = v; - } - return Namer.Lookup(var); - } - - public override string translate(VCExpr expr, int polarity) { - //Contract.Requires(expr != null); - Contract.Ensures(Contract.Result() != null); - - DateTime start = DateTime.UtcNow; - if (CommandLineOptions.Clo.Trace) - Console.Write("Linearising ... "); - - // handle the types in the VCExpr - TypeEraser eraser; - switch (CommandLineOptions.Clo.TypeEncodingMethod) { - case CommandLineOptions.TypeEncoding.Arguments: - eraser = new TypeEraserArguments((TypeAxiomBuilderArguments)AxBuilder, Gen); - break; - case CommandLineOptions.TypeEncoding.Monomorphic: - eraser = null; - break; - default: - eraser = new TypeEraserPremisses((TypeAxiomBuilderPremisses)AxBuilder, Gen); - break; - } - VCExpr exprWithoutTypes = eraser != null ? eraser.Erase(expr, polarity) : expr; - Contract.Assert(exprWithoutTypes!=null); - - LetBindingSorter letSorter = new LetBindingSorter(Gen); - Contract.Assert(letSorter!=null); - VCExpr sortedExpr = letSorter.Mutate(exprWithoutTypes, true); - Contract.Assert(sortedExpr!=null); - VCExpr sortedAxioms = letSorter.Mutate(AxBuilder.GetNewAxioms(), true); - Contract.Assert(sortedAxioms!=null); - - DeclCollector.Collect(sortedAxioms); - DeclCollector.Collect(sortedExpr); - FeedTypeDeclsToProver(); - if (Opts.Lets != 3) { - // replace let expressions with implies - Let2ImpliesMutator letImplier = new Let2ImpliesMutator(Gen, Opts.Lets == 1, Opts.Lets == 2); - sortedExpr = letImplier.Mutate(sortedExpr); - sortedAxioms = letImplier.Mutate(sortedAxioms); - } - - ////////////////////////////////////////////////////////////////////////// - //SubtermCollector! coll = new SubtermCollector (gen); - //coll.Traverse(sortedExpr, true); - //coll.Traverse(sortedAxioms, true); - //coll.UnifyClusters(); - //Console.WriteLine(coll); - ////////////////////////////////////////////////////////////////////////// - - LineariserOptions linOptions = new Z3LineariserOptions(false, Opts, new List()); - - AddAxiom(SimplifyLikeExprLineariser.ToString(sortedAxioms, linOptions, Namer)); - - string res = SimplifyLikeExprLineariser.ToString(sortedExpr, linOptions, Namer); - Contract.Assert(res!=null); - - if (CommandLineOptions.Clo.Trace) { - TimeSpan elapsed = DateTime.UtcNow - start; - Console.WriteLine("finished [{0} s]", elapsed.TotalSeconds); - } - return res; - } - - private void FeedTypeDeclsToProver() { - foreach (string s in DeclCollector.GetNewDeclarations()) { - Contract.Assert(s != null); - AddTypeDecl(s); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - // ----------------------------------------------------------------------------------------------- - - public class Factory : ProverFactory - { - - public override object SpawnProver(ProverOptions popts, object ctxt) - { - //Contract.Requires(popts != null); - //Contract.Requires(ctxt != null); - Contract.Ensures(Contract.Result() != null); - - Z3InstanceOptions opts = cce.NonNull((Z3InstanceOptions)popts); - return this.SpawnProver(cce.NonNull((DeclFreeProverContext)ctxt).ExprGen, - cce.NonNull((DeclFreeProverContext)ctxt), - opts); - } - - public override object NewProverContext(ProverOptions options) { - //Contract.Requires(options != null); - //Contract.Ensures(Contract.Result() != null); - - if (CommandLineOptions.Clo.BracketIdsInVC < 0) { - CommandLineOptions.Clo.BracketIdsInVC = 0; - } - - Z3InstanceOptions opts = cce.NonNull((Z3InstanceOptions)options); - VCExpressionGenerator gen = new VCExpressionGenerator (); - List!*/> proverCommands = new List (); - proverCommands.Add("z3"); - proverCommands.Add("simplifyLike"); - VCGenerationOptions genOptions = new VCGenerationOptions(proverCommands); - - return NewProverContext(gen, genOptions, opts); - } - - public override ProverOptions BlankProverOptions() - { - Contract.Ensures(Contract.Result() != null); - return new Z3InstanceOptions(); - } - - protected virtual Z3ProcessTheoremProver SpawnProver(VCExpressionGenerator gen, - DeclFreeProverContext ctx, - Z3InstanceOptions opts) { - Contract.Requires(gen != null); - Contract.Requires(ctx != null); - Contract.Requires(opts != null); - Contract.Ensures(Contract.Result() != null); - - return new Z3ProcessTheoremProver(gen, ctx, opts); - } - - protected virtual DeclFreeProverContext NewProverContext(VCExpressionGenerator gen, - VCGenerationOptions genOptions, - Z3InstanceOptions opts) - { - return new DeclFreeProverContext(gen, genOptions); - } - } -} diff --git a/Source/Provers/Z3/TypeDeclCollector.cs b/Source/Provers/Z3/TypeDeclCollector.cs deleted file mode 100644 index 19c88409..00000000 --- a/Source/Provers/Z3/TypeDeclCollector.cs +++ /dev/null @@ -1,398 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using Microsoft.Boogie.VCExprAST; - -namespace Microsoft.Boogie.Z3 -{ - // Visitor for collecting the occurring function symbols in a VCExpr, - // and for creating the corresponding declarations that can be fed into - // Z3 - - // (should this be rather done by Context.DeclareFunction? right now, - // the TypeErasure visitor introduces new function symbols that are - // not passed to this method) - - public class TypeDeclCollector : BoundVarTraversingVCExprVisitor { - - private readonly UniqueNamer Namer; - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(Namer!=null); - Contract.Invariant(AllDecls != null); - Contract.Invariant(IncDecls != null); - Contract.Invariant(cce.NonNull(KnownFunctions)); - Contract.Invariant(cce.NonNull(KnownVariables)); - Contract.Invariant(cce.NonNull(KnownTypes)); - Contract.Invariant(cce.NonNull(KnownBvOps)); - Contract.Invariant(cce.NonNull(KnownSelectFunctions)); - Contract.Invariant(cce.NonNull(KnownStoreFunctions)); -} - - - private readonly bool NativeBv; - - public TypeDeclCollector(UniqueNamer namer, bool nativeBv) { - Contract.Requires(namer != null); - this.Namer = namer; - this.NativeBv = nativeBv; - AllDecls = new List (); - IncDecls = new List (); - KnownFunctions = new HashSet(); - KnownVariables = new HashSet(); - KnownTypes = new HashSet(); - KnownBvOps = new HashSet(); - - KnownStoreFunctions = new HashSet(); - KnownSelectFunctions = new HashSet(); - } - - internal TypeDeclCollector(UniqueNamer namer, TypeDeclCollector coll) { - Contract.Requires(namer!=null); - Contract.Requires(coll!=null); - this.Namer = namer; - this.NativeBv = coll.NativeBv; - AllDecls = new List (coll.AllDecls); - IncDecls = new List (coll.IncDecls); - KnownFunctions = new HashSet(coll.KnownFunctions); - KnownVariables = new HashSet(coll.KnownVariables); - KnownTypes = new HashSet(coll.KnownTypes); - KnownBvOps = new HashSet(coll.KnownBvOps); - - KnownStoreFunctions = new HashSet(coll.KnownStoreFunctions); - KnownSelectFunctions = new HashSet(coll.KnownSelectFunctions); - } - - // not used - protected override bool StandardResult(VCExpr node, bool arg) { - //Contract.Requires(node != null); - return true; - } - - private readonly List!*/> AllDecls; - private readonly List!*/> IncDecls; - - private readonly HashSet/*!*/ KnownFunctions; - private readonly HashSet/*!*/ KnownVariables; - - // bitvector types have to be registered as well - private readonly HashSet/*!*/ KnownTypes; - - // the names of registered BvConcatOps and BvExtractOps - private readonly HashSet/*!*/ KnownBvOps; - - private readonly HashSet/*!*/ KnownStoreFunctions; - private readonly HashSet/*!*/ KnownSelectFunctions; - - public List!*/> AllDeclarations { get { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - List!*/> res = new List (); - res.AddRange(AllDecls); - return res; - } } - - public List!*/> GetNewDeclarations() { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - List!*/> res = new List (); - res.AddRange(IncDecls); - IncDecls.Clear(); - return res; - } - - private void AddDeclaration(string decl) { - Contract.Requires(decl != null); - AllDecls.Add(decl); - IncDecls.Add(decl); - } - - public void Collect(VCExpr expr) { - Contract.Requires(expr != null); - Traverse(expr, true); - } - - /////////////////////////////////////////////////////////////////////////// - - private static string TypeToString(Type t) { - Contract.Requires(t!= null); - Contract.Ensures(Contract.Result() != null); - - return SimplifyLikeExprLineariser.TypeToString(t); - } - - private void RegisterType(Type type) - { - Contract.Requires(type != null); - if (KnownTypes.Contains(type)) return; - - if (type.IsMap && CommandLineOptions.Clo.MonomorphicArrays) { - KnownTypes.Add(type); - string declString = ""; - MapType mapType = type.AsMap; - Contract.Assert(mapType != null); - - foreach (Type t in mapType.Arguments) { - Contract.Assert(t != null); - RegisterType(t); - } - RegisterType(mapType.Result); - - declString += "(DEFTYPE " + TypeToString(type); - - if (CommandLineOptions.Clo.UseArrayTheory) { - declString += " :BUILTIN Array "; - foreach (Type t in mapType.Arguments) { - declString += TypeToString(t); - declString += " "; - } - declString += TypeToString(mapType.Result); - } - - declString += ")"; - AddDeclaration(declString); - return; - } - - if (type.IsBv && NativeBv) { - int bits = type.BvBits; - string name = TypeToString(type); - - AddDeclaration("(DEFTYPE " + name + " :BUILTIN BitVec " + bits + ")"); - // If we add the BUILTIN then the conversion axiom does not work - AddDeclaration("(DEFOP " + name + "_to_int " + name + " $int)"); // :BUILTIN bv2int $int)"); - AddDeclaration("(DEFOP $make_bv" + bits + " $int " + name + " :BUILTIN int2bv " + bits + ")"); - string expr = "($make_bv" + bits + " (" + name + "_to_int x))"; - AddDeclaration("(BG_PUSH (FORALL (x :TYPE " + name + ") (PATS " - + expr + ") (QID bvconv" + bits + ") (EQ " + expr + " x)))"); - - KnownTypes.Add(type); - return; - } - - if (type.IsBool || type.IsInt) - return; - - if (CommandLineOptions.Clo.TypeEncodingMethod == CommandLineOptions.TypeEncoding.Monomorphic) { - AddDeclaration("(DEFTYPE " + TypeToString(type) + ")"); - KnownTypes.Add(type); - return; - } - - } - - public override bool Visit(VCExprNAry node, bool arg) { - Contract.Requires(node != null); - // there are a couple cases where operators have to be - // registered by generating appropriate Z3 statements - - if (node.Op is VCExprBvOp) { - if (NativeBv) { - RegisterType(node[0].Type); - RegisterType(node.Type); - } - } else if (node.Op is VCExprBvConcatOp) { - // - if (NativeBv) { - RegisterType(node[0].Type); - RegisterType(node[1].Type); - RegisterType(node.Type); - - string name = SimplifyLikeExprLineariser.BvConcatOpName(node); - if (!KnownBvOps.Contains(name)) { - AddDeclaration("(DEFOP " + name + - " " + TypeToString(node[0].Type) + - " " + TypeToString(node[1].Type) + - " " + TypeToString(node.Type) + - " :BUILTIN concat)"); - KnownBvOps.Add(name); - } - } - // - } else if (node.Op is VCExprBvExtractOp) { - // - if (NativeBv) { - RegisterType(node[0].Type); - RegisterType(node.Type); - - VCExprBvExtractOp op = (VCExprBvExtractOp)node.Op; - Contract.Assert(op!=null); - string name = SimplifyLikeExprLineariser.BvExtractOpName(node); - if (!KnownBvOps.Contains(name)) { - AddDeclaration("(DEFOP " + name + - " " + TypeToString(node[0].Type) + - " " + TypeToString(node.Type) + - " :BUILTIN extract " + - (op.End - 1) + " " + op.Start + ")"); - KnownBvOps.Add(name); - } - } - // - } else if (node.Op is VCExprStoreOp) { - RegisterType(node.Type); // this is the map type, registering it should register also the index and value types - string name = SimplifyLikeExprLineariser.StoreOpName(node); - if (!KnownStoreFunctions.Contains(name)) { - string decl = "(DEFOP " + name; - - foreach (VCExpr ch in node) { - decl += " " + TypeToString(ch.Type); - } - decl += " " + TypeToString(node.Type); - - if (CommandLineOptions.Clo.UseArrayTheory) - decl += " :BUILTIN store"; - decl += ")"; - AddDeclaration(decl); - - if (CommandLineOptions.Clo.MonomorphicArrays && !CommandLineOptions.Clo.UseArrayTheory) { - var sel = SimplifyLikeExprLineariser.SelectOpName(node); - - if (!KnownSelectFunctions.Contains(name)) { - // need to declare it before reference - string seldecl = "(DEFOP " + sel; - foreach (VCExpr ch in node) { - seldecl += " " + TypeToString(ch.Type); - } - AddDeclaration(seldecl + ")"); - KnownSelectFunctions.Add(name); - } - - var eq = "EQ"; - if (node[node.Arity - 1].Type.IsBool) - eq = "IFF"; - - string ax1 = "(BG_PUSH (FORALL ("; - string ax2 = "(BG_PUSH (FORALL ("; - string argX = "", argY = ""; - string dist = ""; - for (int i = 0; i < node.Arity; i++) { - var t = " :TYPE " + TypeToString(node[i].Type); - var x = " x" + i; - var y = " y" + i; - ax1 += x + t; - ax2 += x + t; - if (i != 0 && i != node.Arity - 1) { - argX += x; - argY += y; - ax2 += y + t; - dist += " (NEQ" + x + y + ")"; - } - } - string v = " x" + (node.Arity - 1); - ax1 += ") "; - ax1 += "(" + eq + " (" + sel + " (" + name + " x0" + argX + v + ")" + argX + ") " + v + ")"; - ax1 += "))"; - - ax2 += ") "; - ax2 += "(IMPLIES (OR " + dist + ") (" + eq + " (" + sel + " (" + name + " x0" + argX + v + ")" + argY + ") (" + sel + " x0" + argY + ")))"; - ax2 += "))"; - - AddDeclaration(ax1); - AddDeclaration(ax2); - } - - KnownStoreFunctions.Add(name); - } - // - } else if (node.Op is VCExprSelectOp) { - // - RegisterType(node[0].Type); - string name = SimplifyLikeExprLineariser.SelectOpName(node); - if (!KnownSelectFunctions.Contains(name)) { - string decl = "(DEFOP " + name; - - foreach (VCExpr ch in node) { - decl += " " + TypeToString(ch.Type); - } - decl += " " + TypeToString(node.Type); - - if (CommandLineOptions.Clo.UseArrayTheory) - decl += " :BUILTIN select"; - decl += ")"; - AddDeclaration(decl); - KnownSelectFunctions.Add(name); - } - // - } else { - // - VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp; - if (op != null && !KnownFunctions.Contains(op.Func)) { - Function f = op.Func; - Contract.Assert(f!=null); - string printedName = Namer.GetName(f, f.Name); - Contract.Assert(printedName!=null); - string decl = "(DEFOP " + SimplifyLikeExprLineariser.MakeIdPrintable(printedName); - - foreach (Variable v in f.InParams) { - Contract.Assert(v!=null); - decl += " " + TypeToString(v.TypedIdent.Type); - RegisterType(v.TypedIdent.Type); - } - Contract.Assert(f.OutParams.Length == 1); - foreach (Variable v in f.OutParams) { - Contract.Assert(v!=null); - decl += " " + TypeToString(v.TypedIdent.Type); - RegisterType(v.TypedIdent.Type); - } - - string builtin = ExtractBuiltin(f); - if (builtin != null) - decl += " :BUILTIN " + builtin; - - decl += ")"; - - AddDeclaration(decl); - KnownFunctions.Add(f); - } - // - } - - return base.Visit(node, arg); - } - - private string ExtractBuiltin(Function f) { - Contract.Requires(f != null); - string retVal = null; - if (NativeBv) { - retVal = f.FindStringAttribute("bvbuiltin"); - } - if (retVal == null) { - retVal = f.FindStringAttribute("builtin"); - } - return retVal; - } - - public override bool Visit(VCExprVar node, bool arg) { - Contract.Requires(node != null); - if (!BoundTermVars.Contains(node) && !KnownVariables.Contains(node)) { - RegisterType(node.Type); - string printedName = Namer.GetName(node, node.Name); - Contract.Assert(printedName!=null); - string decl = - "(DEFOP " + SimplifyLikeExprLineariser.MakeIdPrintable(printedName) - + " " + TypeToString(node.Type) + ")"; - AddDeclaration(decl); - KnownVariables.Add(node); - } - - return base.Visit(node, arg); - } - - public override bool Visit(VCExprQuantifier node, bool arg) { - Contract.Requires(node != null); - foreach (VCExprVar v in node.BoundVars) { - Contract.Assert(v != null); - RegisterType(v.Type); - } - - return base.Visit(node, arg); - } - } -} \ No newline at end of file diff --git a/Source/Provers/Z3/Z3.csproj b/Source/Provers/Z3/Z3.csproj deleted file mode 100644 index e559b663..00000000 --- a/Source/Provers/Z3/Z3.csproj +++ /dev/null @@ -1,218 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {BB49B90B-BE21-4BE8-85BA-359FDB55F4DF} - Library - Properties - Microsoft.Boogie.Z3 - Provers.Z3 - v4.0 - 512 - 1 - true - ..\..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for Z3.ruleset - true - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\Provers.Z3.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - - - - - 3.5 - - - - - - - - - - - - - - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - AIFramework - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} - VCExpr - - - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - VCGeneration - - - {FEE9F01B-9722-4A76-A24B-72A4016DFA8E} - Simplify - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file diff --git a/Source/Provers/Z3/cce.cs b/Source/Provers/Z3/cce.cs deleted file mode 100644 index ef594484..00000000 --- a/Source/Provers/Z3/cce.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using SA=System.Attribute; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -//using Microsoft.Boogie; - -/// -/// A class containing static methods to extend the functionality of Code Contracts -/// - -public static class cce { - //[Pure] - //public static bool NonNullElements(Microsoft.Dafny.Graph collection) { - // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); - //} - [Pure] - public static T NonNull(T t) { - Contract.Assert(t != null); - return t; - } - [Pure] - public static bool NonNullElements(IEnumerable collection) { - return collection != null && Contract.ForAll(collection, c => c != null); - } - [Pure] - public static bool NonNullElements(IDictionary collection) { - return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); - } - //[Pure] - //public static bool NonNullElements(VariableSeq collection) { - // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); - //} - /// - /// For possibly-null lists of non-null elements - /// - /// - /// - /// If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>! - /// - [Pure] - public static bool NonNullElements(IEnumerable collection, bool nullability) { - return (nullability && collection == null) || cce.NonNullElements(collection); - //Should be the same as: - /*if(nullability&&collection==null) - * return true; - * return cce.NonNullElements(collection) - */ - - } - [Pure] - public static bool NonNullElements(KeyValuePair kvp) { - return kvp.Key != null && kvp.Value != null; - } - [Pure] - public static bool NonNullElements(IEnumerator iEnumerator) { - return iEnumerator != null; - } - //[Pure] - //public static bool NonNullElements(Graphing.Graph graph) { - // return cce.NonNullElements(graph.TopologicalSort()); - //} - [Pure] - public static void BeginExpose(object o) { - } - [Pure] - public static void EndExpose() { - } - [Pure] - public static bool IsPeerConsistent(object o) { - return true; - } - [Pure] - public static bool IsConsistent(object o) { - return true; - } - [Pure] - public static bool IsExposable(object o) { - return true; - } - [Pure] - public static bool IsExposed(object o) { - return true; - } - [Pure] - public static bool IsNew(object o) { - return true; - } - public static class Owner { - [Pure] - public static bool Same(object o, object p) { - return true; - } - [Pure] - public static void AssignSame(object o, object p) { - } - [Pure] - public static object ElementProxy(object o) { - return o; - } - [Pure] - public static bool None(object o) { - return true; - } - [Pure] - public static bool Different(object o, object p) { - return true; - } - [Pure] - public static bool New(object o) { - return true; - } - } - [Pure] - public static void LoopInvariant(bool p) { - Contract.Assert(p); - } - public class UnreachableException : Exception { - public UnreachableException() { - } - } - //[Pure] - //public static bool IsValid(Microsoft.Dafny.Expression expression) { - // return true; - //} - //public static List toList(PureCollections.Sequence s) { - // List toRet = new List(); - // foreach (T t in s.elems) - // if(t!=null) - // toRet.Add(t); - // return toRet; - //} - - //internal static bool NonNullElements(Set set) { - // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); - //} -} - -public class PeerAttribute : SA { -} -public class RepAttribute : SA { -} -public class CapturedAttribute : SA { -} -public class NotDelayedAttribute : SA { -} -public class NoDefaultContractAttribute : SA { -} -public class VerifyAttribute : SA { - public VerifyAttribute(bool b) { - - } -} -public class StrictReadonlyAttribute : SA { -} -public class AdditiveAttribute : SA { -} -public class ReadsAttribute : SA { - public enum Reads { - Nothing, - Everything, - }; - public ReadsAttribute(object o) { - } -} -public class GlobalAccessAttribute : SA { - public GlobalAccessAttribute(bool b) { - } -} -public class EscapesAttribute : SA { - public EscapesAttribute(bool b, bool b_2) { - } -} -public class NeedsContractsAttribute : SA { - public NeedsContractsAttribute() { - } - public NeedsContractsAttribute(bool ret, bool parameters) { - } - public NeedsContractsAttribute(bool ret, int[] parameters) { - } -} -public class ImmutableAttribute : SA { -} -public class InsideAttribute : SA { -} -public class SpecPublicAttribute : SA { -} -public class ElementsPeerAttribute : SA { -} -public class ResultNotNewlyAllocatedAttribute : SA { -} -public class OnceAttribute : SA { -} \ No newline at end of file diff --git a/Source/VCGeneration/BlockPredicator.cs b/Source/VCGeneration/BlockPredicator.cs deleted file mode 100644 index 9df1c086..00000000 --- a/Source/VCGeneration/BlockPredicator.cs +++ /dev/null @@ -1,373 +0,0 @@ -using Graphing; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Linq; - -namespace Microsoft.Boogie { - -public class BlockPredicator { - - Program prog; - Implementation impl; - Graph blockGraph; - - bool createCandidateInvariants = true; - bool useProcedurePredicates = true; - - Expr returnBlockId; - - LocalVariable curVar, pVar; - IdentifierExpr cur, p, fp; - Expr pExpr; - Dictionary havocVars = - new Dictionary(); - Dictionary blockIds = new Dictionary(); - HashSet doneBlocks = new HashSet(); - - BlockPredicator(Program p, Implementation i, bool cci, bool upp) { - prog = p; - impl = i; - createCandidateInvariants = cci; - useProcedurePredicates = upp; - } - - void PredicateCmd(List blocks, Block block, Cmd cmd, out Block nextBlock) { - if (!useProcedurePredicates && cmd is CallCmd) { - var trueBlock = new Block(); - blocks.Add(trueBlock); - trueBlock.Label = block.Label + ".call.true"; - trueBlock.Cmds.Add(new AssumeCmd(Token.NoToken, p)); - trueBlock.Cmds.Add(cmd); - - var falseBlock = new Block(); - blocks.Add(falseBlock); - falseBlock.Label = block.Label + ".call.false"; - falseBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(p))); - - var contBlock = new Block(); - blocks.Add(contBlock); - contBlock.Label = block.Label + ".call.cont"; - - block.TransferCmd = - new GotoCmd(Token.NoToken, new BlockSeq(trueBlock, falseBlock)); - trueBlock.TransferCmd = falseBlock.TransferCmd = - new GotoCmd(Token.NoToken, new BlockSeq(contBlock)); - nextBlock = contBlock; - } else { - PredicateCmd(block.Cmds, cmd); - nextBlock = block; - } - } - - void PredicateCmd(CmdSeq cmdSeq, Cmd cmd) { - if (cmd is AssignCmd) { - var aCmd = (AssignCmd)cmd; - cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss, - new List(aCmd.Lhss.Zip(aCmd.Rhss, (lhs, rhs) => - new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(p, rhs, lhs.AsExpr)))))); - } else if (cmd is AssertCmd) { - var aCmd = (AssertCmd)cmd; - if (cmdSeq.Last() is AssignCmd && - cmdSeq.Cast().SkipEnd(1).All(c => c is AssertCmd)) { - // This may be a loop invariant. Make sure it continues to appear as - // the first statement in the block. - var assign = cmdSeq.Last(); - cmdSeq.Truncate(cmdSeq.Length-1); - Expr newExpr = new EnabledReplacementVisitor(pExpr).VisitExpr(aCmd.Expr); - aCmd.Expr = QKeyValue.FindBoolAttribute(aCmd.Attributes, "do_not_predicate") ? newExpr : Expr.Imp(pExpr, newExpr); - cmdSeq.Add(aCmd); - // cmdSeq.Add(new AssertCmd(aCmd.tok, Expr.Imp(pExpr, aCmd.Expr))); - cmdSeq.Add(assign); - } else { - aCmd.Expr = Expr.Imp(p, aCmd.Expr); - cmdSeq.Add(aCmd); - // cmdSeq.Add(new AssertCmd(aCmd.tok, Expr.Imp(p, aCmd.Expr))); - } - } else if (cmd is AssumeCmd) { - var aCmd = (AssumeCmd)cmd; - cmdSeq.Add(new AssumeCmd(Token.NoToken, Expr.Imp(p, aCmd.Expr))); - } else if (cmd is HavocCmd) { - var hCmd = (HavocCmd)cmd; - foreach (IdentifierExpr v in hCmd.Vars) { - Microsoft.Boogie.Type type = v.Decl.TypedIdent.Type; - Contract.Assert(type != null); - - IdentifierExpr havocTempExpr; - if (havocVars.ContainsKey(type)) { - havocTempExpr = havocVars[type]; - } else { - var havocVar = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, - "_HAVOC_" + type.ToString(), type)); - impl.LocVars.Add(havocVar); - havocVars[type] = havocTempExpr = - new IdentifierExpr(Token.NoToken, havocVar); - } - cmdSeq.Add(new HavocCmd(Token.NoToken, - new IdentifierExprSeq(havocTempExpr))); - cmdSeq.Add(Cmd.SimpleAssign(Token.NoToken, v, - new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(p, havocTempExpr, v)))); - } - } else if (cmd is CallCmd) { - Debug.Assert(useProcedurePredicates); - var cCmd = (CallCmd)cmd; - cCmd.Ins.Insert(0, p); - cmdSeq.Add(cCmd); - } - else if (cmd is CommentCmd) { - // skip - } - else if (cmd is StateCmd) { - var sCmd = (StateCmd)cmd; - var newCmdSeq = new CmdSeq(); - foreach (Cmd c in sCmd.Cmds) - PredicateCmd(newCmdSeq, c); - sCmd.Cmds = newCmdSeq; - cmdSeq.Add(sCmd); - } - else { - Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); - } - } - - void PredicateTransferCmd(CmdSeq cmdSeq, TransferCmd cmd) { - if (cmd is GotoCmd) { - var gCmd = (GotoCmd)cmd; - var targets = new List( - gCmd.labelTargets.Cast().Select(b => blockIds[b])); - if (targets.Count == 1) { - PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, targets[0])); - } else { - PredicateCmd(cmdSeq, new HavocCmd(Token.NoToken, - new IdentifierExprSeq(cur))); - PredicateCmd(cmdSeq, new AssumeCmd(Token.NoToken, - targets.Select(t => (Expr)Expr.Eq(cur, t)).Aggregate(Expr.Or))); - } - - foreach (Block b in gCmd.labelTargets) { - if (blockGraph.Predecessors(b).Count() == 1) { - if (!doneBlocks.Contains(b)) { - var assumes = b.Cmds.Cast().TakeWhile(c => c is AssumeCmd); - if (assumes.Count() > 0) { - foreach (AssumeCmd aCmd in assumes) { - cmdSeq.Add(new AssumeCmd(Token.NoToken, - Expr.Imp(Expr.Eq(cur, blockIds[b]), - aCmd.Expr))); - } - b.Cmds = - new CmdSeq(b.Cmds.Cast().Skip(assumes.Count()).ToArray()); - } - } - } - } - } else if (cmd is ReturnCmd) { - PredicateCmd(cmdSeq, Cmd.SimpleAssign(Token.NoToken, cur, returnBlockId)); - } else { - Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); - } - } - - void PredicateImplementation() { - blockGraph = prog.ProcessLoops(impl); - var sortedBlocks = blockGraph.LoopyTopSort(); - - int blockId = 0; - foreach (var block in impl.Blocks) - blockIds[block] = Expr.Literal(blockId++); - returnBlockId = Expr.Literal(blockId++); - - curVar = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, "cur", - Microsoft.Boogie.Type.Int)); - impl.LocVars.Add(curVar); - cur = Expr.Ident(curVar); - - pVar = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, "p", - Microsoft.Boogie.Type.Bool)); - impl.LocVars.Add(pVar); - p = Expr.Ident(pVar); - - if (useProcedurePredicates) - fp = Expr.Ident(impl.InParams[0]); - - var newBlocks = new List(); - - Block entryBlock = new Block(); - entryBlock.Label = "entry"; - entryBlock.Cmds = new CmdSeq(Cmd.SimpleAssign(Token.NoToken, cur, - CreateIfFPThenElse(blockIds[sortedBlocks[0].Item1], - returnBlockId))); - newBlocks.Add(entryBlock); - - var prevBlock = entryBlock; - foreach (var n in sortedBlocks) { - if (n.Item2) { - var backedgeBlock = new Block(); - newBlocks.Add(backedgeBlock); - - backedgeBlock.Label = n.Item1.Label + ".backedge"; - backedgeBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, - Expr.Eq(cur, blockIds[n.Item1]), - new QKeyValue(Token.NoToken, "backedge", new List(), null))); - backedgeBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(n.Item1)); - - var tailBlock = new Block(); - newBlocks.Add(tailBlock); - - tailBlock.Label = n.Item1.Label + ".tail"; - tailBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, - Expr.Neq(cur, blockIds[n.Item1]))); - - prevBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(backedgeBlock, tailBlock)); - prevBlock = tailBlock; - } else { - var runBlock = n.Item1; - var oldCmdSeq = runBlock.Cmds; - runBlock.Cmds = new CmdSeq(); - newBlocks.Add(runBlock); - prevBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(runBlock)); - - pExpr = Expr.Eq(cur, blockIds[runBlock]); - if (createCandidateInvariants && blockGraph.Headers.Contains(runBlock)) { - AddUniformCandidateInvariant(runBlock.Cmds, runBlock); - AddNonUniformCandidateInvariant(runBlock.Cmds, runBlock); - } - runBlock.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, p, pExpr)); - var transferCmd = runBlock.TransferCmd; - foreach (Cmd cmd in oldCmdSeq) - PredicateCmd(newBlocks, runBlock, cmd, out runBlock); - PredicateTransferCmd(runBlock.Cmds, transferCmd); - - prevBlock = runBlock; - doneBlocks.Add(runBlock); - } - } - - prevBlock.TransferCmd = new ReturnCmd(Token.NoToken); - impl.Blocks = newBlocks; - } - - private Expr CreateIfFPThenElse(Expr then, Expr eElse) { - if (useProcedurePredicates) { - return new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(fp, then, eElse)); - } else { - return then; - } - } - - private void AddUniformCandidateInvariant(CmdSeq cs, Block header) { - cs.Add(prog.CreateCandidateInvariant(Expr.Eq(cur, - CreateIfFPThenElse(blockIds[header], returnBlockId)), - "uniform loop")); - } - - private void AddNonUniformCandidateInvariant(CmdSeq cs, Block header) { - var loopNodes = new HashSet(); - foreach (var b in blockGraph.BackEdgeNodes(header)) - loopNodes.UnionWith(blockGraph.NaturalLoops(header, b)); - var exits = new HashSet(); - foreach (var ln in loopNodes) { - if (ln.TransferCmd is GotoCmd) { - var gCmd = (GotoCmd) ln.TransferCmd; - foreach (var exit in gCmd.labelTargets.Cast() - .Where(b => !loopNodes.Contains(b))) - exits.Add(blockIds[exit]); - } - if (ln.TransferCmd is ReturnCmd) - exits.Add(returnBlockId); - } - var curIsHeaderOrExit = exits.Aggregate((Expr)Expr.Eq(cur, blockIds[header]), - (e, exit) => Expr.Or(e, Expr.Eq(cur, exit))); - cs.Add(prog.CreateCandidateInvariant( - CreateIfFPThenElse(curIsHeaderOrExit, Expr.Eq(cur, returnBlockId)), - "non-uniform loop")); - } - - public static void Predicate(Program p, - bool createCandidateInvariants = true, - bool useProcedurePredicates = true) { - foreach (var decl in p.TopLevelDeclarations.ToList()) { - if (useProcedurePredicates && decl is DeclWithFormals && !(decl is Function)) { - var dwf = (DeclWithFormals)decl; - var fpVar = new Formal(Token.NoToken, - new TypedIdent(Token.NoToken, "_P", - Microsoft.Boogie.Type.Bool), - /*incoming=*/true); - dwf.InParams = new VariableSeq( - (new Variable[] {fpVar}.Concat(dwf.InParams.Cast())) - .ToArray()); - - if (dwf is Procedure) - { - var proc = (Procedure)dwf; - var newRequires = new RequiresSeq(); - foreach (Requires r in proc.Requires) - { - newRequires.Add(new Requires(r.Free, - new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(r.Condition))); - } - var newEnsures = new EnsuresSeq(); - foreach (Ensures e in proc.Ensures) - { - newEnsures.Add(new Ensures(e.Free, - new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(e.Condition))); - } - } - - } - - try { - var impl = decl as Implementation; - if (impl != null) - new BlockPredicator(p, impl, createCandidateInvariants, useProcedurePredicates).PredicateImplementation(); - } - catch (Program.IrreducibleLoopException) { } - } - } - - public static void Predicate(Program p, Implementation impl) { - try { - new BlockPredicator(p, impl, false, false).PredicateImplementation(); - } - catch (Program.IrreducibleLoopException) { } - } - -} - - -class EnabledReplacementVisitor : StandardVisitor -{ - private Expr pExpr; - - internal EnabledReplacementVisitor(Expr pExpr) - { - this.pExpr = pExpr; - } - - public override Expr VisitExpr(Expr node) - { - if (node is IdentifierExpr) - { - IdentifierExpr iExpr = node as IdentifierExpr; - if (iExpr.Decl is Constant && QKeyValue.FindBoolAttribute(iExpr.Decl.Attributes, "__enabled")) - { - return pExpr; - } - } - return base.VisitExpr(node); - } -} - -} diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs index ca0c0e59..795fc9ca 100644 --- a/Source/VCGeneration/ConditionGeneration.cs +++ b/Source/VCGeneration/ConditionGeneration.cs @@ -10,7 +10,7 @@ using System.Diagnostics; using System.Threading; using System.IO; using Microsoft.Boogie; -using Graphing; +using Microsoft.Boogie.GraphUtil; using System.Diagnostics.Contracts; using Microsoft.Basetypes; using Microsoft.Boogie.VCExprAST; diff --git a/Source/VCGeneration/DoomCheck.cs b/Source/VCGeneration/DoomCheck.cs deleted file mode 100644 index d7e297cd..00000000 --- a/Source/VCGeneration/DoomCheck.cs +++ /dev/null @@ -1,401 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC -{ - internal class Evc { - - public DoomErrorHandler ErrorHandler { - set { - m_ErrorHandler = value; - } - } - - [ContractInvariantMethod] -void ObjectInvariant() -{ - Contract.Invariant(m_Checker!=null); -} - - private Checker m_Checker; - private DoomErrorHandler m_ErrorHandler; - - [NotDelayed] - public Evc(Checker check) { - Contract.Requires(check != null); - m_Checker = check; - - } - - public void Initialize(VCExpr evc) { - Contract.Requires(evc != null); - m_Checker.PushVCExpr(evc); - } - - - public bool CheckReachvar(List lv,Dictionary finalreachvars, - int k, int l, bool usenew , out ProverInterface.Outcome outcome) { - Contract.Requires(lv != null); - - VCExpr vc = VCExpressionGenerator.False; - if (usenew ) - { - foreach (Variable v in lv) - { - - vc = m_Checker.VCExprGen.Or( - m_Checker.VCExprGen.Neq( - m_Checker.VCExprGen.Integer(BigNum.ZERO), - m_Checker.TheoremProver.Context.BoogieExprTranslator.LookupVariable(v)), - vc); - } - //Console.WriteLine("TPQuery k={0}, l={1}, |Sp|={2}", k, l, finalreachvars.Count); - - VCExpr vc21 = m_Checker.VCExprGen.Integer(BigNum.ZERO); // Ask: is the necessary or can we use the same instance term in two inequalities? - VCExpr vc22 = m_Checker.VCExprGen.Integer(BigNum.ZERO); - - foreach (KeyValuePair kvp in finalreachvars) - { - - vc21 = m_Checker.VCExprGen.Add(vc21, m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)); - vc22 = m_Checker.VCExprGen.Add(vc22, m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)); - } - - VCExpr post = m_Checker.VCExprGen.Gt(m_Checker.VCExprGen.Integer(BigNum.FromInt(l)), vc21); - - if (k != -1) - { - post = m_Checker.VCExprGen.Or( - post, m_Checker.VCExprGen.Gt(vc22, m_Checker.VCExprGen.Integer(BigNum.FromInt(k))) - ); - } - vc = (m_Checker.VCExprGen.Or(vc, (post) )); - - } - else - { - - foreach (Variable v in lv) - { - - vc = m_Checker.VCExprGen.Or( - m_Checker.VCExprGen.Eq( - m_Checker.VCExprGen.Integer(BigNum.ONE), - m_Checker.TheoremProver.Context.BoogieExprTranslator.LookupVariable(v)), - vc); - } - Contract.Assert(vc != null); - - // Add the desired outcome of the reachability variables - foreach (KeyValuePair kvp in finalreachvars) - { - vc = m_Checker.VCExprGen.Or( - m_Checker.VCExprGen.Neq( - m_Checker.VCExprGen.Integer(BigNum.FromInt(kvp.Value)), - m_Checker.TheoremProver.Context.BoogieExprTranslator.Translate(kvp.Key)), - vc); - } - - } - - // Todo: Check if vc is trivial true or false - outcome = ProverInterface.Outcome.Undetermined; - Contract.Assert( m_ErrorHandler !=null); - m_Checker.BeginCheck(lv[0].Name, vc, m_ErrorHandler); - m_Checker.ProverDone.WaitOne(); - - try { - outcome = m_Checker.ReadOutcome(); - } catch (UnexpectedProverOutputException e) - { - if (CommandLineOptions.Clo.TraceVerify) { - Console.WriteLine("Prover is unable to check {0}! Reason:", lv[0].Name); - Console.WriteLine(e.ToString()); - } - return false; - } - return true; - } - } - - internal class DoomCheck { - - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(Label2Absy!=null); - Contract.Invariant(m_Check != null); - Contract.Invariant(m_Evc != null); - Contract.Invariant(m_Order != null); - } - - #region Attributes - public Hashtable Label2Absy; - public DoomErrorHandler ErrorHandler { - set { - m_ErrHandler = value; - m_Evc.ErrorHandler = value; - } - - get { - return m_ErrHandler; - } - } - - private DoomErrorHandler m_ErrHandler; - private Checker m_Check; - private DoomDetectionStrategy m_Order; - private Evc m_Evc; - #endregion - - public void __DEBUG_PrintStatistics() - { - Console.WriteLine("Checked/Total: Bl {0} / {1} EQ {2} / {3} {4} Tr {5} {6} / {7}", m_Order.__DEBUG_BlocksChecked, m_Order.__DEBUG_BlocksTotal, m_Order.__DEBUG_EQCChecked, m_Order.__DEBUG_EQCTotal, m_Order.__DEBUG_EQCLeaf, m_Order.__DEBUG_TracesChecked, m_Order.__DEBUG_InfeasibleTraces, m_Order.__DEBUG_TracesTotal); - } - - [NotDelayed] - public DoomCheck (Implementation passive_impl, Block unifiedExit, Checker check, List uncheckable, out int assertionCount) { - Contract.Requires(passive_impl != null); - Contract.Requires(check != null); - Contract.Requires(uncheckable != null); - m_Check = check; - - int replaceThisByCmdLineOption = CommandLineOptions.Clo.DoomStrategy ; - if (CommandLineOptions.Clo.DoomStrategy!=-1) Console.Write("Running experiments using {0} /", replaceThisByCmdLineOption); - switch (replaceThisByCmdLineOption) - { - default: - { - if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("Path Cover specialK Strategy"); - m_Order = new PathCoverStrategyK(passive_impl, unifiedExit, uncheckable); - break; - } - case 1: - { - if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("Path Cover L Strategy"); - m_Order = new PathCoverStrategy(passive_impl, unifiedExit, uncheckable); - break; - } - case 2: - { - if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("hasse strategy"); - m_Order = new HierachyStrategy(passive_impl, unifiedExit, uncheckable); - - break; - } - case 3: - { - if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("hasse+ce strategy"); - m_Order = new HierachyCEStrategy(passive_impl, unifiedExit, uncheckable); - break; - } - case 4: - { - if (CommandLineOptions.Clo.DoomStrategy != -1) Console.WriteLine("no strategy"); - m_Order = new NoStrategy(passive_impl, unifiedExit, uncheckable); - break; - } - - } - - Label2Absy = new Hashtable(); // This is only a dummy - m_Evc = new Evc(check); - Hashtable l2a = null; - VCExpr vce = this.GenerateEVC(passive_impl, out l2a, check, out assertionCount); - Contract.Assert(vce != null); - Contract.Assert( l2a!=null); - Label2Absy = l2a; - - m_Evc.Initialize(vce); - } - - - public void RespawnChecker(Implementation passive_impl, Checker check) - { - Contract.Requires(check != null); - m_Check = check; - Label2Absy = new Hashtable(); // This is only a dummy - m_Evc = new Evc(check); - Hashtable l2a = null; - int assertionCount; // compute and then ignore - VCExpr vce = this.GenerateEVC(passive_impl, out l2a, check, out assertionCount); - Contract.Assert(vce != null); - Contract.Assert(l2a != null); - Label2Absy = l2a; - - m_Evc.Initialize(vce); - } - - /* - Set b to the next block that needs to be checked. - - Returns false and set b to null if all blocks are checked. - - Has to be alternated with CheckLabel; might crash otherwise - */ - public bool GetNextBlock(out List lb) - { - return m_Order.GetNextBlock(out lb); - } - - public Stopwatch DEBUG_ProverTime = new Stopwatch(); - - /* - Checking a label means to ask the prover if |= ( rvar=false -> vc ) holds. - - outcome is set to Outcome.Invalid if the Block denoted by reachvar is doomed. - - returns false if the theorem prover throws an exception, otherwise true. - */ - public bool CheckLabel(List lv,Dictionary finalreachvars, out ProverInterface.Outcome outcome) { - Contract.Requires(lv != null); - outcome = ProverInterface.Outcome.Undetermined; - DEBUG_ProverTime.Reset(); - DEBUG_ProverTime.Start(); - if (m_Evc.CheckReachvar(lv,finalreachvars,m_Order.MaxBlocks,m_Order.MinBlocks,m_Order.HACK_NewCheck, out outcome) ) { - DEBUG_ProverTime.Stop(); - if (!m_Order.SetCurrentResult(lv, outcome, m_ErrHandler)) { - outcome = ProverInterface.Outcome.Undetermined; - } - return true; - } else { - DEBUG_ProverTime.Stop(); - Console.WriteLine(outcome); - m_Order.SetCurrentResult(lv, ProverInterface.Outcome.Undetermined, m_ErrHandler); - return false; - } - } - - public List!>!*/>> DoomedSequences { - get { - Contract.Ensures(Contract.ForAll(Contract.Result>>(), i=> cce.NonNullElements(i))); - - return m_Order.DetectedBlock; - } - } - - - #region Error Verification Condition Generation - /* - #region _TESTING_NEW_STUFF_ - CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Block; - //VCExpr wp = Wlp.Block(block, SuccCorrect, context); // Computes wp.S.true - - CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Doomed; - #endregion - - */ - - VCExpr GenerateEVC(Implementation impl, out Hashtable label2absy, Checker ch, out int assertionCount) { - Contract.Requires(impl != null); - Contract.Requires(ch != null); - Contract.Ensures(Contract.Result() != null); - - TypecheckingContext tc = new TypecheckingContext(null); - impl.Typecheck(tc); - label2absy = new Hashtable/**/(); - VCExpr vc; - switch (CommandLineOptions.Clo.vcVariety) { - case CommandLineOptions.VCVariety.Doomed: - vc = LetVC(cce.NonNull(impl.Blocks[0]), label2absy, ch.TheoremProver.Context, out assertionCount); - break; - - default: - Contract.Assert(false); throw new cce.UnreachableException(); // unexpected enumeration value - } - return vc; - } - - public VCExpr LetVC(Block startBlock, - Hashtable/**/ label2absy, - ProverContext proverCtxt, - out int assertionCount) - { - Contract.Requires(startBlock != null); - Contract.Requires(label2absy != null); - Contract.Requires(proverCtxt != null); - Contract.Ensures(Contract.Result() != null); - - Hashtable/**/ blockVariables = new Hashtable/**/(); - List bindings = new List(); - VCExpr startCorrect = LetVC(startBlock, label2absy, blockVariables, bindings, proverCtxt, out assertionCount); - if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { - return proverCtxt.ExprGen.Let(bindings, proverCtxt.ExprGen.Not(startCorrect) ); - } else { - return proverCtxt.ExprGen.Let(bindings, startCorrect ); - } - } - - VCExpr LetVC(Block block, - Hashtable/**/ label2absy, - Hashtable/**/ blockVariables, - List bindings, - ProverContext proverCtxt, - out int assertionCount) - { - Contract.Requires(label2absy != null); - Contract.Requires(blockVariables != null); - Contract.Requires(proverCtxt != null); - Contract.Requires(cce.NonNullElements(bindings)); - Contract.Ensures(Contract.Result() != null); - - assertionCount = 0; - VCExpressionGenerator gen = proverCtxt.ExprGen; - Contract.Assert(gen != null); - VCExprVar v = (VCExprVar)blockVariables[block]; - if (v == null) { - /* - * For block A (= block), generate: - * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct)) - * with the side effect of adding the let bindings to "bindings" for any - * successor not yet visited. - */ - VCExpr SuccCorrect; - GotoCmd gotocmd = block.TransferCmd as GotoCmd; - if (gotocmd == null) { - if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { - SuccCorrect = VCExpressionGenerator.False; - } else { - SuccCorrect = VCExpressionGenerator.True; - } - } else { - Contract.Assert( gotocmd.labelTargets != null); - List SuccCorrectVars = new List(gotocmd.labelTargets.Length); - foreach (Block successor in gotocmd.labelTargets) { - Contract.Assert(successor != null); - int ac; - VCExpr s = LetVC(successor, label2absy, blockVariables, bindings, proverCtxt, out ac); - assertionCount += ac; - SuccCorrectVars.Add(s); - } - SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars); - } - - VCContext context = new VCContext(label2absy, proverCtxt); - // m_Context = context; - - VCExpr vc = Wlp.Block(block, SuccCorrect, context); - assertionCount += context.AssertionCount; - v = gen.Variable(block.Label + "_correct", Microsoft.Boogie.Type.Bool); - - bindings.Add(gen.LetBinding(v, vc)); - blockVariables.Add(block, v); - } - return v; - } - - - #endregion - - } - -} diff --git a/Source/VCGeneration/DoomErrorHandler.cs b/Source/VCGeneration/DoomErrorHandler.cs deleted file mode 100644 index 5f00a3cf..00000000 --- a/Source/VCGeneration/DoomErrorHandler.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC -{ - internal class DoomErrorHandler : ProverInterface.ErrorHandler - { - - protected Hashtable label2Absy; - protected VerifierCallback callback; - private List m_CurrentTrace = new List(); - - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(label2Absy != null); - Contract.Invariant(callback != null); - Contract.Invariant(cce.NonNullElements(m_CurrentTrace)); - } - - - public DoomErrorHandler(Hashtable label2Absy, VerifierCallback callback) - { - Contract.Requires(label2Absy != null); - Contract.Requires(callback != null); - this.label2Absy = label2Absy; - this.callback = callback; - } - - public override Absy Label2Absy(string label) - { - //Contract.Requires(label != null); - Contract.Ensures(Contract.Result() != null); - - int id = int.Parse(label); - return cce.NonNull((Absy)label2Absy[id]); - } - - public override void OnProverWarning(string msg) - { - //Contract.Requires(msg != null); - this.callback.OnWarning(msg); - } - - - public List/*!>!*/ TraceNodes - { - get - { - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - return m_CurrentTrace; - } - } - - public override void OnModel(IList/*!>!*/ labels, Model model) - { - // TODO: it would be better to check which reachability variables are actually set to one! - List traceNodes = new List(); - List assertNodes = new List(); - foreach (string s in labels) - { - Contract.Assert(s != null); - Absy node = Label2Absy(s); - if (node is Block) - { - Block b = (Block)node; - traceNodes.Add(b); - //Console.Write("{0}, ", b.Label); - } - } - m_CurrentTrace.AddRange(traceNodes); - } - - } - -} \ No newline at end of file diff --git a/Source/VCGeneration/DoomedLoopUnrolling.cs b/Source/VCGeneration/DoomedLoopUnrolling.cs deleted file mode 100644 index 5469a1db..00000000 --- a/Source/VCGeneration/DoomedLoopUnrolling.cs +++ /dev/null @@ -1,650 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC -{ - #region Loop handeling for doomed code detection - - #region Loop Remover - internal class LoopRemover - { - GraphAnalyzer m_GraphAnalyzer; - - public LoopRemover(GraphAnalyzer ga) - { - m_GraphAnalyzer = ga; - } - - private void m_RemoveBackEdge(Loop l) - { - // first remove the backedges of the nested loops - foreach (Loop c in l.NestedLoops) m_RemoveBackEdge(c); - //Debugger.Break(); - GraphNode loopSkip = null; - foreach (GraphNode gn in l.Cutpoint.Suc) - { - if (l.LoopExitNodes.Contains(gn)) - { - loopSkip = gn; break; - } - } - if (loopSkip == null) - { // We didn't find a loop exit node. There must be a bug - Debugger.Break(); - } - foreach (GraphNode gn in l.Cutpoint.LoopingPred) - { - List newsuc = new List(); - foreach (GraphNode s in gn.Suc) - { - if (s == l.Cutpoint) newsuc.Add(loopSkip); - else newsuc.Add(s); - } - gn.Suc = newsuc; - } - } - - private void m_AbstractLoop(Loop l) - { - foreach (Loop c in l.NestedLoops) m_AbstractLoop(c); - m_HavocLoopBody(l); - m_RemoveBackEdge(l); - } - - public void AbstractLoopUnrolling() - { - foreach (Loop l in m_GraphAnalyzer.Graphloops) - { - m_MarkLoopExitUncheckable(l); - m_AbstractLoopUnrolling(l,null, "",true); - } - } - - private void m_HavocLoopBody(Loop l) - { - List loopblocks = new List(); - foreach (GraphNode g in l.LoopNodes) loopblocks.Add(g.Label); - HavocCmd hcmd = m_ComputHavocCmd(loopblocks, l.Cutpoint.Label.tok); - - //Add Havoc before and after the loop body - foreach (GraphNode g in l.Cutpoint.Suc) // before - { - if (l.LoopNodes.Contains(g)) m_AddHavocCmdToFront(g.Label, hcmd); - } - foreach (GraphNode g in l.Cutpoint.Pre) // and after - { - if (l.LoopNodes.Contains(g)) m_AddHavocCmdToFront(g.Label, hcmd); - } - } - - private void m_AddHavocCmdToFront(Block b, HavocCmd hcmd) - { - CmdSeq cs = new CmdSeq(); - cs.Add(hcmd); cs.AddRange(b.Cmds); - b.Cmds = cs; - } - - private HavocCmd m_ComputHavocCmd(List bl, IToken tok) - { - Contract.Requires(bl != null); - Contract.Requires(tok != null); - Contract.Ensures(Contract.Result() != null); - - VariableSeq varsToHavoc = new VariableSeq(); - foreach (Block b in bl) - { - Contract.Assert(b != null); - foreach (Cmd c in b.Cmds) - { - Contract.Assert(c != null); - c.AddAssignedVariables(varsToHavoc); - } - } - IdentifierExprSeq havocExprs = new IdentifierExprSeq(); - foreach (Variable v in varsToHavoc) - { - Contract.Assert(v != null); - IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v); - if (!havocExprs.Has(ie)) - havocExprs.Add(ie); - } - // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct - // the source location for this later on - return new HavocCmd(tok, havocExprs); - } - - private void m_AbstractLoopUnrolling(Loop l, Loop parent, string prefix, bool unfold) - { - //Debugger.Break(); - if (unfold) - { - - Loop first = new Loop(l, m_GraphAnalyzer,prefix+"FI_"); - Loop last = new Loop(l, m_GraphAnalyzer,prefix+"LA_"); - Loop abs = new Loop(l, m_GraphAnalyzer, prefix + "AB_"); - foreach (Loop c in first.NestedLoops) m_AbstractLoopUnrolling(c, first, prefix + "FI_", false); - foreach (Loop c in last.NestedLoops) m_AbstractLoopUnrolling(c, last, prefix + "LA_", false); - foreach (Loop c in abs.NestedLoops) m_AbstractLoopUnrolling(c, abs, prefix + "AB_", true); - - //Debugger.Break(); - - if (parent != null) - { - foreach (GraphNode gn in l.LoopNodes) - { - if (parent.LoopNodes.Contains(gn)) parent.LoopNodes.Remove(gn); - } - foreach (GraphNode gn in abs.LoopNodes) - { - if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); - } - foreach (GraphNode gn in first.LoopNodes) - { - if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); - } - foreach (GraphNode gn in last.LoopNodes) - { - if (!parent.LoopNodes.Contains(gn)) parent.LoopNodes.Add(gn); - } - } - - m_HavocLoopBody(abs); - List backupPre = new List(); - backupPre.AddRange(l.Cutpoint.Pre); - foreach (GraphNode pre in backupPre) - { - if (!l.Cutpoint.LoopingPred.Contains(pre)) - { - pre.RemoveEdgeTo(l.Cutpoint); - pre.RemoveEdgeTo(abs.Cutpoint); - pre.AddEdgeTo(first.Cutpoint); - } - } - - m_RemoveRegularLoopExit(last); - m_RemoveRegularLoopExit(abs); - - m_ReplaceBackEdge(first, abs.Cutpoint); - m_ReplaceBackEdge(abs, last.Cutpoint); - foreach (GraphNode gn in first.Cutpoint.Suc) - { - if (!first.LoopNodes.Contains(gn)) - { - m_ReplaceBackEdge(last, gn); - break; - } - } - - // Remove all remaining connections to the original loop - foreach (GraphNode gn in l.LoopExitNodes) - { - List tmp = new List(); - tmp.AddRange(gn.Pre); - foreach (GraphNode g in tmp) - { - if (l.LoopNodes.Contains(g)) - { - //Debugger.Break(); - g.RemoveEdgeTo(gn); - } - } - } - foreach (GraphNode gn in l.LoopNodes) - { - m_GraphAnalyzer.DeleteGraphNode(gn); - } - foreach (GraphNode gn in first.LoopNodes) - { - if (gn != first.Cutpoint && !m_GraphAnalyzer.UncheckableNodes.Contains(gn) ) - m_GraphAnalyzer.UncheckableNodes.Add(gn); - } - foreach (GraphNode gn in last.LoopNodes) - { - if (gn != last.Cutpoint && !m_GraphAnalyzer.UncheckableNodes.Contains(gn)) - m_GraphAnalyzer.UncheckableNodes.Add(gn); - } - MakeLoopExitUncheckable(last.LoopExitNodes); - } - else - { - foreach (Loop c in l.NestedLoops) m_AbstractLoopUnrolling(c, l, prefix, false); - m_AbstractLoop(l); - //MakeLoopExitUncheckable(l.LoopExitNodes); - } - } - - // the loop exit has to be marked uncheckable because otherwise - // while(true) would report unreachable code. - private void m_MarkLoopExitUncheckable(Loop l) - { - - foreach (GraphNode g in l.Cutpoint.Suc) - { - if (!l.LoopNodes.Contains(g)) - { - foreach (GraphNode g_ in m_MarkLoopExitUncheckable(g, l)) - { - if (!m_GraphAnalyzer.UncheckableNodes.Contains(g_)) - m_GraphAnalyzer.UncheckableNodes.Add(g_); - } - } - } - } - - private List m_MarkLoopExitUncheckable(GraphNode g, Loop l) - { - List ret = new List(); - - if (g.Pre.Count > 1) return ret; - ret.Add(g); - foreach (GraphNode gn in g.Suc) - { - ret.AddRange(m_MarkLoopExitUncheckable(gn, l)); - } - - return ret; - } - - // to avoid problems with unreachable code after while(true) {}, try to make the loopexit nodes uncheckable. - private void MakeLoopExitUncheckable(List le) - { - foreach (GraphNode gn in le) - { - if (gn.Suc.Count==1) m_GraphAnalyzer.UncheckableNodes.Add(gn); - } - } - - private void m_RemoveRegularLoopExit(Loop l) - { - List lg = new List(); - lg.AddRange( l.Cutpoint.Suc ); - foreach (GraphNode gn in lg) - { - if (l.LoopExitNodes.Contains(gn)) - { - l.Cutpoint.RemoveEdgeTo(gn); - l.LoopExitNodes.Remove(gn); - } - } - } - - private void m_ReplaceBackEdge(Loop l, GraphNode loopSkip) - { - - foreach (GraphNode gn in l.Cutpoint.LoopingPred) - { - List newsuc = new List(); - foreach (GraphNode s in gn.Suc) - { - if (s == l.Cutpoint) newsuc.Add(loopSkip); - else newsuc.Add(s); - } - gn.Suc = newsuc; - } - } - - - } - #endregion - - #region Graph Analyzer - internal class GraphAnalyzer - { - public List UncheckableNodes = new List(); - - public Dictionary GraphMap = new Dictionary(); - - public List Graphloops = null; - - public GraphAnalyzer(List blocks) - { - //ExitBlock = dedicatedExitBlock; - if (blocks.Count < 1) return; - foreach (Block b in blocks) GraphMap[b] = new GraphNode(b); - foreach (Block b in blocks) - { - foreach (Block pre in b.Predecessors) GraphMap[b].Pre.Add(GraphMap[pre]); - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc != null) - { - foreach (Block suc in gc.labelTargets) GraphMap[b].Suc.Add(GraphMap[suc]); - } - } - - - m_DetectCutPoints(GraphMap[blocks[0]]); - - //m_DetectCutPoints(GraphMap[blocks[0]], null, new List()); - Graphloops = m_CollectLoops(GraphMap[blocks[0]], null); - - } - - public List ToImplementation(out List uncheckables) - { - List blocks = new List(); - uncheckables = new List(); - - foreach (KeyValuePair kvp in GraphMap) - { - Block b = kvp.Key; - if (UncheckableNodes.Contains(GraphMap[b])) uncheckables.Add(b); - blocks.Add(b); - b.Predecessors = new BlockSeq(); - foreach (GraphNode p in kvp.Value.Pre) b.Predecessors.Add(p.Label); - if (kvp.Value.Suc.Count > 0) - { - BlockSeq bs = new BlockSeq(); - foreach (GraphNode s in kvp.Value.Suc) bs.Add(s.Label); - b.TransferCmd = new GotoCmd(b.tok, bs); - } - else - { - b.TransferCmd = new ReturnCmd(b.tok); - } - } - - return blocks; - } - - public GraphNode CloneGraphNode(GraphNode gn, string prefix) - { - CmdSeq cmds = new CmdSeq(gn.Label.Cmds); - - Block b = new Block(gn.Label.tok, prefix+gn.Label.Label, cmds, gn.Label.TransferCmd); - GraphNode clone = new GraphNode(b); - clone.IsCutpoint = gn.IsCutpoint; - clone.Suc.AddRange(gn.Suc); - clone.Pre.AddRange(gn.Pre); - clone.LoopingPred.AddRange(gn.LoopingPred); - GraphMap[b] = clone; - //if (gn.Label == ExitBlock) ExitBlock = b; - return clone; - } - - public void DeleteGraphNode(GraphNode gn) - { - List affected = new List(); - - foreach (KeyValuePair kvp in GraphMap) - { - if (kvp.Value == gn && !affected.Contains(kvp.Key)) affected.Add(kvp.Key); - } - foreach (Block b in affected) - { - GraphMap.Remove(b); - } - } -/* - private void m_DetectCutPoints(GraphNode gn, GraphNode pred, List visited ) - { - if (visited.Contains(gn) ) - { - if (pred != null && !gn.LoopingPred.Contains(pred)) gn.LoopingPred.Add(pred); - gn.IsCutpoint = true; - Console.WriteLine("Normal RootNode {0}", gn.Label.Label); - return; - } - else - { - List visited_ = new List(); - visited_.AddRange(visited); - visited_.Add(gn); - foreach (GraphNode next in gn.Suc) - { - m_DetectCutPoints(next,gn,visited_); - } - } - - } -*/ - - - private void m_DetectCutPoints(GraphNode gn) - { - List todo = new List(); - List done = new List(); - todo.Add(gn); - - GraphNode current = null; - todo[0].Index = 0; - - while (todo.Count > 0) - { - current = todo[0]; - todo.Remove(current); - - bool ready = true; - foreach (GraphNode p in current.Pre) - { - if (!done.Contains(p) ) - { - _loopbacktracking.Clear(); - if (!m_isLoop(current, p, todo, done)) - { - todo.Add(current); - ready = false; - break; - } - else - { - if (!current.LoopingPred.Contains(p)) current.LoopingPred.Add(p); - current.IsCutpoint = true; - } - } - } - if (!ready) continue; - done.Add(current); - foreach (GraphNode s in current.Suc) - { - if (!todo.Contains(s) && !done.Contains(s)) todo.Add(s); - } - } - - } - - List _loopbacktracking = new List(); - private bool m_isLoop(GraphNode loophead, GraphNode gn, List l1, List l2) - { - if (loophead == gn) return true; - if (l1.Contains(gn) || l2.Contains(gn) || _loopbacktracking.Contains(gn)) return false; - _loopbacktracking.Add(gn); - foreach (GraphNode p in gn.Pre) - { - if (m_isLoop(loophead, p, l1, l2)) return true; - } - return false; - } - - private List m_CollectLoops(GraphNode gn, Loop lastLoop) - { - List ret = new List(); - if (gn.Visited) return ret; - gn.Visited = true; - List loopingSucs = new List(); - if (gn.IsCutpoint) - { - Loop l = new Loop(gn); - if (lastLoop != null) - { - lastLoop.SucLoops.Add(l); - l.PreLoops.Add(lastLoop); - } - loopingSucs = l.LoopNodes; - lastLoop = l; - ret.Add(lastLoop); - } - foreach (GraphNode suc in gn.Suc) - { - if (!loopingSucs.Contains(suc)) ret.AddRange(m_CollectLoops(suc, lastLoop)); - } - //Debugger.Break(); - return ret; - } - } - #endregion - - #region GraphNodeStructure - internal class GraphNode - { - public int Index = -1; // Used for scc detection - public int LowLink = -1; // Used for scc detection - - public GraphNode(Block b) - { - Label = b; IsCutpoint = false; - } - public Block Label; - public List Pre = new List(); - public List Suc = new List(); - public bool IsCutpoint; - public bool Visited = false; - public List LoopingPred = new List(); - - public void AddEdgeTo(GraphNode other) - { - if (!this.Suc.Contains(other)) this.Suc.Add(other); - if (!other.Pre.Contains(this)) other.Pre.Add(this); - } - - public void RemoveEdgeTo(GraphNode other) - { - if (this.Suc.Contains(other)) this.Suc.Remove(other); - if (other.Pre.Contains(this)) other.Pre.Remove(this); - } - - } - #endregion - - #region LoopStructure - internal class Loop - { - public Loop(GraphNode cutpoint) - { - if (!cutpoint.IsCutpoint) - { - Debugger.Break(); - } - Cutpoint = cutpoint; - LoopNodes.Add(Cutpoint); - foreach (GraphNode gn in Cutpoint.LoopingPred) - { - CollectLoopBody(gn); - } - CollectLoopExitNodes(); - } - - // Copy Constructor - public Loop(Loop l, GraphAnalyzer ga, string prefix) - { - - Dictionary clonemap = new Dictionary(); - GraphNode clonecutpoint = null; - foreach (GraphNode gn in l.LoopNodes) - { - clonemap[gn] = ga.CloneGraphNode(gn, prefix); - if (gn == l.Cutpoint) clonecutpoint = clonemap[gn]; - } - - if (clonecutpoint == null) - { - Debugger.Break(); - return; - } - // Replace the pre and post nodes by the corresponding clone - foreach (GraphNode gn in l.LoopNodes) - { - List newl = new List(); - foreach (GraphNode g in clonemap[gn].Pre) - { - if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); - else newl.Add(g); - } - clonemap[gn].Pre = newl; - newl = new List(); - foreach (GraphNode g in clonemap[gn].Suc) - { - if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); - else newl.Add(g); - } - clonemap[gn].Suc = newl; - newl = new List(); - foreach (GraphNode g in clonemap[gn].LoopingPred) - { - if (clonemap.ContainsKey(g)) newl.Add(clonemap[g]); - else newl.Add(g); - } - clonemap[gn].LoopingPred = newl; - } - - foreach (GraphNode gn in l.Cutpoint.LoopingPred) - { - clonecutpoint.LoopingPred.Remove(gn); - clonecutpoint.LoopingPred.Add(clonemap[gn]); - } - - - - SucLoops.AddRange(l.SucLoops); - PreLoops.AddRange(l.PreLoops); - Cutpoint = clonecutpoint; - LoopNodes.Add(Cutpoint); - foreach (GraphNode gn in Cutpoint.LoopingPred) - { - CollectLoopBody(gn); - } - CollectLoopExitNodes(); - } - - private void CollectLoopBody(GraphNode gn) - { - if (gn == Cutpoint) return; - if (!LoopNodes.Contains(gn)) - { - if (gn.IsCutpoint) // nested loop found - { - Loop lo = new Loop(gn); - foreach (GraphNode lgn in lo.LoopNodes) - { - if (!LoopNodes.Contains(lgn)) LoopNodes.Add(lgn); - } - NestedLoops.Add(lo); - } - else - { - LoopNodes.Add(gn); - } - foreach (GraphNode pre in gn.Pre) if (!gn.LoopingPred.Contains(pre)) CollectLoopBody(pre); - } - } - - private void CollectLoopExitNodes() - { - foreach (GraphNode gn in LoopNodes) - { - foreach (GraphNode gn_ in gn.Suc) - { - if (!LoopNodes.Contains(gn_) && !LoopExitNodes.Contains(gn_)) LoopExitNodes.Add(gn_); - } - } - } - - public GraphNode Cutpoint; - public List LoopExitNodes = new List(); - public List NestedLoops = new List(); - public List SucLoops = new List(); - public List PreLoops = new List(); - public List LoopNodes = new List(); - } - #endregion - - #endregion -} \ No newline at end of file diff --git a/Source/VCGeneration/DoomedStrategy.cs b/Source/VCGeneration/DoomedStrategy.cs deleted file mode 100644 index c08662b1..00000000 --- a/Source/VCGeneration/DoomedStrategy.cs +++ /dev/null @@ -1,528 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC -{ - #region SuperClass for different doomed code detection strategies - abstract internal class DoomDetectionStrategy - { - public int __DEBUG_BlocksChecked = 0; - public int __DEBUG_BlocksTotal = 0; - public int __DEBUG_InfeasibleTraces = 0; - public int __DEBUG_TracesChecked = 0; - public int __DEBUG_TracesTotal = 0; - public int __DEBUG_EQCTotal = 0; - public int __DEBUG_EQCLeaf = 0; - public int __DEBUG_EQCChecked = 0; - - //Please use this one to toggle your Debug output - protected bool __DEBUGOUT = CommandLineOptions.Clo.DoomStrategy != -1; - - protected Implementation impl; - protected BlockHierachy m_BlockH = null; - - protected int m_MaxBranchingDepth = 0; - protected int m_MaxK = 0; - - protected Stopwatch sw = new Stopwatch(); - - - // This is the List with all detected doomed program points. This List is used by VCDoomed.cs to - // create an error message - public List/*!*/>/*!*/ DetectedBlock = new List/*!*/>(); - - private List __DEBUG_minelements = new List(); - - // There is no default constructor, because these parameters are needed for most subclasses - public DoomDetectionStrategy(Implementation imp, Block unifiedexit, List unreach) - { - m_BlockH = new BlockHierachy(imp, unifiedexit); - __DEBUG_EQCLeaf = m_BlockH.Leaves.Count; - - //foreach (BlockHierachyNode bhn in m_BlockH.Leaves) - //{ - // if (bhn.Content.Count > 0) __DEBUG_minelements.Add(bhn.Content[0]); - //} - //if (imp.Blocks.Count>0) m_GatherInfo(imp.Blocks[0], 0, 0,0); - - - if (__DEBUGOUT) - { - Console.WriteLine("MaBranchingDepth {0} MaxMinPP {1} ", m_MaxBranchingDepth, m_MaxK); - - Console.WriteLine("AvgLeaverPerPath {0} AvgPLen {1}", 0, 0); - } - - MaxBlocks = imp.Blocks.Count; - MinBlocks = imp.Blocks.Count; - HACK_NewCheck = false; - __DEBUG_BlocksTotal = imp.Blocks.Count; - } - - public int MaxBlocks, MinBlocks; - public bool HACK_NewCheck; - - // This method is called by the prover while it returns true. The prover checks for each - // List lb if - // |= !lb_1 /\ ... /\ !lb_n => wlp(Program, false) - // and passes the result to SetCurrentResult - abstract public bool GetNextBlock(out List passBlock); - - // This method is called to inform about the prover outcome for the previous GetNextBlock call. - abstract public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb); - - protected List m_GetErrorTraceFromCE(DoomErrorHandler cb) - { - BlockHierachyNode tn=null; - List errortrace = new List(); - foreach (Block b in cb.TraceNodes) - { - if (errortrace.Contains(b)) continue; - if (m_BlockH.BlockToHierachyMap.TryGetValue(b, out tn)) - { - foreach (Block b_ in tn.Unavoidable) - { - if (!errortrace.Contains(b_)) errortrace.Add(b_); - } - foreach (Block b_ in tn.Content) - { - if (!errortrace.Contains(b_)) errortrace.Add(b_); - } - } - } - return errortrace; - } - - private List __pathLength = new List(); - private List __leavespp = new List(); - protected void m_GatherInfo(Block b, int branchingdepth, int leavespp, int plen) - { - if (b.Predecessors.Length > 1) branchingdepth--; - - GotoCmd gc = b.TransferCmd as GotoCmd; - if (__DEBUG_minelements.Contains(b)) leavespp++; - plen++; - if (gc != null && gc.labelTargets.Length>0) - { - if (gc.labelTargets.Length > 1) branchingdepth++; - m_MaxBranchingDepth = (branchingdepth > m_MaxBranchingDepth) ? branchingdepth : m_MaxBranchingDepth; - foreach (Block s in gc.labelTargets) - { - m_GatherInfo(s, branchingdepth, leavespp,plen); - } - } - else - { - __pathLength.Add(plen); - __leavespp.Add(leavespp); - m_MaxK = (m_MaxK > leavespp) ? m_MaxK : leavespp; - } - } - - - - } - #endregion - - #region BruteForce Strategy - internal class NoStrategy : DoomDetectionStrategy - { - private List m_Blocks = new List(); - private int m_Current = 0; - - public NoStrategy(Implementation imp, Block unifiedexit, List unreach) - : base(imp, unifiedexit, unreach) - { - m_Blocks = imp.Blocks; - } - - override public bool GetNextBlock(out List lb) - { - if (m_Current < m_Blocks.Count) - { - lb = new List(); - lb.Add(m_Blocks[m_Current]); - m_Current++; - return true; - } - lb = null; - return false; - } - - // This method is called to inform about the prover outcome for the previous GetNextBlock call. - override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) - { - this.__DEBUG_BlocksChecked++; - // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) - if (outcome == ProverInterface.Outcome.Valid && m_Current <= m_Blocks.Count) - { - List lb = new List(); - lb.Add(m_Blocks[m_Current - 1]); - DetectedBlock.Add(lb); - } - return true; - } - } - #endregion - - #region Only check the minimal elements of the Hasse diagram - internal class HierachyStrategy : DoomDetectionStrategy - { - private List m_Blocks = new List(); - private List m_doomedBlocks = new List(); - private int m_Current = 0; - - public HierachyStrategy(Implementation imp, Block unifiedexit, List unreach) - : base(imp, unifiedexit, unreach) - { - foreach (BlockHierachyNode bhn in m_BlockH.Leaves) - { - if (bhn.Content.Count > 0) - { - m_Blocks.Add(bhn.Content[0]); - } - } - } - - override public bool GetNextBlock(out List lb) - { - sw.Start(); - if (m_Current < m_Blocks.Count) - { - lb = new List(); - lb.Add(m_Blocks[m_Current]); - m_Current++; - return true; - } - else - { - DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_doomedBlocks)); - } - lb = null; - return false; - } - - // This method is called to inform about the prover outcome for the previous GetNextBlock call. - override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) - { - this.__DEBUG_BlocksChecked++; - // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) - if (outcome == ProverInterface.Outcome.Valid && m_Current <= m_Blocks.Count) - { - m_doomedBlocks.Add(m_Blocks[m_Current - 1]); - } - if (__DEBUGOUT) Console.WriteLine("K := {0,3} , out {1,8}, time {2,12}", MaxBlocks, outcome, sw.ElapsedTicks); - sw.Stop(); - sw.Reset(); - - return true; - } - } - #endregion - - #region Only check the minimal elements of the Hasse diagram and use CEs - internal class HierachyCEStrategy : DoomDetectionStrategy - { - private List m_Blocks = new List(); - private List m_doomedBlocks = new List(); - private Block m_Current = null; - - public HierachyCEStrategy(Implementation imp, Block unifiedexit, List unreach) - : base(imp, unifiedexit, unreach) - { - foreach (BlockHierachyNode bhn in m_BlockH.Leaves) - { - if (bhn.Content.Count > 0) - { - m_Blocks.Add(bhn.Content[0]); - } - } - } - - override public bool GetNextBlock(out List lb) - { - m_Current = null; - if (m_Blocks.Count > 0) - { - m_Current = m_Blocks[0]; - m_Blocks.Remove(m_Current); - lb = new List(); - lb.Add(m_Current); - return true; - } - else - { - DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_doomedBlocks)); - } - lb = null; - return false; - } - - // This method is called to inform about the prover outcome for the previous GetNextBlock call. - override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) - { - this.__DEBUG_BlocksChecked++; - // outcome==Valid means that there is no feasible execution for the current block/path (i.e., might be doomed) - if (outcome == ProverInterface.Outcome.Valid && m_Current != null) - { - m_doomedBlocks.Add(m_Current); - } - else if (outcome == ProverInterface.Outcome.Invalid) - { - List errortrace = m_GetErrorTraceFromCE(cb); - foreach (Block b in errortrace) - { - if (m_Blocks.Contains(b)) - { - m_Blocks.Remove(b); - } - } - cb.TraceNodes.Clear(); - } - return true; - } - } - #endregion - - #region Path Cover Optimization with L - internal class PathCoverStrategy : DoomDetectionStrategy - { - List m_Uncheckedlocks = new List(); - List m_Ignore = new List(); - - Random m_Random = new Random(); - bool m_NoMoreMoves = false; - - private List m_foundBlock = new List(); - - public PathCoverStrategy(Implementation imp, Block unifiedexit, List unreach) - : base(imp, unifiedexit, unreach) - { - m_Ignore = unreach; - HACK_NewCheck = true; - impl = imp; - foreach (BlockHierachyNode bhn in m_BlockH.Leaves) - { - if (bhn.Content.Count > 0) - { - m_Uncheckedlocks.Add(bhn.Content[0]); - } - - } - m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); - MinBlocks = m_MaxK / 2 + (m_MaxK % 2 > 0 ? 1 : 0); - MaxBlocks = -1; - } - - override public bool GetNextBlock(out List lb) - { - sw.Start(); - - lb = new List(); - - if (m_Uncheckedlocks.Count == 0 || m_NoMoreMoves) - { - if (m_Uncheckedlocks.Count > 0) - { - DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_Uncheckedlocks)); - } - - return false; - } - - lb.AddRange(m_Uncheckedlocks); - - return true; - } - - override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) - { - this.__DEBUG_BlocksChecked++; - // Valid means infeasible... - int oldl = MinBlocks; - int oldsize = m_Uncheckedlocks.Count; - - - if (outcome == ProverInterface.Outcome.Valid) - { - this.__DEBUG_InfeasibleTraces++; - if (MinBlocks == 1) - { - m_NoMoreMoves = true; - } - else - { - MinBlocks = 1; - } - } - else if (outcome == ProverInterface.Outcome.Invalid) - { - this.__DEBUG_TracesChecked++; - - List errortrace = m_GetErrorTraceFromCE(cb); - foreach (Block b in errortrace) - { - if (m_Uncheckedlocks.Contains(b)) - { - m_Uncheckedlocks.Remove(b); - } - } - cb.TraceNodes.Clear(); - m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); - if (m_MaxK < 1) - { - m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); - } - MinBlocks = m_MaxK / 2 + (m_MaxK % 2 > 0 ? 1 : 0); - //if (MinBlocks > m_MaxK) MinBlocks = m_MaxK; - - } - else - { - m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); - } - if (__DEBUGOUT) - Console.WriteLine("K := {0,3}, L := {1,3}, deltaSp {2,3}, out {3,8}, time {4,8}", MaxBlocks, oldl, (oldsize - m_Uncheckedlocks.Count), outcome, sw.ElapsedTicks); - sw.Stop(); - sw.Reset(); - return true; - } - - - } - #endregion - - #region Path Cover Optimization with K - internal class PathCoverStrategyK : DoomDetectionStrategy - { - List m_Uncheckedlocks = new List(); - List m_Ignore = new List(); - - Random m_Random = new Random(); - bool m_NoMoreMoves = false; - - private List m_foundBlock = new List(); - - public PathCoverStrategyK(Implementation imp, Block unifiedexit, List unreach) - : base(imp, unifiedexit, unreach) - { - m_Ignore = unreach; - HACK_NewCheck = true; - impl = imp; - foreach (BlockHierachyNode bhn in m_BlockH.Leaves) - { - if (bhn.Content.Count > 0) - { - m_Uncheckedlocks.Add(bhn.Content[0]); - } - - } - - m_MaxK = m_BlockH.GetMaxK(m_Uncheckedlocks); - - MaxBlocks = m_Uncheckedlocks.Count; - if (m_MaxK < m_Uncheckedlocks.Count && m_MaxK > 0) - { - MaxBlocks = m_MaxK; - } - else if (m_MaxK >= m_Uncheckedlocks.Count) - { - MaxBlocks = m_Uncheckedlocks.Count; - } - else - { - MaxBlocks = 1; - } - //Console.WriteLine("InitK {0}, Max {1}", m_MaxK, MaxBlocks); - } - - override public bool GetNextBlock(out List lb) - { - sw.Start(); - - lb = new List(); - - if (m_Uncheckedlocks.Count == 0 || m_NoMoreMoves) - { - if (m_Uncheckedlocks.Count > 0) - { - DetectedBlock.Add(m_BlockH.GetOtherDoomedBlocks(m_Uncheckedlocks)); - } - - return false; - } - - lb.AddRange(m_Uncheckedlocks); - - MaxBlocks = MaxBlocks > m_Uncheckedlocks.Count ? m_Uncheckedlocks.Count : MaxBlocks; - MinBlocks = MaxBlocks / 2 + (MaxBlocks % 2 > 0 ? 1 : 0); - return true; - } - - override public bool SetCurrentResult(List reachvar, ProverInterface.Outcome outcome, DoomErrorHandler cb) - { - this.__DEBUG_BlocksChecked++; - // Valid means infeasible... - int oldk = MaxBlocks; - int oldl = MinBlocks; - int oldsize = m_Uncheckedlocks.Count; - - if (outcome == ProverInterface.Outcome.Valid) - { - this.__DEBUG_InfeasibleTraces++; - if (MaxBlocks == 1) - { - m_NoMoreMoves = true; - } - else - { - MaxBlocks /= 2; - } - } - else if (outcome == ProverInterface.Outcome.Invalid) - { - this.__DEBUG_TracesChecked++; - - List errortrace = m_GetErrorTraceFromCE(cb); - foreach (Block b in errortrace) - { - if (m_Uncheckedlocks.Contains(b)) - { - m_Uncheckedlocks.Remove(b); - } - } - cb.TraceNodes.Clear(); - - int k = m_BlockH.GetMaxK(m_Uncheckedlocks); - MaxBlocks = (k > MaxBlocks) ? MaxBlocks : k; - } - else - { - m_NoMoreMoves = true; m_Uncheckedlocks.Clear(); - } - if (__DEBUGOUT) - Console.WriteLine("K := {0,3}, L := {1,3}, deltaSp {2,3}, out {3,8}, time {4,8}", oldk, oldl, (oldsize - m_Uncheckedlocks.Count), outcome, sw.ElapsedTicks); - sw.Stop(); - sw.Reset(); - return true; - } - - - } - #endregion - -} \ No newline at end of file diff --git a/Source/VCGeneration/GraphAlgorithms.cs b/Source/VCGeneration/GraphAlgorithms.cs deleted file mode 100644 index 006a923f..00000000 --- a/Source/VCGeneration/GraphAlgorithms.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Graphing; -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Linq; - -namespace Microsoft.Boogie { - -public static class GraphAlgorithms { - - public static Graph Dual(this Graph g, Node dummySource) { - var exits = g.Nodes.Where(n => g.Successors(n).Count() == 0).ToList(); - if (exits.Count == 0) - return null; - var dual = new Graph(new HashSet>(g.Edges.Select(e => new Tuple(e.Item2, e.Item1)))); - if (exits.Count == 1) - dual.AddSource(exits[0]); - else { - dual.AddSource(dummySource); - foreach (var exit in exits) - dual.AddEdge(dummySource, exit); - } - return dual; - } - - public static List> LoopyTopSort(this Graph g) { - Contract.Assert(g.Reducible); - - int n = g.Nodes.Count; - var nodeToNumber = new Dictionary(n); - var numberToNode = new Node[n]; - var allNodes = new List(); - int counter = 0; - foreach (Node node in g.Nodes) { - numberToNode[counter] = node; - nodeToNumber[node] = counter; - allNodes.Add(counter); - counter++; - } - - var loops = new List[n]; - foreach (var h in g.Headers) { - var loopNodes = new HashSet(); - foreach (var b in g.BackEdgeNodes(h)) - loopNodes.UnionWith(g.NaturalLoops(h, b)); - loops[nodeToNumber[h]] = - new List(loopNodes.Select(node => nodeToNumber[node])); - } - - var successors = new List[n]; - int[] incomingEdges = new int[n]; - - foreach (var e in g.Edges) { - Contract.Assert(e.Item1 != null); - Contract.Assert(e.Item2 != null); - int source = nodeToNumber[e.Item1], target = nodeToNumber[e.Item2]; - if (loops[target] == null || !loops[target].Contains(source)) { - if (successors[source] == null) - successors[source] = new List(); - successors[source].Add(target); - incomingEdges[target]++; - } - } - - var sortedNodes = new List>(); - - var regionStack = new Stack>>(); - regionStack.Push(new Tuple>(default(Node), allNodes)); - - while (regionStack.Count != 0) { - int rootIndex = -1; - foreach (var i in regionStack.Peek().Item2) { - if (incomingEdges[i] == 0) { - rootIndex = i; - break; - } - } - if (rootIndex == -1) { - var region = regionStack.Pop(); - if (regionStack.Count != 0) - sortedNodes.Add(new Tuple(region.Item1, true)); - continue; - } - incomingEdges[rootIndex] = -1; - sortedNodes.Add(new Tuple(numberToNode[rootIndex], false)); - if (successors[rootIndex] != null) - foreach (int s in successors[rootIndex]) - incomingEdges[s]--; - if (loops[rootIndex] != null) - regionStack.Push(new Tuple>(numberToNode[rootIndex], - loops[rootIndex])); - } - - return sortedNodes; - } - - // Algorithm from Jeanne Ferrante, Karl J. Ottenstein, Joe D. Warren, - // "The Program Dependence Graph and Its Use in Optimization" - public static Dictionary> ControlDependence(this Graph g) where Node : class, new() { - Graph dual = g.Dual(new Node()); - DomRelation pdom = dual.DominatorMap; - var result = new Dictionary>(); - - var S = g.Edges.Where(e => !pdom.DominatedBy(e.Item1, e.Item2)); - foreach (var edge in S) { - var L = pdom.LeastCommonAncestor(edge.Item1, edge.Item2); - var deps = new List(); - if (L == edge.Item1) { - pdom.DominatedBy(edge.Item2, edge.Item1, deps); - deps.Add(edge.Item2); - deps.Add(edge.Item1); - } else { - pdom.DominatedBy(edge.Item2, L, deps); - deps.Add(edge.Item2); - } - if (result.ContainsKey(edge.Item1)) { - result[edge.Item1].UnionWith(deps); - } else { - result[edge.Item1] = new HashSet(deps); - } - } - return result; - } - -} - -} diff --git a/Source/VCGeneration/HasseDiagram.cs b/Source/VCGeneration/HasseDiagram.cs deleted file mode 100644 index d5fdfb66..00000000 --- a/Source/VCGeneration/HasseDiagram.cs +++ /dev/null @@ -1,424 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC -{ - internal class BlockHierachyNode - { - public List Unavoidable; - public List Content = new List(); - public List Parents = new List(); - public List Children = new List(); - - public bool Checked, Doomed, DoubleChecked; - - public BlockHierachyNode(Block current, List unavoidable) - { - Checked = false; Doomed = false; DoubleChecked = false; - Unavoidable = unavoidable; - Content.Add(current); - } - - public static bool operator <(BlockHierachyNode left, BlockHierachyNode right) - { - return Compare(left,right)>0; - } - - public static bool operator >(BlockHierachyNode left, BlockHierachyNode right) - { - return Compare(left, right) < 0; - } - - // Compare the unavoidable blocks of two BlockHierachyNodes. - // returns 0 if sets have the same size, -1 if l2 has an element - // that is not in l1, otherwise the size of the intersection. - public static int Compare(BlockHierachyNode l1, BlockHierachyNode l2) - { - List tmp = new List(); - tmp.AddRange(l2.Unavoidable); - foreach (Block b in l1.Unavoidable) - { - if (tmp.Contains(b)) tmp.Remove(b); - else return -1; - } - return tmp.Count; - } - } - - internal class HasseDiagram - { - public readonly List Leaves = new List(); - public readonly List Roots = new List(); - - public HasseDiagram(List nodes) - { - Dictionary> largerElements = new Dictionary>(); - foreach (BlockHierachyNode left in nodes) - { - largerElements[left] = new List(); - foreach (BlockHierachyNode right in nodes) - { - if (left != right) - { - if (left < right) - { - largerElements[left].Add(right); - } - } - } - if (largerElements[left].Count == 0) Leaves.Add(left); - } - - List done = new List(); - List lastround = null; - - //Debugger.Break(); - - // Now that we have the leaves, build the Hasse diagram - while (done.Count < nodes.Count) - { - List maxelements = new List(); - maxelements.AddRange(nodes); - foreach (BlockHierachyNode bhn in nodes) - { - if (!done.Contains(bhn)) - { - foreach (BlockHierachyNode tmp in largerElements[bhn]) - { - if (maxelements.Contains(tmp)) maxelements.Remove(tmp); - } - } - else - { - maxelements.Remove(bhn); - } - } - - done.AddRange(maxelements); - - if (lastround != null) - { - foreach (BlockHierachyNode tmp in lastround) - { - foreach (BlockHierachyNode tmp2 in maxelements) - { - if (largerElements[tmp].Contains(tmp2)) - { - if (!tmp.Children.Contains(tmp2)) tmp.Children.Add(tmp2); - if (!tmp2.Parents.Contains(tmp)) tmp2.Parents.Add(tmp); - } - } - } - } - else - { - Roots.AddRange(maxelements); - } - lastround = maxelements; - } - } - - - } - - internal class BlockHierachy - { - public BlockHierachyNode RootNode = null; - readonly public Dictionary BlockToHierachyMap = new Dictionary(); - readonly public Dictionary> Dominators = new Dictionary>(); - readonly public Dictionary> PostDominators = new Dictionary>(); - readonly public List Leaves = new List(); - - private Implementation m_Impl; - - public BlockHierachy(Implementation impl, Block unifiedExit) - { - m_Impl = impl; - List blocks = impl.Blocks; - List tmp_hnodes = new List(); - Dictionary> unavoidable = new Dictionary>(); - - BfsTraverser(blocks[0], true, Dominators); - BfsTraverser(unifiedExit, false, PostDominators); - - foreach (Block b in blocks) - { - List l1 = Dominators[b]; - List l2 = PostDominators[b]; - unavoidable[b] = m_MergeLists(l1, l2); - - BlockHierachyNode bhn = new BlockHierachyNode(b, unavoidable[b]); - bool found = false; - foreach (KeyValuePair kvp in BlockToHierachyMap) - { - if (BlockHierachyNode.Compare(kvp.Value, bhn) == 0) // using the overloaded compare operator - { - kvp.Value.Content.AddRange(bhn.Content); - BlockToHierachyMap[b] = kvp.Value; - found = true; - break; - } - } - if (!found) - { - BlockToHierachyMap[b] = bhn; - tmp_hnodes.Add(bhn); - } - } - - HasseDiagram hd = new HasseDiagram(tmp_hnodes); - Leaves = hd.Leaves; - } - - public int GetMaxK(List blocks) - { - m_GetMaxK(blocks); - return (m_MaxK>0) ? m_MaxK : 1; - } - - private int m_MaxK = 0; - private void m_GetMaxK(List blocks) - { - m_MaxK = 0; - Dictionary kstore = new Dictionary(); - List todo = new List(); - List done = new List(); - todo.Add(m_Impl.Blocks[0]); - kstore[m_Impl.Blocks[0]] = 0; - int localmax; - Block current = null; - while (todo.Count > 0) - { - current = todo[0]; - todo.Remove(current); - bool ready = true; - localmax = 0; - if (current.Predecessors!=null) { - foreach (Block p in current.Predecessors) - { - if (!done.Contains(p)) - { - ready = false; break; - } - else localmax = (localmax > kstore[p]) ? localmax : kstore[p]; - } - } - if (!ready) - { - todo.Add(current); continue; - } - done.Add(current); - kstore[current] = (blocks.Contains(current)) ? localmax +1 : localmax; - - m_MaxK = (kstore[current] > m_MaxK) ? kstore[current] : m_MaxK; - - GotoCmd gc = current.TransferCmd as GotoCmd; - if (gc != null) - { - foreach (Block s in gc.labelTargets) - { - if (!todo.Contains(s)) todo.Add(s); - } - } - } - - } - - public List GetOtherDoomedBlocks(List doomedblocks) - { - List alsoDoomed = new List(); - List todo = new List(); - foreach (Block b in doomedblocks) - { - BlockToHierachyMap[b].Doomed = true; - todo.Add(BlockToHierachyMap[b]); - } - - while (todo.Count > 0) - { - BlockHierachyNode current = todo[0]; - todo.Remove(current); - if (!current.Doomed && current.Children.Count > 0) - { - bool childrenDoomed = true; - foreach (BlockHierachyNode c in current.Children) - { - if (!c.Doomed) { childrenDoomed = false; break; } - } - if (childrenDoomed) current.Doomed = true; - } - - if (current.Doomed) - { - foreach (BlockHierachyNode p in current.Parents) - { - if (!todo.Contains(p)) todo.Add(p); - } - foreach (Block b in current.Content) - { - if (!alsoDoomed.Contains(b)) alsoDoomed.Add(b); - } - } - } - - return alsoDoomed; - } - - public void Impl2Dot(string filename) - { - - Contract.Requires(filename != null); - List nodes = new List(); - List edges = new List(); - - string nodestyle = "[shape=box];"; - - List nl = new List(); - foreach (BlockHierachyNode h in BlockToHierachyMap.Values) if (!nl.Contains(h)) nl.Add(h); - - - foreach (BlockHierachyNode b in nl) - { - String l1 = ""; - foreach (Block bl in b.Content) l1 = String.Format("{0}_{1}", l1, bl.Label); - - Contract.Assert(b != null); - nodes.Add(string.Format("\"{0}\" {1}", l1, nodestyle)); - foreach (BlockHierachyNode b_ in b.Children) - { - - String l2 = ""; - foreach (Block bl in b_.Content) l2 = String.Format("{0}_{1}", l2, bl.Label); - edges.Add(String.Format("\"{0}\" -> \"{1}\";", l1, l2)); - } - - } - - using (StreamWriter sw = new StreamWriter(filename)) - { - sw.WriteLine(String.Format("digraph {0} {{", "DISCO")); - // foreach (string! s in nodes) { - // sw.WriteLine(s); - // } - foreach (string s in edges) - { - Contract.Assert(s != null); - sw.WriteLine(s); - } - sw.WriteLine("}}"); - sw.Close(); - } - } - - private void BfsTraverser(Block current, bool forward, Dictionary> unavoidableBlocks) - { - List todo = new List(); - List done = new List(); - unavoidableBlocks[current] = new List(); - //Debugger.Break(); - todo.Add(current); - while (todo.Count > 0) - { - current = todo[0]; - todo.Remove(current); - BlockSeq pre = m_Predecessors(current, forward); - bool ready = true; - if (pre != null) - { - foreach (Block bpre in pre) - { - if (!done.Contains(bpre)) - { - ready = false; - break; - } - } - } - if (!ready) - { - todo.Add(current); - continue; - } - done.Add(current); - unavoidableBlocks[current].Add(current); - - BlockSeq suc = m_Succecessors(current, forward); - if (suc == null) continue; - foreach (Block bsuc in suc) - { - if (unavoidableBlocks.ContainsKey(bsuc)) - { - unavoidableBlocks[bsuc] = m_IntersectLists(unavoidableBlocks[bsuc], unavoidableBlocks[current]); - } - else - { - todo.Add(bsuc); - unavoidableBlocks[bsuc] = new List(); - unavoidableBlocks[bsuc].AddRange(unavoidableBlocks[current]); - } - - } - } - - } - - private List m_MergeLists(List lb1, List lb2) - { - List ret = new List(); - ret.AddRange(lb1); - foreach (Block b in lb2) - { - if (!ret.Contains(b)) ret.Add(b); - } - return ret; - } - - private List m_IntersectLists(List lb1, List lb2) - { - List ret = new List(); - ret.AddRange(lb1); - foreach (Block b in lb2) - { - if (!lb1.Contains(b)) ret.Remove(b); - } - foreach (Block b in lb1) - { - if (ret.Contains(b) && !lb2.Contains(b)) ret.Remove(b); - } - return ret; - } - - private BlockSeq m_Predecessors(Block b, bool forward) - { - if (forward) return b.Predecessors; - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc != null) - { - return gc.labelTargets; - } - return null; - } - - private BlockSeq m_Succecessors(Block b, bool forward) - { - return m_Predecessors(b, !forward); - } - - - } - -} \ No newline at end of file diff --git a/Source/VCGeneration/SmartBlockPredicator.cs b/Source/VCGeneration/SmartBlockPredicator.cs deleted file mode 100644 index b4f5a3df..00000000 --- a/Source/VCGeneration/SmartBlockPredicator.cs +++ /dev/null @@ -1,528 +0,0 @@ -using Graphing; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Linq; - -namespace Microsoft.Boogie { - -public class SmartBlockPredicator { - - Program prog; - Implementation impl; - Graph blockGraph; - List> sortedBlocks; - - Func useProcedurePredicates; - - Dictionary predMap, defMap; - Dictionary> ownedMap; - Dictionary parentMap; - Dictionary partInfo; - - IdentifierExpr fp; - Dictionary havocVars = - new Dictionary(); - Dictionary blockIds = new Dictionary(); - HashSet doneBlocks = new HashSet(); - bool myUseProcedurePredicates; - UniformityAnalyser uni; - - SmartBlockPredicator(Program p, Implementation i, Func upp, UniformityAnalyser u) { - prog = p; - impl = i; - useProcedurePredicates = upp; - myUseProcedurePredicates = useProcedurePredicates(i.Proc); - uni = u; - } - - void PredicateCmd(Expr p, List blocks, Block block, Cmd cmd, out Block nextBlock) { - var cCmd = cmd as CallCmd; - if (cCmd != null && !useProcedurePredicates(cCmd.Proc)) { - if (p == null) { - block.Cmds.Add(cmd); - nextBlock = block; - return; - } - - var trueBlock = new Block(); - blocks.Add(trueBlock); - trueBlock.Label = block.Label + ".call.true"; - trueBlock.Cmds.Add(new AssumeCmd(Token.NoToken, p)); - trueBlock.Cmds.Add(cmd); - - var falseBlock = new Block(); - blocks.Add(falseBlock); - falseBlock.Label = block.Label + ".call.false"; - falseBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(p))); - - var contBlock = new Block(); - blocks.Add(contBlock); - contBlock.Label = block.Label + ".call.cont"; - - block.TransferCmd = - new GotoCmd(Token.NoToken, new BlockSeq(trueBlock, falseBlock)); - trueBlock.TransferCmd = falseBlock.TransferCmd = - new GotoCmd(Token.NoToken, new BlockSeq(contBlock)); - nextBlock = contBlock; - } else { - PredicateCmd(p, block.Cmds, cmd); - nextBlock = block; - } - } - - void PredicateCmd(Expr p, CmdSeq cmdSeq, Cmd cmd) { - if (cmd is CallCmd) { - var cCmd = (CallCmd)cmd; - Debug.Assert(useProcedurePredicates(cCmd.Proc)); - cCmd.Ins.Insert(0, p != null ? p : Expr.True); - cmdSeq.Add(cCmd); - } else if (p == null) { - cmdSeq.Add(cmd); - } else if (cmd is AssignCmd) { - var aCmd = (AssignCmd)cmd; - cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss, - new List(aCmd.Lhss.Zip(aCmd.Rhss, (lhs, rhs) => - new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(p, rhs, lhs.AsExpr)))))); - } else if (cmd is AssertCmd) { - var aCmd = (AssertCmd)cmd; - Expr newExpr = new EnabledReplacementVisitor(p).VisitExpr(aCmd.Expr); - aCmd.Expr = QKeyValue.FindBoolAttribute(aCmd.Attributes, "do_not_predicate") ? newExpr : Expr.Imp(p, newExpr); - cmdSeq.Add(aCmd); - } else if (cmd is AssumeCmd) { - var aCmd = (AssumeCmd)cmd; - cmdSeq.Add(new AssumeCmd(Token.NoToken, Expr.Imp(p, aCmd.Expr))); - } else if (cmd is HavocCmd) { - var hCmd = (HavocCmd)cmd; - foreach (IdentifierExpr v in hCmd.Vars) { - Microsoft.Boogie.Type type = v.Decl.TypedIdent.Type; - Contract.Assert(type != null); - - IdentifierExpr havocTempExpr; - if (havocVars.ContainsKey(type)) { - havocTempExpr = havocVars[type]; - } else { - var havocVar = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, - "_HAVOC_" + type.ToString(), type)); - impl.LocVars.Add(havocVar); - havocVars[type] = havocTempExpr = - new IdentifierExpr(Token.NoToken, havocVar); - } - cmdSeq.Add(new HavocCmd(Token.NoToken, - new IdentifierExprSeq(havocTempExpr))); - cmdSeq.Add(Cmd.SimpleAssign(Token.NoToken, v, - new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(p, havocTempExpr, v)))); - } - } else if (cmd is CommentCmd) { - // skip - } else if (cmd is StateCmd) { - var sCmd = (StateCmd)cmd; - var newCmdSeq = new CmdSeq(); - foreach (Cmd c in sCmd.Cmds) - PredicateCmd(p, newCmdSeq, c); - sCmd.Cmds = newCmdSeq; - cmdSeq.Add(sCmd); - } else { - Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); - } - } - - // hasPredicatedRegion is true iff the block or its targets are predicated - // (i.e. we enter, stay within or exit a predicated region). - void PredicateTransferCmd(Expr p, Block src, CmdSeq cmdSeq, TransferCmd cmd, out bool hasPredicatedRegion) { - hasPredicatedRegion = predMap.ContainsKey(src); - - if (cmd is GotoCmd) { - var gCmd = (GotoCmd)cmd; - - hasPredicatedRegion = hasPredicatedRegion || - gCmd.labelTargets.Cast().Any(b => predMap.ContainsKey(b)); - - if (gCmd.labelTargets.Length == 1) { - if (defMap.ContainsKey(gCmd.labelTargets[0])) - PredicateCmd(p, cmdSeq, - Cmd.SimpleAssign(Token.NoToken, - Expr.Ident(predMap[gCmd.labelTargets[0]]), Expr.True)); - } else { - Debug.Assert(gCmd.labelTargets.Length > 1); - Debug.Assert(gCmd.labelTargets.Cast().All(t => uni.IsUniform(impl.Name, t) || - partInfo.ContainsKey(t))); - foreach (Block target in gCmd.labelTargets) { - if (!partInfo.ContainsKey(target)) - continue; - - var part = partInfo[target]; - if (defMap.ContainsKey(part.realDest)) - PredicateCmd(p, cmdSeq, - Cmd.SimpleAssign(Token.NoToken, - Expr.Ident(predMap[part.realDest]), part.pred)); - var predsExitingLoop = new Dictionary>(); - foreach (Block exit in LoopsExited(src, target)) { - List predList; - if (!predsExitingLoop.ContainsKey(exit)) - predList = predsExitingLoop[exit] = new List(); - else - predList = predsExitingLoop[exit]; - predList.Add(part.pred); - } - foreach (var pred in predsExitingLoop) { - PredicateCmd(p, cmdSeq, - Cmd.SimpleAssign(Token.NoToken, - Expr.Ident(predMap[pred.Key]), - Expr.Not(pred.Value.Aggregate(Expr.Or)))); - } - } - } - } else if (cmd is ReturnCmd) { - // Blocks which end in a return will never share a predicate with a block - // which appears after it. Furthermore, such a block cannot be part of a - // loop. So it is safe to do nothing here. - } else { - Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString()); - } - } - - Variable FreshPredicate(ref int predCount) { - var pVar = new LocalVariable(Token.NoToken, - new TypedIdent(Token.NoToken, - "p" + predCount++, - Microsoft.Boogie.Type.Bool)); - impl.LocVars.Add(pVar); - return pVar; - } - - void AssignPredicates(Graph blockGraph, - DomRelation dom, - DomRelation pdom, - IEnumerator> i, - Variable headPredicate, - ref int predCount) { - var header = i.Current.Item1; - var regionPreds = new List>(); - var ownedPreds = new HashSet(); - ownedMap[header] = ownedPreds; - - if (headPredicate != null) { - predMap[header] = headPredicate; - defMap[header] = headPredicate; - regionPreds.Add(new Tuple(header, headPredicate)); - } - - while (i.MoveNext()) { - var block = i.Current; - if (uni != null && uni.IsUniform(impl.Name, block.Item1)) - continue; - if (block.Item2) { - if (block.Item1 == header) - return; - } else { - if (blockGraph.Headers.Contains(block.Item1)) { - parentMap[block.Item1] = header; - var loopPred = FreshPredicate(ref predCount); - ownedPreds.Add(loopPred); - AssignPredicates(blockGraph, dom, pdom, i, loopPred, ref predCount); - } else { - bool foundExisting = false; - foreach (var regionPred in regionPreds) { - if (dom.DominatedBy(block.Item1, regionPred.Item1) && - pdom.DominatedBy(regionPred.Item1, block.Item1)) { - predMap[block.Item1] = regionPred.Item2; - foundExisting = true; - break; - } - } - if (!foundExisting) { - var condPred = FreshPredicate(ref predCount); - predMap[block.Item1] = condPred; - defMap[block.Item1] = condPred; - ownedPreds.Add(condPred); - regionPreds.Add(new Tuple(block.Item1, condPred)); - } - } - } - } - } - - void AssignPredicates() { - DomRelation dom = blockGraph.DominatorMap; - - Graph dualGraph = blockGraph.Dual(new Block()); - DomRelation pdom = dualGraph.DominatorMap; - - var iter = sortedBlocks.GetEnumerator(); - if (!iter.MoveNext()) { - predMap = defMap = null; - ownedMap = null; - return; - } - - int predCount = 0; - predMap = new Dictionary(); - defMap = new Dictionary(); - ownedMap = new Dictionary>(); - parentMap = new Dictionary(); - AssignPredicates(blockGraph, dom, pdom, iter, - myUseProcedurePredicates ? impl.InParams[0] : null, - ref predCount); - } - - IEnumerable LoopsExited(Block src, Block dest) { - var i = sortedBlocks.GetEnumerator(); - while (i.MoveNext()) { - var b = i.Current; - if (b.Item1 == src) { - return LoopsExitedForwardEdge(dest, i); - } else if (b.Item1 == dest) { - return LoopsExitedBackEdge(src, i); - } - } - Debug.Assert(false); - return null; - } - - private IEnumerable LoopsExitedBackEdge(Block src, IEnumerator> i) { - var headsSeen = new HashSet(); - while (i.MoveNext()) { - var b = i.Current; - if (!b.Item2 && blockGraph.Headers.Contains(b.Item1)) - headsSeen.Add(b.Item1); - else if (b.Item2) - headsSeen.Remove(b.Item1); - if (b.Item1 == src) - return headsSeen; - } - Debug.Assert(false); - return null; - } - - private IEnumerable LoopsExitedForwardEdge(Block dest, IEnumerator> i) { - var headsSeen = new HashSet(); - while (i.MoveNext()) { - var b = i.Current; - if (b.Item1 == dest) - yield break; - else if (!b.Item2 && blockGraph.Headers.Contains(b.Item1)) - headsSeen.Add(b.Item1); - else if (b.Item2 && !headsSeen.Contains(b.Item1)) - yield return b.Item1; - } - Debug.Assert(false); - } - - class PartInfo { - public PartInfo(Expr p, Block r) { pred = p; realDest = r; } - public Expr pred; - public Block realDest; - } - - Dictionary BuildPartitionInfo() { - var partInfo = new Dictionary(); - foreach (var block in blockGraph.Nodes) { - if (uni.IsUniform(impl.Name, block)) - continue; - - var parts = block.Cmds.Cast().TakeWhile( - c => c is AssumeCmd && - QKeyValue.FindBoolAttribute(((AssumeCmd)c).Attributes, "partition")); - - Expr pred = null; - if (parts.Count() > 0) { - pred = parts.Select(a => ((AssumeCmd)a).Expr).Aggregate(Expr.And); - block.Cmds = - new CmdSeq(block.Cmds.Cast().Skip(parts.Count()).ToArray()); - } else { - continue; - } - - Block realDest = block; - if (block.Cmds.Length == 0) { - var gc = block.TransferCmd as GotoCmd; - if (gc != null && gc.labelTargets.Length == 1) - realDest = gc.labelTargets[0]; - } - partInfo[block] = new PartInfo(pred, realDest); - } - - return partInfo; - } - - void PredicateImplementation() { - blockGraph = prog.ProcessLoops(impl); - sortedBlocks = blockGraph.LoopyTopSort(); - - AssignPredicates(); - partInfo = BuildPartitionInfo(); - - if (myUseProcedurePredicates) - fp = Expr.Ident(impl.InParams[0]); - - var newBlocks = new List(); - Block prevBlock = null; - foreach (var n in sortedBlocks) { - if (predMap.ContainsKey(n.Item1)) { - var p = predMap[n.Item1]; - var pExpr = Expr.Ident(p); - - if (n.Item2) { - var backedgeBlock = new Block(); - newBlocks.Add(backedgeBlock); - - backedgeBlock.Label = n.Item1.Label + ".backedge"; - backedgeBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, pExpr, - new QKeyValue(Token.NoToken, "backedge", new List(), null))); - backedgeBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(n.Item1)); - - var tailBlock = new Block(); - newBlocks.Add(tailBlock); - - tailBlock.Label = n.Item1.Label + ".tail"; - tailBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, - Expr.Not(pExpr))); - - if (uni != null && !uni.IsUniform(impl.Name, n.Item1)) { - uni.AddNonUniform(impl.Name, backedgeBlock); - uni.AddNonUniform(impl.Name, tailBlock); - } - - if (prevBlock != null) - prevBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(backedgeBlock, tailBlock)); - prevBlock = tailBlock; - } else { - PredicateBlock(pExpr, n.Item1, newBlocks, ref prevBlock); - } - } else { - if (!n.Item2) { - PredicateBlock(null, n.Item1, newBlocks, ref prevBlock); - } - } - } - - if (prevBlock != null) - prevBlock.TransferCmd = new ReturnCmd(Token.NoToken); - - impl.Blocks = newBlocks; - } - - private void PredicateBlock(Expr pExpr, Block block, List newBlocks, ref Block prevBlock) { - var firstBlock = block; - - var oldCmdSeq = block.Cmds; - block.Cmds = new CmdSeq(); - newBlocks.Add(block); - if (prevBlock != null) { - prevBlock.TransferCmd = new GotoCmd(Token.NoToken, new BlockSeq(block)); - } - - if (parentMap.ContainsKey(block)) { - var parent = parentMap[block]; - if (predMap.ContainsKey(parent)) { - var parentPred = predMap[parent]; - if (parentPred != null) { - block.Cmds.Add(new AssertCmd(Token.NoToken, - pExpr != null ? (Expr)Expr.Imp(pExpr, Expr.Ident(parentPred)) - : Expr.Ident(parentPred))); - } - } - } - - var transferCmd = block.TransferCmd; - foreach (Cmd cmd in oldCmdSeq) - PredicateCmd(pExpr, newBlocks, block, cmd, out block); - - if (ownedMap.ContainsKey(firstBlock)) { - var owned = ownedMap[firstBlock]; - foreach (var v in owned) - block.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, Expr.Ident(v), Expr.False)); - } - - bool hasPredicatedRegion; - PredicateTransferCmd(pExpr, block, block.Cmds, transferCmd, out hasPredicatedRegion); - - if (hasPredicatedRegion) - prevBlock = block; - else - prevBlock = null; - - doneBlocks.Add(block); - } - - private Expr CreateIfFPThenElse(Expr then, Expr eElse) { - if (myUseProcedurePredicates) { - return new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(fp, then, eElse)); - } else { - return then; - } - } - - public static void Predicate(Program p, - Func useProcedurePredicates = null, - UniformityAnalyser uni = null) { - useProcedurePredicates = useProcedurePredicates ?? (proc => false); - if (uni != null) { - var oldUPP = useProcedurePredicates; - useProcedurePredicates = proc => oldUPP(proc) && !uni.IsUniform(proc.Name); - } - - foreach (var decl in p.TopLevelDeclarations.ToList()) { - if (decl is Procedure || decl is Implementation) { - var proc = decl as Procedure; - Implementation impl = null; - if (proc == null) { - impl = (Implementation)decl; - proc = impl.Proc; - } - - bool upp = useProcedurePredicates(proc); - if (upp) { - var dwf = (DeclWithFormals)decl; - var fpVar = new Formal(Token.NoToken, - new TypedIdent(Token.NoToken, "_P", - Microsoft.Boogie.Type.Bool), - /*incoming=*/true); - dwf.InParams = new VariableSeq( - (new Variable[] {fpVar}.Concat(dwf.InParams.Cast())) - .ToArray()); - - if (impl == null) { - var newRequires = new RequiresSeq(); - foreach (Requires r in proc.Requires) { - newRequires.Add(new Requires(r.Free, - new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(r.Condition))); - } - var newEnsures = new EnsuresSeq(); - foreach (Ensures e in proc.Ensures) { - newEnsures.Add(new Ensures(e.Free, - new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(e.Condition))); - } - } - } - - if (impl != null) { - try { - new SmartBlockPredicator(p, impl, useProcedurePredicates, uni).PredicateImplementation(); - } catch (Program.IrreducibleLoopException) { } - } - } - } - } - - public static void Predicate(Program p, Implementation impl) { - try { - new SmartBlockPredicator(p, impl, proc => false, null).PredicateImplementation(); - } - catch (Program.IrreducibleLoopException) { } - } - -} - -} diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index 5c6a5f68..6ad97141 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Text; using System.IO; using Microsoft.Boogie; -using Graphing; +using Microsoft.Boogie.GraphUtil; using System.Diagnostics.Contracts; using Microsoft.Basetypes; using Microsoft.Boogie.VCExprAST; diff --git a/Source/VCGeneration/UniformityAnalyser.cs b/Source/VCGeneration/UniformityAnalyser.cs deleted file mode 100644 index 802ee2d2..00000000 --- a/Source/VCGeneration/UniformityAnalyser.cs +++ /dev/null @@ -1,556 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Diagnostics; -using Graphing; - -namespace Microsoft.Boogie -{ - - public class UniformityAnalyser - { - private Program prog; - - private bool doAnalysis, unstructured; - - private ISet entryPoints; - - private IEnumerable nonUniformVars; - - private bool ProcedureChanged; - - private Dictionary>> uniformityInfo; - - private Dictionary> nonUniformLoops; - - private Dictionary> nonUniformBlocks; - - private Dictionary> loopsWithNonuniformReturn; - - private Dictionary> inParameters; - - private Dictionary> outParameters; - - private List loopStack; - - private bool hitNonuniformReturn; - - public UniformityAnalyser(Program prog, bool doAnalysis, bool unstructured, ISet entryPoints, IEnumerable nonUniformVars) - { - this.prog = prog; - this.doAnalysis = doAnalysis; - this.unstructured = unstructured; - this.entryPoints = entryPoints; - this.nonUniformVars = nonUniformVars; - uniformityInfo = new Dictionary>>(); - nonUniformLoops = new Dictionary>(); - nonUniformBlocks = new Dictionary>(); - loopsWithNonuniformReturn = new Dictionary>(); - inParameters = new Dictionary>(); - outParameters = new Dictionary>(); - loopStack = new List(); - } - - public void Analyse() - { - var impls = prog.TopLevelDeclarations.OfType(); - - foreach (var Impl in impls) - { - bool uniformProcedure = doAnalysis || entryPoints.Contains(Impl); - - uniformityInfo.Add(Impl.Name, new KeyValuePair> - (uniformProcedure, new Dictionary ())); - - nonUniformLoops.Add(Impl.Name, new HashSet()); - loopsWithNonuniformReturn.Add(Impl.Name, new HashSet()); - - foreach (var v in nonUniformVars) - SetNonUniform(Impl.Name, v.Name); - - foreach (Variable v in Impl.LocVars) - { - if (doAnalysis) - { - SetUniform(Impl.Name, v.Name); - } - else - { - SetNonUniform(Impl.Name, v.Name); - } - } - - inParameters[Impl.Name] = new List(); - - foreach (Variable v in Impl.InParams) - { - inParameters[Impl.Name].Add(v.Name); - if (doAnalysis) - { - SetUniform(Impl.Name, v.Name); - } - else - { - SetNonUniform(Impl.Name, v.Name); - } - } - - outParameters[Impl.Name] = new List(); - foreach (Variable v in Impl.OutParams) - { - outParameters[Impl.Name].Add(v.Name); - if (doAnalysis) - { - SetUniform(Impl.Name, v.Name); - } - else - { - SetNonUniform(Impl.Name, v.Name); - } - } - - ProcedureChanged = true; - } - - if (doAnalysis) - { - while (ProcedureChanged) - { - ProcedureChanged = false; - - foreach (var Impl in impls) - { - hitNonuniformReturn = false; - Analyse(Impl, uniformityInfo[Impl.Name].Key); - } - } - } - - foreach (var Impl in impls) - { - if (!IsUniform (Impl.Name)) - { - List newIns = new List(); - newIns.Add("_P"); - foreach (string s in inParameters[Impl.Name]) - { - newIns.Add(s); - } - inParameters[Impl.Name] = newIns; - } - } - } - - private void Analyse(Implementation Impl, bool ControlFlowIsUniform) - { - if (unstructured) - { - if (!ControlFlowIsUniform) - { - nonUniformBlocks[Impl.Name] = new HashSet(Impl.Blocks); - - foreach (Variable v in Impl.LocVars) { - if (IsUniform(Impl.Name, v.Name)) { - SetNonUniform(Impl.Name, v.Name); - } - } - - foreach (Variable v in Impl.InParams) { - if (IsUniform(Impl.Name, v.Name)) { - SetNonUniform(Impl.Name, v.Name); - } - } - - foreach (Variable v in Impl.OutParams) { - if (IsUniform(Impl.Name, v.Name)) { - SetNonUniform(Impl.Name, v.Name); - } - } - - return; - } - - Graph blockGraph = prog.ProcessLoops(Impl); - var ctrlDep = blockGraph.ControlDependence(); - - // Compute transitive closure of control dependence info. - bool changed; - do - { - changed = false; - foreach (var depEntry in ctrlDep) - { - var newDepSet = new HashSet(depEntry.Value); - foreach (var dep in depEntry.Value) - { - if (ctrlDep.ContainsKey(dep)) - newDepSet.UnionWith(ctrlDep[dep]); - } - if (newDepSet.Count != depEntry.Value.Count) - { - depEntry.Value.UnionWith(newDepSet); - changed = true; - } - } - } while (changed); - - var nonUniformBlockSet = new HashSet(); - nonUniformBlocks[Impl.Name] = nonUniformBlockSet; - - do { - changed = false; - foreach (var block in Impl.Blocks) { - bool uniform = !nonUniformBlockSet.Contains(block); - bool newUniform = Analyse(Impl, block.Cmds, uniform); - if (uniform && !newUniform) { - changed = true; - nonUniformBlockSet.Add(block); - Block pred = blockGraph.Predecessors(block).Single(); - if (ctrlDep.ContainsKey(pred)) - nonUniformBlockSet.UnionWith(ctrlDep[pred]); - } - } - } while (changed); - } - else - { - Analyse(Impl, Impl.StructuredStmts, ControlFlowIsUniform); - } - } - - - private void Analyse(Implementation impl, StmtList stmtList, bool ControlFlowIsUniform) - { - ControlFlowIsUniform &= !hitNonuniformReturn; - foreach (BigBlock bb in stmtList.BigBlocks) - { - Analyse(impl, bb, ControlFlowIsUniform); - } - } - - private Implementation GetImplementation(string procedureName) - { - foreach (Declaration D in prog.TopLevelDeclarations) - { - if (D is Implementation && ((D as Implementation).Name == procedureName)) - { - return D as Implementation; - } - } - return null; - } - - private void Analyse(Implementation impl, BigBlock bb, bool ControlFlowIsUniform) - { - ControlFlowIsUniform &= !hitNonuniformReturn; - Analyse(impl, bb.simpleCmds, ControlFlowIsUniform); - - if (bb.ec is WhileCmd) - { - WhileCmd wc = bb.ec as WhileCmd; - loopStack.Add(wc); - Analyse(impl, wc.Body, ControlFlowIsUniform && IsUniform(impl.Name, wc.Guard) && - !nonUniformLoops[impl.Name].Contains(GetLoopId(wc))); - loopStack.RemoveAt(loopStack.Count - 1); - } - else if (bb.ec is IfCmd) - { - IfCmd ifCmd = bb.ec as IfCmd; - Analyse(impl, ifCmd.thn, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard)); - if (ifCmd.elseBlock != null) - { - Analyse(impl, ifCmd.elseBlock, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard)); - } - Debug.Assert(ifCmd.elseIf == null); - } - else if (bb.ec is BreakCmd) - { - if (!ControlFlowIsUniform && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[loopStack.Count - 1]))) - { - SetNonUniform(impl.Name, loopStack[loopStack.Count - 1]); - } - } - - if (bb.tc is ReturnCmd && !ControlFlowIsUniform) - { - hitNonuniformReturn = true; - if (loopStack.Count > 0 && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[0]))) - { - SetNonUniform(impl.Name, loopStack[0]); - loopsWithNonuniformReturn[impl.Name].Add(GetLoopId(loopStack[0])); - } - } - - - } - - private bool Analyse(Implementation impl, CmdSeq cmdSeq, bool ControlFlowIsUniform) - { - foreach (Cmd c in cmdSeq) - { - if (c is AssignCmd) - { - AssignCmd assignCmd = c as AssignCmd; - foreach (var a in assignCmd.Lhss.Zip(assignCmd.Rhss)) - { - - if (a.Item1 is SimpleAssignLhs) - { - SimpleAssignLhs lhs = a.Item1 as SimpleAssignLhs; - Expr rhs = a.Item2; - if (IsUniform(impl.Name, lhs.AssignedVariable.Name) && - (!ControlFlowIsUniform || !IsUniform(impl.Name, rhs))) - { - SetNonUniform(impl.Name, lhs.AssignedVariable.Name); - } - - } - } - } - else if (c is HavocCmd) - { - HavocCmd havocCmd = c as HavocCmd; - foreach(IdentifierExpr ie in havocCmd.Vars) - { - if(IsUniform(impl.Name, ie.Decl.Name)) { - SetNonUniform(impl.Name, ie.Decl.Name); - } - } - } - else if (c is CallCmd) - { - CallCmd callCmd = c as CallCmd; - Implementation CalleeImplementation = GetImplementation(callCmd.callee); - - if (CalleeImplementation != null) - { - - if (!ControlFlowIsUniform) - { - if (IsUniform(callCmd.callee)) - { - SetNonUniform(callCmd.callee); - } - } - for (int i = 0; i < CalleeImplementation.InParams.Length; i++) - { - if (IsUniform(callCmd.callee, CalleeImplementation.InParams[i].Name) - && !IsUniform(impl.Name, callCmd.Ins[i])) - { - SetNonUniform(callCmd.callee, CalleeImplementation.InParams[i].Name); - } - } - - for (int i = 0; i < CalleeImplementation.OutParams.Length; i++) - { - if (IsUniform(impl.Name, callCmd.Outs[i].Name) - && !IsUniform(callCmd.callee, CalleeImplementation.OutParams[i].Name)) - { - SetNonUniform(impl.Name, callCmd.Outs[i].Name); - } - } - - } - } - else if (c is AssumeCmd) - { - var ac = (AssumeCmd)c; - if (ControlFlowIsUniform && QKeyValue.FindBoolAttribute(ac.Attributes, "partition") && - !IsUniform(impl.Name, ac.Expr)) - { - ControlFlowIsUniform = false; - } - } - } - - return ControlFlowIsUniform; - } - - private int GetLoopId(WhileCmd wc) - { - AssertCmd inv = wc.Invariants[0] as AssertCmd; - Debug.Assert(inv.Attributes.Key.Contains("loophead_")); - return Convert.ToInt32(inv.Attributes.Key.Substring("loophead_".Length)); - } - - private void SetNonUniform(string procedureName) - { - uniformityInfo[procedureName] = new KeyValuePair> - (false, uniformityInfo[procedureName].Value); - RecordProcedureChanged(); - } - - private void SetNonUniform(string procedureName, WhileCmd wc) - { - nonUniformLoops[procedureName].Add(GetLoopId(wc)); - RecordProcedureChanged(); - } - - public bool IsUniform(string procedureName) - { - if (!uniformityInfo.ContainsKey(procedureName)) - { - return false; - } - return uniformityInfo[procedureName].Key; - } - - public bool IsUniform(string procedureName, Block b) - { - if (!nonUniformBlocks.ContainsKey(procedureName)) - { - return false; - } - return !nonUniformBlocks[procedureName].Contains(b); - } - - class UniformExpressionAnalysisVisitor : StandardVisitor { - - private bool isUniform = true; - private Dictionary uniformityInfo; - - public UniformExpressionAnalysisVisitor(Dictionary uniformityInfo) { - this.uniformityInfo = uniformityInfo; - } - - public override Variable VisitVariable(Variable v) { - if (!uniformityInfo.ContainsKey(v.Name)) { - isUniform = isUniform && (v is Constant); - } else if (!uniformityInfo[v.Name]) { - isUniform = false; - } - - return v; - } - - internal bool IsUniform() { - return isUniform; - } - } - - public bool IsUniform(string procedureName, Expr expr) - { - UniformExpressionAnalysisVisitor visitor = new UniformExpressionAnalysisVisitor(uniformityInfo[procedureName].Value); - visitor.VisitExpr(expr); - return visitor.IsUniform(); - } - - public bool IsUniform(string procedureName, string v) - { - if (!uniformityInfo.ContainsKey(procedureName)) - { - return false; - } - - if (!uniformityInfo[procedureName].Value.ContainsKey(v)) - { - return false; - } - return uniformityInfo[procedureName].Value[v]; - } - - private void SetUniform(string procedureName, string v) - { - uniformityInfo[procedureName].Value[v] = true; - RecordProcedureChanged(); - } - - private void RecordProcedureChanged() - { - ProcedureChanged = true; - } - - private void SetNonUniform(string procedureName, string v) - { - uniformityInfo[procedureName].Value[v] = false; - RecordProcedureChanged(); - } - - public void dump() - { - foreach (string p in uniformityInfo.Keys) - { - Console.WriteLine("Procedure " + p + ": " - + (uniformityInfo[p].Key ? "uniform" : "nonuniform")); - foreach (string v in uniformityInfo[p].Value.Keys) - { - Console.WriteLine(" " + v + ": " + - (uniformityInfo[p].Value[v] ? "uniform" : "nonuniform")); - } - Console.Write("Ins ["); - for (int i = 0; i < inParameters[p].Count; i++) - { - Console.Write((i == 0 ? "" : ", ") + inParameters[p][i]); - } - Console.WriteLine("]"); - Console.Write("Outs ["); - for (int i = 0; i < outParameters[p].Count; i++) - { - Console.Write((i == 0 ? "" : ", ") + outParameters[p][i]); - } - Console.WriteLine("]"); - Console.Write("Non-uniform loops:"); - foreach (int l in nonUniformLoops[p]) - { - Console.Write(" " + l); - } - Console.WriteLine(); - Console.Write("Non-uniform blocks:"); - foreach (Block b in nonUniformBlocks[p]) - { - Console.Write(" " + b.Label); - } - Console.WriteLine(); - } - } - - - public string GetInParameter(string procName, int i) - { - return inParameters[procName][i]; - } - - public string GetOutParameter(string procName, int i) - { - return outParameters[procName][i]; - } - - - public bool knowsOf(string p) - { - return uniformityInfo.ContainsKey(p); - } - - public void AddNonUniform(string proc, string v) - { - if (uniformityInfo.ContainsKey(proc)) - { - Debug.Assert(!uniformityInfo[proc].Value.ContainsKey(v)); - uniformityInfo[proc].Value[v] = false; - } - } - - public void AddNonUniform(string proc, Block b) { - if (nonUniformBlocks.ContainsKey(proc)) { - Debug.Assert(!nonUniformBlocks[proc].Contains(b)); - nonUniformBlocks[proc].Add(b); - } - } - - public bool IsUniform(string proc, WhileCmd wc) - { - if (unstructured) - return false; - - return !nonUniformLoops[proc].Contains(GetLoopId(wc)); - } - - public bool HasNonuniformReturn(string proc, WhileCmd whileCmd) - { - return loopsWithNonuniformReturn[proc].Contains(GetLoopId(whileCmd)); - } - } - -} diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs index 6efae58c..b13b7e35 100644 --- a/Source/VCGeneration/VC.cs +++ b/Source/VCGeneration/VC.cs @@ -11,7 +11,7 @@ using System.Linq; using System.Threading; using System.IO; using Microsoft.Boogie; -using Graphing; +using Microsoft.Boogie.GraphUtil; using System.Diagnostics.Contracts; using Microsoft.Basetypes; using Microsoft.Boogie.VCExprAST; @@ -2058,12 +2058,6 @@ namespace VC { } #endregion - if (CommandLineOptions.Clo.DoPredication && CommandLineOptions.Clo.StratifiedInlining == 0) { - DesugarCalls(impl); - BlockPredicator.Predicate(program, impl); - impl.ComputePredecessorsForBlocks(); - } - if (CommandLineOptions.Clo.LiveVariableAnalysis > 0) { Microsoft.Boogie.LiveVariableAnalysis.ComputeLiveVariables(impl); } @@ -3038,36 +3032,6 @@ namespace VC { } } - /// - /// Simplifies the CFG of the given implementation impl by merging each - /// basic block with a single predecessor into that predecessor if the - /// predecessor has a single successor. If a uniformity analyser is - /// being used then block will only be merged if they are both uniform - /// or both non-uniform - /// - public static void MergeBlocksIntoPredecessors(Program prog, Implementation impl, UniformityAnalyser uni) { - var blockGraph = prog.ProcessLoops(impl); - var predMap = new Dictionary(); - foreach (var block in blockGraph.Nodes) { - try { - var pred = blockGraph.Predecessors(block).Single(); - if (blockGraph.Successors(pred).Single() == block && - (uni == null || - (uni.IsUniform(impl.Name, pred) && uni.IsUniform(impl.Name, block)) || - (!uni.IsUniform(impl.Name, pred) && !uni.IsUniform(impl.Name, block)))) { - Block predMapping; - while (predMap.TryGetValue(pred, out predMapping)) - pred = predMapping; - pred.Cmds.AddRange(block.Cmds); - pred.TransferCmd = block.TransferCmd; - impl.Blocks.Remove(block); - predMap[block] = pred; - } - // If Single throws an exception above (i.e. not exactly one pred/succ), skip this block. - } catch (InvalidOperationException) {} - } - } - static void DumpMap(Hashtable /*Variable->Expr*/ map) { Contract.Requires(map != null); foreach (DictionaryEntry de in map) { diff --git a/Source/VCGeneration/VCDoomed.cs b/Source/VCGeneration/VCDoomed.cs deleted file mode 100644 index 962f9f26..00000000 --- a/Source/VCGeneration/VCDoomed.cs +++ /dev/null @@ -1,827 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (C) Microsoft Corporation. All Rights Reserved. -// -//----------------------------------------------------------------------------- -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.IO; -using Microsoft.Boogie; -using Graphing; -using System.Diagnostics.Contracts; -using Microsoft.Basetypes; -using Microsoft.Boogie.VCExprAST; - -namespace VC { - public partial class DCGen : ConditionGeneration { - private bool _print_time = CommandLineOptions.Clo.DoomStrategy!=-1; - #region Attributes - static private Dictionary/*!*/ m_BlockReachabilityMap; - Dictionary/*!*/ m_copiedBlocks = new Dictionary(); - const string reachvarsuffix = "__ivebeenthere"; - List/*!*/ m_doomedCmds = new List(); - [ContractInvariantMethod] - void ObjectInvariant() { - - } - - #endregion - - - /// - /// Constructor. Initializes the theorem prover. - /// - public DCGen(Program program, string/*?*/ logFilePath, bool appendLogFile) - : base(program) { - Contract.Requires(program != null); - - this.appendLogFile = appendLogFile; - this.logFilePath = logFilePath; - m_BlockReachabilityMap = new Dictionary(); - } - - /// - /// Debug method that prints a dot file of the - /// current set of blocks in impl to filename. - /// - private void Impl2Dot(Implementation impl, string filename) { - Contract.Requires(impl != null); - Contract.Requires(filename != null); - List nodes = new List(); - List edges = new List(); - - string nodestyle = "[shape=box];"; - - foreach (Block b in impl.Blocks) { - Contract.Assert(b != null); - nodes.Add(string.Format("\"{0}\" {1}", b.Label, nodestyle)); - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc != null) - { - Contract.Assert(gc.labelTargets != null); - foreach (Block b_ in gc.labelTargets) - { - Contract.Assert(b_ != null); - edges.Add(String.Format("\"{0}\" -> \"{1}\";", b.Label, b_.Label)); - } - } - - //foreach (Block b_ in b.Predecessors) - //{ - // edges.Add(String.Format("\"{0}\" -> \"{1}\";", b.Label, b_.Label)); - //} - } - - using (StreamWriter sw = new StreamWriter(filename)) { - sw.WriteLine(String.Format("digraph {0} {{", impl.Name)); - // foreach (string! s in nodes) { - // sw.WriteLine(s); - // } - foreach (string s in edges) { - Contract.Assert(s != null); - sw.WriteLine(s); - } - sw.WriteLine("}}"); - sw.Close(); - } - } - private const string _copyPrefix = "CPY__"; - - private List m_UncheckableBlocks = null; - - /// - /// MSchaef: - /// - remove loops and add reach variables - /// - make it a passive program - /// - compute the wlp for each block - /// - check if |= (reach=false) => wlp.S.false holds for each reach - /// - /// - public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) { - Contract.EnsuresOnThrow(true); - - Console.WriteLine(); - Console.WriteLine("Checking function {0}", impl.Name); - callback.OnProgress("doomdetector", 0, 0, 0); - - bool restartTP = CommandLineOptions.Clo.DoomRestartTP ; - - //Impl2Dot(impl, String.Format("c:/dot/{0}_orig.dot", impl.Name)); - - Transform4DoomedCheck(impl); - - //Impl2Dot(impl, String.Format("c:/dot/{0}_fin.dot", impl.Name)); - - Checker checker = FindCheckerFor(impl, 1000); - Contract.Assert(checker != null); - int assertionCount; - DoomCheck dc = new DoomCheck(impl, this.exitBlock, checker, m_UncheckableBlocks, out assertionCount); - CumulativeAssertionCount += assertionCount; - - //EmitImpl(impl, false); - - int _totalchecks = 0; - - ProverInterface.Outcome outcome; - dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); - - System.TimeSpan ts = new TimeSpan(); - - if (_print_time) Console.WriteLine("Total number of blocks {0}", impl.Blocks.Count); - - List lb; - List lv = new List(); - - while (dc.GetNextBlock(out lb)) - { - Contract.Assert(lb != null); - outcome = ProverInterface.Outcome.Undetermined; - - Variable v = null; - lv.Clear(); - - foreach (Block b_ in lb) - { - if (!m_BlockReachabilityMap.TryGetValue(b_, out v)) - { - // This should cause an error - continue; - } - //Console.Write("{0}, ",b_.Label); - lv.Add(v); - } - //Console.WriteLine(); - Dictionary finalreachvars = m_GetPostconditionVariables(impl.Blocks,lb); - if (lv.Count < 1) - { - - continue; - } - - Contract.Assert(lv != null); - _totalchecks++; - - - if (!dc.CheckLabel(lv,finalreachvars, out outcome)) { - return Outcome.Inconclusive; - } - ts += dc.DEBUG_ProverTime.Elapsed; - - if (restartTP) - { - checker.Close(); - checker = FindCheckerFor(impl, 1000); - dc.RespawnChecker(impl, checker); - dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); - } - - } - checker.Close(); - - if (_print_time) - { - Console.WriteLine("Number of Checkes / #Blocks: {0} of {1}", _totalchecks, impl.Blocks.Count); - dc.__DEBUG_PrintStatistics(); - Console.WriteLine("Total time for this method: {0}", ts.ToString()); - } - #region Try to produce a counter example (brute force) - if (dc.DoomedSequences.Count > 0) { - int counter = 0; - List _all = new List(); - foreach (List lb_ in dc.DoomedSequences) - { - foreach (Block b_ in lb_) - { - if (!_all.Contains(b_) && !m_UncheckableBlocks.Contains(b_)) - { - _all.Add(b_); counter++; - if (!_print_time) Console.WriteLine(b_.Label); - } - } - } - if (_all.Count > 0) - { - Console.WriteLine("#Dead Blocks found: {0}: ", counter); - return Outcome.Errors; - } - } - #endregion - - - return Outcome.Correct; - } - - private Dictionary m_GetPostconditionVariables(List allblock, List passBlock) - { - Dictionary r = new Dictionary(); - foreach (Block b in allblock) - { - Variable v; - if (m_BlockReachabilityMap.TryGetValue(b, out v)) - { - if (passBlock.Contains(b)) r[m_LastReachVarIncarnation[v]] = 1; - } - else - { - Console.WriteLine("there is no reachability variable for {0}", b.Label); - } - } - return r; - } - -#if false - #region Error message construction - private void SearchCounterexample(Implementation impl, DoomErrorHandler errh, VerifierCallback callback) { - Contract.Requires(impl != null); - Contract.Requires(errh != null); - Contract.Requires(callback != null); - Contract.Requires(errh.m_Reachvar != null); - //if (errh.m_Reachvar==null) { - // Contract.Assert(false);throw new cce.UnreachableException(); - //} - m_doomedCmds.Clear(); - - Dictionary cmdbackup = new Dictionary(); - - BruteForceCESearch(errh.m_Reachvar, impl, callback, cmdbackup, 0, impl.Blocks.Count / 2 - 1); - BruteForceCESearch(errh.m_Reachvar, impl, callback, cmdbackup, impl.Blocks.Count / 2, impl.Blocks.Count - 1); - - List causals = CollectCausalStatements(impl.Blocks[0]); - foreach (Cmd c in causals) { - Contract.Assert(c != null); - GenerateErrorMessage(c, causals); - } - - #region Undo all modifications - foreach (KeyValuePair kvp in cmdbackup) { - Contract.Assert(kvp.Key != null); - Contract.Assert(kvp.Value != null); - kvp.Key.Cmds = kvp.Value; - } - #endregion - } - - #region Causal Statement Tree - - private void GenerateErrorMessage(Cmd causalStatement, List causals) { - Contract.Requires(causalStatement != null); - Contract.Requires(cce.NonNullElements(causals)); - AssumeCmd uc = causalStatement as AssumeCmd; - AssertCmd ac = causalStatement as AssertCmd; - ConsoleColor col = Console.ForegroundColor; - - // Trivial case. Must be either assume or assert false - if (m_doomedCmds.Count == 1) { - Console.WriteLine("Found a trivial error:"); - if (uc != null) { - Console.Write("Trivial false assumption: "); - Console.Write("({0};{1}):", uc.tok.line, uc.tok.col); - } - if (ac != null) { - Console.Write("Trivial false assertion: "); - Console.Write("({0};{1}):", ac.tok.line, ac.tok.col); - } - causalStatement.Emit(new TokenTextWriter("", Console.Out, false), 0); - } else { - // Safety error - if (ac != null) { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Safety error:"); - Console.ForegroundColor = col; - Console.Write("This assertion is violated: "); - Console.Write("({0};{1}):", ac.tok.line, ac.tok.col); - ac.Emit(new TokenTextWriter("", Console.Out, false), 0); - } - if (uc != null) { - bool containsAssert = false; - foreach (Cmd c in m_doomedCmds) { - Contract.Assert(c != null); - if (causals.Contains(c)) { - continue; - } - AssertCmd asrt = c as AssertCmd; - if (asrt != null) { - containsAssert = true; - break; - } - } - // Plausibility error - if (containsAssert) { - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine("Plausibility error:"); - Console.ForegroundColor = col; - Console.Write("There is no legal exeuction passing: "); - Console.Write("({0};{1})", uc.tok.line, uc.tok.col); - uc.Emit(new TokenTextWriter("", Console.Out, false), 0); - } else { // Reachability error - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine("Reachability error:"); - Console.ForegroundColor = col; - Console.Write("No execution can reach: "); - Console.Write("({0};{1})", uc.tok.line, uc.tok.col); - uc.Emit(new TokenTextWriter("", Console.Out, false), 0); - } - - } - - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine("...on any execution passing through:"); - foreach (Cmd c in m_doomedCmds) { - Contract.Assert(c != null); - if (causals.Contains(c)) { - continue; - } - Console.ForegroundColor = col; - Console.Write("In ({0};{1}): ", c.tok.line, c.tok.col); - Console.ForegroundColor = ConsoleColor.DarkYellow; - c.Emit(new TokenTextWriter("", Console.Out, false), 0); - } - Console.ForegroundColor = col; - Console.WriteLine("--"); - - } - } - - private List CollectCausalStatements(Block b) { - Contract.Requires(b != null); - Contract.Ensures(cce.NonNullElements(Contract.Result>())); - - Cmd lastCausal = null; - foreach (Cmd c in b.Cmds) { - Contract.Assert(c != null); - AssertCmd ac = c as AssertCmd; - AssumeCmd uc = c as AssumeCmd; - if (ac != null && !ContainsReachVariable(ac)) { - if (ac.Expr != Expr.True) { - lastCausal = c; - } - } else if (uc != null && !ContainsReachVariable(uc)) { - lastCausal = c; - } - } - - List causals = new List(); - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc != null && gc.labelTargets != null) { - List tmp; - //bool allcausal = true; - foreach (Block b_ in gc.labelTargets) { - Contract.Assert(b_ != null); - tmp = CollectCausalStatements(b_); - - foreach (Cmd cau in tmp) { - if (!causals.Contains(cau)) - causals.Add(cau); - } - } - //if (allcausal) - if (causals.Count > 0) - return causals; - } - if (lastCausal != null) - causals.Add(lastCausal); - return causals; - } - - #endregion - - bool BruteForceCESearch(Variable reachvar, Implementation impl, VerifierCallback callback, - Dictionary cmdbackup, int startidx, int endidx) { - Contract.Requires(reachvar != null); - Contract.Requires(impl != null); - Contract.Requires(callback != null); - Contract.Requires(cce.NonNullElements(cmdbackup)); - #region Modify implementation - for (int i = startidx; i <= endidx; i++) { - if (_copiedBlock.Contains(impl.Blocks[i])) - continue; - CmdSeq cs = new CmdSeq(); - cmdbackup.Add(impl.Blocks[i], impl.Blocks[i].Cmds); - foreach (Cmd c in impl.Blocks[i].Cmds) { - Contract.Assert(c != null); - if (ContainsReachVariable(c)) { - cs.Add(c); - continue; - } - AssertCmd ac = c as AssertCmd; - AssumeCmd uc = c as AssumeCmd; - if (ac != null) { - cs.Add(new AssertCmd(ac.tok, Expr.True)); - } else if (uc != null) { - cs.Add(new AssertCmd(uc.tok, Expr.True)); - } else { - cs.Add(c); - } - } - impl.Blocks[i].Cmds = cs; - } - #endregion - - ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined; - if (!ReCheckImpl(reachvar, impl, callback, out outcome)) { - UndoBlockModifications(impl, cmdbackup, startidx, endidx); - return false; - } - if (outcome == ProverInterface.Outcome.Valid) { - return true; - } else if (outcome == ProverInterface.Outcome.Invalid) { - UndoBlockModifications(impl, cmdbackup, startidx, endidx); - int mid = startidx + (endidx - startidx) / 2; - if (startidx >= endidx) { - // Now we found an interesting Block and we have to - // search for the interesting statements. - int cmdcount = impl.Blocks[endidx].Cmds.Length; - BruteForceCmd(impl.Blocks[endidx], 0, cmdcount / 2 - 1, reachvar, impl, callback); - BruteForceCmd(impl.Blocks[endidx], cmdcount / 2, cmdcount - 1, reachvar, impl, callback); - return true; - } else { - BruteForceCESearch(reachvar, impl, callback, cmdbackup, startidx, mid); - BruteForceCESearch(reachvar, impl, callback, cmdbackup, mid + 1, endidx); - return true; - } - } else { - UndoBlockModifications(impl, cmdbackup, startidx, endidx); - return false; - } - } - - bool BruteForceCmd(Block b, int startidx, int endidx, Variable reachvar, - Implementation impl, VerifierCallback callback) { - Contract.Requires(b != null); - Contract.Requires(reachvar != null); - Contract.Requires(impl != null); - Contract.Requires(callback != null); - #region Modify Cmds - CmdSeq backup = b.Cmds; - Contract.Assert(backup != null); - CmdSeq cs = new CmdSeq(); - for (int i = 0; i < startidx; i++) { - cs.Add(b.Cmds[i]); - } - for (int i = startidx; i <= endidx; i++) { - Cmd c = b.Cmds[i]; - if (ContainsReachVariable(c)) { - cs.Add(c); - continue; - } - cs.Add(new AssertCmd(c.tok, Expr.True)); - } - for (int i = endidx + 1; i < b.Cmds.Length; i++) { - cs.Add(b.Cmds[i]); - } - - b.Cmds = cs; - #endregion - - #region Recheck - ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined; - if (!ReCheckImpl(reachvar, impl, callback, out outcome)) { - b.Cmds = backup; - return false; - } - #endregion - - if (outcome == ProverInterface.Outcome.Valid) { - return true; - } else if (outcome == ProverInterface.Outcome.Invalid) { - b.Cmds = backup; - if (startidx >= endidx) { - if (!ContainsReachVariable(b.Cmds[endidx])) { - // Console.Write(" Witness ("); - // - // ConsoleColor col = Console.ForegroundColor; - // Console.ForegroundColor = ConsoleColor.White; - // Console.Write("{0};{1}", b.Cmds[endidx].tok.line, b.Cmds[endidx].tok.col ); - // Console.ForegroundColor = col; - // Console.Write("): "); - // Console.ForegroundColor = ConsoleColor.Yellow; - // b.Cmds[endidx].Emit(new TokenTextWriter("", Console.Out, false), 0); - // Console.ForegroundColor = col; - - m_doomedCmds.Add(b.Cmds[endidx]); - return true; - } else { - return false; - } - } else { - int mid = startidx + (endidx - startidx) / 2; - BruteForceCmd(b, startidx, mid, reachvar, impl, callback); - BruteForceCmd(b, mid + 1, endidx, reachvar, impl, callback); - return false; // This is pure random - } - } else { - b.Cmds = backup; - return false; - } - } - - void UndoBlockModifications(Implementation impl, Dictionary/*!*/ cmdbackup, - int startidx, int endidx) { - Contract.Requires(cce.NonNullElements(cmdbackup)); - Contract.Requires(impl != null); - for (int i = startidx; i <= endidx; i++) { - CmdSeq cs = null; - if (cmdbackup.TryGetValue(impl.Blocks[i], out cs)) { - Contract.Assert(cs != null); - impl.Blocks[i].Cmds = cs; - cmdbackup.Remove(impl.Blocks[i]); - } - } - } - - bool ReCheckImpl(Variable reachvar, Implementation impl, VerifierCallback callback, - out ProverInterface.Outcome outcome) { - Contract.Requires(reachvar != null); - Contract.Requires(impl != null); - Contract.Requires(callback != null); - Checker checker = FindCheckerFor(impl, 1000); - Contract.Assert(checker != null); - DoomCheck dc = new DoomCheck(impl, this.exitBlock, checker, m_UncheckableBlocks); - dc.ErrorHandler = new DoomErrorHandler(dc.Label2Absy, callback); - outcome = ProverInterface.Outcome.Undetermined; - List rv = new List(); - rv.Add(reachvar); - if (!dc.CheckLabel(rv,null, out outcome)) { - checker.Close(); - return false; - } - checker.Close(); - return true; - } - - - - bool ContainsReachVariable(Cmd c) { - Contract.Requires(c != null); - AssertCmd artc = c as AssertCmd; - AssumeCmd amec = c as AssumeCmd; - Expr e; - if (artc != null) { - e = artc.Expr; - } else if (amec != null) { - e = amec.Expr; - } else { - return false; - } - Set freevars = new Set(); - e.ComputeFreeVariables(freevars); - foreach (Variable v in freevars) { - Contract.Assert(v != null); - if (v.Name.Contains(reachvarsuffix)) - return true; - } - return false; - } -#endregion -#endif - - - Block exitBlock; - - #region Program Passification - private void GenerateHelperBlocks(Implementation impl) { - Contract.Requires(impl != null); - Hashtable gotoCmdOrigins = new Hashtable(); - exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins); - Contract.Assert(exitBlock != null); - - AddBlocksBetween(impl.Blocks); - - #region Insert pre- and post-conditions and where clauses as assume and assert statements - { - CmdSeq cc = new CmdSeq(); - // where clauses of global variables - foreach (Declaration d in program.TopLevelDeclarations) { - GlobalVariable gvar = d as GlobalVariable; - if (gvar != null && gvar.TypedIdent.WhereExpr != null) { - Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr); - cc.Add(c); - } - } - // where clauses of in- and out-parameters - cc.AddRange(GetParamWhereClauses(impl)); - // where clauses of local variables - foreach (Variable lvar in impl.LocVars) { - Contract.Assert(lvar != null); - if (lvar.TypedIdent.WhereExpr != null) { - Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr); - cc.Add(c); - } - } - - // add cc and the preconditions to new blocks preceding impl.Blocks[0] - InjectPreconditions(impl, cc); - - // append postconditions, starting in exitBlock and continuing into other blocks, if needed - exitBlock = InjectPostConditions(impl, exitBlock, gotoCmdOrigins); - } - #endregion - } - - - private Hashtable/*TransferCmd->ReturnCmd*/ PassifyProgram(Implementation impl, ModelViewInfo mvInfo) { - Contract.Requires(impl != null); - Contract.Requires(mvInfo != null); - Contract.Requires(this.exitBlock != null); - Contract.Ensures(Contract.Result() != null); - - CurrentLocalVariables = impl.LocVars; - return Convert2PassiveCmd(impl, mvInfo); - //return new Hashtable(); - } - - /// - /// Add additional variable to allow checking as described in the paper - /// "It's doomed; we can prove it" - /// - private CmdSeq GenerateReachabilityPredicates(Implementation impl) - { - Contract.Requires(impl != null); - - foreach (Block b in impl.Blocks) - { - Contract.Assert(b != null); - //if (b.Predecessors.Length==0) continue; - //if (b.Cmds.Length == 0 ) continue; - - Variable v_ = new LocalVariable(Token.NoToken, - new TypedIdent(b.tok, b.Label + reachvarsuffix, new BasicType(SimpleType.Int ))); - - impl.LocVars.Add(v_); - - m_BlockReachabilityMap[b] = v_; - - IdentifierExpr lhs = new IdentifierExpr(b.tok, v_); - Contract.Assert(lhs != null); - - impl.Proc.Modifies.Add(lhs); - - List lhsl = new List(); - lhsl.Add(new SimpleAssignLhs(Token.NoToken, lhs)); - List rhsl = new List(); - rhsl.Add(Expr.Literal(1) ); - - - CmdSeq cs = new CmdSeq(new AssignCmd(Token.NoToken, lhsl, rhsl)); - cs.AddRange(b.Cmds); - b.Cmds = cs; - - //checkBlocks.Add(new CheckableBlock(v_,b)); - } - - CmdSeq incReachVars = new CmdSeq(); - foreach (KeyValuePair kvp in m_BlockReachabilityMap) - { - IdentifierExpr lhs = new IdentifierExpr(Token.NoToken, kvp.Value); - impl.Proc.Modifies.Add(lhs); - incReachVars.Add(new AssumeCmd(Token.NoToken, Expr.Le(lhs, Expr.Literal(1)))); - } - - return incReachVars; - } - - #endregion - - #region Compute loop-free approximation - - // this might be redundant, but I didn't find a better place to get this information. - private Dictionary m_LastReachVarIncarnation = new Dictionary(); - - private void Transform4DoomedCheck(Implementation impl) - { - variable2SequenceNumber = new Hashtable/*Variable -> int*/(); - incarnationOriginMap = new Dictionary(); - if (impl.Blocks.Count < 1) return; - - impl.PruneUnreachableBlocks(); - AddBlocksBetween(impl.Blocks); - ResetPredecessors(impl.Blocks); - - GraphAnalyzer ga = new GraphAnalyzer(impl.Blocks); - LoopRemover lr = new LoopRemover(ga); - lr.AbstractLoopUnrolling(); - - impl.Blocks = ga.ToImplementation(out m_UncheckableBlocks); - ResetPredecessors(impl.Blocks); - - // Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks - List oldblocks = new List(); - oldblocks.AddRange(impl.Blocks); - GenerateHelperBlocks(impl); - #region Check for the "BlocksBetween" if all their successors are in m_UncheckableBlocks - foreach (Block b in impl.Blocks) - { - if (oldblocks.Contains(b)) continue; - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc != null) - { - bool allsuccUncheckable = true; - foreach (Block _b in gc.labelTargets) - { - if (!m_UncheckableBlocks.Contains(_b)) - { - allsuccUncheckable = false; break; - } - } - if (allsuccUncheckable && !m_UncheckableBlocks.Contains(b)) m_UncheckableBlocks.Add(b); - } - } - #endregion - - impl.Blocks = DeepCopyBlocks(impl.Blocks, m_UncheckableBlocks); - - m_BlockReachabilityMap = new Dictionary(); - CmdSeq cs = GenerateReachabilityPredicates(impl); - - //foreach (Block test in getTheFFinalBlock(impl.Blocks[0])) - //{ - // test.Cmds.AddRange(cs); - //} - - ResetPredecessors(impl.Blocks); - //EmitImpl(impl,false); - - Hashtable/*Variable->Expr*/ htbl = PassifyProgram(impl, new ModelViewInfo(program, impl)); - - // Collect the last incarnation of each reachability variable in the passive program - foreach (KeyValuePair kvp in m_BlockReachabilityMap) - { - if (htbl.ContainsKey(kvp.Value)) - { - m_LastReachVarIncarnation[kvp.Value] = (Expr)htbl[kvp.Value]; - } - } - } - - - List getTheFFinalBlock(Block b) - { - List lb = new List(); - GotoCmd gc = b.TransferCmd as GotoCmd; - if (gc == null) lb.Add(b); - else - { - foreach (Block s in gc.labelTargets) - { - foreach (Block r in getTheFFinalBlock(s)) if (!lb.Contains(r)) lb.Add(r); - } - } - return lb; - } - - - private List DeepCopyBlocks(List lb, List uncheckables) - { - List clones = new List(); - List uncheck_ = new List(); - Dictionary clonemap = new Dictionary(); - - foreach (Block b in lb) - { - Block clone = CloneBlock(b); - clones.Add(clone); - clonemap[b] = clone; - if (uncheckables.Contains(b)) uncheck_.Add(clone); - } - uncheckables.Clear(); - uncheckables.AddRange(uncheck_); - // update the successors and predecessors - foreach (Block b in lb) - { - BlockSeq newpreds = new BlockSeq(); - foreach (Block b_ in b.Predecessors) - { - newpreds.Add(clonemap[b_]); - } - clonemap[b].Predecessors = newpreds; - GotoCmd gc = b.TransferCmd as GotoCmd; - ReturnCmd rc = b.TransferCmd as ReturnCmd; - if (gc != null) - { - StringSeq lseq = new StringSeq(); - BlockSeq bseq = new BlockSeq(); - foreach (string s in gc.labelNames) lseq.Add(s); - foreach (Block b_ in gc.labelTargets) bseq.Add(clonemap[b_]); - GotoCmd tcmd = new GotoCmd(gc.tok, lseq, bseq); - clonemap[b].TransferCmd = tcmd; - } - else if (rc != null) - { - clonemap[b].TransferCmd = new ReturnCmd(rc.tok); - } - } - return clones; - } - - private Block CloneBlock(Block b) - { - Block clone = new Block(b.tok, b.Label, b.Cmds, b.TransferCmd); - if (this.exitBlock == b) this.exitBlock = clone; - return clone; - } - #endregion - } -} diff --git a/Source/VCGeneration/VCGeneration.csproj b/Source/VCGeneration/VCGeneration.csproj index 98958c66..0c98a891 100644 --- a/Source/VCGeneration/VCGeneration.csproj +++ b/Source/VCGeneration/VCGeneration.csproj @@ -144,22 +144,12 @@ - - - - - - - - - - diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs index c691d9da..39829bb0 100644 --- a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs +++ b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs @@ -255,11 +255,7 @@ namespace DafnyLanguage ConditionGeneration vcgen = null; try { - if (Bpl.CommandLineOptions.Clo.vcVariety == Bpl.CommandLineOptions.VCVariety.Doomed) { - vcgen = new DCGen(program, Bpl.CommandLineOptions.Clo.SimplifyLogFilePath, Bpl.CommandLineOptions.Clo.SimplifyLogFileAppend); - } else { - vcgen = new VCGen(program, Bpl.CommandLineOptions.Clo.SimplifyLogFilePath, Bpl.CommandLineOptions.Clo.SimplifyLogFileAppend); - } + vcgen = new VCGen(program, Bpl.CommandLineOptions.Clo.SimplifyLogFilePath, Bpl.CommandLineOptions.Clo.SimplifyLogFileAppend); } catch (Bpl.ProverException) { return PipelineOutcome.FatalError; } -- cgit v1.2.3