Exemple #1
0
    public RtlExp GhostIfThenElse(RtlExp eTest, Func <RtlExp> feThen, Func <RtlExp> feElse)
    {
        if (stmtExprEnabled && ignoreStmtExpr == 0)
        {
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + eTest + ") {", new RtlExp[0]));
            Indent();
        }
        var eThen = feThen();

        if (stmtExprEnabled && ignoreStmtExpr == 0)
        {
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            stmts.Add(new RtlGhostStmtComputed(s => "if (!(" + eTest + ")) {", new RtlExp[0]));
            Indent();
        }
        var eElse = feElse();

        if (stmtExprEnabled && ignoreStmtExpr == 0)
        {
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
        }
        return(new RtlLiteral("(if (" + eTest + ") then ("
                              + eThen + ") else (" + eElse + "))"));
    }
Exemple #2
0
    public void AddTypeWellFormed(List <RtlExp> specs, RtlExp exp, bool isGhost, Type t, List <UserDefinedType> recs)
    {
        UserDefinedType ut = t as UserDefinedType;

        if (minVerify && !isGhost && t is IntType)
        {
            specs.Add(new RtlApply("word", new RtlExp[] { exp }));
            return;
        }
        if (t is NatType)
        {
            specs.Add(new RtlBinary(">=", exp, new RtlInt(0)));
        }
        if (ut != null && ut.AsDatatype != null &&
            recs.TrueForAll(r => ut.Name != r.Name)
            )
        {
            recs.Add(ut);
            foreach (var ctor in ut.AsDatatype.Ctors)
            {
                List <RtlExp> cspecs = new List <RtlExp>();
                foreach (var f in ctor.Formals)
                {
                    AddTypeWellFormed(cspecs, new RtlLiteral(f.Name + "#" + ctor.Name + "(" + exp + ")"),
                                      isGhost, f.Type, recs);
                }
                foreach (var spec in cspecs)
                {
                    specs.Add(new RtlLiteral("((" + exp + ") is " + ctor.Name + " ==> (" + spec + "))"));
                }
            }
            recs.RemoveAt(recs.Count - 1);
        }
    }
Exemple #3
0
 public RtlArg(bool isIn, bool isOut, RtlExp e, string pinReg = null)
 {
     this.isIn   = isIn;
     this.isOut  = isOut;
     this.e      = e;
     this.pinReg = pinReg;
 }
Exemple #4
0
 //- Assert that et is a well-formed value of type t, represented by integer ei
 public static RtlExp IntEqTyped(Type t, RtlExp et, RtlExp ei)
 {
     return
         ((t is BoolType) ?
          new RtlBinary("||",
                        new RtlBinary("&&", et, new RtlBinary("==", ei, new RtlInt(1))),
                        new RtlBinary("&&", new RtlApply("!", new RtlExp[] { et }), new RtlBinary("==", ei, new RtlInt(0)))) :
          (t is RealType) ? new RtlBinary("==", et, new RtlApply("real", new RtlExp[] { ei })) :
          new RtlBinary("==", et, ei));
 }
Exemple #5
0
 public RtlMem(RtlExp ptr, RtlExp scale, RtlExp index, RtlExp offset)
 {
     if (index is RtlInt)
     {
         Util.Assert(scale is RtlInt && offset is RtlInt);
         offset = new RtlInt(((RtlInt)offset).i + ((RtlInt)scale).i * ((RtlInt)index).i);
         scale = null;
         index = null;
     }
     this.ptr = ptr;
     this.scale = scale;
     this.index = index;
     this.offset = offset;
 }
Exemple #6
0
 public RtlMem(RtlExp ptr, RtlExp scale, RtlExp index, RtlExp offset)
 {
     if (index is RtlInt)
     {
         Util.Assert(scale is RtlInt && offset is RtlInt);
         offset = new RtlInt(((RtlInt)offset).i + ((RtlInt)scale).i * ((RtlInt)index).i);
         scale  = null;
         index  = null;
     }
     this.ptr    = ptr;
     this.scale  = scale;
     this.index  = index;
     this.offset = offset;
 }
Exemple #7
0
 public readonly RtlExp e; //- ghost expression, does not count as a use
 public RtlAssert(RtlExp e, bool isLoop = false) { this.e = e; this.isLoop = isLoop; }
Exemple #8
0
 public readonly RtlExp e; //- ghost expression, does not count as a use
 public RtlAssert(RtlExp e, bool isLoop = false)
 {
     this.e = e; this.isLoop = isLoop;
 }
Exemple #9
0
 public RtlBinary(string op, RtlExp e0, RtlExp e1)
 {
     this.op = op;
     this.e0 = e0;
     this.e1 = e1;
 }
Exemple #10
0
 public RtlCallInOut(int index, bool isRet, RtlExp e):
     base(null, new RtlArg[] { new RtlArg(!isRet, isRet, e) }, false)
 {
     this.index = index;
     this.isRet = isRet;
 }
Exemple #11
0
 public RtlMem(RtlExp ptr, string offset) : this(ptr, new RtlLiteral(offset))
 {
 }
Exemple #12
0
 //- Assert that et is a well-formed value of type t, represented by integer ei
 public static RtlExp IntEqTyped(Type t, RtlExp et, RtlExp ei)
 {
     return
         (t is BoolType) ?
             new RtlBinary("||",
                 new RtlBinary("&&", et, new RtlBinary("==", ei, new RtlInt(1))),
                 new RtlBinary("&&", new RtlApply("!", new RtlExp[] { et }), new RtlBinary("==", ei, new RtlInt(0)))) :
         (t is RealType) ? new RtlBinary("==", et, new RtlApply("real", new RtlExp[] { ei })) :
         new RtlBinary("==", et, ei);
 }
Exemple #13
0
 public RtlMem(RtlExp ptr, RtlExp offset) : this(ptr, null, null, offset)
 {
 }
