From 252912e27601128555efddd88d2312d6c01a548f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Thu, 15 Jun 2023 14:37:26 +0800 Subject: [PATCH] Generating more instructions --- .../org/lflang/analyses/evm/Instruction.java | 14 +++- .../lflang/analyses/evm/InstructionBIT.java | 7 ++ .../lflang/analyses/evm/InstructionDU.java | 19 +++++ .../lflang/analyses/evm/InstructionEIT.java | 11 +-- .../lflang/analyses/evm/InstructionEXE.java | 11 +-- .../analyses/evm/InstructionGenerator.java | 72 ++++++++++++++++--- .../lflang/analyses/evm/InstructionINC2.java | 7 ++ .../lflang/analyses/evm/InstructionJMP.java | 7 ++ .../lflang/analyses/evm/InstructionSAC.java | 7 ++ .../lflang/analyses/evm/InstructionSTP.java | 7 ++ .../lflang/analyses/evm/InstructionWU.java | 23 ++++++ .../generator/c/CStaticScheduleGenerator.java | 2 +- 12 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionBIT.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionDU.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionINC2.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionJMP.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionSAC.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionSTP.java create mode 100644 core/src/main/java/org/lflang/analyses/evm/InstructionWU.java diff --git a/core/src/main/java/org/lflang/analyses/evm/Instruction.java b/core/src/main/java/org/lflang/analyses/evm/Instruction.java index 27f82e1579..ae82218d62 100644 --- a/core/src/main/java/org/lflang/analyses/evm/Instruction.java +++ b/core/src/main/java/org/lflang/analyses/evm/Instruction.java @@ -1,6 +1,6 @@ package org.lflang.analyses.evm; -public interface Instruction { +abstract public class Instruction { /** VM Instruction Set */ public enum Opcode { @@ -26,5 +26,15 @@ public enum Opcode { WU, // WU rs1, rs2 : Wait Until a counting variable (rs1) to reach a desired value (rs2). } - public Opcode getOpcode(); + /** Opcode of this instruction */ + protected Opcode opcode; + + /** A getter of the opcode */ + public Opcode getOpcode() { + return this.opcode; + } + + public String toString() { + return opcode.toString(); + } } diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionBIT.java b/core/src/main/java/org/lflang/analyses/evm/InstructionBIT.java new file mode 100644 index 0000000000..d38a6d8815 --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionBIT.java @@ -0,0 +1,7 @@ +package org.lflang.analyses.evm; + +public class InstructionBIT extends Instruction { + public InstructionBIT() { + this.opcode = Opcode.BIT; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionDU.java b/core/src/main/java/org/lflang/analyses/evm/InstructionDU.java new file mode 100644 index 0000000000..f534785807 --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionDU.java @@ -0,0 +1,19 @@ +package org.lflang.analyses.evm; + +import org.lflang.TimeValue; + +public class InstructionDU extends Instruction { + + /** The physical time point to delay until */ + TimeValue releaseTime; + + public InstructionDU(TimeValue releaseTime) { + this.opcode = Opcode.DU; + this.releaseTime = releaseTime; + } + + @Override + public String toString() { + return "DU: " + releaseTime; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionEIT.java b/core/src/main/java/org/lflang/analyses/evm/InstructionEIT.java index 4ae7c42815..791f2429b7 100644 --- a/core/src/main/java/org/lflang/analyses/evm/InstructionEIT.java +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionEIT.java @@ -2,24 +2,17 @@ import org.lflang.generator.ReactionInstance; -public class InstructionEIT implements Instruction { - - /** Opcode of this instruction */ - private final Opcode opcode = Opcode.EIT; +public class InstructionEIT extends Instruction { /** Reaction to be executed */ public ReactionInstance reaction; /** Constructor */ public InstructionEIT(ReactionInstance reaction) { + this.opcode = Opcode.EIT; this.reaction = reaction; } - @Override - public Opcode getOpcode() { - return this.opcode; - } - @Override public String toString() { return opcode + ": " + this.reaction; diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionEXE.java b/core/src/main/java/org/lflang/analyses/evm/InstructionEXE.java index 08e88b3c55..88f53c4edd 100644 --- a/core/src/main/java/org/lflang/analyses/evm/InstructionEXE.java +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionEXE.java @@ -2,24 +2,17 @@ import org.lflang.generator.ReactionInstance; -public class InstructionEXE implements Instruction { - - /** Opcode of this instruction */ - private final Opcode opcode = Opcode.EXE; +public class InstructionEXE extends Instruction { /** Reaction to be executed */ public ReactionInstance reaction; /** Constructor */ public InstructionEXE(ReactionInstance reaction) { + this.opcode = Opcode.EXE; this.reaction = reaction; } - @Override - public Opcode getOpcode() { - return this.opcode; - } - @Override public String toString() { return opcode + ": " + this.reaction; diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionGenerator.java b/core/src/main/java/org/lflang/analyses/evm/InstructionGenerator.java index 321df9d5c8..1942c366d8 100644 --- a/core/src/main/java/org/lflang/analyses/evm/InstructionGenerator.java +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionGenerator.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Map; import java.util.Queue; + +import org.lflang.TargetConfig; import org.lflang.analyses.dag.Dag; import org.lflang.analyses.dag.DagEdge; import org.lflang.analyses.dag.DagNode; @@ -18,6 +20,8 @@ public class InstructionGenerator { /** A partitioned Dag */ Dag dag; + TargetConfig targetConfig; + /** Number of workers */ int workers; @@ -25,9 +29,10 @@ public class InstructionGenerator { List> instructions; /** Constructor */ - public InstructionGenerator(Dag dagParitioned, int workers) { + public InstructionGenerator(Dag dagParitioned, TargetConfig targetConfig) { this.dag = dagParitioned; - this.workers = workers; + this.targetConfig = targetConfig; + this.workers = targetConfig.workers; // Initialize instructions array. instructions = new ArrayList<>(); @@ -45,6 +50,13 @@ public void generate() { // Debug int count = 0; + // If timeout is specified, add BIT instructions. + if (this.targetConfig.timeout != null) { + for (var schedule : instructions) { + schedule.add(new InstructionBIT()); + } + } + // Initialize indegree of all nodes to be the size of their respective upstream node set. for (DagNode node : dag.dagNodes) { indegree.put(node, dag.dagEdgesRev.getOrDefault(node, new HashMap<>()).size()); @@ -63,19 +75,55 @@ public void generate() { current.setDotDebugMsg("count: " + count++); System.out.println("Current: " + current); - /* Generate instructions for the current node */ // Get the upstream nodes. - List upstream = - dag.dagEdgesRev.getOrDefault(current, new HashMap<>()).keySet().stream().toList(); - System.out.println("Upstream: " + upstream); + List upstreamReactionNodes = dag.dagEdgesRev + .getOrDefault(current, new HashMap<>()) + .keySet().stream() + .filter(n -> n.nodeType == dagNodeType.REACTION) + .toList(); + System.out.println("Upstream: " + upstreamReactionNodes); - // If the reaction is triggered by a timer, - // generate an EXE instructions. - // FIXME: Handle a reaction triggered by timers and ports. + /* Generate instructions for the current node */ if (current.nodeType == dagNodeType.REACTION) { ReactionInstance reaction = current.getReaction(); + + // If the reaction is triggered by a timer, + // generate an EXE instruction. + // FIXME: Handle a reaction triggered by both timers and ports. if (reaction.triggers.stream().anyMatch(trigger -> trigger instanceof TimerInstance)) { instructions.get(current.getWorker()).add(new InstructionEXE(reaction)); + instructions.get(current.getWorker()).add(new InstructionINC2()); + } + // Otherwise, generate an EIT instruction. + else { + // If the reaction depends on upstream reactions owned by other + // workers, generate WU instructions to resolve the dependencies. + for (DagNode n : upstreamReactionNodes) { + int upstreamOwner = n.getWorker(); + if (upstreamOwner != current.getWorker()) { + instructions.get(current.getWorker()).add( + new InstructionWU( + upstreamOwner, + n.nodeReaction + )); + } + } + + instructions.get(current.getWorker()).add(new InstructionEIT(reaction)); + instructions.get(current.getWorker()).add(new InstructionINC2()); + } + } + else if (current.nodeType == dagNodeType.SYNC) { + if (current != dag.head && current != dag.tail) { + for (DagNode n : upstreamReactionNodes) { + instructions.get(n.getWorker()).add(new InstructionDU(current.timeStep)); + } + } + else if (current == dag.tail) { + for (var schedule : instructions) { + schedule.add(new InstructionSAC()); + schedule.add(new InstructionDU(current.timeStep)); + } } } @@ -101,6 +149,12 @@ public void generate() { throw new RuntimeException( "The graph has at least one cycle, thus cannot be topologically sorted."); } + + // Add JMP and STP instructions. + for (var schedule : instructions) { + schedule.add(new InstructionJMP()); + schedule.add(new InstructionSTP()); + } } public Dag getDag() { diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionINC2.java b/core/src/main/java/org/lflang/analyses/evm/InstructionINC2.java new file mode 100644 index 0000000000..2ade6e297a --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionINC2.java @@ -0,0 +1,7 @@ +package org.lflang.analyses.evm; + +public class InstructionINC2 extends Instruction { + public InstructionINC2() { + this.opcode = Opcode.INC2; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionJMP.java b/core/src/main/java/org/lflang/analyses/evm/InstructionJMP.java new file mode 100644 index 0000000000..f0ab03ed1a --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionJMP.java @@ -0,0 +1,7 @@ +package org.lflang.analyses.evm; + +public class InstructionJMP extends Instruction { + public InstructionJMP() { + this.opcode = Opcode.JMP; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionSAC.java b/core/src/main/java/org/lflang/analyses/evm/InstructionSAC.java new file mode 100644 index 0000000000..6bfac6c8ec --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionSAC.java @@ -0,0 +1,7 @@ +package org.lflang.analyses.evm; + +public class InstructionSAC extends Instruction { + public InstructionSAC() { + this.opcode = Opcode.SAC; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionSTP.java b/core/src/main/java/org/lflang/analyses/evm/InstructionSTP.java new file mode 100644 index 0000000000..323aec955a --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionSTP.java @@ -0,0 +1,7 @@ +package org.lflang.analyses.evm; + +public class InstructionSTP extends Instruction { + public InstructionSTP() { + this.opcode = Opcode.STP; + } +} diff --git a/core/src/main/java/org/lflang/analyses/evm/InstructionWU.java b/core/src/main/java/org/lflang/analyses/evm/InstructionWU.java new file mode 100644 index 0000000000..77a6e6bf37 --- /dev/null +++ b/core/src/main/java/org/lflang/analyses/evm/InstructionWU.java @@ -0,0 +1,23 @@ +package org.lflang.analyses.evm; + +import org.lflang.generator.ReactionInstance; + +public class InstructionWU extends Instruction { + + /** The reaction this WU instruction waits on */ + ReactionInstance reaction; + + /** ID of the worker processing the reaction */ + int worker; + + public InstructionWU(int worker, ReactionInstance reaction) { + this.opcode = Opcode.WU; + this.worker = worker; + this.reaction = reaction; + } + + @Override + public String toString() { + return "WU: worker " + worker + " finish " + reaction; + } +} diff --git a/core/src/main/java/org/lflang/generator/c/CStaticScheduleGenerator.java b/core/src/main/java/org/lflang/generator/c/CStaticScheduleGenerator.java index 52c94aa8f1..25e62ed5e0 100644 --- a/core/src/main/java/org/lflang/generator/c/CStaticScheduleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CStaticScheduleGenerator.java @@ -116,7 +116,7 @@ public StaticScheduler createStaticScheduler(Dag dag) { /** Generate VM instructions for each DAG partition. */ public void generateInstructionsFromPartitions(Dag dagParitioned) { InstructionGenerator instGen = - new InstructionGenerator(dagParitioned, this.targetConfig.workers); + new InstructionGenerator(dagParitioned, this.targetConfig); instGen.generate(); instGen.display();