Example #1
0
        void GeneratePrologue(CheatSheet cheat_sheet)
        {
            // simple enough, the prologue needs to be the entire loop up to the instructions whose
            // destination operand are needed for the last iteration instructions
            m_last_dep_iter = -1;
            m_last_dep_slot = -1;

            // go through instructions that belong to the last iteration and find the last instruction
            // needed.

            // each line in the schedule
            for (int slot = 0; slot < m_schedule.GetLength(0); ++slot)
            {
                // odd and even pipeline
                for (int pipe = 0; pipe < 2; ++pipe)
                {
                    // wrong iteration, or its a nop
                    if (m_schedule[slot, pipe] == null || m_schedule[slot, pipe].m_iter != m_total_iterations - 1 || m_schedule[slot, pipe].m_inst.IsBranch(cheat_sheet))
                    {
                        continue;
                    }

                    // so we now have a last iteration instruction. Get its dependencies and choose the last one
                    for (int r = 0; r < m_schedule[slot, pipe].m_inst.m_reg_info.Count; ++r)
                    {
                        ProgramInfo.RegisterDependencyNode reg = m_schedule[slot, pipe].m_inst.m_reg_info[r];

                        // not something we need to worry about
                        if (reg.IsOutputOperand() == true || reg.m_allocated_reg == -1 || reg.m_dependency == null)
                        {
                            continue;
                        }

                        // look at the instruction we depend on, and see when it is scheduled
                        int dep_iter = m_instruction_to_schedule_map[reg.m_dependency.m_inst_num].m_iteration;
                        int dep_slot = m_instruction_to_schedule_map[reg.m_dependency.m_inst_num].m_schedule_slot;

                        if (dep_iter > m_last_dep_iter || (dep_iter == m_last_dep_iter && dep_slot > m_last_dep_slot))
                        {
                            // todo: this alone isnt enough to determine the prologue.  Using slot num alone, if you need
                            // the even instruction in the final slot, then you pick up the branch as well
                            m_last_dep_iter = dep_iter;
                            m_last_dep_slot = dep_slot;
                        }
                    }
                }
            }
        }