Exemple #14
0
 public RtlCallInOut(int index, bool isRet, RtlExp e) :
     base(null, new RtlArg[] { new RtlArg(!isRet, isRet, e) }, false)
 {
     this.index = index;
     this.isRet = isRet;
 }
    public void Compile()
    {
        Util.Assert(!isPrinting);
        string        name       = FunName(DafnySpec.SimpleName(typeApply.AppName()));
        string        fullName   = FunName(DafnySpec.SimpleName(typeApply.AppFullName()));
        bool          isAxiom    = Attributes.Contains(function.Attributes, "axiom");
        bool          isPrivate  = Attributes.Contains(function.Attributes, "private");
        bool          hidden     = Attributes.Contains(function.Attributes, "opaque");
        bool          isHeap     = DafnySpec.IsHeapFunction(function);
        List <string> heapParams = isHeap ? new List <string> {
            "$absMem:[int][int]int"
        } : new List <string>();
        List <string> heapArgs = isHeap ? new List <string> {
            "$absMem"
        } : new List <string>();
        var formals = function.Formals;
        var reads   = function.Reads.Where(e => e.Field != null).ToList().ConvertAll(e =>
                                                                                     new Formal(e.tok, e.FieldName, e.Field.Type, true, e.Field.IsGhost));

        formals = reads.Concat(formals).ToList();
        if (hidden && formals.Count == 0)
        {
            formals = new List <Formal> {
                new Formal(function.tok, "___dummy", Type.Bool, true, true)
            };
        }
        if (hidden && !function.Name.EndsWith("_FULL"))
        {
            ClassDecl cls  = (ClassDecl)function.EnclosingClass;
            Function  full = (Function)cls.Members.Find(m => m.Name == "#" + function.Name + "_FULL");
            dafnySpec.Compile_Function(full, typeApply.typeArgs);
        }
        bool   isFull     = hidden && function.Name.EndsWith("_FULL");
        string unfullName = isFull ? name.Substring(0, name.Length - "__FULL".Length)
                            .Replace("#", "").Replace("____HASH", "") : null;

        string        argsNoRec = String.Join(", ", heapArgs.Concat(formals.Select(f => GhostVar(f.Name))));
        List <RtlExp> reqsNoRec = minVerify ? new List <RtlExp>() : function.Req.ConvertAll(e => GhostExpression(e, true));
        List <RtlExp> enssNoRec = minVerify ? new List <RtlExp>() : function.Ens.ConvertAll(e => GhostExpression(e, true));

        AddTypeWellFormed(reqsNoRec, formals);
        AddTypeWellFormed(enssNoRec, name + "(" + argsNoRec + ")", function.IsGhost, function.ResultType);
        if (function.Body != null && !minVerify)
        {
            recFunName      = name;
            stmtExprEnabled = true;
            GhostExpression(function.Body);
            function.IsRecursive = recCalls.Count != 0;
            stmtExprEnabled      = false;
            stmts      = new List <RtlStmt>();
            recCalls   = new List <List <RtlExp> >();
            recFunName = null;
        }
        if (function.IsRecursive)
        {
            recFunName = name;
        }
        stmts           = new List <RtlStmt>();
        stmtExprEnabled = true;
        var            bodyDecls = PushForall();
        RtlExp         body      = (function.Body == null || minVerify) ? null : GhostExpression(function.Body);
        List <RtlStmt> bodyStmts = stmts;

        PopForall();
        stmtExprEnabled = false;
        stmts           = new List <RtlStmt>();
        string parms = String.Join(", ", heapParams.Concat(
                                       formals.Select(f => GhostVar(f.Name) + ":" + TypeString(AppType(f.Type)))));
        string args = String.Join(", ", heapArgs.Concat(
                                      formals.Select(f => GhostVar(f.Name))));
        string        sep       = (heapArgs.Count + formals.Count != 0) ? ", " : "";
        string        ret       = TypeString(AppType(function.ResultType));
        string        recName   = "rec_" + name;
        string        decreases = null;
        List <RtlExp> reqs      = minVerify ? new List <RtlExp>() : function.Req.ConvertAll(e => GhostExpression(e, true));
        List <RtlExp> enss      = minVerify ? new List <RtlExp>() : function.Ens.ConvertAll(e => GhostExpression(e, true));

        AddTypeWellFormed(reqs, formals);
        AddTypeWellFormed(enss, name + "(" + args + ")", function.IsGhost, function.ResultType);
        string reqConjunct = "(true" + String.Concat(reqs.Select(e => " && (" + e + ")")) + ")";
        string ensConjunct = "(true" + String.Concat(enss.Select(e => " && (" + e + ")")) + ")";

        Util.Assert(!isPrinting);
        if (function.IsRecursive && function.Body != null && !minVerify)
        {
            decreases = DecreasesExp(function);
        }
        List <RtlExp> enssRec = null;

        if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify)
        {
            enssRec = function.Ens.ConvertAll(e => GhostExpression(e, true));
        }
        isPrinting = true;
        var fiWriter = isPrivate ? writer : iwriter;

        if (function.IsRecursive && function.Body != null && !minVerify)
        {
            iwriter.WriteLine("function decreases0_" + name + "(" + parms + "):int { " + decreases + " }");
            iwriter.WriteLine("function decreases_" + name + "(" + parms + "):int { if decreases0_"
                              + name + "(" + args + ") < 0 then 0 else 1 + decreases0_" + name + "(" + args + ") }");
            iwriter.WriteLine("function " + recName + "(__decreases:int, __unroll:int" + sep + parms
                              + "):" + ret + ";");
            fiWriter.WriteLine("function implementation{" + FunName("unroll") + "(__unroll), "
                               + recName + "(__decreases, __unroll" + sep + args + ")} "
                               + recName + "(__decreases:int, __unroll:int" + sep + parms + "):" + ret);
            fiWriter.WriteLine("{");
            fiWriter.WriteLine("    " + body.ToString());
            fiWriter.WriteLine("}");
        }
        iwriter.WriteLine("function " + name + "(" + parms + "):" + ret + ";");
        if (hidden && !isFull && !minVerify)
        {
            iwriter.WriteLine("function unhide_" + name + "(" + parms + "):bool { true }");
            fiWriter.WriteLine("function implementation{unhide_" + name + "(" + args + ")} "
                               + name + "(" + parms + "):" + ret);
            fiWriter.WriteLine("{");
            fiWriter.WriteLine("    " + fullName + "(" + args + ")");
            fiWriter.WriteLine("}");
            iwriter.WriteLine("atomic ghost procedure "
                              + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "();");
            string forall = "forall " + parms + "::" + name + "(" + args + ") == "
                            + fullName + "(" + args + ")";
            iwriter.WriteLine("    ensures (" + forall + ");");
            writer.WriteLine("implementation "
                             + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "()");
            writer.WriteLine("{");
            writer.WriteLine("    " + forall);
            writer.WriteLine("    {");
            writer.WriteLine("        assert unhide_" + name + "(" + args + ");");
            writer.WriteLine("    }");
            writer.WriteLine("}");
        }
        if (body != null && (!hidden || isFull))
        {
            fiWriter.WriteLine("function implementation{" + name + "(" + args + ")" + "} " + name
                               + "(" + parms + "):" + ret);
            fiWriter.WriteLine("{");
            if (function.IsRecursive)
            {
                fiWriter.WriteLine("    " + recName + "(decreases_" + name + "(" + args + "), 0" + sep + args + ")");
            }
            else
            {
                fiWriter.WriteLine("    " + body.ToString());
            }
            fiWriter.WriteLine("}");
        }
        if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify)
        {
            AddTypeWellFormed(enssRec, recName + "(__decreases, __unroll" + sep + args + ")",
                              function.IsGhost, function.ResultType);
            string ensRecConjunct = "(true" + String.Concat(enssRec.Select(e => " && (" + e + ")")) + ")";
            iwriter.WriteLine("atomic ghost procedure lemma_unroll2_" + recName
                              + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ");");
            iwriter.WriteLine("    requires __decreases == decreases_" + name + "(" + args + ");");
            iwriter.WriteLine("    ensures  " + reqConjunct + " ==> " + ensRecConjunct + " && "
                              + recName + "(__decreases, __unroll" + sep + args + ") == "
                              + recName + "(__decreases, __unroll2" + sep + args + ");");

            writer.WriteLine("implementation lemma_unroll2_" + recName
                             + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ")");
            writer.WriteLine("{");
            writer.WriteLine("    " + bodyDecls);
            writer.WriteLine("    assert fun_unroll(__unroll) && fun_unroll(__unroll2);");
            dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes);
            writer.WriteLine("    if (" + reqConjunct + ")");
            writer.WriteLine("    {");
            bodyStmts.ForEach(s => writer.WriteLine("    " + s));
            writer.WriteLine("    }");
            foreach (List <RtlExp> recArgs in recCalls)
            {
                string rec_args     = String.Join(", ", recArgs);
                string rec_decrease = "decreases_" + name + "(" + rec_args + ")";
                writer.WriteLine("    if (0 <= " + rec_decrease + " && " + rec_decrease + " < __decreases)");
                writer.WriteLine("    {");
                writer.WriteLine("        call lemma_unroll2_" + recName + "(" + rec_decrease
                                 + ", __unroll + 1, __unroll2 + 1" + sep + rec_args + ");");
                writer.WriteLine("    }");
            }
            writer.WriteLine("}");
            string unroll_args  = "decreases_" + name + "(" + args + "), __unroll";
            string unroll_args0 = "decreases_" + name + "(" + args + "), 0";
            string unroll       = recName + "(" + unroll_args + sep + args + ")";
            string unroll0      = recName + "(" + unroll_args0 + sep + args + ")";


            var    lwriter   = isPrivate ? writer : iwriter;
            string recForall = "forall __unroll:int" + sep + parms + "::"
                               + "{fun_unroll(__unroll), " + unroll + "} "
                               + reqConjunct + " ==> fun_unroll(__unroll) ==> " + unroll + " == " + body;
            lwriter.WriteLine("atomic ghost procedure lemma_unroll_" + recName + "();");
            lwriter.WriteLine("    ensures  (" + recForall + ");");
            writer.WriteLine("implementation lemma_unroll_" + recName + "()");
            writer.WriteLine("{");
            dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes);
            writer.WriteLine("    " + recForall);
            writer.WriteLine("    {");
            writer.WriteLine("    " + bodyDecls);
            writer.WriteLine("    if (" + reqConjunct + ")");
            writer.WriteLine("    {");
            bodyStmts.ForEach(s => writer.WriteLine("    " + s));
            writer.WriteLine("    }");
            writer.WriteLine("    }");
            writer.WriteLine("}");
            dafnySpec.AddLemma(new LemmaCall((isPrivate ? "private##" : "") + moduleName,
                                             visibleElementType,
                                             "call lemma_unroll_" + recName + "();",
                                             false));

            Func <string, string> forall = s => "forall __unroll:int" + sep + parms + "::"
                                           + "{" + s + unroll + "} "
                                           + "{fun_unroll__all(__unroll), " + unroll + "} "
                                           + reqConjunct + " ==> " + unroll + " == " + name + "(" + args + ") && " + ensConjunct;
            iwriter.WriteLine("atomic ghost procedure lemma_unroll_" + name + "();");
            iwriter.WriteLine("    ensures  (" + forall(unroll0 + ", ") + ");");
            writer.WriteLine("implementation lemma_unroll_" + name + "()");
            writer.WriteLine("{");
            dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes);
            writer.WriteLine("    " + forall(""));
            writer.WriteLine("    {");
            writer.WriteLine("        call lemma_unroll2_" + recName + "("
                             + unroll_args + ", 0" + sep + args + ");");
            writer.WriteLine("        if (" + reqConjunct + ")");
            writer.WriteLine("        {");
            enss.ForEach(e => writer.WriteLine("            assert " + e + ";"));
            writer.WriteLine("        }");
            writer.WriteLine("    }");
            writer.WriteLine("}");
            dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType,
                                             "call lemma_unroll_" + name + "();", false));
        }
        else if (enssNoRec.Count > 0 && !minVerify)
        {
            string reqConjunctNoRec = "(true" + String.Concat(reqsNoRec.Select(e => " && (" + e + ")")) + ")";
            string ensConjunctNoRec = "(true" + String.Concat(enssNoRec.Select(e => " && (" + e + ")")) + ")";
            iwriter.WriteLine("function trigger_" + name + "(" + parms + "):bool { true }");
            iwriter.WriteLine("atomic ghost procedure lemma_fun_ensures_" + name + "();");
            string forallNoRec = "forall " + parms
                                 + "::{" + name + "(" + argsNoRec + ")}"
                                 + (isFull ? ("{" + unfullName + "(" + argsNoRec + ")}") : "")
                                 + "{trigger_" + name + "(" + argsNoRec + ")}"
                                 + "trigger_" + name + "(" + argsNoRec + ") ==> "
                                 + reqConjunctNoRec + " ==> " + ensConjunctNoRec;
            iwriter.WriteLine("    ensures (" + forallNoRec + ");");
            if (body != null || hidden || isAxiom)
            {
                writer.WriteLine("implementation lemma_fun_ensures_" + name + "()");
                writer.WriteLine("{");
                dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes);
                writer.WriteLine("    " + forallNoRec);
                writer.WriteLine("    {");
                writer.WriteLine("        " + bodyDecls);
                writer.WriteLine("        if (" + reqConjunct + ")");
                writer.WriteLine("        {");
                if (isAxiom)
                {
                    writer.WriteLine("        // dummy lemma body for axiom");
                }
                else
                {
                    bodyStmts.ForEach(s => writer.WriteLine("            " + s));
                }
                writer.WriteLine("        }");
                if (hidden && !isFull)
                {
                    writer.WriteLine("        assert unhide_" + name + "(" + argsNoRec + ");");
                }
                if (hidden && isFull)
                {
                    writer.WriteLine("        assert unhide_" + unfullName + "(" + argsNoRec + ");");
                }
                writer.WriteLine("        if (" + reqConjunct + ")");
                writer.WriteLine("        {");
                enssNoRec.ForEach(e => writer.WriteLine("            assert " + e + ";"));
                writer.WriteLine("        }");
                writer.WriteLine("    }");
                writer.WriteLine("}");
            }
            dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType,
                                             "call lemma_fun_ensures_" + name + "();", false));
        }
        isPrinting = false;
    }
