feedbackJoineersNeedingPrep.add(joiner);
feedbackJoinersNeedingPrep.add(joiner);
    public static void generateJoiner(FlatNode node) {                SIRJoiner joiner = (SIRJoiner)node.contents;        if (joiner.getSumOfWeights() == 0) {            // The joiner is not doing any work                    return;        }        int init_counts, steady_counts;        Integer init_int = (Integer)ClusterBackend.initExecutionCounts.get(node);        if (init_int==null) {            init_counts = 0;        } else {            init_counts = init_int.intValue();        }        steady_counts = ((Integer)ClusterBackend.steadyExecutionCounts.get(node)).intValue();        CType baseType = CommonUtils.getBaseType(CommonUtils.getJoinerType(node));        int thread_id = NodeEnumerator.getSIROperatorId(node.contents);        List<Tape> in = RegisterStreams.getNodeInStreams(node.contents);        List<Tape> out_v = RegisterStreams.getNodeOutStreams(node.contents);        Tape out = out_v.get(0);        CodegenPrintWriter p = null;        try {            p = new CodegenPrintWriter(new FileWriter("thread"+thread_id+".cpp"));        } catch (IOException e) {            e.printStackTrace();            System.exit(1);        }                ClusterCodeGenerator gen = new ClusterCodeGenerator(joiner, new JFieldDeclaration[0]);        p.print("// init counts: "+init_counts+" steady counts: "+steady_counts+"\n");         p.newLine();        //  +=============================+        //  | Preamble                    |        //  +=============================+             FlatIRToCluster f2c = new FlatIRToCluster(p);        gen.generatePreamble(f2c,p);//        p.print("void save_peek_buffer__"+thread_id+"(object_write_buffer *buf) {}\n");//        p.print("void load_peek_buffer__"+thread_id+"(object_write_buffer *buf) {}\n");//        p.newLine();////        p.println("void save_file_pointer__"+thread_id+"(object_write_buffer *buf) {}");//        p.println("void load_file_pointer__"+thread_id+"(object_write_buffer *buf) {}");//        p.newLine();        // declare any external data needed for input and output tapes.        out.upstreamDeclarationExtern();        for (Tape ns : in) {          if (ns != null) {              ns.downstreamDeclarationExtern();          }        }        // declare pop routine for cluster tapes.        out.upstreamDeclaration();        for (Tape ns : in) {           if (ns != null) {               ns.downstreamDeclaration();           }         }               //  +=============================+        //  | Init Path                   |        //  +=============================+        if (joiner.getParent() instanceof SIRFeedbackLoop) {                    SIRFeedbackLoop floop = (SIRFeedbackLoop)joiner.getParent();            p.print("//delay = "+((JIntLiteral)floop.getDelay()).intValue());            p.newLine();            JMethodDeclaration ipath = floop.getInitPath();            ipath.setName("__Init_Path_"+thread_id);            FlatIRToCluster fir = new FlatIRToCluster();            fir.setDeclOnly(false);            ipath.accept(fir);            p.print(fir.getPrinter().getString());            p.newLine();            p.newLine();        }        // +==============================+        // | Joiner Prep Feedbackloop     |        // +==============================+                if (joiner.getParent() instanceof SIRFeedbackLoop                && ((SIRFeedbackLoop) joiner.getParent()).getDelayInt() > 0) {            //            // Joiner is a part of feedbackloop with non-zero delay:            // we need initialization code to put enqueues onto tape from loop            // portion            // back to joiner.            //            feedbackJoineersNeedingPrep.add(joiner);            Tape loopTape = RegisterStreams.getNodeInStreams(joiner).get(1);            int enqueue_count = ((SIRFeedbackLoop) joiner.getParent())                    .getDelayInt();            p.println("void __feedbackjoiner_" + thread_id + "_prep() {");            p.indent();            p.print(loopTape.pushbackInit(enqueue_count));            p.print("for (int __i = 0; __i < " + enqueue_count                    + "; __i++) {\n");            p.indent();            p.print(loopTape.pushbackPrefix());            p.print("__Init_Path_" + thread_id + "(__i)");            p.print(loopTape.pushbackSuffix());            p.print(";\n");            p.outdent();            p.println("}");            p.print(loopTape.pushbackCleanup());            p.outdent();            p.println("}");            p.print("  " + baseType.toString() + " tmp;\n");        }                // +=============+        // | Joiner Work |        //  +============+         p.newLine();        if (joiner.getType().equals(SIRJoinType.ROUND_ROBIN)                || joiner.getType().equals(SIRJoinType.WEIGHTED_RR)) {            p.print("void __joiner_" + thread_id + "_work(int ____n) {\n");            p.print("  for (;____n > 0; ____n--) {\n");            int sum = joiner.getSumOfWeights();            // depending on the weight unroll fully or by some constant factor            if (sum < MAX_SUM_WEIGHTS_TO_UNROLL) {                // unroll fully!                for (int i = 0; i < in.size(); i++) {                    int num = joiner.getWeight(i);                    if (num != 0) {                        Tape s = in.get(i);                        for (int y = 0; y < num; y++) {                            printCopyTapeElement(p, s, out);                        }                    }                }            } else {                // do not unroll fully weight >= MAX_WEIGHTS_TO_UNROLL                for (int i = 0; i < in.size(); i++) {                    int num = joiner.getWeight(i);                    if (num != 0) {                        Tape s = in.get(i);                        if (num / UNROLL_BY > 0) {                            p.println("  for (int __k = 0; __k < " + num                                    / UNROLL_BY + "; __k++) {\n");                            for (int y = 0; y < UNROLL_BY; y++) {                                printCopyTapeElement(p, s, out);                            }                            p.println("  }\n");                        }                        int rem = num % UNROLL_BY;                        for (int y = 0; y < rem; y++) {                            printCopyTapeElement(p, s, out);                        }                    }                }            }            p.print("  }\n");            p.print("}\n");            p.newLine();        } // if (joiner.getType().equals(SIRJoinType.ROUND_ROBIN) ...)         // else: no work function for null joiner.                //  +=============================+        //  | Run Function                |        //  +=============================+        Vector<String> run = gen.generateRunFunction(null, "__joiner_"                + thread_id + "_main", new Vector<String>());        for (int i = 0; i < run.size(); i++) {            p.print(run.elementAt(i).toString());        }        //  +=============================+        //  | Write Joiner to File        |        //  +=============================+        try {            p.close();        }        catch (Exception e) {            System.err.println("Unable to write joiner code to file thread"                    + thread_id + ".cpp");        }        if (ClusterBackend.debugPrint)            System.out.println("Code for " + node.contents.getName() +                               " written to thread"+thread_id+".cpp");    }