public void TypeCheck() { foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "pure")) { continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { Error(proc, "Pure procedure must not yield"); continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "layer")) { Error(proc, "Pure procedure must not have layers"); continue; } if (proc.Modifies.Count > 0) { Error(proc, "Pure procedure must not modify a global variable"); continue; } procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); } foreach (var proc in program.Procedures) { if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { continue; } var procLayerNums = FindLayers(proc.Attributes); if (procLayerNums.Count == 0) { continue; } foreach (IdentifierExpr ie in proc.Modifies) { if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) { Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); continue; } } int lower, upper; if (procLayerNums.Count == 1) { lower = procLayerNums[0]; upper = procLayerNums[0]; } else if (procLayerNums.Count == 2) { lower = procLayerNums[0]; upper = procLayerNums[1]; if (lower >= upper) { Error(proc, "Lower layer must be less than upper layer"); continue; } } else { Error(proc, "Atomic procedure must specify a layer range"); continue; } LayerRange layerRange = new LayerRange(lower, upper); procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(layerRange); } if (errorCount > 0) { return; } foreach (Implementation impl in program.Implementations) { if (!procToAtomicProcedureInfo.ContainsKey(impl.Proc)) { continue; } var atomicProcedureInfo = procToAtomicProcedureInfo[impl.Proc]; if (atomicProcedureInfo.isPure) { this.enclosingImpl = impl; (new PurityChecker(this)).VisitImplementation(impl); } else { this.enclosingImpl = impl; this.sharedVarsAccessed = new HashSet <Variable>(); (new PurityChecker(this)).VisitImplementation(impl); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = atomicProcedureInfo.layerRange; if (!lowerBound.Subset(upperBound)) { Error(impl, "Atomic procedure cannot access global variable"); } this.sharedVarsAccessed = null; } } if (errorCount > 0) { return; } foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { continue; } int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; List <int> attrs = FindLayers(proc.Attributes); if (attrs.Count == 1) { createdAtLayerNum = attrs[0]; } else if (attrs.Count == 2) { createdAtLayerNum = attrs[0]; availableUptoLayerNum = attrs[1]; } else { Error(proc, "Incorrect number of layers"); continue; } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); if (moverType == MoverType.Top) { continue; } CodeExpr codeExpr = e.Condition as CodeExpr; if (codeExpr == null) { Error(e, "An atomic action must be a CodeExpr"); continue; } if (procToActionInfo.ContainsKey(proc)) { Error(proc, "A procedure can have at most one atomic action"); continue; } if (availableUptoLayerNum <= createdAtLayerNum) { Error(proc, "Creation layer number must be less than the available upto layer number"); continue; } sharedVarsAccessed = new HashSet <Variable>(); enclosingProc = proc; enclosingImpl = null; base.VisitEnsures(e); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); if (lowerBound.Subset(upperBound)) { procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); } else { Error(e, "A variable being accessed in this action is unavailable"); } sharedVarsAccessed = null; } if (errorCount > 0) { continue; } if (!procToActionInfo.ContainsKey(proc)) { if (availableUptoLayerNum < createdAtLayerNum) { Error(proc, "Creation layer number must be no more than the available upto layer number"); continue; } else { procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); } } } if (errorCount > 0) { return; } foreach (var impl in program.Implementations) { if (!procToActionInfo.ContainsKey(impl.Proc)) { continue; } ActionInfo actionInfo = procToActionInfo[impl.Proc]; procToActionInfo[impl.Proc].hasImplementation = true; if (actionInfo.isExtern) { Error(impl.Proc, "Extern procedure cannot have an implementation"); } } if (errorCount > 0) { return; } foreach (Procedure proc in procToActionInfo.Keys) { for (int i = 0; i < proc.InParams.Count; i++) { Variable v = proc.InParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < proc.OutParams.Count; i++) { Variable v = proc.OutParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } } foreach (Implementation node in program.Implementations) { if (!procToActionInfo.ContainsKey(node.Proc)) { continue; } foreach (Variable v in node.LocVars) { var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) { continue; } var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { Variable v = node.Proc.OutParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) { continue; } var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(layer); } } if (errorCount > 0) { return; } this.VisitProgram(program); if (errorCount > 0) { return; } YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }
public void TypeCheck() { // Pure procedures foreach (var proc in program.Procedures.Where(proc => proc.IsPure())) { if (proc.IsYield()) { Error(proc, "Pure procedure must not yield"); continue; } if (FindLayers(proc.Attributes).Count != 0) { Error(proc, "Pure procedure must not have layers"); continue; } if (proc.Modifies.Count > 0) { Error(proc, "Pure procedure must not modify a global variable"); continue; } procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); } // Atomic procedures (not yielding) foreach (var proc in program.Procedures.Where(proc => !proc.IsYield())) { var procLayerNums = FindLayers(proc.Attributes); if (procLayerNums.Count == 0) continue; foreach (IdentifierExpr ie in proc.Modifies) { if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) { Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); continue; } } int lower, upper; if (procLayerNums.Count == 1) { lower = procLayerNums[0]; upper = procLayerNums[0]; } else if (procLayerNums.Count == 2) { lower = procLayerNums[0]; upper = procLayerNums[1]; if (lower >= upper) { Error(proc, "Lower layer must be less than upper layer"); continue; } } else { Error(proc, "Atomic procedure must specify a layer range"); continue; } LayerRange layerRange = new LayerRange(lower, upper); procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(layerRange); } if (errorCount > 0) return; // Implementations of atomic procedures foreach (Implementation impl in program.Implementations) { AtomicProcedureInfo atomicProcedureInfo; if (!procToAtomicProcedureInfo.TryGetValue(impl.Proc, out atomicProcedureInfo)) continue; if (atomicProcedureInfo.isPure) { this.enclosingImpl = impl; (new PurityChecker(this)).VisitImplementation(impl); } else { this.enclosingImpl = impl; this.sharedVarsAccessed = new HashSet<Variable>(); (new PurityChecker(this)).VisitImplementation(impl); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = atomicProcedureInfo.layerRange; if (!lowerBound.Subset(upperBound)) { Error(impl, "Atomic procedure cannot access global variable"); } this.sharedVarsAccessed = null; } } if (errorCount > 0) return; // Yielding procedures foreach (var proc in program.Procedures.Where(proc => proc.IsYield())) { int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; List<int> attrs = FindLayers(proc.Attributes); if (attrs.Count == 1) { createdAtLayerNum = attrs[0]; } else if (attrs.Count == 2) { createdAtLayerNum = attrs[0]; availableUptoLayerNum = attrs[1]; } else { Error(proc, "Incorrect number of layers"); continue; } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); if (moverType == MoverType.Top) continue; CodeExpr codeExpr = e.Condition as CodeExpr; if (codeExpr == null) { Error(e, "An atomic action must be a CodeExpr"); continue; } if (procToActionInfo.ContainsKey(proc)) { Error(proc, "A procedure can have at most one atomic action"); continue; } if (availableUptoLayerNum <= createdAtLayerNum) { Error(proc, "Creation layer number must be less than the available upto layer number"); continue; } sharedVarsAccessed = new HashSet<Variable>(); enclosingProc = proc; enclosingImpl = null; base.VisitEnsures(e); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); if (lowerBound.Subset(upperBound)) { procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); } else { Error(e, "A variable being accessed in this action is unavailable"); } sharedVarsAccessed = null; } if (errorCount > 0) continue; if (!procToActionInfo.ContainsKey(proc)) { if (availableUptoLayerNum < createdAtLayerNum) { Error(proc, "Creation layer number must be no more than the available upto layer number"); continue; } else { procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); } } } if (errorCount > 0) return; foreach (var impl in program.Implementations) { if (!procToActionInfo.ContainsKey(impl.Proc)) continue; ActionInfo actionInfo = procToActionInfo[impl.Proc]; procToActionInfo[impl.Proc].hasImplementation = true; if (actionInfo.isExtern) { Error(impl.Proc, "Extern procedure cannot have an implementation"); } } if (errorCount > 0) return; foreach (Procedure proc in procToActionInfo.Keys) { for (int i = 0; i < proc.InParams.Count; i++) { Variable v = proc.InParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < proc.OutParams.Count; i++) { Variable v = proc.OutParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } } foreach (Implementation node in program.Implementations) { if (!procToActionInfo.ContainsKey(node.Proc)) continue; foreach (Variable v in node.LocVars) { var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { Variable v = node.Proc.OutParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) continue; var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(layer); } } if (errorCount > 0) return; this.VisitProgram(program); if (errorCount > 0) return; YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }
public void TypeCheck() { foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "pure")) continue; if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { Error(proc, "Pure procedure must not yield"); continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "layer")) { Error(proc, "Pure procedure must not have layers"); continue; } if (proc.Modifies.Count > 0) { Error(proc, "Pure procedure must not modify a global variable"); continue; } procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); } foreach (var proc in program.Procedures) { if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; var procLayerNums = RemoveDuplicatesAndSort(FindLayers(proc.Attributes)); if (procLayerNums.Count == 0) continue; foreach (IdentifierExpr ie in proc.Modifies) { if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) { Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); } else if (globalVarToSharedVarInfo[ie.Decl].introLayerNum != procLayerNums[0]) { Error(proc, "The introduction layer of a modified global variable must be identical to the layer of the atomic procedure"); } } if (proc.Modifies.Count == 0 || procLayerNums.Count == 1) { procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(new HashSet<int>(procLayerNums)); } else { Error(proc, "An atomic procedure with more than one layer must not modify a global variable"); } } if (errorCount > 0) return; foreach (Implementation impl in program.Implementations) { if (!procToAtomicProcedureInfo.ContainsKey(impl.Proc)) continue; var atomicProcedureInfo = procToAtomicProcedureInfo[impl.Proc]; if (atomicProcedureInfo.isPure) { this.enclosingImpl = impl; (new PurityChecker(this)).VisitImplementation(impl); } else { this.enclosingImpl = impl; this.sharedVarsAccessed = new HashSet<Variable>(); (new PurityChecker(this)).VisitImplementation(impl); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = new LayerRange(atomicProcedureInfo.layers); if (!lowerBound.Subset(upperBound)) { Error(impl, "Atomic procedure cannot access global variable"); } this.sharedVarsAccessed = null; } } if (errorCount > 0) return; foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) continue; int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; List<int> attrs = FindLayers(proc.Attributes); if (attrs.Count == 1) { createdAtLayerNum = attrs[0]; } else if (attrs.Count == 2) { createdAtLayerNum = attrs[0]; availableUptoLayerNum = attrs[1]; } else { Error(proc, "Incorrect number of layers"); continue; } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); if (moverType == MoverType.Top) continue; CodeExpr codeExpr = e.Condition as CodeExpr; if (codeExpr == null) { Error(e, "An atomic action must be a CodeExpr"); continue; } if (procToActionInfo.ContainsKey(proc)) { Error(proc, "A procedure can have at most one atomic action"); continue; } if (availableUptoLayerNum <= createdAtLayerNum) { Error(proc, "Creation layer number must be less than the available upto layer number"); continue; } sharedVarsAccessed = new HashSet<Variable>(); enclosingProc = proc; enclosingImpl = null; base.VisitEnsures(e); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); if (lowerBound.Subset(upperBound)) { procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); } else { Error(e, "A variable being accessed in this action is unavailable"); } sharedVarsAccessed = null; } if (errorCount > 0) continue; if (!procToActionInfo.ContainsKey(proc)) { if (availableUptoLayerNum < createdAtLayerNum) { Error(proc, "Creation layer number must be no more than the available upto layer number"); continue; } else { procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); } } } if (errorCount > 0) return; foreach (Implementation node in program.Implementations) { if (!procToActionInfo.ContainsKey(node.Proc)) continue; foreach (Variable v in node.LocVars) { var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(QKeyValue.FindBoolAttribute(node.Attributes, "ghost"), layer); } for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; var layer = FindLocalVariableLayer(node.Proc, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(false, layer); localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(false, layer); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { Variable v = node.Proc.OutParams[i]; var layer = FindLocalVariableLayer(node.Proc, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) continue; localVarToLocalVariableInfo[v] = new LocalVariableInfo(false, layer); localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(false, layer); } } if (errorCount > 0) return; foreach (var impl in program.Implementations) { if (!procToActionInfo.ContainsKey(impl.Proc)) continue; ActionInfo actionInfo = procToActionInfo[impl.Proc]; procToActionInfo[impl.Proc].hasImplementation = true; if (actionInfo.isExtern) { Error(impl.Proc, "Extern procedure cannot have an implementation"); } } foreach (var g in this.globalVarToSharedVarInfo.Keys) { var info = globalVarToSharedVarInfo[g]; if (!this.AllCreatedLayerNums.Contains(info.introLayerNum)) { Error(g, "Variable must be introduced with creation of some atomic action"); } if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum)) { Error(g, "Variable must be hidden with creation of some atomic action"); } } if (errorCount > 0) return; this.VisitProgram(program); if (errorCount > 0) return; YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }