public override Variable VisitVariable(Variable node) { string domainName = FindDomainName(node); if (domainName != null) { varToDomainName[node] = domainName; LinearKind kind = FindLinearKind(node); if (kind != LinearKind.LINEAR) { if (node is GlobalVariable || node is LocalVariable || (node is Formal formal && !formal.InComing)) { Error(node, "Variable must be declared linear (as opposed to linear_in or linear_out)"); } } } return base.VisitVariable(node); }
public LinearQualifier(string domainName, LinearKind kind) { this.domainName = domainName; this.kind = kind; }
private HashSet<Variable> PropagateAvailableLinearVarsAcrossBlock(Block b) { HashSet<Variable> start = new HashSet<Variable>(availableLinearVars[b]); foreach (Cmd cmd in b.Cmds) { if (cmd is AssignCmd assignCmd) { for (int i = 0; i < assignCmd.Lhss.Count; i++) { if (FindDomainName(assignCmd.Lhss[i].DeepAssignedVariable) == null) continue; IdentifierExpr ie = assignCmd.Rhss[i] as IdentifierExpr; if (!start.Contains(ie.Decl)) { Error(ie, "unavailable source for a linear read"); } else { start.Remove(ie.Decl); } } foreach (AssignLhs assignLhs in assignCmd.Lhss) { if (FindDomainName(assignLhs.DeepAssignedVariable) == null) continue; start.Add(assignLhs.DeepAssignedVariable); } } else if (cmd is CallCmd callCmd) { foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) { Error(cmd, $"Global variable {g.Name} must be available at a call"); } for (int i = 0; i < callCmd.Proc.InParams.Count; i++) { Variable param = callCmd.Proc.InParams[i]; if (FindDomainName(param) == null) continue; IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; LinearKind paramKind = FindLinearKind(param); if (start.Contains(ie.Decl)) { if (callCmd.IsAsync || paramKind == LinearKind.LINEAR_IN) { start.Remove(ie.Decl); } } else { if (paramKind == LinearKind.LINEAR_OUT) { start.Add(ie.Decl); } else { Error(ie, "unavailable source for a linear read"); } } } AddAvailableVars(callCmd, start); availableLinearVars[callCmd] = new HashSet<Variable>(start); } else if (cmd is ParCallCmd parCallCmd) { foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) { Error(cmd, $"Global variable {g.Name} must be available at a call"); } foreach (CallCmd parCallCallCmd in parCallCmd.CallCmds) { for (int i = 0; i < parCallCallCmd.Proc.InParams.Count; i++) { Variable param = parCallCallCmd.Proc.InParams[i]; if (FindDomainName(param) == null) continue; IdentifierExpr ie = parCallCallCmd.Ins[i] as IdentifierExpr; LinearKind paramKind = FindLinearKind(param); if (start.Contains(ie.Decl)) { if (paramKind == LinearKind.LINEAR_IN) { start.Remove(ie.Decl); } } else { if (paramKind == LinearKind.LINEAR_OUT) { start.Add(ie.Decl); } else { Error(ie, "unavailable source for a linear read"); } } } } AddAvailableVars(parCallCmd, start); availableLinearVars[parCallCmd] = new HashSet<Variable>(start); } else if (cmd is HavocCmd havocCmd) { foreach (IdentifierExpr ie in havocCmd.Vars) { if (FindDomainName(ie.Decl) == null) continue; start.Remove(ie.Decl); } } else if (cmd is YieldCmd) { foreach (GlobalVariable g in globalVarToDomainName.Keys.Except(start)) { Error(cmd, $"Global variable {g.Name} must be available at a yield"); } availableLinearVars[cmd] = new HashSet<Variable>(start); } } return start; }