Example #2
0
        public void SimpleSchedule(ProgramInfo prog_info, CheatSheet cheat_sheet)
        {
            if (prog_info.m_original_program.Count == 0)
            {
                m_log = "\n\nno instructions found to schedule. Try writing some code";
                m_as_string = "";
                return;
            }

            m_log = "\n\nscheduling logic:";

            int mii = prog_info.MinII;
            m_schedule = new ScheduleSlot[mii, 2];
            m_instruction_to_schedule_map = Enumerable.Repeat<InstructionToScheduleMapNode>(null, prog_info.m_original_program.Count).ToList();

            // schedule the final jump
            int final_slot = prog_info.m_original_program.Count - 1;
            ProgramInfo.InstructionNode final_jump_inst = prog_info.m_original_program[final_slot];
            if (!final_jump_inst.IsBranch(cheat_sheet))
            {
                Debug.Fail("last instruction must be a jump to the start of the loop");
                m_log += "\nlast instruction must be a jump to the start of the loop";
                return;
            }
            m_instruction_to_schedule_map[final_slot] = new InstructionToScheduleMapNode(mii - 1, 0);
            m_schedule[mii - 1, 1] = new ScheduleSlot(final_jump_inst, 0);

            // schedule other instruction
            for (int i = 0; i < prog_info.m_original_program.Count - 1; ++i)
            {
                // step 1: find all dependencies and figure out when the last one finishes

                // each operand can have at most one dependency
                ProgramInfo.InstructionNode inst = prog_info.m_original_program[i];

                // don't schedule instructions that are unused or don't need to be included
                if (inst.m_include_in_schedule == false)
                {
                    continue;
                }

                int num_regs = inst.m_reg_info.Count;

                if (inst.IsBranch(cheat_sheet))
                {
                    Debug.Fail("no jump instructions allowed in the middle of a loop");
                    return;
                }

                // absolute cycle time, not which slot in the schedule. iteration num * mii + schedule slot num
                int cycle_to_schedule = 0;

                for (int d = 0; d < num_regs; ++d)
                {
                    ProgramInfo.DepPair dep_pair = inst.m_reg_info[d].m_dependency;
                    if (dep_pair != null)
                    {
                        int dependency_index = dep_pair.m_inst_num;
                        InstructionToScheduleMapNode dependency_location = m_instruction_to_schedule_map[dependency_index];

                        if (dependency_location.m_schedule_slot >= 0)
                        {
                            ProgramInfo.InstructionNode dependency = prog_info.m_original_program[dependency_index];
                            cycle_to_schedule = Math.Max
                            (
                                cycle_to_schedule,
                                dependency_location.m_iteration * mii + dependency_location.m_schedule_slot + dependency.m_latency
                            );
                        }
                    }
                }

                // step 2: see if that slot is free. If not, keep going until free slot found
                // todo: what happens if we can't find a valid schedule? We need to back up and reschedule

                int schedule_slot = cycle_to_schedule % mii;
                int schedule_iter = cycle_to_schedule / mii;
                int pipeline_index = inst.m_pipeline == Program.Pipe.EVEN ? 0 : 1;
                while (m_schedule[schedule_slot, pipeline_index] != null)
                {
                    ++cycle_to_schedule;
                    schedule_slot = cycle_to_schedule % mii;
                    schedule_iter = cycle_to_schedule / mii;
                }

                // step 3: schedule the instruction

                m_instruction_to_schedule_map[i] = new InstructionToScheduleMapNode(schedule_slot, schedule_iter);
                m_schedule[schedule_slot, pipeline_index] = new ScheduleSlot(inst, schedule_iter);
                m_total_iterations = Math.Max(m_total_iterations, schedule_iter + 1);

                m_log += string.Format("\nscheduling {0} in slot {1} iteration {2}", inst.m_opcode, schedule_slot, schedule_iter);
            }

            // so now that we have our schedule and know what belongs to what iteration, do register allocation.
            // this is necessary mainly to avoid anti-dependencies from rearranging instructions.
            // TODO: because we are now inserting copies to deal with antidependencies, register allocation can
            // fail if there is no valid place to put the copy.  We need to be in a loop and try to schedule again
            // if something fails
            AllocateRegisters(prog_info, mii);
            GeneratePrologue(cheat_sheet);
            m_as_string = BuildScheduleString(cheat_sheet);
        }
Example #3
0
        string BuildScheduleString(CheatSheet cs)
        {
            string as_string = string.Format("\n\nbest schedule found: {0} cycles with {1} iterations in flight", m_schedule.GetLength(0), m_total_iterations);
            if (m_last_dep_iter > -1)
            {
                as_string += string.Format("\n\nPrologue:");
                for (int iter = 0; iter < m_last_dep_iter; ++iter)
                {
                    for (int inst = 0; inst < m_schedule.GetLength(0); ++inst)
                    {
                        if (m_schedule[inst, 0] != null && m_schedule[inst, 0].m_iter == iter)
                        {
                            as_string += string.Format("\n{0}", m_schedule[inst, 0].m_inst.ToString());
                        }
                        if (m_schedule[inst, 1] != null && m_schedule[inst, 1].m_iter == iter && m_schedule[inst, 1].m_inst.IsBranch(cs) == false)
                        {
                            as_string += string.Format("\n{0}", m_schedule[inst, 1].m_inst.ToString());
                        }
                    }
                }

                for (int inst = 0; inst <= m_last_dep_slot; ++inst)
                {
                    if (m_schedule[inst, 0] != null && m_schedule[inst, 0].m_iter == m_last_dep_iter)
                    {
                        as_string += string.Format("\n{0}", m_schedule[inst, 0].m_inst.ToString());
                    }
                    if (m_schedule[inst, 1] != null && m_schedule[inst, 1].m_iter == m_last_dep_iter)
                    {
                        as_string += string.Format("\n{0}", m_schedule[inst, 1].m_inst.ToString());
                    }
                }
            }

            as_string += string.Format("\n\nSchedule:");
            for (int i = 0; i < m_schedule.GetLength(0); ++i)
            {
                as_string += string.Format("\n\n{0}) {1} (iter {2}) {3}",
                    i,
                    m_schedule[i, 0] != null ? m_schedule[i, 0].m_inst.ToString() : "nop",
                    m_schedule[i, 0] != null ? m_schedule[i, 0].m_iter : 0,
                    m_schedule[i, 0] != null && m_schedule[i, 0].m_inst.m_original_inst_num == -1 ? "live too long: reg copy" : "");
                as_string += string.Format("\n{0}) {1} (iter {2} {3})",
                    i,
                    m_schedule[i, 1] != null ? m_schedule[i, 1].m_inst.ToString() : "lnop",
                    m_schedule[i, 1] != null ? m_schedule[i, 1].m_iter : 0,
                    m_schedule[i, 1] != null && m_schedule[i, 1].m_inst.m_original_inst_num == -1 ? "live too long: reg copy" : "");
            }

            return as_string;
        }