Exemple #16
0
 public void MoveGhost(RtlVar destVar, RtlExp rhs)
 {
     stmts.Add(new RtlGhostMove(new RtlVar[] { destVar }, new RtlExp[] { rhs }));
 }
Exemple #17
0
 public RtlExp GetTypeWellFormedExp(List<Tuple<string,bool,Type>> vars, string op, RtlExp rhs)
 {
     var exps = GetTypeWellFormed(vars);
     foreach(var e in exps)
     {
         rhs = new RtlBinary(op, e, rhs);
     }
     return rhs;
 }
Exemple #18
0
 public void AddTypeWellFormed(List<RtlExp> specs, RtlExp exp, bool isGhost, Type t, List<UserDefinedType> recs)
 {
     UserDefinedType ut = t as UserDefinedType;
     if (minVerify && !isGhost && t is IntType)
     {
         specs.Add(new RtlApply("word", new RtlExp[] { exp }));
         return;
     }
     if (t is NatType)
     {
         specs.Add(new RtlBinary(">=", exp, new RtlInt(0)));
     }
     if (ut != null && ut.AsDatatype != null
         && recs.TrueForAll(r => ut.Name != r.Name) 
         )
     {
         recs.Add(ut);
         foreach (var ctor in ut.AsDatatype.Ctors)
         {
             List<RtlExp> cspecs = new List<RtlExp>();
             foreach (var f in ctor.Formals)
             {
                 AddTypeWellFormed(cspecs, new RtlLiteral(f.Name + "#" + ctor.Name + "(" + exp + ")"),
                     isGhost, f.Type, recs);
             }
             foreach (var spec in cspecs)
             {
                 specs.Add(new RtlLiteral("((" + exp + ") is " + ctor.Name + " ==> (" + spec + "))"));
             }
         }
         recs.RemoveAt(recs.Count - 1);
     }
 }
Exemple #19
0
 public RtlExp GhostIfThenElse(RtlExp eTest, Func<RtlExp> feThen, Func<RtlExp> feElse)
 {
     if (stmtExprEnabled && ignoreStmtExpr == 0)
     {
         stmts.Add(new RtlGhostStmtComputed(s => "if (" + eTest + ") {", new RtlExp[0]));
         Indent();
     }
     var eThen = feThen();
     if (stmtExprEnabled && ignoreStmtExpr == 0)
     {
         Unindent();
         stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
         stmts.Add(new RtlGhostStmtComputed(s => "if (!(" + eTest + ")) {", new RtlExp[0]));
         Indent();
     }
     var eElse = feElse();
     if (stmtExprEnabled && ignoreStmtExpr == 0)
     {
         Unindent();
         stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
     }
     return new RtlLiteral("(if (" + eTest + ") then ("
         + eThen + ") else (" + eElse + "))");
 }
Exemple #20
0
 public RtlBinary(string op, RtlExp e0, RtlExp e1)
 {
     this.op = op;
     this.e0 = e0;
     this.e1 = e1;
 }
