in ironclad-apps/tools/DafnyCC/CompileMethod.cs [1522:1652]
public void CompileInstruction()
{
string name = GhostProcName(DafnySpec.SimpleSanitizedName(method));
bool strictOperands = Attributes.Contains(method.Attributes, "strict_operands");
List<RtlExp> reqs = method.Req.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes));
List<RtlExp> enss = method.Ens.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes));
AddTypeWellFormed(reqs, method.Ins);
AddTypeWellFormed(enss, method.Outs);
List<Tuple<string,string>> operands = InstructionAttributes(method.Attributes);
List<Tuple<Formal,string>> ins = new List<Tuple<Formal,string>>();
List<Tuple<Formal,string>> outs = new List<Tuple<Formal,string>>();
int kIn = 0, kOut = 0;
List<string> parms = new List<string>();
List<string> args = new List<string>();
Func<string,string> opnName = s => "$opn_" + DafnySpec.CleanName(s);
string outRegs = "";
List<string> opnReqs = new List<string>();
List<string> allPins = operands.ConvertAll(p => p.Item2).Where(p => p != null).ToList();
foreach (var r in operands)
{
string arg;
Action<string,Func<string,string>> opnReq = (a, f) =>
{
if (r.Item2 != null) { opnReqs.Add(a + " == " + f(r.Item2)); }
else if (allPins.Count > 0) { opnReqs.Add(String.Join(" && ", allPins.Select(pin => a + " != " + f(pin)))); }
};
switch (r.Item1)
{
case "in":
arg = opnName(method.Ins[kIn].Name);
parms.Add(arg + ":opn");
opnReq(arg, s => "OReg(" + s + ")");
ins.Add(Tuple.Create(method.Ins[kIn], "Eval(r_old, " + arg + ")"));
kIn++;
break;
case "inout":
arg = opnName(method.Ins[kIn].Name);
parms.Add(arg + ":int");
opnReq(arg, s => s);
ins.Add(Tuple.Create(method.Ins[kIn], "r_old.regs[" + arg + "]"));
kIn++;
outs.Add(Tuple.Create(method.Outs[kOut], "r.regs[" + arg + "]"));
outRegs += "[" + arg + " := " + GhostVar(method.Outs[kOut].Name) + "]";
kOut++;
break;
case "out":
arg = opnName(method.Outs[kOut].Name);
parms.Add(arg + ":int");
opnReq(arg, s => s);
outs.Add(Tuple.Create(method.Outs[kOut], "r.regs[" + arg + "]"));
outRegs += "[" + arg + " := " + GhostVar(method.Outs[kOut].Name) + "]";
kOut++;
break;
case "mem":
arg = opnName(method.Ins[kIn].Name);
parms.Add(arg + ":opn_mem");
ins.Add(Tuple.Create(method.Ins[kIn], "EvalPtr(r_old, " + arg + ")"));
kIn++;
break;
default: throw new Exception("expected 'in' or 'inout' or 'out' or 'mem' in attributes of method" + method.Name);
}
args.Add(arg);
}
if (method.Body != null)
{
stmtExprEnabled = true;
instructionProcArgs = args;
foreach (var x in method.Ins.Concat(method.Outs))
{
string xName = GhostVar(x.Name);
allVars[xName] = new RtlVar(xName, x.IsGhost, AppType(x.Type));
}
foreach (Statement stmt in method.Body.Body)
{
AddStatement(stmt);
}
instructionProcArgs = null;
stmtExprEnabled = false;
}
bool isRelational = dafnycc.relational && reqs.Concat(enss).ToList().Exists(s =>
s is RtlApply && (((RtlApply)s).op == "public" || ((RtlApply)s).op == "relation"));
bool modifiesIo = Attributes.Contains(method.Attributes, "modifies_io");
string envOther = ", objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, $commonVars:commonVars, $gcVars:gcVars, init:bool, stk:mem, statics:mem, core_state:core_state, ptMem:mem, mems:mems, $stacksFrames:[int]Frames";
string nucArgs = "objLayouts, $S, $toAbs, $absMem, $commonVars, $gcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames";
string envIn = modifiesIo ? ", linear io_old:IOState" + envOther : "";
string envOut = modifiesIo ? ", linear io:IOState" : "";
string pIns = String.Concat(method.Ins.Select(f => ", " + GhostVar(f.Name) + ":" + TypeString(f.Type)));
string pOuts = String.Concat(method.Outs.Select(f => ", " + GhostVar(f.Name) + ":" + TypeString(f.Type)));
envIn += pIns;
envOut += pOuts;
Util.Assert(!isPrinting);
isPrinting = true;
string operandList = String.Concat(parms.Select(p => ", " + p));
iwriter.WriteLine("atomic procedure " + name + "(my r_old:regs" + envIn + operandList + ") returns(my r:regs" + envOut + ");");
Func<string,RtlExp,string> lets_e = (lets, e) =>
!(e is RtlApply) ? lets + e :
((RtlApply)e).op == "public" ? "public(" + lets + ((RtlApply)e).args[0] + ")" :
((RtlApply)e).op == "relation" ? "relation(" + lets + ((RtlApply)e).args[0] + ")" :
lets + e;
if (strictOperands) { opnReqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";")); }
ins.ForEach(p => iwriter.WriteLine(" requires " + GhostVar(p.Item1.Name) + " == " + p.Item2 + ";"));
reqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";"));
if (modifiesIo) { WriteDefaultRelationalRequires(isRelational); }
if (modifiesIo) { iwriter.WriteLine(" requires NucleusInv(" + nucArgs + ", io_old);"); }
GetStaticFieldMods().ForEach(x => iwriter.WriteLine(" modifies " + x + ";"));
enss.ForEach(e => iwriter.WriteLine(" ensures " + e + ";"));
iwriter.WriteLine(" ensures r.regs == r_old.regs" + outRegs + ";");
if (modifiesIo) { WriteDefaultRelationalEnsures(isRelational); }
if (modifiesIo) { iwriter.WriteLine(" ensures NucleusInv(" + nucArgs + ", io);"); }
if (method.Body != null)
{
writer.WriteLine("implementation " + name + "(my r_old:regs" + envIn + operandList + ") returns(my r:regs" + envOut + ")");
writer.WriteLine("{");
WriteAllVars();
writer.WriteLine("r := r_old;");
if (modifiesIo) { writer.WriteLine("io := io_old;"); }
dafnySpec.WriteLemmas(writer, this, visibleModules, method.Attributes);
foreach (RtlStmt s in stmts)
{
writer.WriteLine(s);
}
writer.WriteLine("}");
}
isPrinting = false;
}