+/* Check 2 instructions and determine if they can be safely */
+/* executed in parallel. Returns 1 if they can be. */
+static int
+parallel_ok (op1, insn1, op2, insn2, exec_type)
+ struct d10v_opcode *op1, *op2;
+ unsigned long insn1, insn2;
+ int exec_type;
+{
+ int i, j, flags, mask, shift, regno;
+ unsigned long ins, mod[2], used[2];
+ struct d10v_opcode *op;
+
+ if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
+ || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
+ || (op1->unit == BOTH) || (op2->unit == BOTH)
+ || (op1->unit == IU && op2->unit == IU)
+ || (op1->unit == MU && op2->unit == MU))
+ return 0;
+
+ /* If the first instruction is a branch and this is auto parallazation,
+ don't combine with any second instruction. */
+ if (exec_type == 0 && (op1->exec_type & BRANCH) != 0)
+ return 0;
+
+ /* The idea here is to create two sets of bitmasks (mod and used)
+ which indicate which registers are modified or used by each
+ instruction. The operation can only be done in parallel if
+ instruction 1 and instruction 2 modify different registers, and
+ the first instruction does not modify registers that the second
+ is using (The second instruction can modify registers that the
+ first is using as they are only written back after the first
+ instruction has completed). Accesses to control registers, PSW,
+ and memory are treated as accesses to a single register. So if
+ both instructions write memory or if the first instruction writes
+ memory and the second reads, then they cannot be done in
+ parallel. Likewise, if the first instruction mucks with the psw
+ and the second reads the PSW (which includes C, F0, and F1), then
+ they cannot operate safely in parallel. */
+
+ /* the bitmasks (mod and used) look like this (bit 31 = MSB) */
+ /* r0-r15 0-15 */
+ /* a0-a1 16-17 */
+ /* cr (not psw) 18 */
+ /* psw 19 */
+ /* mem 20 */
+
+ for (j=0;j<2;j++)
+ {
+ if (j == 0)
+ {
+ op = op1;
+ ins = insn1;
+ }
+ else
+ {
+ op = op2;
+ ins = insn2;
+ }
+ mod[j] = used[j] = 0;
+ if (op->exec_type & BRANCH_LINK)
+ mod[j] |= 1 << 13;
+
+ for (i = 0; op->operands[i]; i++)
+ {
+ flags = d10v_operands[op->operands[i]].flags;
+ shift = d10v_operands[op->operands[i]].shift;
+ mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits);
+ if (flags & OPERAND_REG)
+ {
+ regno = (ins >> shift) & mask;
+ if (flags & (OPERAND_ACC0|OPERAND_ACC1))
+ regno += 16;
+ else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
+ {
+ if (regno == 0)
+ regno = 19;
+ else
+ regno = 18;
+ }
+ else if (flags & (OPERAND_FFLAG|OPERAND_CFLAG))
+ regno = 19;
+
+ if ( flags & OPERAND_DEST )
+ {
+ mod[j] |= 1 << regno;
+ if (flags & OPERAND_EVEN)
+ mod[j] |= 1 << (regno + 1);
+ }
+ else
+ {
+ used[j] |= 1 << regno ;
+ if (flags & OPERAND_EVEN)
+ used[j] |= 1 << (regno + 1);
+
+ /* Auto inc/dec also modifies the register. */
+ if (op->operands[i+1] != 0
+ && (d10v_operands[op->operands[i+1]].flags
+ & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
+ mod[j] |= 1 << regno;
+ }
+ }
+ else if (flags & OPERAND_ATMINUS)
+ {
+ /* SP implicitly used/modified */
+ mod[j] |= 1 << 15;
+ used[j] |= 1 << 15;
+ }
+ }
+ if (op->exec_type & RMEM)
+ used[j] |= 1 << 20;
+ else if (op->exec_type & WMEM)
+ mod[j] |= 1 << 20;
+ else if (op->exec_type & RF0)
+ used[j] |= 1 << 19;
+ else if (op->exec_type & WF0)
+ mod[j] |= 1 << 19;
+ else if (op->exec_type & WCAR)
+ mod[j] |= 1 << 19;
+ }
+ if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
+ return 1;
+ return 0;
+}
+
+