Exemple #21
0
    public List <RtlStmt> Alloc()
    {
        assigned = new List <List <string> >(new List <string> [stmts.Count]);
        Func <int, string>    slotMem  = offset => "stk.map[r.regs[ESP] + " + offset + "]";
        Func <RtlExp, string> spillLoc = e => "EvalPtr(r, " + e.AsOperand() + ")";
        Func <RtlExp, string> spillMem = e => "stk.map[" + spillLoc(e) + "]";
        Stack <int>           workList = new Stack <int>();

        List <RtlStmt>          newStmts = new List <RtlStmt>();
        Action <string, string> move     = (string dest, string src) =>
        {
            if (dest != src)
            {
                newStmts.Add(new RtlInst("instr_Mov", new RtlVar[] { new RtlVar(dest, false) },
                                         new RtlVar[0], new RtlExp[] { new RtlVar(src, false) }, false)
                             .WithComment("regalloc_move:: " + dest + " := " + src));
            }
        };
        Action <string, RtlExp, string> sLoad = (string dest, RtlExp src, string var) =>
        {
            int dbgTag = debugTag++;
            Util.DebugWriteLine("sLoad: dest = " + dest + " " + dbgTag);
            newStmts.Add(new RtlStmtComputed((inst =>
            {
                var eDst = inst.args[0].e;
                string opPtr = inst.args[1].e.AsOperand();
                string ptr = "EvalPtr(r, " + opPtr + ")";
                return(IsPtr(var)
                        ? "call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, "
                       + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, "
                       + eDst + ", " + opPtr + ", " + ptr + ");"
                       + Environment.NewLine
                       + "    " + var + "__abs := frameGet($stacksFrames, " + ptr + ");"
                        : "call r := logical_Load(r, core_state, stk, " + eDst + ", " + opPtr + ");");
            }),
                                             new RtlArg[] { new RtlArg(true, false, new RtlVar(dest, false)),
                                                            new RtlArg(true, false, src) }, false)
                         .WithComment(() => "regalloc_stack_load:: " + dest + " := " + src + "  // var = " + var + " " + dbgTag));
        };
        Action <RtlExp, string, string> sStore = (RtlExp dest, string src, string var) =>
        {
            newStmts.Add(new RtlStmtComputed((inst =>
            {
                string opPtr = inst.args[0].e.AsOperand();
                string opVal = inst.args[1].e.AsOperand();
                string ptr = "EvalPtr(r, " + opPtr + ")";
                string val = "Eval(r, " + opVal + ")";
                return(IsPtr(var)
                        ? "call mems, $stacksFrames := "
                       + "heapStoreStack(r, core_state, stk, statics, io, mems, "
                       + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, "
                       + opPtr + ", " + opVal + ", " + ptr + ", " + var + "__abs);"
                        : "call stk := logical_Store(r, core_state, stk, " + opPtr + ", " + opVal + ");");
            }),
                                             new RtlArg[] { new RtlArg(true, false, dest),
                                                            new RtlArg(true, false, new RtlVar(src, false)) }, false)
                         .WithComment(() => "regalloc_stack_store:: " + dest + " := " + src + "  // var = " + var));
        };

        workList.Push(0);
        while (workList.Count > 0)
        {
            int     i    = workList.Pop();
            RtlStmt stmt = stmts[i];
            stmt.Uses().ForEach(x =>
                                preds[i].ForEach(p =>
                                                 { if (!defVars[p].Contains(x))
                                                   {
                                                       throw new Exception(
                                                           "variable " + x + " is used before it is assigned");
                                                   }
                                                 }));
            Util.DebugWriteLine(i + ": " + stmt);
            List <string> vars       = stmt.Vars();
            List <string> assignment = new List <string>((i == 0) ? initAssign :
                                                         preds[i].ConvertAll(p => assigned[p]).Find(a => a != null));
            Util.DebugWriteLine("  " + String.Join(", ", assignment));
            RtlInst inst = stmt as RtlInst;
            List <Tuple <string, string> > pinVars = (inst == null) ? new List <Tuple <string, string> >() :
                                                     inst.args.Where(arg => arg.pinReg != null && arg.e is RtlVar)
                                                     .Select(arg => Tuple.Create(((RtlVar)arg.e).x, arg.pinReg)).ToList();
            for (int r = 0; r < regs.Count; r++)
            {
                string rx = assignment[r];
                if (rx != null && !liveVars[i].ContainsKey(rx))
                {
                    assignment[r] = null;
                }

                if (pinVars.Exists(p => p.Item1 == rx))
                {
                    assignment[r] = null;
                }

                foreach (var p in pinVars)
                {
                    if (p.Item2 == regs[r])
                    {
                        assignment[r] = p.Item1;
                    }
                }
            }
            if (stmt is RtlCall)
            {
                RtlCall call = (RtlCall)stmt;
                if (!call.ghost)
                {
                    for (int r = 0; r < regs.Count; r++)
                    {
                        assignment[r] = null;
                    }

                    /*
                     * Func<RtlExp, bool> shouldSkip = (RtlExp e) => ((e is RtlVar) && ((RtlVar)e).isGhost);
                     * int[] outsToReg = new int[2] { regs.IndexOf("EAX"), regs.IndexOf("ESI") };
                     * int[] argsToReg = new int[3] { regs.IndexOf("ECX"), regs.IndexOf("EDX"), regs.IndexOf("EBX") };
                     *
                     * for (int r = 0; r < regs.Count; r++)
                     * {
                     *  string rx = assignment[r];
                     *  if (rx != null && (call.outs.Where(v => v.ToString() == rx).Count() != 0 || call.args.Where(v => v.ToString() == rx).Count() != 0))
                     *  {
                     *      assignment[r] = null;
                     *  }
                     * }
                     * for (int idx = 0; idx < 2; idx++)
                     * {
                     *  if (call.outs.Count >= idx + 1 && !shouldSkip(call.outs[idx]))
                     *  {
                     *      int r = outsToReg[idx];
                     *      string rx = assignment[r];
                     *      if (rx != null)
                     *      {
                     *          sStore(Spill(rx), regs[r]);
                     *      }
                     *      assignment[r] = call.outs[idx].ToString();
                     *  }
                     * }
                     * for (int idx = 0; idx < 3; idx++)
                     * {
                     *  if (call.args.Count >= idx + 1 && !shouldSkip(call.args[idx]))
                     *  {
                     *      int r = argsToReg[idx];
                     *      string rx = assignment[r];
                     *      if (rx != null)
                     *      {
                     *          sStore(Spill(rx), regs[r]);
                     *      }
                     *      assignment[r] = call.args[idx].ToString();
                     *  }
                     * }
                     */
                }
            }
            else if (stmt is RtlReturn)
            {
                for (int r = 0; r < regs.Count; r++)
                {
                    assignment[r] = null;
                }
            }
            else if (inst == null || !inst.ghost)
            {
                foreach (string x in vars)
                {
                    Tuple <int, int> bestEvict = null;
                    for (int r = 0; r < regs.Count; r++)
                    {
                        var rx = assignment[r];
                        if (rx == x)
                        {
                            goto done;
                        }
                        if (!vars.Contains(rx))
                        {
                            int thisEvict = (rx == null) ? Int32.MaxValue : liveVars[i][rx];
                            if (bestEvict == null || thisEvict > bestEvict.Item2)
                            {
                                bestEvict = Tuple.Create(r, thisEvict);
                            }
                        }
                    }
                    string ex = assignment[bestEvict.Item1];
                    if (ex != null)
                    {
                        Spill(ex);
                    }
                    assignment[bestEvict.Item1] = x;
                    done : {}
                }
            }
            Util.DebugWriteLine("  vars =  " + String.Join(", ", vars));
            Util.DebugWriteLine("  preds = " + String.Join(", ", preds[i]));
            Util.DebugWriteLine("  succs = " + String.Join(", ", succs[i]));
            Util.DebugWriteLine("  live =  " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x]))));
            Util.DebugWriteLine("  assign: " + String.Join(", ", assignment));
            assigned[i] = assignment;
            succs[i].Where(s => assigned[s] == null).ToList().ForEach(workList.Push);
        }
        for (int i = 0; i < stmts.Count; i++)
        {
            RtlJump jump = stmts[i] as RtlJump;
            if (jump != null && jump.cond != null)
            {
                List <string> assignment1 = assigned[i];
                List <string> assignment2 = assigned[labels[jump.label]];
                List <string> condVars    = jump.cond.Vars();
                for (int r = 0; r < regs.Count; r++)
                {
                    string x1 = assignment1[r];
                    string x2 = assignment2[r];
                    if (x1 != null && x2 != null && condVars.Contains(x1) && x1 != x2)
                    {
                        assignment2[r] = null;
                        Spill(x2);
                    }
                }
            }
        }

        Action <List <string>, Dictionary <string, int>, Dictionary <string, int>, Dictionary <string, string> > transition =
            (List <string> assignment2, Dictionary <string, int> live, Dictionary <string, int> liveAlt, Dictionary <string, string> varToReg) =>
        {
            Util.DebugWriteLine("start transition");


            varToReg.Keys.Where(x => x != null && !live.ContainsKey(x) && !liveAlt.ContainsKey(x)).ToList()
            .ForEach(x => varToReg.Remove(x));

            bool done;
            do
            {
                done = true;
                for (int rx = 0; rx < regs.Count; rx++)
                {
                    string x   = assignment2[rx];
                    string reg = regs[rx];
                    if (x != null && varToReg.ContainsKey(x) && varToReg[x] != reg &&
                        !varToReg.ContainsValue(reg))
                    {
                        Util.DebugWriteLine("move " + x + ": " + regs[rx] + " <- " + varToReg[x]);
                        move(regs[rx], varToReg[x]);
                        varToReg[x] = reg;
                        done        = false;
                    }
                }
            } while (!done);

            List <string> toSpill = new List <string>();
            foreach (var current in varToReg)
            {
                string x  = current.Key;
                int    rx = regs.IndexOf(current.Value);
                Util.DebugWriteLine("current = " + x + " -> " + regs[rx]);
                Util.DebugWriteLine("assign  = " + assignment2[rx] + " -> " + regs[rx]);
                if (assignment2[rx] != x && (live.ContainsKey(x) || liveAlt.ContainsKey(x)))
                {
                    Util.DebugWriteLine("spilling " + x + " from " + regs[rx]);
                    toSpill.Add(x);
                    sStore(Spill(x), regs[rx], x);
                }
            }
            toSpill.ForEach(x => varToReg.Remove(x));
            Util.DebugWriteLine("live   = " + String.Join(", ", live));

            for (int rx = 0; rx < regs.Count; rx++)
            {
                string x = assignment2[rx];
                if (x != null && live.ContainsKey(x))
                {
                    Util.DebugWriteLine("assign  = " + x + " -> " + regs[rx]);
                    if (varToReg.ContainsKey(x))
                    {
                        Util.Assert(varToReg[x] == regs[rx]);
                    }
                    else
                    {
                        Util.DebugWriteLine("loading  " + x + " to   " + regs[rx]);
                        sLoad(regs[rx], Spill(x), x);
                        Util.DebugWriteLine("loaded   " + x + " to   " + regs[rx]);
                        varToReg.Add(x, regs[rx]);
                    }
                }
            }
        };

        Util.DebugWriteLine("spilled: " + String.Join(", ", spillInts.Keys));

        Action <string> DebugWriteLine = s =>
        {
        };

        if (stmts.Count > 0)
        {
            transition(assigned[0], liveVars[0], liveVars[0], new Dictionary <string, string>());
        }
        for (int i = 0; i < stmts.Count; i++)
        {
            List <string> assignment             = assigned[i];
            RtlStmt       stmt                   = stmts[i];
            List <string> vars                   = stmt.Vars();
            List <string> uses                   = stmt.Uses();
            Dictionary <string, string> varToReg = new Dictionary <string, string>();
            Util.DebugWriteLine(i + ":  " + stmt);
            Util.DebugWriteLine("  assignment: " + String.Join(", ", assignment));
            Util.DebugWriteLine("  vars:" + String.Join(", ", vars));
            Util.DebugWriteLine("  uses:" + String.Join(", ", uses));
            DebugWriteLine(i + ":  " + stmt.GetType() + ": " + stmt);
            DebugWriteLine("  vars =  " + String.Join(", ", vars));
            DebugWriteLine("  uses =  " + String.Join(", ", uses));
            DebugWriteLine("  preds = " + String.Join(", ", preds[i]));
            DebugWriteLine("  succs = " + String.Join(", ", succs[i]));
            DebugWriteLine("  live =  " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x]))));
            DebugWriteLine("  defs =  " + String.Join(", ", defVars[i]));
            DebugWriteLine("  assign: " + String.Join(", ", assignment));
            Action <int, int> transitionTarget = (int target, int altTarget) =>
            {
                Util.DebugWriteLine("transition from " + i + " to " + target);
                transition(assigned[target], liveVars[target], liveVars[altTarget], varToReg);
            };


            int r;
            for (r = 0; r < regs.Count; r++)
            {
                string x = assignment[r];
                if (x != null)
                {
                    varToReg.Add(x, regs[r]);
                }
            }
            r = 0;
            foreach (string x in vars)
            {
                if (varToReg.ContainsKey(x) || stmt is RtlReturn)
                {
                    continue;
                }
                int rx = assignment.IndexOf(x);
                if (rx < 0)
                {
                    rx = assignment.IndexOf(null, r);
                    Util.Assert(rx >= 0);
                    Util.DebugWriteLine(i + ": MOVE(1): " + x);
                    sLoad(regs[rx], Spill(x), x);
                    r = rx + 1;
                }
                varToReg.Add(x, regs[rx]);
            }

            Util.DebugWriteLine("vars = " + String.Join(", ", vars));
            List <string> defs = stmt.Defs();
            stmt = stmt.Subst(varToReg);
            Dictionary <string, string> regToVar = new Dictionary <string, string>();
            varToReg.ToList().ForEach(p => regToVar.Add(p.Value, p.Key));
            RtlJump      jump  = stmt as RtlJump;
            RtlReturn    ret   = stmt as RtlReturn;
            RtlLabel     label = stmt as RtlLabel;
            RtlCall      call  = stmt as RtlCall;
            RtlCallInOut inOut = stmt as RtlCallInOut;
            if (ret != null)
            {
                Util.DebugWriteLine("RETURN: " + outVars.Count);


                for (int rr = 0; rr < regs.Count; rr++)
                {
                    string rx = assignment[rr];
                    if (rx != null)
                    {
                        newStmts.Add(new RtlComment("spill variable " + rx + " from register " + regs[rr]));
                        sStore(Spill(rx), regs[rr], rx);
                    }
                }
            }
            if (jump == null)
            {
                List <string> spilledArgs = new List <string>();

                if (inOut != null)
                {
                    string reg    = ((RtlVar)(inOut.args[0].e)).getName();
                    string var    = regToVar[reg];
                    bool   isPtr  = IsPtr(var);
                    int    offset = 4 * inOut.index;
                    RtlExp slot   = new RtlExpComputed(e => isPtr ? StackOMemPtr(offset) : StackOMem(offset));
                    newStmts.Add(new RtlComment(inOut.comment));
                    if (inOut.isRet)
                    {
                        if (isPtr)
                        {
                            callPtrRets = Math.Max(callPtrRets, inOut.index + 1);
                        }
                        else
                        {
                            callIntRets = Math.Max(callIntRets, inOut.index + 1);

                            newStmts.Add(new RtlInst(null,
                                                     new RtlVar[] { new RtlVar(var, true) }, new RtlVar[0],
                                                     new RtlExp[] { new RtlLiteral(
                                                                        CompileMethod.IntToTyped(varTypes[var], slotMem(offset))) },
                                                     true));
                        }
                        Util.DebugWriteLine("  var = " + var + " live = " + String.Join(",", liveVars[i].Keys) + " live' = " + String.Join(",", liveVars[i + 1].Keys));
                        if (i + 1 >= liveVars.Count || liveVars[i + 1].ContainsKey(var))
                        {
                            Util.DebugWriteLine("sLoad inOut: " + reg + " " + slot + " " + var);
                            sLoad(reg, slot, var);
                        }
                    }
                    else
                    {
                        if (isPtr)
                        {
                            callPtrArgs = Math.Max(callPtrArgs, inOut.index + 1);
                        }
                        else
                        {
                            callIntArgs = Math.Max(callIntArgs, inOut.index + 1);
                        }
                        sStore(slot, reg, var);
                    }
                }
                else
                {
                    newStmts.Add(stmt);

                    defs.Where(x => !IsPtr(x)).ToList()
                    .ForEach(x => newStmts.Add(new RtlInst(null,
                                                           new RtlVar[] { new RtlVar(x, true) }, new RtlVar[0],
                                                           new RtlExp[] { new RtlLiteral(
                                                                              CompileBase.IntToTyped(varTypes[x], Reg(varToReg[x]))) },
                                                           true)));
                }

                Util.DebugWriteLine("sLoad spilled: " + String.Join(", ", spilledArgs.Select(arg => "(" + varToReg[arg] + " <- " + arg + ")")));
                spilledArgs.ForEach(arg => sLoad(varToReg[arg], Spill(arg), arg));
            }
            if (label != null && label.loop)
            {
                List <RtlExp> typeInvs = new List <RtlExp>();
                newStmts.Add(new RtlComment("loop invariants"));
                foreach (string x in liveVars[i].Keys)
                {
                    if (defVars[i].Contains(x))
                    {
                        compileMethod.AddTypeWellFormed(typeInvs, x, false, varTypes[x]);
                        string save_x = x;
                        RtlExp loc    = varToReg.ContainsKey(x) ? new RtlVar(Reg(varToReg[x]), false)
                            : (RtlExp) new RtlExpComputed(e => spillMem(Spill(save_x)));
                        if (IsPtr(x))
                        {
                            string absData = "Abs_" + TypeString(varTypes[x]) + "(" + x + ")";
                            if (varToReg.ContainsKey(x))
                            {
                                newStmts.Add(new RtlAssert(new RtlLiteral(
                                                               "HeapAbsData(heap, " + x + "__abs) == " + absData), true));
                                newStmts.Add(new RtlAssert(new RtlExpComputed(e =>
                                                                              "HeapValue(objLayouts, true, $toAbs, " + loc + ", " + save_x + "__abs)"), true));
                                if (IsArray(x))
                                {
                                    newStmts.Add(new RtlAssert(new RtlLiteral(
                                                                   x + "__abs == " + x + ".arrAbs"), true));
                                }
                            }
                            else
                            {
                                newStmts.Add(new RtlAssert(new RtlExpComputed(e =>
                                                                              "StackAbsSlot(heap, $stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + absData), true));
                                if (IsArray(x))
                                {
                                    newStmts.Add(new RtlAssert(new RtlExpComputed(e =>
                                                                                  "frameGet($stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + save_x + ".arrAbs"), true));
                                }
                            }
                        }
                        else
                        {
                            newStmts.Add(new RtlAssert(CompileMethod.IntEqTyped(varTypes[x],
                                                                                new RtlVar(x, false),
                                                                                new RtlExpComputed(e => loc.ToString())), true));
                        }
                    }
                }
                typeInvs.ForEach(e => newStmts.Add(new RtlAssert(e, true)));
            }

            bool fallThru = (ret == null && i + 1 < stmts.Count && (jump == null || jump.cond != null));
            if (jump != null)
            {
                transitionTarget(labels[jump.label], fallThru ? (i + 1) : labels[jump.label]);
                newStmts.Add(stmt);
            }
            if (fallThru)
            {
                transitionTarget(i + 1, i + 1);
            }
        }
        return(newStmts);
    }
Exemple #22
0
 public void MoveGhost(RtlVar destVar, RtlExp rhs)
 {
     stmts.Add(new RtlGhostMove(new RtlVar[] { destVar }, new RtlExp[] { rhs }));
 }
Exemple #23
0
    public RtlExp GhostExpressionRec(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false)
    {
        Util.Assert(!isPrinting);
        exp = GetExp(exp);
        StmtExpr         stmtExpr    = exp as StmtExpr;
        IdentifierExpr   idExp       = exp as IdentifierExpr;
        LiteralExpr      literal     = exp as LiteralExpr;
        BinaryExpr       binary      = exp as BinaryExpr;
        UnaryExpr        unary       = exp as UnaryExpr;
        ITEExpr          ite         = exp as ITEExpr;
        ExistsExpr       existsExp   = exp as ExistsExpr;
        ForallExpr       forallExp   = exp as ForallExpr;
        LetExpr          letExp      = exp as LetExpr;
        MatchExpr        matchExp    = exp as MatchExpr;
        OldExpr          oldExp      = exp as OldExpr;
        FreshExpr        freshExp    = exp as FreshExpr;
        FunctionCallExpr funCall     = exp as FunctionCallExpr;
        DatatypeValue    dataVal     = exp as DatatypeValue;
        FieldSelectExpr  fieldSelect = exp as FieldSelectExpr;
        SeqSelectExpr    seqSelect   = exp as SeqSelectExpr;
        SeqUpdateExpr    seqUpdate   = exp as SeqUpdateExpr;
        SeqDisplayExpr   seqDisplay  = exp as SeqDisplayExpr;

        Func <Expression, RtlExp> G = e => GhostExpression(e, inRecSpec, inRequiresOrOld);

        if (stmtExpr != null)
        {
            if (stmtExprEnabled)
            {
                if (ignoreStmtExpr == 0)
                {
                    AddGhostStatement(stmtExpr.S);
                }
                return(G(stmtExpr.E));
            }
            else
            {
                throw new Exception("not implemented: cannot handle statement expression here");
            }
        }
        else if (idExp != null)
        {
            return(AsVar(idExp));
        }
        else if (literal != null && literal.Value is BigInteger)
        {
            return(new RtlInt((BigInteger)(literal.Value)));
        }
        else if (literal != null && literal.Value is bool)
        {
            return(new RtlLiteral((bool)(literal.Value) ? "true" : "false"));
        }
        else if (literal != null && literal.Value == null)
        {
            return(new RtlLiteral("ArrayOfInt(0 - 1, NO_ABS)"));
        }
        else if (literal != null && literal.Value is Microsoft.Basetypes.BigDec)
        {
            return(new RtlLiteral(((Microsoft.Basetypes.BigDec)literal.Value).ToDecimalString()));
        }
        else if (binary != null)
        {
            string          op              = null;
            string          internalOp      = null;
            CompileFunction compileFunction = this as CompileFunction;
            string          thisFuncName    = (compileFunction == null) ? null : compileFunction.function.Name;
            switch (binary.ResolvedOp)
            {
            case BinaryExpr.ResolvedOpcode.SeqEq:
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                                    new RtlExp[] { G(binary.E0), G(binary.E1) }));

            case BinaryExpr.ResolvedOpcode.SeqNeq:
                return(new RtlLiteral("(!" +
                                      new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"),
                                                   new RtlExp[] { G(binary.E0), G(binary.E1) }) + ")"));

            case BinaryExpr.ResolvedOpcode.Concat:
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.Type), "Seq_Append"),
                                    new RtlExp[] { G(binary.E0), G(binary.E1) }));
            }
            if (binary.Op == BinaryExpr.Opcode.Exp)
            {
                binary = new BinaryExpr(binary.tok, BinaryExpr.Opcode.Imp, binary.E0, binary.E1);
            }
            switch (binary.Op)
            {
            case BinaryExpr.Opcode.Disjoint:
            case BinaryExpr.Opcode.In:
            case BinaryExpr.Opcode.NotIn:
                throw new Exception("not implemented: binary operator '" + BinaryExpr.OpcodeString(binary.Op) + "'");
            }
            if (AppType(binary.E0.Type) is IntType && AppType(binary.E1.Type) is IntType)
            {
                switch (binary.Op)
                {
                case BinaryExpr.Opcode.Le: internalOp = "INTERNAL_le_boogie"; break;

                case BinaryExpr.Opcode.Lt: internalOp = "INTERNAL_lt_boogie"; break;

                case BinaryExpr.Opcode.Ge: internalOp = "INTERNAL_ge_boogie"; break;

                case BinaryExpr.Opcode.Gt: internalOp = "INTERNAL_gt_boogie"; break;

                case BinaryExpr.Opcode.Add: internalOp = "INTERNAL_add_boogie"; break;

                case BinaryExpr.Opcode.Sub: internalOp = "INTERNAL_sub_boogie"; break;

                case BinaryExpr.Opcode.Mul:
                    op = "*";
                    if (thisFuncName != "INTERNAL_mul")
                    {
                        internalOp = FunName("INTERNAL__mul");
                    }
                    break;

                case BinaryExpr.Opcode.Div:
                    op = "div";
                    if (thisFuncName != "INTERNAL_div")
                    {
                        internalOp = FunName("INTERNAL__div");
                    }
                    break;

                case BinaryExpr.Opcode.Mod:
                    op = "mod";
                    if (thisFuncName != "INTERNAL_mod")
                    {
                        internalOp = FunName("INTERNAL__mod");
                    }
                    break;

                default:
                    op = BinaryExpr.OpcodeString(binary.Op);
                    break;
                }
            }
            else
            {
                op = BinaryExpr.OpcodeString(binary.Op);
            }
            if (internalOp == null)
            {
                return(new RtlBinary(op, G(binary.E0), G(binary.E1)));
            }
            else
            {
                return(new RtlApply(internalOp, new RtlExp[]
                                    { G(binary.E0), G(binary.E1) }));
            }
        }
        else if (unary != null && unary.Op == UnaryExpr.Opcode.Not)
        {
            return(new RtlLiteral("(!(" + G(unary.E) + "))"));
        }
        else if (unary != null && unary.Op == UnaryExpr.Opcode.SeqLength)
        {
            return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(unary.E.Type), "Seq_Length"),
                                new RtlExp[] { G(unary.E) }));
        }
        else if (ite != null)
        {
            return(GhostIfThenElse(G(ite.Test), () => G(ite.Thn), () => G(ite.Els)));
        }
        else if (funCall != null)
        {
            switch (funCall.Function.Name)
            {
            case "left":
            case "right":
            case "relation":
            case "public":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply(funCall.Function.Name, new RtlExp[] { G(funCall.Args[0]) }));

            case "sizeof":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply(funCall.Function.Name + "##" + TypeString(AppType(funCall.Args[0].Type)),
                                    new RtlExp[] { G(funCall.Args[0]) }));

            case "INTERNAL_add_raw":
                Util.Assert(funCall.Args.Count == 2);
                return(new RtlBinary("+", G(funCall.Args[0]), G(funCall.Args[1])));

            case "INTERNAL_sub_raw":
                Util.Assert(funCall.Args.Count == 2);
                return(new RtlBinary("-", G(funCall.Args[0]), G(funCall.Args[1])));

            case "IntToReal":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply("real", new RtlExp[] { G(funCall.Args[0]) }));

            case "RealToInt":
                Util.Assert(funCall.Args.Count == 1);
                return(new RtlApply("int", new RtlExp[] { G(funCall.Args[0]) }));
            }
            TypeApply app = dafnySpec.Compile_Function(funCall.Function,
                                                       funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value)));
            string        name     = FunName(SimpleName(app.AppName()));
            string        fullName = FunName(SimpleName(app.AppFullName()));
            List <RtlExp> rtlArgs  = funCall.Args.Select(G).ToList();
            List <RtlExp> rtlReads = funCall.Function.Reads.Where(e => e.Field != null).ToList()
                                     .ConvertAll(e => (RtlExp) new RtlVar(
                                                     GhostVar(e.FieldName), e.Field.IsGhost, AppType(e.Field.Type)));
            rtlArgs = rtlReads.Concat(rtlArgs).ToList();
            if (name.EndsWith("__INTERNAL__HEAP"))
            {
                name = name.Substring(0, name.Length - "__INTERNAL__HEAP".Length);
            }
            else if (DafnySpec.IsHeapFunction(funCall.Function))
            {
                rtlArgs.Insert(0, new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"));
            }
            if (Attributes.Contains(funCall.Function.Attributes, "opaque") &&
                funCall.Function.Formals.Count + rtlReads.Count == 0)
            {
                rtlArgs.Insert(0, new RtlLiteral("true"));
            }
            if (fullName == recFunName)
            {
                name = fullName;
            }
            if (name == recFunName)
            {
                recCalls.Add(new List <RtlExp>(rtlArgs));
                rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List <RtlExp>(rtlArgs)));
                rtlArgs.Insert(1, new RtlLiteral(inRecSpec ? "__unroll" : "__unroll + 1"));
                name = "rec_" + name;
            }
            return(new RtlApply(name, rtlArgs));
        }
        else if (dataVal != null)
        {
            bool isSeq = dataVal.Type.TypeName(null).StartsWith("Seq<");
            return(new RtlApply((isSeq ? "_" : "") + dafnySpec.Compile_Constructor(
                                    dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(),
                                dataVal.Arguments.Select(G)));
        }
        else if (existsExp != null || forallExp != null)
        {
            QuantifierExpr qExp               = (QuantifierExpr)exp;
            bool           isForall           = forallExp != null;
            var            varTuples          = qExp.BoundVars.Select(v => Tuple.Create(GhostVar(v.Name), v.IsGhost, v.Type));
            var            oldRenamer         = PushRename(qExp.BoundVars.Select(v => v.Name));
            var            oldStmtExprEnabled = stmtExprEnabled;
            stmtExprEnabled = false;
            RtlExp rExp = new RtlLiteral((isForall ? "(forall " : "(exists ")
                                         + string.Join(", ", qExp.BoundVars.Select(v => GhostVar(v.Name) + ":" + TypeString(AppType(v.Type))))
                                         + " :: " + Triggers(qExp.Attributes, G) + " "
                                         + GetTypeWellFormedExp(varTuples.ToList(), isForall ? "==>" : "&&", G(qExp.Term)) + ")");
            stmtExprEnabled = oldStmtExprEnabled;
            PopRename(oldRenamer);
            return(rExp);
        }
        else if (letExp != null)
        {
            List <RtlExp> rhss;
            if (letExp.Exact)
            {
                rhss = letExp.RHSs.ConvertAll(e => G(e));
            }
            else if (letExp.LHSs.Count == 1 && LiteralExpr.IsTrue(letExp.RHSs[0]) && AppType(letExp.LHSs[0].Var.Type) is IntType)
            {
                rhss = new List <RtlExp> {
                    new RtlLiteral("0")
                };
            }
            else
            {
                throw new Exception("not implemented: LetExpr: " + letExp);
            }
            return(GhostLet(exp.tok, letExp.LHSs.ConvertAll(lhs => lhs.Var), rhss, () => G(letExp.Body)));
        }
        else if (matchExp != null)
        {
            if (matchExp.MissingCases.Count != 0)
            {
                throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp);
            }
            //- match src case c1(ps1) => e1 ... cn(psn) => en
            //-   -->
            //- let x := src in
            //-   if x is c1 then let ps1 := ...x.f1... in e1 else
            //-   if x is c2 then let ps2 := ...x.f2... in e2 else
            //-                   let ps3 := ...x.f3... in e3
            var           src   = G(matchExp.Source);
            var           cases = matchExp.Cases;
            string        x     = TempName();
            Func <RtlExp> body  = null;
            for (int i = cases.Count; i > 0;)
            {
                i--;
                MatchCaseExpr         c     = cases[i];
                Func <List <RtlExp> > cRhss = () => c.Ctor.Formals.ConvertAll(f => (RtlExp) new RtlLiteral("("
                                                                                                           + f.Name + "#" + c.Ctor.Name + "(" + GhostVar(x) + "))"));
                Func <RtlExp> ec = () => GhostLet(exp.tok, c.Arguments, cRhss(), () => G(c.Body));
                if (body == null)
                {
                    body = ec;
                }
                else
                {
                    var prevBody = body;
                    body = () => GhostIfThenElse(new RtlLiteral("(" + GhostVar(x) + " is " + c.Ctor.Name + ")"),
                                                 ec, prevBody);
                }
            }
            return(GhostLet(exp.tok, new List <BoundVar> {
                new BoundVar(exp.tok, x, matchExp.Source.Type)
            },
                            new List <RtlExp> {
                src
            }, body));
        }
        else if (oldExp != null)
        {
            return(new RtlLiteral("old(" + GhostExpression(oldExp.E, inRecSpec, true) + ")"));
        }
        else if (freshExp != null)
        {
            Util.Assert(DafnySpec.IsArrayType(freshExp.E.Type));
            string abs = G(freshExp.E) + ".arrAbs";
            return(new RtlLiteral("(heap_old.absData[" + abs + "] is AbsNone)"));
        }
        else if (fieldSelect != null && fieldSelect.FieldName.EndsWith("?"))
        {
            string constructor = fieldSelect.FieldName.Substring(0, fieldSelect.FieldName.Length - 1);
            constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type, constructor, null, typeApply.typeArgs).AppName();
            bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return(isSeq
                ? new RtlLiteral("is_" + constructor + "(" + G(fieldSelect.Obj) + ")")
                : new RtlLiteral("((" + G(fieldSelect.Obj) + ") is " + constructor + ")"));
        }
        else if (fieldSelect != null && !fieldSelect.Field.IsStatic && AppType(fieldSelect.Obj.Type) is UserDefinedType &&
                 fieldSelect.Field is DatatypeDestructor)
        {
            DatatypeDestructor field       = (DatatypeDestructor)fieldSelect.Field;
            string             constructor = dafnySpec.Compile_Constructor(fieldSelect.Obj.Type,
                                                                           field.EnclosingCtor.Name, null, typeApply.typeArgs).AppName();
            bool isSeq = fieldSelect.Obj.Type.TypeName(null).StartsWith("Seq<");
            return(new RtlLiteral("(" + fieldSelect.FieldName + (isSeq ? "_" : "#") + constructor
                                  + "(" + G(fieldSelect.Obj) + "))"));
        }
        else if (fieldSelect != null && DafnySpec.IsArrayType(AppType(fieldSelect.Obj.Type)) &&
                 fieldSelect.FieldName == "Length")
        {
            return(new RtlLiteral("(Arr_Length(" + G(fieldSelect.Obj) + "))"));
        }
        else if (fieldSelect != null && fieldSelect.Obj is ImplicitThisExpr)
        {
            //- we don't support objects yet, so interpret this as a global variable
            return(new RtlVar(GhostVar(fieldSelect.FieldName), true, fieldSelect.Type));
        }
        else if (seqSelect != null)
        {
            if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
            {
                return(new RtlExpComputed(e => "fun_INTERNAL__array__elems__index("
                                          + (inRequiresOrOld ? "$absMem_old" : "$absMem") + "[" + e.args[0] + ".arrAbs], ("
                                          + e.args[1] + "))", new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }));
            }
            else if (seqSelect.SelectOne)
            {
                return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Seq.Type), "Seq_Index"),
                                    new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }));
            }
            else
            {
                RtlExp seq = G(seqSelect.Seq);
                if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type)))
                {
                    seq = new RtlApply(FunName("Seq__FromArray"), new RtlExp[] {
                        new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"), seq
                    });
                }
                if (seqSelect.E1 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Take"),
                                       new RtlExp[] { seq, G(seqSelect.E1) });
                }
                if (seqSelect.E0 != null)
                {
                    seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Drop"),
                                       new RtlExp[] { seq, G(seqSelect.E0) });
                }
                return(seq);
            }
        }
        else if (seqUpdate != null)
        {
            if (seqUpdate.ResolvedUpdateExpr != null)
            {
                return(GhostExpressionRec(seqUpdate.ResolvedUpdateExpr, inRecSpec, inRequiresOrOld));
            }
            return(new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqUpdate.Seq.Type), "Seq_Update"),
                                new RtlExp[] { G(seqUpdate.Seq), G(seqUpdate.Index), G(seqUpdate.Value) }));
        }
        else if (seqDisplay != null)
        {
            RtlExp seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Empty"), new RtlExp[0]);
            foreach (Expression ei in seqDisplay.Elements)
            {
                seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Build"),
                                   new RtlExp[] { seq, G(ei) });
            }
            return(seq);
        }
        else
        {
            throw new Exception("not implemented: " + exp);
        }
    }
