+/* Determine if there are any resource conflicts among two manually
+ parallelized instructions. Some of this was lifted from parallel_ok. */
+
+static void
+check_resource_conflict (struct d10v_opcode *op1,
+ unsigned long insn1,
+ struct d10v_opcode *op2,
+ unsigned long insn2)
+{
+ int i, j, flags, mask, shift, regno;
+ unsigned long ins, mod[2];
+ struct d10v_opcode *op;
+
+ if ((op1->exec_type & SEQ)
+ || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
+ {
+ as_warn (_("packing conflict: %s must dispatch sequentially"),
+ op1->name);
+ return;
+ }
+
+ if ((op2->exec_type & SEQ)
+ || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
+ {
+ as_warn (_("packing conflict: %s must dispatch sequentially"),
+ op2->name);
+ return;
+ }
+
+ /* See if both instructions write to the same resource.
+
+ 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 neither instruction
+ modifies the same register. Accesses to control registers 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. We treat reads to the PSW
+ (which includes C, F0, and F1) in isolation. So simultaneously writing
+ C and F0 in two different sub-instructions is permitted. */
+
+ /* The bitmasks (mod and used) look like this (bit 31 = MSB).
+ r0-r15 0-15
+ a0-a1 16-17
+ cr (not psw) 18
+ psw(other) 19
+ mem 20
+ psw(C flag) 21
+ psw(F0 flag) 22 */
+
+ for (j = 0; j < 2; j++)
+ {
+ if (j == 0)
+ {
+ op = op1;
+ ins = insn1;
+ }
+ else
+ {
+ op = op2;
+ ins = insn2;
+ }
+ mod[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)
+ regno = 22;
+ else if (flags & OPERAND_CFLAG)
+ regno = 21;
+
+ if (flags & OPERAND_DEST
+ /* Auto inc/dec also modifies the register. */
+ || (op->operands[i + 1] != 0
+ && (d10v_operands[op->operands[i + 1]].flags
+ & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
+ {
+ mod[j] |= 1 << regno;
+ if (flags & OPERAND_EVEN)
+ mod[j] |= 1 << (regno + 1);
+ }
+ }
+ else if (flags & OPERAND_ATMINUS)
+ {
+ /* SP implicitly used/modified. */
+ mod[j] |= 1 << 15;
+ }
+ }
+
+ if (op->exec_type & WMEM)
+ mod[j] |= 1 << 20;
+ else if (op->exec_type & WF0)
+ mod[j] |= 1 << 22;
+ else if (op->exec_type & WCAR)
+ mod[j] |= 1 << 21;
+ }
+
+ if ((mod[0] & mod[1]) == 0)
+ return;
+ else
+ {
+ unsigned long x;
+ x = mod[0] & mod[1];
+
+ for (j = 0; j <= 15; j++)
+ if (x & (1 << j))
+ as_warn (_("resource conflict (R%d)"), j);
+ for (j = 16; j <= 17; j++)
+ if (x & (1 << j))
+ as_warn (_("resource conflict (A%d)"), j - 16);
+ if (x & (1 << 19))
+ as_warn (_("resource conflict (PSW)"));
+ if (x & (1 << 21))
+ as_warn (_("resource conflict (C flag)"));
+ if (x & (1 << 22))
+ as_warn (_("resource conflict (F flag)"));
+ }
+}
+
+/* Check 2 instructions and determine if they can be safely
+ executed in parallel. Return 1 if they can be. */
+
+static int
+parallel_ok (struct d10v_opcode *op1,
+ unsigned long insn1,
+ struct d10v_opcode *op2,
+ unsigned long insn2,
+ packing_type 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 this is auto parallelization, and the first instruction is a
+ branch or should not be packed, then don't parallelize. */
+ if (exec_type == PACK_UNSPEC
+ && (op1->exec_type & (ALONE | BRANCH)))
+ 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;
+}
+