Example #4
0
    public MainWindow()
        : base(Gtk.WindowType.Toplevel)
    {
        Build ();

        this.OriginalCode2.Buffer.Text =
            ".L4:" + '\n' +
            "	.macro_begin MyMacro p1,p2,p3" + '\n' +
            "	.macro_end" + '\n' +
            "	shufb	$0,$0,$0,$0" + '\n' +
            "	shufb	$0,$0,$0,$0" + '\n' +
            "	shufb	$1,$1,$1,$1" + '\n' +
            "	shufb	$2,$2,$2,$2" + '\n' +
            "	shufb	$3,$3,$3,$3" + '\n' +
            "	a       $5,$0,$0" + '\n' +
            "	lqd	    $4,0($4)" + '\n' +
            "	lqd	    $8,0($8)" + '\n' +
            "	a       $7,$5,$8" + '\n' +
            ".L8: brz $4, .L4";

        this.Log.Buffer.Text = "Welcome to TREMBLE, the Jaymin Kessler institute for kids who can't pipeline good";
        string[] fake_program_lines = this.OriginalCode2.Buffer.Text.Split(new char[]{'\n'});

        m_cheat_sheet = new pipelining_tool_test.CheatSheet("../../SPU_cheat_sheet.txt");

        ScheduleFromLines(fake_program_lines);

        // perhaps allow people to click on a register and see where its used everywhere
        this.PipelinedSchedule.Buffer.MarkSet += OnPipelinedScheduleBufferMoveCursor;

        TextView text_view = OriginalCode2;
        TextBuffer buffer = text_view.Buffer;
        buffer.RemoveAllTags(buffer.GetIterAtOffset(0), buffer.GetIterAtOffset(buffer.Text.Length));

        // highlight the error (from http://go-mono.com/forums/#nabble-td1545615)
           	m_tag_error = new TextTag("error");
           	// not a fixed width font so making errors bold is annoying
        //m_tag_error.Weight = Pango.Weight.Bold;
        m_tag_error.Foreground = "red";
           	buffer.TagTable.Add(m_tag_error);

        text_view = PipelinedSchedule;
        buffer = text_view.Buffer;
           	m_tag_reg_highlight = new TextTag("reghighlight");
           	// not a fixed width font so making errors bold is annoying
        //m_tag_reg_highlight.Weight = Pango.Weight.Bold;
        m_tag_reg_highlight.Foreground = "red";
           	buffer.TagTable.Add(m_tag_reg_highlight);
    }
Example #5
0
 public bool IsBranch(CheatSheet cs)
 {
     return cs.m_branch_opcodes.Contains(m_opcode);
 }