Exemple #24
0
 public RtlArg(bool isIn, bool isOut, RtlExp e, string pinReg = null)
 {
     this.isIn = isIn;
     this.isOut = isOut;
     this.e = e;
     this.pinReg = pinReg;
 }
Exemple #25
0
    public RtlExp GetTypeWellFormedExp(List <Tuple <string, bool, Type> > vars, string op, RtlExp rhs)
    {
        var exps = GetTypeWellFormed(vars);

        foreach (var e in exps)
        {
            rhs = new RtlBinary(op, e, rhs);
        }
        return(rhs);
    }
Exemple #26
0
 public RtlMem(RtlExp ptr, string offset):this(ptr, new RtlLiteral(offset)) { }
Exemple #27
0
    public virtual void AddResolvedGhostStatement(Statement stmt)
    {
        BlockStmt          block      = stmt as BlockStmt;
        IfStmt             ifStmt     = stmt as IfStmt;
        AssertStmt         assertStmt = stmt as AssertStmt;
        AssignStmt         assignStmt = stmt as AssignStmt;
        CallStmt           callStmt   = stmt as CallStmt;
        VarDecl            varDecl    = stmt as VarDecl;
        CalcStmt           calcStmt   = stmt as CalcStmt;
        ForallStmt         forallStmt = stmt as ForallStmt;
        AssignSuchThatStmt existsStmt = stmt as AssignSuchThatStmt;

        if (block != null)
        {
            var oldRenamer = PushRename();
            block.Body.ForEach(AddGhostStatement);
            PopRename(oldRenamer);
        }
        else if (varDecl != null)
        {
            AddGhostVarDecl(varDecl.Name, varDecl.Type, varDecl.IsGhost);
        }
        else if (minVerify)
        {
            return;
        }
        else if (assignStmt != null)
        {
            ExprRhs expRhs = assignStmt.Rhs as ExprRhs;
            if (expRhs != null)
            {
                FieldSelectExpr fieldSelect = assignStmt.Lhs as FieldSelectExpr;
                RtlVar          destVar;
                if (fieldSelect != null)
                {
                    destVar = new RtlVar(GhostVar(fieldSelect.FieldName), true, fieldSelect.Type);
                }
                else
                {
                    destVar = AsVar(assignStmt.Lhs);
                    Util.Assert(destVar != null);
                }
                stmts.Add(new RtlGhostMove(new RtlVar[] { destVar },
                                           new RtlExp[] { GhostExpression(expRhs.Expr) }));
            }
            else
            {
                throw new Exception("not implemented: " + assignStmt.Rhs);
            }
        }
        else if (callStmt != null)
        {
            AddGhostCall(callStmt.Lhs.ConvertAll(AsVar), callStmt.Args,
                         dafnySpec.Compile_Method(callStmt.Method,
                                                  callStmt.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))),
                         DafnySpec.IsHeapMethod(callStmt.Method));
            SymdiffLinearityPoint();
        }
        else if (ifStmt != null)
        {
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                                               new RtlExp[] { GhostExpression(ifStmt.Guard) }));
            Indent();
            AddGhostStatement(ifStmt.Thn);
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            if (ifStmt.Els != null)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {",
                                                   new RtlExp[] {
                    GhostExpression(new UnaryExpr(Bpl.Token.NoToken, UnaryExpr.Opcode.Not, ifStmt.Guard))
                }));
                Indent();
                AddGhostStatement(ifStmt.Els);
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else if (assertStmt != null)
        {
            stmts.Add(new RtlAssert(GhostExpression(assertStmt.Expr)));
        }
        else if (forallStmt != null)
        {
            var    oldRenamer = PushRename(forallStmt.BoundVars.Select(v => v.Name));
            RtlExp ens        = new RtlLiteral("true");
            foreach (var e in forallStmt.Ens)
            {
                ens = new RtlBinary("&&", ens, GhostExpression(e.E));
            }
            RtlExp range = (forallStmt.Range == null) ? new RtlLiteral("true")
                : GhostExpression(forallStmt.Range);
            List <RtlExp> wellFormed = GetTypeWellFormed(forallStmt.BoundVars.
                                                         Select(x => Tuple.Create(GhostVar(x.Name), x.IsGhost, x.Type)).ToList());
            wellFormed.ForEach(e => range = new RtlBinary("&&", e, range));
            ens = new RtlBinary("==>", range, ens);
            string vars = String.Join(", ", forallStmt.BoundVars.Select(x => GhostVar(x.Name) + ":" +
                                                                        TypeString(AppType(x.Type))));
            stmts.Add(new RtlGhostStmtComputed(s => "forall " + vars + "::(" + s.args[0] + ")",
                                               new List <RtlExp> {
                ens
            }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            stmts.Add(PushForall());
            stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                                               new List <RtlExp> {
                range
            }));
            stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
            Indent();
            AddGhostStatement(forallStmt.Body);
            foreach (var e in forallStmt.Ens)
            {
                stmts.Add(new RtlAssert(GhostExpression(e.E)));
            }
            PopForall();
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            Unindent();
            stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            PopRename(oldRenamer);
        }
        else if (existsStmt != null)
        {
            List <RtlStmt> assigns = new List <RtlStmt>();
            List <RtlVar>  tmps    = new List <RtlVar>();
            List <Tuple <string, bool, Type> > varTuples = new List <Tuple <string, bool, Type> >();
            var oldRenamer = PushRename();
            foreach (var lhs in existsStmt.Lhss)
            {
                IdentifierExpr idExp   = lhs.Resolved as IdentifierExpr;
                RtlVar         origVar = AsVar(lhs);
                AddRename(idExp.Name);
                RtlVar renameVar = AsVar(lhs);
                tmps.Add(renameVar);
                varTuples.Add(Tuple.Create(renameVar.ToString(), true, idExp.Type));
                assigns.Add(new RtlGhostMove(new RtlVar[] { origVar },
                                             new RtlExp[] { renameVar }));
            }
            string vars = String.Join(", ", tmps.Select(x => x.getName() + ":" + TypeString(AppType(x.type))));
            stmts.Add(new RtlGhostStmtComputed(s => "exists " + vars + "::(" + s.args[0] + ");",
                                               new List <RtlExp> {
                GetTypeWellFormedExp(varTuples.ToList(), "&&", GhostExpression(existsStmt.Expr))
            }));
            stmts.AddRange(assigns);
            PopRename(oldRenamer);
        }
        else if (calcStmt != null)
        {
            Util.Assert(calcStmt.Steps.Count == calcStmt.Hints.Count);
            CalcStmt.BinaryCalcOp binOp = calcStmt.Op as CalcStmt.BinaryCalcOp;
            bool isImply = binOp != null && binOp.Op == BinaryExpr.Opcode.Imp && calcStmt.Steps.Count > 0;
            if (isImply)
            {
                stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")",
                                                   new RtlExp[] { GhostExpression(CalcStmt.Lhs(calcStmt.Steps[0])) }));
                stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                Indent();
            }
            var stepCount = calcStmt.Hints.Last().Body.Count == 0 ? calcStmt.Steps.Count - 1 : calcStmt.Steps.Count;
            for (int i = 0; i < stepCount; i++)
            {
                if (calcStmt.Hints[i] == null)
                {
                    stmts.Add(new RtlAssert(GhostExpression(calcStmt.Steps[i])));
                }
                else
                {
                    stmts.Add(new RtlGhostStmtComputed(s => "forall::(" + s.args[0] + ")",
                                                       new List <RtlExp> {
                        GhostExpression(calcStmt.Steps[i])
                    }));
                    stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0]));
                    Indent();
                    var dict = new Dictionary <string, RtlVar>();
                    stmts.Add(new RtlGhostStmtComputed(s => String.Concat(dict.Values.Select(
                                                                              x => "var " + x.x + ":" + TypeString(x.type) + ";")),
                                                       new RtlExp[0]));
                    forallVars.Add(dict);
                    AddGhostStatement(calcStmt.Hints[i]);
                    forallVars.RemoveAt(forallVars.Count - 1);
                    Unindent();
                    stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
                }
            }
            if (isImply)
            {
                Unindent();
                stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0]));
            }
        }
        else
        {
            throw new Exception("not implemented in ghost methods: " + stmt);
        }
    }
Exemple #28
0
 public RtlMem(RtlExp ptr, RtlExp offset):this(ptr, null, null, offset) { }