protected override void GenerateConvertGhosts_LH() { var ps = new List <string>(); foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) { var v = pgp.symbolsLow.Globals.Lookup(varName); if (v == null) { v = pgp.symbolsHigh.Globals.Lookup(varName); if (v is GlobalGhostArmadaVariable ghost) { var p = ResolveInit(ghost.initialValue); if (p == null) { AH.PrintError(pgp.prog, $"Introduced ghost variable {varName} must be initialized"); } ps.Add(p); } } else if (v is GlobalGhostArmadaVariable) { ps.Add($"ghosts.{v.FieldName}"); } } var fn = $@" function ConvertGhosts_LH(ghosts: L.Armada_Ghosts) : H.Armada_Ghosts {{ H.Armada_Ghosts({AH.CombineStringsWithCommas(ps)}) }} "; pgp.AddFunction(fn, "convert"); }
public override void GenerateProof() { if (!CheckEquivalence()) { AH.PrintError(pgp.prog, "Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy"); return; } AddIncludesAndImports(); GeneratePCFunctions_L(); MakeTrivialPCMap(); GenerateNextRoutineMap(); GenerateProofHeader(); GenerateAtomicSpecs(); GenerateInvariantProof(pgp); GenerateStateAbstractionFunctions_LH(); GenerateConvertStep_LH(); GenerateConvertAtomicPath_LH(); GenerateLocalViewCommutativityLemmas(); GenerateLiftingRelation(); GenerateLiftAtomicPathLemmas(); GenerateEstablishInitRequirementsLemma(); GenerateEstablishStateOKRequirementLemma(); GenerateEstablishRelationRequirementLemma(); GenerateEstablishAtomicPathLiftableLemma(); GenerateEstablishAtomicPathsLiftableLemma(false, false); GenerateLiftLAtomicToHAtomicLemma(false, false); GenerateFinalProof(); }
protected override void GenerateConvertGhosts_HL() { var ps = new List <string>(); foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) { if (introducedVariables.Contains(varName)) { continue; } var v = pgp.symbolsHigh.Globals.Lookup(varName); if (v is GlobalGhostArmadaVariable) { ps.Add($"ghosts.{v.FieldName}"); } } var fn = $@" function ConvertGhosts_HL(ghosts: H.Armada_Ghosts) : L.Armada_Ghosts {{ L.Armada_Ghosts({AH.CombineStringsWithCommas(ps)}) }} "; pgp.AddFunction(fn, "convert"); }
public override Expression GetStoreBufferLocationInfo(ref List <Expression> fields) { if (parent.NoTSO()) { return(null); } if (parent is GlobalsArmadaLValue) { return(AH.MakeNameSegment($"Armada_GlobalStaticVar_{fieldName}", "Armada_GlobalStaticVar")); } else if (!(parent.Type is UserDefinedType)) { return(null); } else { var ut = (UserDefinedType)parent.Type; var ret = parent.GetStoreBufferLocationInfo(ref fields); if (ret == null) { return(null); } var struct_field_type = AH.MakeNameSegment($"Armada_FieldType_{ut.Name}'{fieldName}", "Armada_FieldType"); var field = AH.MakeApply1("Armada_FieldStruct", struct_field_type, "Armada_Field"); fields.Add(field); return(ret); } }
private void GenerateCombiningRequest() { var acrequest = AH.MakeGenericTypeSpecific("ArmadaCombiningRequest", new List <Type> { AH.ReferToType("LPlusState"), AH.ReferToType("L.Armada_TraceEntry"), AH.ReferToType("L.Armada_PC"), AH.ReferToType("HState"), AH.ReferToType("H.Armada_TraceEntry"), AH.ReferToType("H.Armada_PC") }); pgp.MainProof.AddTypeSynonymDecl("ACRequest", acrequest); string str = @" function GetArmadaCombiningRequest() : ACRequest { ArmadaCombiningRequest(LPlus_GetSpecFunctions(), H.Armada_GetSpecFunctions(), GetLPlusHRefinementRelation(), InductiveInv, ConvertTotalState_LPlusH, ConvertTraceEntry_LH, ConvertPC_LH, IsInnerPC) } "; pgp.AddFunction(str); }
public override Expression GetValueInLValueState(ResolutionContext context) { var s = context.GetLValueState(); var mem = AH.MakeExprDotName(s, "mem", "Armada_SharedMemory"); return(AH.MakeExprDotName(mem, "globals", "Armada_Globals")); }
public override Expression UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector, Expression val_new) { var s = context.GetLValueState(); return(AH.MakeDatatypeUpdateExpr(s, "ghosts", val_new)); }
public override ArmadaLValue ApplyExprDotName(IToken i_tok, ResolutionContext context, string fieldName, Type ty) { if (!(type is UserDefinedType)) { context.Fail(i_tok, $"Attempt to take a field ({fieldName}) of non-struct, non-datatype type {type}"); return(null); } UserDefinedType ut = (UserDefinedType)type; if (context.symbols.DoesStructExist(ut.Name)) { Type fieldType = context.symbols.GetStructFieldType(ut.Name, fieldName); if (fieldType == null) { context.Fail(i_tok, $"Attempt to take non-existent field ({fieldName}) in struct type {ut.Name}"); return(null); } if (!AH.TypesMatch(fieldType, ty)) { context.Fail(i_tok, $"Field {fieldName} of type {fieldType} used as type {ty}"); return(null); } } return(new UnaddressableFieldArmadaLValue(i_tok, ty, this, crashAvoidance, fieldName, false)); }
public override ArmadaLValue ApplySeqSelect(IToken i_tok, ResolutionContext context, ArmadaRValue idx1, Type ty) { if (!(type is SizedArrayType)) { context.Fail(i_tok, "Attempt to obtain element of non-array type"); return(null); } SizedArrayType st = (SizedArrayType)type; if (!AH.TypesMatch(st.Range, ty)) { context.Fail(i_tok, $"Element of type {st.Range} used as type {ty}"); return(null); } var crashAvoidance = address.UndefinedBehaviorAvoidance + idx1.UndefinedBehaviorAvoidance; var s = context.GetLValueState(); var mem = AH.MakeExprDotName(s, "mem", "Armada_SharedMemory"); var h = AH.MakeExprDotName(mem, "heap", "Armada_Heap"); var tree = AH.MakeExprDotName(h, "tree", "Armada_Tree"); crashAvoidance.Add(AH.MakeInExpr(address.Val, tree)); var node = AH.MakeSeqSelectExpr(tree, address.Val, "Armada_Node"); var children = AH.MakeExprDotName(node, "children", AH.MakeChildrenType()); var idx1_as_int = AH.ConvertToIntIfNotInt(idx1.Val); var field = AH.MakeApply1("Armada_FieldArrayIndex", idx1_as_int, "Armada_Field"); var child = AH.MakeSeqSelectExpr(children, field, new PointerType(st.Range)); crashAvoidance.Add(AH.MakeInExpr(field, children)); return(new AddressableArmadaLValue(i_tok, st.Range, new ArmadaRValue(crashAvoidance, child))); }
public override Expression UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector, Expression val_new) { var s = context.GetLValueState(); var mem = AH.MakeExprDotName(s, "mem", "Armada_SharedMemory"); var h = AH.MakeExprDotName(mem, "heap", "Armada_Heap"); var valid = AH.GetInvocationOfValidPointer(h, address.Val, type); if (valid == null) { constraintCollector.Fail(tok, $"Type {type} is currently not supported in the heap"); } else { constraintCollector.AddUndefinedBehaviorAvoidanceConstraint(valid); } var h_new = AH.GetInvocationOfUpdatePointer(h, address.Val, val_new); if (h_new == null) { constraintCollector.Fail(tok, $"Type {type} is currently not supported in the heap"); } var mem_new = AH.MakeDatatypeUpdateExpr(mem, "heap", h_new); return(AH.MakeDatatypeUpdateExpr(s, "mem", mem_new)); }
private string InsertExtraMaterial(string name, string contents, int minPos = 0) { // Remove any "ProofCustomizationGoesHere();" and note its position. int insertionPos = contents.IndexOf("ProofCustomizationGoesHere();", minPos); if (insertionPos >= 0) { contents = contents.Substring(0, insertionPos) + contents.Substring(insertionPos + 29); } if (extraMaterial.ContainsKey(name)) { string extra = extraMaterial[name]; // If there was no "ProofCustomizationGoesHere();", use the position right after the first open brace. if (insertionPos < 0) { var bracePos = contents.IndexOf("{", minPos); if (bracePos < 0) { AH.PrintError(prog, $"Could not find place in contents of {name} to insert extra material"); return(contents); } insertionPos = bracePos + 1; } return(contents.Substring(0, insertionPos) + "\n" + extra + "\n" + contents.Substring(insertionPos)); } else { return(contents); } }
public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context) { var globals = context.GetRValueGlobals(); var val = AH.MakeExprDotName(globals, name, ty); return(new ArmadaRValue(val)); }
public Expression Extract(Expression extra) { Expression e; if (extra != null) { var conjunctsPlusExtra = new List <Expression>(conjuncts); conjunctsPlusExtra.Add(extra); e = AH.CombineExpressionsWithAnd(conjunctsPlusExtra); } else { if (conjuncts.Count == 0) { return(null); } e = AH.CombineExpressionsWithAnd(conjuncts); } for (int i = variableNames.Count - 1; i >= 0; --i) { e = AH.MakeLet1Expr(variableNames[i], variableValues[i], e); } return(e); }
public ArmadaStruct(Program prog, ClassDecl c) { name = c.Name; fieldTypes = new Dictionary <string, Type>(); fieldNames = new List <string>(); foreach (MemberDecl member in c.Members) { if (member is Field) { var f = (Field)member; if (!f.IsStatic) { fieldNames.Add(f.Name); fieldTypes[f.Name] = f.Type; if (f.InitialValue != null) { AH.PrintError(prog, $"Ignoring initializer {f.InitialValue} of field {f.Name} of struct {name}"); } } else { AH.PrintError(prog, $"Ignoring static field {f.Name} in struct"); } } } }
public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector, string val_new) { var s = context.GetLValueState(); var h = $"({s}).mem.heap"; var valid = AH.GetInvocationOfValidPointer(h, address.Val, type); if (valid == null) { constraintCollector.Fail(tok, $"Type {type} is currently not supported in the heap"); } else { constraintCollector.AddUndefinedBehaviorAvoidanceConstraint(valid); } var h_new = AH.GetInvocationOfUpdatePointer(h, address.Val, val_new, type); if (h_new == null) { constraintCollector.Fail(tok, $"Type {type} is currently not supported in the heap"); } return($"{s}.(mem := {s}.mem.(heap := {h_new}))"); }
//////////////////////////////////////////////////////////////////////// /// Checking that the layers are similar enough to generate a proof //////////////////////////////////////////////////////////////////////// // We have to override the default implementation of CheckGlobalsEquivalence because we need to // skip hidden variables. protected override bool CheckGlobalsEquivalence() { var globalVarsLow = pgp.symbolsLow.Globals.VariableNames.Where(s => !hiddenVariables.Contains(s)).ToArray(); var globalVarsHigh = pgp.symbolsHigh.Globals.VariableNames.ToArray(); if (globalVarsLow.Length != globalVarsHigh.Length) { AH.PrintError(pgp.prog, $"There are {globalVarsLow.Length} global variables in level {pgp.mLow.Name} (not counting hidden ones) but {globalVarsHigh.Length} in level {pgp.mHigh.Name}"); return(false); } for (int i = 0; i < globalVarsLow.Length; ++i) { if (globalVarsLow[i] != globalVarsHigh[i]) { AH.PrintError(pgp.prog, $"Global variable number {i+1} (not counting hidden ones) in level {pgp.mLow.Name} is {globalVarsLow[i]}, which doesn't match global variable number {i+1} in level {pgp.mHigh.Name} which is {globalVarsHigh[i]}"); return(false); } var name = globalVarsLow[i]; if (!CheckGlobalVariableEquivalence(name, pgp.symbolsLow.Globals.Lookup(name), pgp.symbolsHigh.Globals.Lookup(name))) { return(false); } } return(true); }
//////////////////////////////////////////////////////////////////////// /// Abstraction functions //////////////////////////////////////////////////////////////////////// protected override void GenerateConvertGlobals_LH() { var ps = new List <string>(); foreach (var varName in pgp.symbolsLow.Globals.VariableNames) { if (hiddenVariables.Contains(varName)) { continue; } var v = pgp.symbolsLow.Globals.Lookup(varName); if (v is GlobalUnaddressableArmadaVariable) { ps.Add($"globals.{v.FieldName}"); } } var fn = $@" function ConvertGlobals_LH(globals: L.Armada_Globals) : H.Armada_Globals {{ H.Armada_Globals({AH.CombineStringsWithCommas(ps)}) }} "; pgp.AddFunction(fn, "convert"); }
public override void GenerateProof() { if (!CheckEquivalence()) { AH.PrintError(pgp.prog, "Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy"); return; } GetWeakenedPCSet(); AddIncludesAndImports(); MakeTrivialPCMap(); GenerateNextRoutineMap(); GenerateProofHeader(); GenerateStarWeakeningRequest(); GenerateStateAbstractionFunctions_LH(); GeneratePCFunctions_L(); foreach (var globalVarName in strategy.GlobalVars) { GenerateNoStoreBufferEntriesLemmas(globalVarName); } GenerateConvertTraceEntry_LH(); GenerateStepRefiner(); GenerateLocalViewCommutativityLemmas(); GenerateLiftNextLemmas(); GenerateAllActionsLiftableWeakenedLemmas(); GenerateInitStatesEquivalentLemma(); GenerateIsInvariantPredicateLemma(); GenerateFinalProof(); }
private void ExtractOldVariablesForBodylessMethod(Program prog, ArmadaSymbolTable symbols, Method meth, ArmadaSingleMethodSymbolTable smst) { if (meth.Ens == null) { return; } if (!meth.Ens.Any()) { return; } var s = AH.MakeNameSegment("s", "Armada_TotalState"); var tid = AH.MakeNameSegment("tid", "Armada_ThreadHandle"); var failureCollector = new SimpleFailureReporter(prog); var ensContext = new BodylessMethodSnapshotResolutionContext(s, tid, meth.Name, symbols, failureCollector); foreach (var ens in meth.Ens) { var ensResolvedJustToGetOldValues = ensContext.ResolveAsRValue(ens.E); } int whichOldValue = 0; foreach (var oldValue in ensContext.OldValues) { var varName = $"Armada_Old{whichOldValue}"; var v = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, oldValue.Type, oldValue, ArmadaVarType.ExternOld, meth.Name); ++whichOldValue; smst.AddVariable(prog, v); } }
protected override void GenerateConvertStackFrame_HL() { var cases = new List <MatchCaseExpr>(); var methodNames = pgp.symbolsHigh.MethodNames; foreach (var methodName in methodNames) { var smst = pgp.symbolsHigh.GetMethodSymbolTable(methodName); var ps = new List <Expression>(); var bvs = new List <BoundVar>(); foreach (var v in smst.AllVariablesInOrder) { var ty = (v is AddressableArmadaVariable) ? AH.ReferToType("Armada_Pointer") : v.ty; var e = AH.MakeNameSegment(v.FieldName, ty); if (methodName != strategy.MethodName || v.name != strategy.VariableName) { ps.Add(e); } var bv = AH.MakeBoundVar(v.FieldName, v.GetFlattenedType(pgp.symbolsHigh)); bvs.Add(bv); } var case_body = AH.MakeApplyN($"L.Armada_StackFrame_{methodName}", ps, "L.Armada_StackFrame"); cases.Add(AH.MakeMatchCaseExpr($"Armada_StackFrame_{methodName}", bvs, case_body)); } var source = AH.MakeNameSegment("frame", "H.Armada_StackFrame"); var body = AH.MakeMatchExpr(source, cases, "L.Armada_StackFrame"); var formals = new List <Formal> { AH.MakeFormal("frame", "H.Armada_StackFrame") }; var fn = AH.MakeFunction("ConvertStackFrame_HL", formals, body); pgp.AddDefaultClassDecl(fn, "convert"); }
public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context) { var top = context.GetRValueTopStackFrame(); var correct_frame_type = AH.MakeExprDotName(top, $"Armada_StackFrame_{methodName}?", new BoolType()); var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint(correct_frame_type); var addr = AH.MakeExprDotName(top, $"{methodName}'AddrOf'{name}", new PointerType(ty)); var h = context.GetRValueHeap(); var valid = AH.GetInvocationOfValidPointer(h, addr, ty); if (valid == null) { context.Fail(tok, "Type {ty} is not supported on the heap, and thus not for addressable stack variables either"); return(null); } crashAvoidance.Add(valid); var val = AH.GetInvocationOfDereferencePointer(h, addr, ty); if (val == null) { context.Fail(tok, "Type {ty} is not supported on the heap, and thus not for addressable stack variables either"); } return(new ArmadaRValue(crashAvoidance, val)); }
public void AddClassInfo(Program prog, ClassDecl c) { if (!c.IsDefaultClass) { AH.PrintError(prog, "Internal error: ArmadaGlobalVariableSymbolTable.AddClassInfo called on non-default class"); return; } foreach (MemberDecl member in c.Members) { if (member is Field) { var f = (Field)member; variableNames.Add(f.Name); ArmadaVariable av = null; if (f.IsGhost) { av = new GlobalGhostArmadaVariable(f.Name, f.Type, f.InitialValue); } else if (f.IsNoAddr) { av = new GlobalUnaddressableArmadaVariable(f.Name, f.Type, f.InitialValue); } else { av = new GlobalAddressableArmadaVariable(f.Name, f.Type, f.InitialValue); } table.Add(f.Name, av); } } }
public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context) { var s = context.GetRValueState(); var addrs = AH.MakeExprDotName(s, "addrs", "Armada_Addrs"); var addr = AH.MakeExprDotName(addrs, name, new PointerType(ty)); var h = context.GetRValueHeap(); var valid = AH.GetInvocationOfValidPointer(h, addr, ty); if (valid == null) { context.Fail(tok, "Type {ty} is currently not supported in the heap"); return(null); } var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint(valid); var val = AH.GetInvocationOfDereferencePointer(h, addr, ty); if (val == null) { context.Fail(tok, "Type {ty} is currently not supported in the heap"); } return(new ArmadaRValue(crashAvoidance, val)); }
public override ArmadaLValue ApplySeqSelect(IToken i_tok, ResolutionContext context, ArmadaRValue idx1, Type indexType, Type exprType) { if (!(type is SizedArrayType)) { context.Fail(i_tok, "Attempt to obtain element of non-array type"); return(null); } SizedArrayType st = (SizedArrayType)type; if (!AH.TypesMatch(st.Range, exprType)) { context.Fail(i_tok, $"Element of type {st.Range} used as type {exprType}"); return(null); } var crashAvoidance = address.UndefinedBehaviorAvoidance + idx1.UndefinedBehaviorAvoidance; var s = context.GetLValueState(); var h = $"({s}).mem.heap"; var idx1_as_int = AH.ConvertToIntIfNotInt(idx1.Val, indexType); crashAvoidance.Add($"{address.Val} in {h}.tree"); crashAvoidance.Add($"0 <= {idx1_as_int} < |{h}.tree[{address.Val}].children|"); var child = $"{h}.tree[{address.Val}].children[{idx1_as_int}]"; return(new AddressableArmadaLValue(i_tok, st.Range, new ArmadaRValue(crashAvoidance, child))); }
public Expression AddVariableDeclaration(string varName, Expression value) { if (!valid) { Debug.Assert(false); return(null); } int count; if (variableUseCount.TryGetValue(varName, out count)) { variableUseCount[varName] = count + 1; varName = $"{varName}{count+1}"; } else { variableUseCount[varName] = 1; } var block = new PredicateBuilderBlock(); block.AddVariableDeclaration(varName, value); blocks.Insert(0, block); return(AH.MakeNameSegment(varName, value.Type)); }
protected override void GenerateConvertAtomicPath_LH() { string str; var skipped_strs = new List <string>(); if (canHideTau) { str = @" predicate IsSkippedTauPath(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle) { && path.LAtomic_Path_Tau? && tid in s.s.threads && |s.s.threads[tid].storeBuffer| > 0 && !CanConvertStoreBufferEntry_LH(s.s.threads[tid].storeBuffer[0]) } "; pgp.AddPredicate(str, "convert"); skipped_strs.Add("IsSkippedTauPath(s, path, tid)"); } string convert_str = @" function ConvertAtomicPath_LH(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle) : HAtomic_Path requires LAtomic_ValidPath(s, path, tid) requires !IsSkippedPath(s, path, tid) { match path "; foreach (var lpath in lAtomic.AtomicPaths) { if (pathMap.ContainsKey(lpath)) { var hpath = pathMap[lpath]; var n = lpath.NextRoutines.Count; convert_str += $"case LAtomic_Path_{lpath.Name}(steps) => HAtomic_Path_{hpath.Name}(HAtomic_PathSteps_{hpath.Name}("; convert_str += String.Join(", ", Enumerable.Range(0, n) .Where(i => nextRoutineMap.ContainsKey(lpath.NextRoutines[i])) .Select(i => $"ConvertStep_LH(steps.step{i})")); convert_str += "))\n"; } else { skipped_strs.Add($"path.LAtomic_Path_{lpath.Name}?"); } } convert_str += "}\n"; pgp.AddPredicate($@" predicate IsSkippedPath(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle) {{ { AH.CombineStringsWithOr(skipped_strs) } }} ", "convert"); pgp.AddFunction(convert_str, "convert"); }
public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context) { var top = context.GetLValueTopStackFrame(); var correct_frame_type = AH.MakeExprDotName(top, $"Armada_StackFrame_{methodName}?", new BoolType()); var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint(correct_frame_type); return(new UnaddressableFieldArmadaLValue(tok, ty, new TopStackFrameArmadaLValue(crashAvoidance), crashAvoidance, $"{methodName}'{name}", true)); }
public void UseMethodAsThreadRoutine(string methodName) { if (allMethodsInfo.LookupMethod(methodName).AtomicCallsAndReturns) { AH.PrintError(prog, $"It's illegal to use create_thread on {methodName} since it uses atomic calls and returns."); } threadRoutines.Add(methodName); }
public void Fail(IToken tok, string reason) { valid = false; if (reason != null) { AH.PrintError(prog, tok, reason); } }
public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context) { var s = context.GetLValueState(); var addrs = AH.MakeExprDotName(s, "addrs", "Armada_Addrs"); var addr = AH.MakeExprDotName(addrs, name, new PointerType(ty)); return(new AddressableArmadaLValue(tok, ty, new ArmadaRValue(addr))); }