+/* Analyze INSN and compute the variables recog_n_operands, recog_n_dups,
+ recog_n_alternatives, recog_operand, recog_operand_loc, recog_constraints,
+ recog_operand_mode, recog_dup_loc and recog_dup_num.
+ If REGISTER_CONSTRAINTS is not defined, also compute
+ recog_operand_address_p. */
+void
+extract_insn (insn)
+ rtx insn;
+{
+ int i;
+ int icode;
+ int noperands;
+ rtx body = PATTERN (insn);
+
+ recog_n_operands = 0;
+ recog_n_alternatives = 0;
+ recog_n_dups = 0;
+
+ switch (GET_CODE (body))
+ {
+ case USE:
+ case CLOBBER:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return;
+
+ case SET:
+ case PARALLEL:
+ case ASM_OPERANDS:
+ recog_n_operands = noperands = asm_noperands (body);
+ if (noperands >= 0)
+ {
+ /* This insn is an `asm' with operands. */
+
+ /* expand_asm_operands makes sure there aren't too many operands. */
+ if (noperands > MAX_RECOG_OPERANDS)
+ abort ();
+
+ /* Now get the operand values and constraints out of the insn. */
+ decode_asm_operands (body, recog_operand, recog_operand_loc,
+ recog_constraints, recog_operand_mode);
+ if (noperands > 0)
+ {
+ char *p = recog_constraints[0];
+ recog_n_alternatives = 1;
+ while (*p)
+ recog_n_alternatives += (*p++ == ',');
+ }
+#ifndef REGISTER_CONSTRAINTS
+ bzero (recog_operand_address_p, sizeof recog_operand_address_p);
+#endif
+ break;
+ }
+
+ /* FALLTHROUGH */
+
+ default:
+ /* Ordinary insn: recognize it, get the operands via insn_extract
+ and get the constraints. */
+
+ icode = recog_memoized (insn);
+ if (icode < 0)
+ fatal_insn_not_found (insn);
+
+ recog_n_operands = noperands = insn_n_operands[icode];
+ recog_n_alternatives = insn_n_alternatives[icode];
+ recog_n_dups = insn_n_dups[icode];
+
+ insn_extract (insn);
+
+ for (i = 0; i < noperands; i++)
+ {
+#ifdef REGISTER_CONSTRAINTS
+ recog_constraints[i] = insn_operand_constraint[icode][i];
+#else
+ recog_operand_address_p[i] = insn_operand_address_p[icode][i];
+#endif
+ recog_operand_mode[i] = insn_operand_mode[icode][i];
+ }
+ }
+ for (i = 0; i < noperands; i++)
+ recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT
+ : recog_constraints[i][0] == '+' ? OP_INOUT
+ : OP_IN);
+
+ if (recog_n_alternatives > MAX_RECOG_ALTERNATIVES)
+ abort ();
+}
+
+/* After calling extract_insn, you can use this function to extract some
+ information from the constraint strings into a more usable form.
+ The collected data is stored in recog_op_alt. */
+void
+preprocess_constraints ()
+{
+ int i;
+
+ for (i = 0; i < recog_n_operands; i++)
+ {
+ int j;
+ struct operand_alternative *op_alt;
+ char *p = recog_constraints[i];
+
+ op_alt = recog_op_alt[i];
+
+ for (j = 0; j < recog_n_alternatives; j++)
+ {
+ op_alt[j].class = NO_REGS;
+ op_alt[j].constraint = p;
+ op_alt[j].matches = -1;
+ op_alt[j].matched = -1;
+
+ if (*p == '\0' || *p == ',')
+ {
+ op_alt[j].anything_ok = 1;
+ continue;
+ }
+
+ for (;;)
+ {
+ char c = *p++;
+ if (c == '#')
+ do
+ c = *p++;
+ while (c != ',' && c != '\0');
+ if (c == ',' || c == '\0')
+ break;
+
+ switch (c)
+ {
+ case '=': case '+': case '*': case '%':
+ case 'E': case 'F': case 'G': case 'H':
+ case 's': case 'i': case 'n':
+ case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P':
+#ifdef EXTRA_CONSTRAINT
+ case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+ /* These don't say anything we care about. */
+ break;
+
+ case '?':
+ op_alt[j].reject += 6;
+ break;
+ case '!':
+ op_alt[j].reject += 600;
+ break;
+ case '&':
+ op_alt[j].earlyclobber = 1;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ op_alt[j].matches = c - '0';
+ op_alt[op_alt[j].matches].matched = i;
+ break;
+
+ case 'm':
+ op_alt[j].memory_ok = 1;
+ break;
+ case '<':
+ op_alt[j].decmem_ok = 1;
+ break;
+ case '>':
+ op_alt[j].incmem_ok = 1;
+ break;
+ case 'V':
+ op_alt[j].nonoffmem_ok = 1;
+ break;
+ case 'o':
+ op_alt[j].offmem_ok = 1;
+ break;
+ case 'X':
+ op_alt[j].anything_ok = 1;
+ break;
+
+ case 'p':
+ op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) BASE_REG_CLASS];
+ break;
+
+ case 'g': case 'r':
+ op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS];
+ break;
+
+ default:
+ op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER ((unsigned char)c)];
+ break;
+ }
+ }
+ }
+ }
+}
+