Example #6
0
        public ProgramInfo(string[] lines, CheatSheet cheat_sheet)
        {
            RegisterOwnerNode[] reg_to_inst = new RegisterOwnerNode[128];

            Regex opcode_operand_comment_splitter = new Regex(@"([A-Za-z]+)\s+([^;]*)(;*)");
            Regex label_rest_of_line_splitter = new Regex(@"^([a-zA-Z_\.][a-zA-Z0-9_]*):(.*)");

            // matches ".macro_begin SomeMacro var1, var2 ,var3 , var4"
            //Regex macro_arg_splitter = new Regex
            //(
            //	@"^\b*\.macro_begin\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*,\s*([a-zA-Z_][a-zA-Z0-9_]*))*"
            //);

            Regex register_extractor = new Regex(@"\$(\d+)");

            m_log = "";

            int lines_of_actual_code = 0;

            // todo: stop overusing trim
            for (int line_num = 0; line_num < lines.Length; ++line_num)
            {
                string current_line = lines[line_num].Trim();

                // early out to skip whole line comments
                if (current_line == "" || current_line[0] == ';')
                {
                    continue;
                }

                Match match;

                // macro processing
                string macro_begin_token = ".macro_begin";
                if (current_line.StartsWith(macro_begin_token))
                {
                    current_line = current_line.Substring(macro_begin_token.Length);
                    string[] args = current_line.Split(new char[] {',',' '}, StringSplitOptions.RemoveEmptyEntries);
                    int num_args = args.Length;

                    if (num_args <= 2)
                    {
                        ErrorMacroWrongNumArgs(line_num);
                        return;
                    }

                    int macro_start_line = line_num;
                    string macro_name = args[0];

                    while (current_line.StartsWith(".macro_end") == false && line_num < lines.Length)
                    {
                        current_line = lines[line_num++].Trim();
                    }

                    // either we found the macro end or we have an unterminated macro
                    if (current_line.StartsWith(".macro_end"))
                    {
                        --line_num;
                        continue;
                    }
                    else
                    {
                        ErrorUnterminatedMacro(macro_start_line, macro_name);
                        return;
                    }
                }

                // deal with labels alone on a line and labels with code after them
                match = label_rest_of_line_splitter.Match(current_line);
                if (match.Success)
                {
                    string lab_to_add = match.Groups[1].Value;

                    // disallow duplicate labels
                    if (m_label_table.ContainsKey(lab_to_add))
                    {
                        ErrorLabelDuplicate(line_num, lab_to_add);
                        return;
                    }

                    // add label to table, and see if there was anything after the label
                    m_label_table.Add(lab_to_add, lines_of_actual_code);

                    // set the current line to everything after the label and continue
                    current_line = match.Groups[2].Value.Trim();

                    // if this is a label by itself, continue.
                    if (current_line == "" || current_line[0] == ';')
                    {
                        continue;
                    }
                }

                match = opcode_operand_comment_splitter.Match(current_line);
                if (match.Success)
                {
                    string opcode = match.Groups[1].Value;

                    // make sure the opcode exists
                    Program.Instruction inst;
                    if (!cheat_sheet.LookupInstruction(opcode, out inst))
                    {
                        ErrorInvalidOpcode(line_num, opcode);
                        return;
                    }

                    InstructionNode dependency_node = new InstructionNode(opcode, inst);
                    dependency_node.m_original_inst_num = m_original_program.Count;
                    m_original_program.Add(dependency_node);
                    ++m_instruction_cnt[inst.m_pipeline == Program.Pipe.EVEN? 0 : 1];

                    // dont allow jumps in the middle of the code. Todo: check branch target as well
                    if (dependency_node.IsBranch(cheat_sheet) && line_num < lines.Length - 1)
                    {
                        ErrorInvalidBranchSlot(line_num);
                        return;
                    }
                    else if (dependency_node.IsBranch(cheat_sheet) == false && line_num == lines.Length - 1)
                    {
                        ErrorLastInstructionNotBranch(line_num);
                        return;
                    }

                    // don't do anything for opcodes that dont require operands
                    int num_expected_operands = inst.GetNumExpectedOperands();
                    if (num_expected_operands > 0)
                    {
                        // group 2 must be opcodes. If it starts with a semicolon, we are missing the proper operands
                        if (match.Groups[2].Value.Length < 1 || match.Groups[2].Value[0] == ';' || match.Groups[2].Value == "")
                        {
                            ErrorNoOperands(line_num, opcode, num_expected_operands);
                            return;
                        }

                        // now the real work begins.  Verify the operands are what they should be
                        string operands_match = match.Groups[2].Value;
                        string[] operands = operands_match.Trim().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                        // wrong number of operands
                        if (operands.Length != num_expected_operands)
                        {
                            ErrorWrongNumOperands(line_num, opcode, num_expected_operands, operands.Length);
                            return;
                        }

                        // verify operand types are what they should be
                        for (int o = 0; o < num_expected_operands; ++o)
                        {
                            string trimmed_operand = operands[o].Trim();

                            // if the operand is a label to jump to, replace it with the label address
                            if (m_label_table.ContainsKey( trimmed_operand ))
                            {
                                trimmed_operand = m_label_table[trimmed_operand].ToString();
                            }

                            // original register number
                            int original_reg_num = -1;
                            int operand_offset = -1;

                            bool operand_type_valid = Program.OperandInfo.GetOperandValues(inst.m_operand_types[o], trimmed_operand, out original_reg_num, out operand_offset);
                            if (!operand_type_valid)
                            {
                                ErrorInvalidOperandType(line_num, opcode, o, inst.m_operand_types[o]);
                                return;
                            }

                            if (original_reg_num > 127)
                            {
                                ErrorRegisterGt127(line_num, o);
                                return;
                            }

                            // add this to the dependency tree
                            RegisterDependencyNode operand_dependency_node = new RegisterDependencyNode(inst.m_operand_types[o]);
                            dependency_node.m_reg_info.Add(operand_dependency_node);
                            operand_dependency_node.m_allocated_reg = original_reg_num;
                            operand_dependency_node.m_immediate_arg = operand_offset;

                            //check for input dependencies on other registers (as opposed to literals)
                            if (inst.m_operand_types[o] == Program.OperandInfo.OperandType.INPUT_REG ||
                                inst.m_operand_types[o] == Program.OperandInfo.OperandType.BASE_REG_AND_SIGNED_LITERAL_OFFSET ||
                                inst.m_operand_types[o] == Program.OperandInfo.OperandType.BASE_REG_AND_SIGNED_LITERAL_OFFSET)
                            {
                                if (original_reg_num >= 0 && reg_to_inst[original_reg_num] != null)
                                {
                                    // if this input register was written to by a previous instruction, then we depend on that instruction
                                    //is_root_node = false;
                                    reg_to_inst[original_reg_num].m_times_used++;
                                    operand_dependency_node.m_dependency = new DepPair(reg_to_inst[original_reg_num].m_owner, 0);
                                    m_original_program[reg_to_inst[original_reg_num].m_owner].m_reg_info[0].m_dependents.Add(new DepPair(lines_of_actual_code, o));
                                }
                            }
                        }

                        // register ownership and removal of unused instructions
                        if (inst.m_operand_types[0] == Program.OperandInfo.OperandType.OUTPUT_REG)
                        {
                            string trimmed_operand = operands[0].Trim();
                            int reg_num = -1;
                            match = register_extractor.Match(trimmed_operand);
                            if (match.Success && int.TryParse(match.Groups[1].Value, out reg_num))
                            {
                                // look at the previous register owner. If between when it wrote its value and now the register is
                                // never used, this is probably an unused instruction and should be removed!
                                if (reg_to_inst[reg_num] != null && reg_to_inst[reg_num].m_times_used == 0)
                                {
                                    // mark this and remove it later, making sure to fix up the odd/even inst count,
                                    // labels, indices, pointers, and who knows what else needs to be fixed :)
                                    int unused_inst_line = reg_to_inst[reg_num].m_owner;
                                    EliminateUnusedInstructionChain(unused_inst_line, reg_to_inst);
                                }

                                // assign register ownership
                                reg_to_inst[reg_num] = new RegisterOwnerNode(lines_of_actual_code);
                            }
                        }
                    }

                    ++lines_of_actual_code;
                }
                else
                {
                    m_program_status.m_error_line = line_num;
                   	m_program_status.m_error_msg = "Parse error. Line: " + line_num.ToString();
                    m_program_status.m_status = ProgramStatus.Status.STATUS_PARSE_ERROR;
                    return;
                }
            }

            // lock the final owners of all regs
            for (int r = 0; r < 128; ++r)
            {
                if (reg_to_inst[r] != null && reg_to_inst[r].m_owner != -1 && m_original_program[reg_to_inst[r].m_owner].m_include_in_schedule == true)
                {
                    m_original_program[reg_to_inst[r].m_owner].m_reg_info[0].m_is_locked = true;
                }
            }
        }