From 026d38685a306238520bd2dc743b94e66ecf450f Mon Sep 17 00:00:00 2001 From: zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Tue, 28 Feb 2006 03:28:18 +0000 Subject: [PATCH] * rtl.def (define_constraint, define_register_constraint) (define_memory_constraint, define_address_constraint): New MD forms. * gensupport.c (process_rtx): Put define_constraint etc on the predicate queue. * genpreds.c (process_define_predicate): Adjust comment. Validate the name, and call validate_exp to validate the expression. (mark_mode_tests, write_extract_subexp): Can assume correct input. (write_predicate_expr): Likewise. NAME argument no longer necessary; all callers changed. (validate_exp, needs_variable, struct constraint_data) (constraints_by_letter_table, first_constraint, last_constraint_ptr) (FOR_ALL_CONSTRAINTS, generic_constraint_letters, const_int_constraints) (const_dbl_constraints, constraint_max_namelen) (have_register_constraints, have_memory_constraints) (have_address_constraints, have_address_constraints) (have_extra_constraints, have_const_int_constraints) (have_const_dbl_constraints, mangle, add_constraint) (process_define_constraint, process_define_register_constraint) (write_enum_constraint_num, write_lookup_constraint) (write_insn_constraint_len, write_regclass_for_constraint) (write_constraint_satisfied_p, write_insn_const_int_ok_for_constraint) (write_insn_extra_memory_constraint) (write_insn_extra_address_constraint) (write_satisfies_constraint_fns): New. (write_tm_preds_h): If we have new-style constraint definitions, prototype the functions generated from them, and define the old constraint interface (still used by generic code) in terms of those functions. (write_insn_preds_c): If we have new-style constraint definitions, generate all relevant functions from those definitions. (main): Handle define_constraint etc. * genoutput.c (struct constraint_data, indep_constraints) (mdep_constraint_letters, constraints_by_letter_table, note_constraint) (mdep_constraint_len): New data structures and functions, defined #ifdef USE_MD_CONSTRAINTS. (check_constraint_len): Don't define #ifdef USE_MD_CONSTRAINTS. (validate_insn_alternatives): If USE_MD_CONSTRAINTS is defined, use new logic to validate operand constraints against constraint definitions. (main): Process define_constraint etc. if USE_MD_CONSTRAINTS is defined. * defaults.h: If none of the old-style constraint macros are defined, define USE_MD_CONSTRAINTS; do not provide defaults for any old-style macros; and poison REG_CLASS_FROM_LETTER, CONST_OK_FOR_LETTER_P, CONST_DOUBLE_OK_FOR_LETTER_P, and EXTRA_CONSTRAINT. * recog.c (reg_fits_class_p): If cl is NO_REGS, return 0 immediately. * doc/md.texi: Document new constraint-definition mechanism and the C interface it provides. Remove references to old mechanism elsewhere in the document. (Machine Constraints): Use pathnames relative to gcc directory, i.e. config/ARCH/FILE. Change i386 section to refer to config/i386/predicates.md; update that section to match docstrings. * doc/tm.texi: Move all documentation of the old constraint- definition macros to their own section, clearly mark as obsolete. * config/i386/predicates.md (R, q, Q, l, a, b, c, d, S, D, A, f, t) (u, y, x, Y, I, J, K, L, M, N, O, G, C, e, Z): New constraint definitions. * config/i386/i386.h (REG_CLASS_FROM_LETTER, CONST_OK_FOR_LETTER_P) (CONST_DOUBLE_OK_FOR_LETTER_P, EXTRA_CONSTRAINT): Delete. * config/i386/i386.md (*movdf_nointeger): Remove stray 'H' from constraint strings. (splits and peepholes): Use satisfies_constraint_*. * config/i386/i386.c (memory_address_length) (ix86_attr_length_immediate_default): Use satisfies_constraint_*. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111508 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 69 +++ gcc/config/i386/i386.c | 8 +- gcc/config/i386/i386.h | 86 ---- gcc/config/i386/i386.md | 23 +- gcc/config/i386/predicates.md | 134 +++++ gcc/defaults.h | 29 ++ gcc/doc/md.texi | 421 ++++++++++++---- gcc/doc/tm.texi | 72 +-- gcc/genoutput.c | 187 ++++++- gcc/genpreds.c | 885 +++++++++++++++++++++++++++++++--- gcc/gensupport.c | 4 + gcc/recog.c | 4 + gcc/rtl.def | 55 +++ 13 files changed, 1678 insertions(+), 299 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eadb2fe1b48f..7538a9f81430 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,72 @@ +2006-02-27 Zack Weinberg <zackw@panix.com> + + * rtl.def (define_constraint, define_register_constraint) + (define_memory_constraint, define_address_constraint): New MD forms. + * gensupport.c (process_rtx): Put define_constraint etc on the + predicate queue. + * genpreds.c (process_define_predicate): Adjust comment. Validate + the name, and call validate_exp to validate the expression. + (mark_mode_tests, write_extract_subexp): Can assume correct input. + (write_predicate_expr): Likewise. NAME argument no longer necessary; + all callers changed. + (validate_exp, needs_variable, struct constraint_data) + (constraints_by_letter_table, first_constraint, last_constraint_ptr) + (FOR_ALL_CONSTRAINTS, generic_constraint_letters, const_int_constraints) + (const_dbl_constraints, constraint_max_namelen) + (have_register_constraints, have_memory_constraints) + (have_address_constraints, have_address_constraints) + (have_extra_constraints, have_const_int_constraints) + (have_const_dbl_constraints, mangle, add_constraint) + (process_define_constraint, process_define_register_constraint) + (write_enum_constraint_num, write_lookup_constraint) + (write_insn_constraint_len, write_regclass_for_constraint) + (write_constraint_satisfied_p, write_insn_const_int_ok_for_constraint) + (write_insn_extra_memory_constraint) + (write_insn_extra_address_constraint) + (write_satisfies_constraint_fns): New. + (write_tm_preds_h): If we have new-style constraint definitions, + prototype the functions generated from them, and define the + old constraint interface (still used by generic code) in terms of + those functions. + (write_insn_preds_c): If we have new-style constraint definitions, + generate all relevant functions from those definitions. + (main): Handle define_constraint etc. + * genoutput.c (struct constraint_data, indep_constraints) + (mdep_constraint_letters, constraints_by_letter_table, note_constraint) + (mdep_constraint_len): New data structures and functions, defined + #ifdef USE_MD_CONSTRAINTS. + (check_constraint_len): Don't define #ifdef USE_MD_CONSTRAINTS. + (validate_insn_alternatives): If USE_MD_CONSTRAINTS is defined, + use new logic to validate operand constraints against constraint + definitions. + (main): Process define_constraint etc. if USE_MD_CONSTRAINTS is + defined. + * defaults.h: If none of the old-style constraint macros are + defined, define USE_MD_CONSTRAINTS; do not provide defaults for any + old-style macros; and poison REG_CLASS_FROM_LETTER, + CONST_OK_FOR_LETTER_P, CONST_DOUBLE_OK_FOR_LETTER_P, and + EXTRA_CONSTRAINT. + * recog.c (reg_fits_class_p): If cl is NO_REGS, return 0 immediately. + * doc/md.texi: Document new constraint-definition mechanism and the + C interface it provides. Remove references to old mechanism + elsewhere in the document. + (Machine Constraints): Use pathnames relative to gcc directory, + i.e. config/ARCH/FILE. Change i386 section to refer to + config/i386/predicates.md; update that section to match docstrings. + * doc/tm.texi: Move all documentation of the old constraint- + definition macros to their own section, clearly mark as obsolete. + + * config/i386/predicates.md (R, q, Q, l, a, b, c, d, S, D, A, f, t) + (u, y, x, Y, I, J, K, L, M, N, O, G, C, e, Z): New constraint + definitions. + * config/i386/i386.h (REG_CLASS_FROM_LETTER, CONST_OK_FOR_LETTER_P) + (CONST_DOUBLE_OK_FOR_LETTER_P, EXTRA_CONSTRAINT): Delete. + * config/i386/i386.md (*movdf_nointeger): Remove stray 'H' from + constraint strings. + (splits and peepholes): Use satisfies_constraint_*. + * config/i386/i386.c (memory_address_length) + (ix86_attr_length_immediate_default): Use satisfies_constraint_*. + 2006-02-27 Daniel Berlin <dberlin@dberlin.org> * lambda-code.c (can_convert_to_perfect_nest): Allow any type of diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index edfe04f57377..fae111e986f0 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13291,9 +13291,7 @@ memory_address_length (rtx addr) /* Find the length of the displacement constant. */ if (disp) { - if (GET_CODE (disp) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K') - && base) + if (base && satisfies_constraint_K (disp)) len = 1; else len = 4; @@ -13326,9 +13324,7 @@ ix86_attr_length_immediate_default (rtx insn, int shortform) if (CONSTANT_P (recog_data.operand[i])) { gcc_assert (!len); - if (shortform - && GET_CODE (recog_data.operand[i]) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (recog_data.operand[i]), 'K')) + if (shortform && satisfies_constraint_K (recog_data.operand[i])) len = 1; else { diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 307cc97d4df4..fc8f62661b58 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1196,92 +1196,6 @@ enum reg_class #define INDEX_REG_CLASS INDEX_REGS #define BASE_REG_CLASS GENERAL_REGS -/* Unused letters: - B TU W - h jk vw z -*/ - -/* Get reg_class from a letter such as appears in the machine description. */ - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'r' ? GENERAL_REGS : \ - (C) == 'R' ? LEGACY_REGS : \ - (C) == 'q' ? TARGET_64BIT ? GENERAL_REGS : Q_REGS : \ - (C) == 'Q' ? Q_REGS : \ - (C) == 'f' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ - ? FLOAT_REGS \ - : NO_REGS) : \ - (C) == 't' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ - ? FP_TOP_REG \ - : NO_REGS) : \ - (C) == 'u' ? (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 \ - ? FP_SECOND_REG \ - : NO_REGS) : \ - (C) == 'a' ? AREG : \ - (C) == 'b' ? BREG : \ - (C) == 'c' ? CREG : \ - (C) == 'd' ? DREG : \ - (C) == 'x' ? TARGET_SSE ? SSE_REGS : NO_REGS : \ - (C) == 'Y' ? TARGET_SSE2? SSE_REGS : NO_REGS : \ - (C) == 'y' ? TARGET_MMX ? MMX_REGS : NO_REGS : \ - (C) == 'A' ? AD_REGS : \ - (C) == 'D' ? DIREG : \ - (C) == 'S' ? SIREG : \ - (C) == 'l' ? INDEX_REGS : \ - NO_REGS) - -/* The letters I, J, K, L, M, N, and O in a register constraint string - can be used to stand for particular ranges of immediate operands. - This macro defines what the ranges are. - C is the letter, and VALUE is a constant value. - Return 1 if VALUE is in the range specified by C. - - I is for non-DImode shifts. - J is for DImode shifts. - K is for signed imm8 operands. - L is for andsi as zero-extending move. - M is for shifts that can be executed by the "lea" opcode. - N is for immediate operands for out/in instructions (0-255) - O is for TImode shifts. - */ - -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 31 \ - : (C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 63 \ - : (C) == 'K' ? (VALUE) >= -128 && (VALUE) <= 127 \ - : (C) == 'L' ? (VALUE) == 0xff || (VALUE) == 0xffff \ - : (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 \ - : (C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 \ - : (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 127 \ - : 0) - -/* Similar, but for floating constants, and defining letters G and H. - Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if - TARGET_387 isn't set, because the stack register converter may need to - load 0.0 into the function value register. */ - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'G' ? standard_80387_constant_p (VALUE) \ - : 0) - -/* A C expression that defines the optional machine-dependent - constraint letters that can be used to segregate specific types of - operands, usually memory references, for the target machine. Any - letter that is not elsewhere defined and not matched by - `REG_CLASS_FROM_LETTER' may be used. Normally this macro will not - be defined. - - If it is required for a particular target machine, it should - return 1 if VALUE corresponds to the operand type represented by - the constraint letter C. If C is not defined as an extra - constraint, the value returned should be 0 regardless of VALUE. */ - -#define EXTRA_CONSTRAINT(VALUE, D) \ - ((D) == 'e' ? x86_64_immediate_operand (VALUE, VOIDmode) \ - : (D) == 'Z' ? x86_64_zext_immediate_operand (VALUE, VOIDmode) \ - : (D) == 'C' ? standard_sse_constant_p (VALUE) \ - : 0) - /* Place additional restrictions on the register class to use when it is necessary to be able to hold a value of mode MODE in a reload register for which class CLASS would ordinarily be used. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 868d33676162..4e64da31a3ff 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2440,9 +2440,9 @@ (define_insn "*movdf_nointeger" [(set (match_operand:DF 0 "nonimmediate_operand" - "=f#Y,m ,f#Y,*r ,o ,Y*x#f,Y*x#f,Y*x#f ,m ") + "=f#Y,m ,f#Y,*r ,o ,Y*x#f,Y*x#f,Y*x#f ,m ") (match_operand:DF 1 "general_operand" - "fm#Y,f#Y,G ,*roF,F*r,C ,Y*x#f,HmY*x#f,Y*x#f"))] + "fm#Y,f#Y,G ,*roF,F*r,C ,Y*x#f,mY*x#f,Y*x#f"))] "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) && ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT) && (reload_in_progress || reload_completed @@ -19038,8 +19038,9 @@ "! TARGET_PARTIAL_REG_STALL && reload_completed && ((GET_MODE (operands[0]) == HImode && ((!optimize_size && !TARGET_FAST_PREFIX) + /* ??? next two lines just !satisfies_constraint_K (...) */ || GET_CODE (operands[2]) != CONST_INT - || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))) + || satisfies_constraint_K (operands[2]))) || (GET_MODE (operands[0]) == QImode && (TARGET_PROMOTE_QImode || optimize_size)))" [(parallel [(set (match_dup 0) @@ -19361,8 +19362,7 @@ (const_int 0)]))] "ix86_match_ccmode (insn, CCNOmode) && (true_regnum (operands[2]) != 0 - || (GET_CODE (operands[3]) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'K'))) + || satisfies_constraint_K (operands[3])) && peep2_reg_dead_p (1, operands[2])" [(parallel [(set (match_dup 0) @@ -19928,8 +19928,7 @@ (match_operand:DI 2 "immediate_operand" ""))) (clobber (reg:CC FLAGS_REG))])] "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && (GET_CODE (operands[2]) != CONST_INT - || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" + && !satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:DI (match_dup 3) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] @@ -19942,8 +19941,7 @@ (match_operand:SI 2 "immediate_operand" ""))) (clobber (reg:CC FLAGS_REG))])] "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && (GET_CODE (operands[2]) != CONST_INT - || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" + && !satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:SI (match_dup 3) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] @@ -19957,8 +19955,7 @@ (match_operand:SI 2 "immediate_operand" "")))) (clobber (reg:CC FLAGS_REG))])] "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && (GET_CODE (operands[2]) != CONST_INT - || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))" + && !satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (zero_extend:DI (mult:SI (match_dup 3) (match_dup 2)))) (clobber (reg:CC FLAGS_REG))])] @@ -19975,7 +19972,7 @@ (clobber (reg:CC FLAGS_REG))]) (match_scratch:DI 3 "r")] "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" + && satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 2)) (parallel [(set (match_dup 0) (mult:DI (match_dup 0) (match_dup 3))) (clobber (reg:CC FLAGS_REG))])] @@ -19991,7 +19988,7 @@ (clobber (reg:CC FLAGS_REG))]) (match_scratch:SI 3 "r")] "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size - && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')" + && satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 2)) (parallel [(set (match_dup 0) (mult:SI (match_dup 0) (match_dup 3))) (clobber (reg:CC FLAGS_REG))])] diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index acc01eeb537b..d97f6fccbca8 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -947,3 +947,137 @@ (define_predicate "absneg_operator" (match_code "abs,neg")) + +;;; Constraint definitions. +;;; Unused letters: +;;; B H TU W +;;; h jk vw z + +;; Integer register constraints. +;; It is not necessary to define 'r' here. +(define_register_constraint "R" "LEGACY_REGS" + "Legacy register---the eight integer registers available on all + i386 processors (@code{a}, @code{b}, @code{c}, @code{d}, + @code{si}, @code{di}, @code{bp}, @code{sp}).") + +(define_register_constraint "q" "TARGET_64BIT ? GENERAL_REGS : Q_REGS" + "Any register accessible as @code{@var{r}l}. In 32-bit mode, @code{a}, + @code{b}, @code{c}, and @code{d}; in 64-bit mode, any integer register.") + +(define_register_constraint "Q" "Q_REGS" + "Any register accessible as @code{@var{r}h}: @code{a}, @code{b}, + @code{c}, and @code{d}.") + +(define_register_constraint "l" "INDEX_REGS" + "@internal Any register that can be used as the index in a base+index + memory access: that is, any general register except the stack pointer.") + +(define_register_constraint "a" "AREG" + "The @code{a} register.") + +(define_register_constraint "b" "BREG" + "The @code{b} register.") + +(define_register_constraint "c" "CREG" + "The @code{c} register.") + +(define_register_constraint "d" "DREG" + "The @code{d} register.") + +(define_register_constraint "S" "SIREG" + "The @code{si} register.") + +(define_register_constraint "D" "DIREG" + "The @code{di} register.") + +(define_register_constraint "A" "AD_REGS" + "The @code{a} and @code{d} registers, as a pair (for instructions + that return half the result in one and half in the other).") + +;; Floating-point register constraints. +(define_register_constraint "f" + "TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 ? FLOAT_REGS : NO_REGS" + "Any 80387 floating-point (stack) register.") + +(define_register_constraint "t" + "TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 ? FP_TOP_REG : NO_REGS" + "Top of 80387 floating-point stack (@code{%st(0)}).") + +(define_register_constraint "u" + "TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387 ? FP_SECOND_REG : NO_REGS" + "Second from top of 80387 floating-point stack (@code{%st(1)}).") + +;; Vector registers (also used for plain floating point nowadays). +(define_register_constraint "y" "TARGET_MMX ? MMX_REGS : NO_REGS" + "Any MMX register.") + +(define_register_constraint "x" "TARGET_SSE ? SSE_REGS : NO_REGS" + "Any SSE register.") + +(define_register_constraint "Y" "TARGET_SSE2? SSE_REGS : NO_REGS" + "@internal Any SSE2 register.") + +;; Integer constant constraints. +(define_constraint "I" + "Integer constant in the range 0 @dots{} 31, for 32-bit shifts." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 31"))) + +(define_constraint "J" + "Integer constant in the range 0 @dots{} 63, for 64-bit shifts." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 63"))) + +(define_constraint "K" + "Signed 8-bit integer constant." + (and (match_code "const_int") + (match_test "ival >= -128 && ival <= 127"))) + +(define_constraint "L" + "@code{0xFF} or @code{0xFFFF}, for andsi as a zero-extending move." + (and (match_code "const_int") + (match_test "ival == 0xFF || ival == 0xFFFF"))) + +(define_constraint "M" + "0, 1, 2, or 3 (shifts for the @code{lea} instruction)." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 3"))) + +(define_constraint "N" + "Unsigned 8-bit integer constant (for @code{in} and @code{out} + instructions)." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 255"))) + +(define_constraint "O" + "@internal Integer constant in the range 0 @dots{} 127, for 128-bit shifts." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 127"))) + +;; Floating-point constant constraints. +;; We allow constants even if TARGET_80387 isn't set, because the +;; stack register converter may need to load 0.0 into the function +;; value register (top of stack). +(define_constraint "G" + "Standard 80387 floating point constant." + (and (match_code "const_double") + (match_test "standard_80387_constant_p (op)"))) + +;; This can theoretically be any mode's CONST0_RTX. +(define_constraint "C" + "Standard SSE floating point constant." + (match_test "standard_sse_constant_p (op)")) + +;; Constant-or-symbol-reference constraints. + +(define_constraint "e" + "32-bit signed integer constant, or a symbolic reference known + to fit that range (for immediate operands in sign-extending x86-64 + instructions)." + (match_operand 0 "x86_64_immediate_operand")) + +(define_constraint "Z" + "32-bit unsigned integer constant, or a symbolic reference known + to fit that range (for immediate operands in zero-extending x86-64 + instructions)." + (match_operand 0 "x86_64_zext_immediate_operand")) diff --git a/gcc/defaults.h b/gcc/defaults.h index a82a7230dc21..624f039dfea2 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -752,6 +752,33 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define DEFAULT_USE_CXA_ATEXIT 0 #endif +/* If none of these macros are defined, the port must use the new + technique of defining constraints in the machine description. + tm_p.h will define those macros that machine-independent code + still uses. */ +#if !defined CONSTRAINT_LEN \ + && !defined REG_CLASS_FROM_LETTER \ + && !defined REG_CLASS_FROM_CONSTRAINT \ + && !defined CONST_OK_FOR_LETTER_P \ + && !defined CONST_OK_FOR_CONSTRAINT_P \ + && !defined CONST_DOUBLE_OK_FOR_LETTER_P \ + && !defined CONST_DOUBLE_OK_FOR_CONSTRAINT_P \ + && !defined EXTRA_CONSTRAINT \ + && !defined EXTRA_CONSTRAINT_STR \ + && !defined EXTRA_MEMORY_CONSTRAINT \ + && !defined EXTRA_ADDRESS_CONSTRAINT + +#define USE_MD_CONSTRAINTS + +#if GCC_VERSION >= 3000 && defined IN_GCC +/* These old constraint macros shouldn't appear anywhere in a + configuration using MD constraint definitions. */ +#pragma GCC poison REG_CLASS_FROM_LETTER CONST_OK_FOR_LETTER_P \ + CONST_DOUBLE_OK_FOR_LETTER_P EXTRA_CONSTRAINT +#endif + +#else /* old constraint mechanism in use */ + /* Determine whether extra constraint letter should be handled via address reload (like 'o'). */ #ifndef EXTRA_MEMORY_CONSTRAINT @@ -791,6 +818,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define EXTRA_CONSTRAINT_STR(OP, C,STR) EXTRA_CONSTRAINT (OP, C) #endif +#endif /* old constraint mechanism in use */ + #ifndef REGISTER_MOVE_COST #define REGISTER_MOVE_COST(m, x, y) 2 #endif diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 462509d049ba..6a3300bae3e8 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -1051,6 +1051,8 @@ have. Constraints can also require two operands to match. * Class Preferences:: Constraints guide which hard register to put things in. * Modifiers:: More precise control over effects of constraints. * Machine Constraints:: Existing constraints for some particular machines. +* Define Constraints:: How to define machine-specific constraints. +* C Constraint Interface:: How to test constraints from C code. @end menu @end ifset @@ -1273,15 +1275,6 @@ Other letters can be defined in machine-dependent fashion to stand for particular classes of registers or other arbitrary operand types. @samp{d}, @samp{a} and @samp{f} are defined on the 68000/68020 to stand for data, address and floating point registers. - -@ifset INTERNALS -The machine description macro @code{REG_CLASS_FROM_LETTER} has first -cut at the otherwise unused letters. If it evaluates to @code{NO_REGS}, -then @code{EXTRA_CONSTRAINT} is evaluated. - -A typical use for @code{EXTRA_CONSTRAINT} would be to distinguish certain -types of memory references that affect other insn operands. -@end ifset @end table @ifset INTERNALS @@ -1624,35 +1617,16 @@ general-purpose registers respectively; @pxref{Simple Constraints}), and @samp{I}, usually the letter indicating the most common immediate-constant format. -For each machine architecture, the -@file{config/@var{machine}/@var{machine}.h} file defines additional -constraints. These constraints are used by the compiler itself for -instruction generation, as well as for @code{asm} statements; therefore, -some of the constraints are not particularly interesting for @code{asm}. -The constraints are defined through these macros: - -@table @code -@item REG_CLASS_FROM_LETTER -Register class constraints (usually lowercase). - -@item CONST_OK_FOR_LETTER_P -Immediate constant constraints, for non-floating point constants of -word size or smaller precision (usually uppercase). - -@item CONST_DOUBLE_OK_FOR_LETTER_P -Immediate constant constraints, for all floating point constants and for -constants of greater than word size precision (usually uppercase). - -@item EXTRA_CONSTRAINT -Special cases of registers or memory. This macro is not required, and -is only defined for some machines. -@end table - -Inspecting these macro definitions in the compiler source for your -machine is the best way to be certain you have the right constraints. -However, here is a summary of the machine-dependent constraints -available on some particular machines. - +Each architecture defines additional constraints. These constraints +are used by the compiler itself for instruction generation, as well as +for @code{asm} statements; therefore, some of the constraints are not +particularly useful for @code{asm}. Here is a summary of some of the +machine-dependent constraints available on some particular machines; +it includes both constraints that are useful for @code{asm} and +constraints that aren't. The compiler source file mentioned in the +table heading for each architecture is the definitive reference for +the meanings of that architecture's constraints. + @table @emph @item ARM family---@file{config/arm/arm.h} @table @code @@ -1908,93 +1882,109 @@ A 15-bit signed integer constant. A positive 16-bit constant. @end table -@item Intel 386---@file{config/i386/i386.h} +@item Intel 386---@file{config/i386/predicates.md} @table @code -@item q -@samp{a}, @code{b}, @code{c}, or @code{d} register for the i386. -For x86-64 it is equivalent to @samp{r} class (for 8-bit instructions that -do not use upper halves). - -@item Q -@samp{a}, @code{b}, @code{c}, or @code{d} register (for 8-bit instructions, -that do use upper halves). - @item R -Legacy register---equivalent to @code{r} class in i386 mode. -(for non-8-bit registers used together with 8-bit upper halves in a single -instruction) - -@item A -Specifies the @samp{a} or @samp{d} registers. This is primarily useful -for 64-bit integer values (when in 32-bit mode) intended to be returned -with the @samp{d} register holding the most significant bits and the -@samp{a} register holding the least significant bits. +Legacy register---the eight integer registers available on all +i386 processors (@code{a}, @code{b}, @code{c}, @code{d}, +@code{si}, @code{di}, @code{bp}, @code{sp}). -@item f -Floating point register +@item q +Any register accessible as @code{@var{r}l}. In 32-bit mode, @code{a}, +@code{b}, @code{c}, and @code{d}; in 64-bit mode, any integer register. -@item t -First (top of stack) floating point register +@item Q +Any register accessible as @code{@var{r}h}: @code{a}, @code{b}, +@code{c}, and @code{d}. -@item u -Second floating point register +@ifset INTERNALS +@item l +Any register that can be used as the index in a base+index memory +access: that is, any general register except the stack pointer. +@end ifset @item a -@samp{a} register +The @code{a} register. @item b -@samp{b} register +The @code{b} register. @item c -@samp{c} register - -@item C -Specifies constant that can be easily constructed in SSE register without -loading it from memory. +The @code{c} register. @item d -@samp{d} register +The @code{d} register. + +@item S +The @code{si} register. @item D -@samp{di} register +The @code{di} register. -@item S -@samp{si} register +@item A +The @code{a} and @code{d} registers, as a pair (for instructions that +return half the result in one and half in the other). -@item x -@samp{xmm} SSE register +@item f +Any 80387 floating-point (stack) register. + +@item t +Top of 80387 floating-point stack (@code{%st(0)}). + +@item u +Second from top of 80387 floating-point stack (@code{%st(1)}). @item y -MMX register +Any MMX register. + +@item x +Any SSE register. + +@ifset INTERNALS +@item Y +Any SSE2 register. +@end ifset @item I -Constant in range 0 to 31 (for 32-bit shifts) +Integer constant in the range 0 @dots{} 31, for 32-bit shifts. @item J -Constant in range 0 to 63 (for 64-bit shifts) +Integer constant in the range 0 @dots{} 63, for 64-bit shifts. @item K -@samp{0xff} +Signed 8-bit integer constant. @item L -@samp{0xffff} +@code{0xFF} or @code{0xFFFF}, for andsi as a zero-extending move. @item M -0, 1, 2, or 3 (shifts for @code{lea} instruction) +0, 1, 2, or 3 (shifts for the @code{lea} instruction). @item N -Constant in range 0 to 255 (for @code{out} instruction) +Unsigned 8-bit integer constant (for @code{in} and @code{out} +instructions). -@item Z -Constant in range 0 to @code{0xffffffff} or symbolic reference known to fit specified range. -(for using immediates in zero extending 32-bit to 64-bit x86-64 instructions) +@ifset INTERNALS +@item O +Integer constant in the range 0 @dots{} 127, for 128-bit shifts. +@end ifset + +@item G +Standard 80387 floating point constant. + +@item C +Standard SSE floating point constant. @item e -Constant in range @minus{}2147483648 to 2147483647 or symbolic reference known to fit specified range. -(for using immediates in 64-bit x86-64 instructions) +32-bit signed integer constant, or a symbolic reference known +to fit that range (for immediate operands in sign-extending x86-64 +instructions). + +@item Z +32-bit unsigned integer constant, or a symbolic reference known +to fit that range (for immediate operands in zero-extending x86-64 +instructions). -@item G -Standard 80387 floating point constant @end table @item Intel IA-64---@file{config/ia64/ia64.h} @@ -2868,6 +2858,257 @@ Unsigned constant valid for BccUI instructions @end table @ifset INTERNALS +@node Define Constraints +@subsection Defining Machine-Specific Constraints +@cindex defining constraints +@cindex constraints, defining + +Machine-specific constraints fall into two categories: register and +non-register constraints. Within the latter category, constraints +which allow subsets of all possible memory or address operands should +be specially marked, to give @code{reload} more information. + +Machine-specific constraints can be given names of arbitrary length, +but they must be entirely composed of letters, digits, underscores +(@samp{_}), and angle brackets (@samp{< >}). Like C identifiers, they +must begin with a letter or underscore. + +In order to avoid ambiguity in operand constraint strings, no +constraint can have a name that begins with any other constraint's +name. For example, if @code{x} is defined as a constraint name, +@code{xy} may not be, and vice versa. As a consequence of this rule, +no constraint may begin with one of the generic constraint letters: +@samp{E F V X g i m n o p r s}. + +Register constraints correspond directly to register classes. +@xref{Register Classes}. There is thus not much flexibility in their +definitions. + +@deffn {MD Expression} define_register_constraint name regclass docstring +All three arguments are string constants. +@var{name} is the name of the constraint, as it will appear in +@code{match_operand} expressions. @var{regclass} can be either the +name of the corresponding register class (@pxref{Register Classes}), +or a C expression which evaluates to the appropriate register class. +If it is an expression, it must have no side effects, and it cannot +look at the operand. The usual use of expressions is to map some +register constraints to @code{NO_REGS} when the register class +is not available on a given subarchitecture. + +@var{docstring} is a sentence documenting the meaning of the +constraint. Docstrings are explained further below. +@end deffn + +Non-register constraints are more like predicates: the constraint +definition gives a Boolean expression which indicates whether the +constraint matches. + +@deffn {MD Expression} define_constraint name docstring exp +The @var{name} and @var{docstring} arguments are the same as for +@code{define_register_constraint}, but note that the docstring comes +immediately after the name for these expressions. @var{exp} is an RTL +expression, obeying the same rules as the RTL expressions in predicate +definitions. @xref{Defining Predicates}, for details. If it +evaluates true, the constraint matches; if it evaluates false, it +doesn't. Constraint expressions should indicate which RTL codes they +might match, just like predicate expressions. + +@code{match_test} C expressions have access to the +following variables: + +@table @var +@item op +The RTL object defining the operand. +@item mode +The machine mode of @var{op}. +@item ival +@samp{INTVAL (@var{op})}, if @var{op} is a @code{const_int}. +@item hval +@samp{CONST_DOUBLE_HIGH (@var{op})}, if @var{op} is an integer +@code{const_double}. +@item lval +@samp{CONST_DOUBLE_LOW (@var{op})}, if @var{op} is an integer +@code{const_double}. +@item rval +@samp{CONST_DOUBLE_REAL_VALUE (@var{op})}, if @var{op} is a floating-point +@code{const_@/double}. +@end table + +The @var{*val} variables should only be used once another piece of the +expression has verified that @var{op} is the appropriate kind of RTL +object. +@end deffn + +Most non-register constraints should be defined with +@code{define_constraint}. The remaining two definition expressions +are only appropriate for constraints that should be handled specially +by @code{reload} if they fail to match. + +@deffn {MD Expression} define_memory_constraint name docstring exp +Use this expression for constraints that match a subset of all memory +operands: that is, @code{reload} can make them match by converting the +operand to the form @samp{@w{(mem (reg @var{X}))}}, where @var{X} is a +base register (from the register class specified by +@code{BASE_REG_CLASS}, @pxref{Register Classes}). + +For example, on the S/390, some instructions do not accept arbitrary +memory references, but only those that do not make use of an index +register. The constraint letter @samp{Q} is defined to represent a +memory address of this type. If @samp{Q} is defined with +@code{define_memory_constraint}, a @samp{Q} constraint can handle any +memory operand, because @code{reload} knows it can simply copy the +memory address into a base register if required. This is analogous to +the way a @samp{o} constraint can handle any memory operand. + +The syntax and semantics are otherwise identical to +@code{define_constraint}. +@end deffn + +@deffn {MD Expression} define_address_constraint name docstring exp +Use this expression for constraints that match a subset of all address +operands: that is, @code{reload} can make the constraint match by +converting the operand to the form @samp{@w{(reg @var{X})}}, again +with @var{X} a base register. + +Constraints defined with @code{define_address_constraint} can only be +used with the @code{address_operand} predicate, or machine-specific +predicates that work the same way. They are treated analogously to +the generic @samp{p} constraint. + +The syntax and semantics are otherwise identical to +@code{define_constraint}. +@end deffn + +For historical reasons, names beginning with the letters @samp{G H} +are reserved for constraints that match only @code{const_double}s, and +names beginning with the letters @samp{I J K L M N O P} are reserved +for constraints that match only @code{const_int}s. This may change in +the future. For the time being, constraints with these names must be +written in a stylized form, so that @code{genpreds} can tell you did +it correctly: + +@smallexample +@group +(define_constraint "[@var{GHIJKLMNOP}]@dots{}" + "@var{doc}@dots{}" + (and (match_code "const_int") ; @r{@code{const_double} for G/H} + @var{condition}@dots{})) ; @r{usually a @code{match_test}} +@end group +@end smallexample +@c the semicolons line up in the formatted manual + +It is fine to use names beginning with other letters for constraints +that match @code{const_double}s or @code{const_int}s. + +Each docstring in a constraint definition should be one or more complete +sentences, marked up in Texinfo format. @emph{They are currently unused.} +In the future they will be copied into the GCC manual, in @ref{Machine +Constraints}, replacing the hand-maintained tables currently found in +that section. Also, in the future the compiler may use this to give +more helpful diagnostics when poor choice of @code{asm} constraints +causes a reload failure. + +If you put the pseudo-Texinfo directive @samp{@@internal} at the +beginning of a docstring, then (in the future) it will appear only in +the internals manual's version of the machine-specific constraint tables. +Use this for constraints that should not appear in @code{asm} statements. + +@node C Constraint Interface +@subsection Testing constraints from C +@cindex testing constraints +@cindex constraints, testing + +It is occasionally useful to test a constraint from C code rather than +implicitly via the constraint string in a @code{match_operand}. The +generated file @file{tm_p.h} declares a few interfaces for working +with machine-specific constraints. None of these interfaces work with +the generic constraints described in @ref{Simple Constraints}. This +may change in the future. + +@strong{Warning:} @file{tm_p.h} may declare other functions that +operate on constraints, besides the ones documented here. Do not use +those functions from machine-dependent code. They exist to implement +the old constraint interface that machine-independent components of +the compiler still expect. They will change or disappear in the +future. + +Some valid constraint names are not valid C identifiers, so there is a +mangling scheme for referring to them from C@. Constraint names that +do not contain angle brackets or underscores are left unchanged. +Underscores are doubled, each @samp{<} is replaced with @samp{_l}, and +each @samp{>} with @samp{_g}. Here are some examples: + +@c the @c's prevent double blank lines in the printed manual. +@example +@multitable {Original} {Mangled} +@headitem Original @tab Mangled @c +@item @code{x} @tab @code{x} @c +@item @code{P42x} @tab @code{P42x} @c +@item @code{P4_x} @tab @code{P4__x} @c +@item @code{P4>x} @tab @code{P4_gx} @c +@item @code{P4>>} @tab @code{P4_g_g} @c +@item @code{P4_g>} @tab @code{P4__g_g} @c +@end multitable +@end example + +Throughout this section, the variable @var{c} is either a constraint +in the abstract sense, or a constant from @code{enum constraint_num}; +the variable @var{m} is a mangled constraint name (usually as part of +a larger identifier). + +@deftp Enum constraint_num +For each machine-specific constraint, there is a corresponding +enumeration constant: @samp{CONSTRAINT_} plus the mangled name of the +constraint. Functions that take an @code{enum constraint_num} as an +argument expect one of these constants. + +Machine-independent constraints do not have associated constants. +This may change in the future. +@end deftp + +@deftypefun {inline bool} satisfies_constraint_@var{m} (rtx @var{exp}) +For each machine-specific, non-register constraint @var{m}, there is +one of these functions; it returns @code{true} if @var{exp} satisfies the +constraint. These functions are only visible if @file{rtl.h} was included +before @file{tm_p.h}. +@end deftypefun + +@deftypefun bool constraint_satisfied_p (rtx @var{exp}, enum constraint_num @var{c}) +Like the @code{satisfies_constraint_@var{m}} functions, but the +constraint to test is given as an argument, @var{c}. If @var{c} +specifies a register constraint, this function will always return +@code{false}. +@end deftypefun + +@deftypefun {enum reg_class} regclass_for_constraint (enum constraint_num @var{c}) +Returns the register class associated with @var{c}. If @var{c} is not +a register constraint, or those registers are not available for the +currently selected subtarget, returns @code{NO_REGS}. +@end deftypefun + +Here is an example use of @code{satisfies_constraint_@var{m}}. In +peephole optimizations (@pxref{Peephole Definitions}), operand +constraint strings are ignored, so if there are relevant constraints, +they must be tested in the C condition. In the example, the +optimization is applied if operand 2 does @emph{not} satisfy the +@samp{K} constraint. (This is a simplified version of a peephole +definition from the i386 machine description.) + +@smallexample +(define_peephole2 + [(match_scratch:SI 3 "r") + (set (match_operand:SI 0 "register_operand" "") + (mult:SI (match_operand:SI 1 "memory_operand" "") + (match_operand:SI 2 "immediate_operand" "")))] + + "!satisfies_constraint_K (operands[2])" + + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 0) (mult:SI (match_dup 3) (match_dup 2)))] + + "") +@end smallexample + @node Standard Names @section Standard Pattern Names For Generation @cindex standard pattern names diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index cebb71cdee22..778ecc9a9a56 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -33,6 +33,7 @@ through the macros defined in the @file{.h} file. * Type Layout:: Defining sizes and properties of basic user data types. * Registers:: Naming and describing the hardware registers. * Register Classes:: Defining the classes of hardware registers. +* Old Constraints:: The old way to define machine-specific constraints. * Stack and Calling:: Defining which way the stack grows and by how much. * Varargs:: Defining the varargs macros. * Trampolines:: Code set up at run time to enter a nested function. @@ -2300,36 +2301,6 @@ address where its value is either multiplied by a scale factor or added to another register (as well as added to a displacement). @end defmac -@defmac CONSTRAINT_LEN (@var{char}, @var{str}) -For the constraint at the start of @var{str}, which starts with the letter -@var{c}, return the length. This allows you to have register class / -constant / extra constraints that are longer than a single letter; -you don't need to define this macro if you can do with single-letter -constraints only. The definition of this macro should use -DEFAULT_CONSTRAINT_LEN for all the characters that you don't want -to handle specially. -There are some sanity checks in genoutput.c that check the constraint lengths -for the md file, so you can also use this macro to help you while you are -transitioning from a byzantine single-letter-constraint scheme: when you -return a negative length for a constraint you want to re-use, genoutput -will complain about every instance where it is used in the md file. -@end defmac - -@defmac REG_CLASS_FROM_LETTER (@var{char}) -A C expression which defines the machine-dependent operand constraint -letters for register classes. If @var{char} is such a letter, the -value should be the register class corresponding to it. Otherwise, -the value should be @code{NO_REGS}. The register letter @samp{r}, -corresponding to class @code{GENERAL_REGS}, will not be passed -to this macro; you do not need to handle it. -@end defmac - -@defmac REG_CLASS_FROM_CONSTRAINT (@var{char}, @var{str}) -Like @code{REG_CLASS_FROM_LETTER}, but you also get the constraint string -passed in @var{str}, so that you can use suffixes to distinguish between -different variants. -@end defmac - @defmac REGNO_OK_FOR_BASE_P (@var{num}) A C expression which is nonzero if register number @var{num} is suitable for use as a base register in operand addresses. It may be @@ -2682,8 +2653,45 @@ as below: @end smallexample @end defmac -Three other special macros describe which operands fit which constraint -letters. +@node Old Constraints +@section Obsolete Macros for Defining Constraints +@cindex defining constraints, obsolete method +@cindex constraints, defining, obsolete method + +Machine-specific constraints can be defined with these macros instead +of the machine description constructs described in @ref{Define +Constraints}. This mechanism is obsolete. New ports should not use +it; old ports should convert to the new mechanism. + +@defmac CONSTRAINT_LEN (@var{char}, @var{str}) +For the constraint at the start of @var{str}, which starts with the letter +@var{c}, return the length. This allows you to have register class / +constant / extra constraints that are longer than a single letter; +you don't need to define this macro if you can do with single-letter +constraints only. The definition of this macro should use +DEFAULT_CONSTRAINT_LEN for all the characters that you don't want +to handle specially. +There are some sanity checks in genoutput.c that check the constraint lengths +for the md file, so you can also use this macro to help you while you are +transitioning from a byzantine single-letter-constraint scheme: when you +return a negative length for a constraint you want to re-use, genoutput +will complain about every instance where it is used in the md file. +@end defmac + +@defmac REG_CLASS_FROM_LETTER (@var{char}) +A C expression which defines the machine-dependent operand constraint +letters for register classes. If @var{char} is such a letter, the +value should be the register class corresponding to it. Otherwise, +the value should be @code{NO_REGS}. The register letter @samp{r}, +corresponding to class @code{GENERAL_REGS}, will not be passed +to this macro; you do not need to handle it. +@end defmac + +@defmac REG_CLASS_FROM_CONSTRAINT (@var{char}, @var{str}) +Like @code{REG_CLASS_FROM_LETTER}, but you also get the constraint string +passed in @var{str}, so that you can use suffixes to distinguish between +different variants. +@end defmac @defmac CONST_OK_FOR_LETTER_P (@var{value}, @var{c}) A C expression that defines the machine-dependent operand constraint diff --git a/gcc/genoutput.c b/gcc/genoutput.c index 7d1feb6fdcaf..4eac58187296 100644 --- a/gcc/genoutput.c +++ b/gcc/genoutput.c @@ -54,12 +54,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA a. `predicate', an int-valued function, is the match_operand predicate for this operand. - b. `constraint' is the constraint for this operand. This exists - only if register constraints appear in match_operand rtx's. + b. `constraint' is the constraint for this operand. c. `address_p' indicates that the operand appears within ADDRESS - rtx's. This exists only if there are *no* register constraints - in the match_operand rtx's. + rtx's. d. `mode' is the machine mode that that operand is supposed to have. @@ -189,8 +187,35 @@ static void gen_insn (rtx, int); static void gen_peephole (rtx, int); static void gen_expand (rtx, int); static void gen_split (rtx, int); + +#ifdef USE_MD_CONSTRAINTS + +struct constraint_data +{ + struct constraint_data *next_this_letter; + int lineno; + unsigned int namelen; + const char name[1]; +}; + +/* This is a complete list (unlike the one in genpreds.c) of constraint + letters and modifiers with machine-independent meaning. The only + omission is digits, as these are handled specially. */ +static const char indep_constraints[] = ",=+%*?!#&<>EFVXgimnoprs"; + +static struct constraint_data * +constraints_by_letter_table[1 << CHAR_BIT]; + +static int mdep_constraint_len (const char *, int, int); +static void note_constraint (rtx, int); + +#else /* !USE_MD_CONSTRAINTS */ + static void check_constraint_len (void); static int constraint_len (const char *, int); + +#endif /* !USE_MD_CONSTRAINTS */ + static void output_prologue (void) @@ -725,6 +750,20 @@ validate_insn_alternatives (struct data *d) for (p = d->operand[start].constraint; (c = *p); p += len) { +#ifdef USE_MD_CONSTRAINTS + if (ISSPACE (c) || strchr (indep_constraints, c)) + len = 1; + else if (ISDIGIT (c)) + { + const char *q = p; + do + q++; + while (ISDIGIT (*q)); + len = q - p; + } + else + len = mdep_constraint_len (p, d->lineno, start); +#else len = CONSTRAINT_LEN (c, p); if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c))) @@ -735,6 +774,7 @@ validate_insn_alternatives (struct data *d) len = 1; have_error = 1; } +#endif if (c == ',') { @@ -826,7 +866,9 @@ gen_insn (rtx insn, int lineno) d->n_operands = max_opno + 1; d->n_dups = num_dups; +#ifndef USE_MD_CONSTRAINTS check_constraint_len (); +#endif validate_insn_operands (d); validate_insn_alternatives (d); place_operands (d); @@ -983,15 +1025,37 @@ main (int argc, char **argv) if (desc == NULL) break; - if (GET_CODE (desc) == DEFINE_INSN) - gen_insn (desc, line_no); - if (GET_CODE (desc) == DEFINE_PEEPHOLE) - gen_peephole (desc, line_no); - if (GET_CODE (desc) == DEFINE_EXPAND) - gen_expand (desc, line_no); - if (GET_CODE (desc) == DEFINE_SPLIT - || GET_CODE (desc) == DEFINE_PEEPHOLE2) - gen_split (desc, line_no); + switch (GET_CODE (desc)) + { + case DEFINE_INSN: + gen_insn (desc, line_no); + break; + + case DEFINE_PEEPHOLE: + gen_peephole (desc, line_no); + break; + + case DEFINE_EXPAND: + gen_expand (desc, line_no); + break; + + case DEFINE_SPLIT: + case DEFINE_PEEPHOLE2: + gen_split (desc, line_no); + break; + +#ifdef USE_MD_CONSTRAINTS + case DEFINE_CONSTRAINT: + case DEFINE_REGISTER_CONSTRAINT: + case DEFINE_ADDRESS_CONSTRAINT: + case DEFINE_MEMORY_CONSTRAINT: + note_constraint (desc, line_no); + break; +#endif + + default: + break; + } next_index_number++; } @@ -1043,6 +1107,102 @@ strip_whitespace (const char *s) return q; } +#ifdef USE_MD_CONSTRAINTS + +/* Record just enough information about a constraint to allow checking + of operand constraint strings above, in validate_insn_alternatives. + Does not validate most properties of the constraint itself; does + enforce no duplicate names, no overlap with MI constraints, and no + prefixes. EXP is the define_*constraint form, LINENO the line number + reported by the reader. */ +static void +note_constraint (rtx exp, int lineno) +{ + const char *name = XSTR (exp, 0); + unsigned int namelen = strlen (name); + struct constraint_data **iter, **slot, *new; + + if (strchr (indep_constraints, name[0])) + { + if (name[1] == '\0') + message_with_line (lineno, "constraint letter '%s' cannot be " + "redefined by the machine description", name); + else + message_with_line (lineno, "constraint name '%s' cannot be defined by " + "the machine description, as it begins with '%c'", + name, name[0]); + have_error = 1; + return; + } + + slot = &constraints_by_letter_table[(unsigned int)name[0]]; + for (iter = slot; *iter; iter = &(*iter)->next_this_letter) + { + /* This causes slot to end up pointing to the + next_this_letter field of the last constraint with a name + of equal or greater length than the new constraint; hence + the new constraint will be inserted after all previous + constraints with names of the same length. */ + if ((*iter)->namelen >= namelen) + slot = iter; + + if (!strcmp ((*iter)->name, name)) + { + message_with_line (lineno, "redefinition of constraint '%s'", name); + message_with_line ((*iter)->lineno, "previous definition is here"); + have_error = 1; + return; + } + else if (!strncmp ((*iter)->name, name, (*iter)->namelen)) + { + message_with_line (lineno, "defining constraint '%s' here", name); + message_with_line ((*iter)->lineno, "renders constraint '%s' " + "(defined here) a prefix", (*iter)->name); + have_error = 1; + return; + } + else if (!strncmp ((*iter)->name, name, namelen)) + { + message_with_line (lineno, "constraint '%s' is a prefix", name); + message_with_line ((*iter)->lineno, "of constraint '%s' " + "(defined here)", (*iter)->name); + have_error = 1; + return; + } + } + new = xmalloc (sizeof (struct constraint_data) + namelen); + strcpy ((char *)new + offsetof(struct constraint_data, name), name); + new->namelen = namelen; + new->lineno = lineno; + new->next_this_letter = *slot; + *slot = new; +} + +/* Return the length of the constraint name beginning at position S + of an operand constraint string, or issue an error message if there + is no such constraint. Does not expect to be called for generic + constraints. */ +static int +mdep_constraint_len (const char *s, int lineno, int opno) +{ + struct constraint_data *p; + + p = constraints_by_letter_table[(unsigned int)s[0]]; + + if (p) + for (; p; p = p->next_this_letter) + if (!strncmp (s, p->name, p->namelen)) + return p->namelen; + + message_with_line (lineno, + "error: undefined machine-specific constraint " + "at this point: \"%s\"", s); + message_with_line (lineno, "note: in operand %d", opno); + have_error = 1; + return 1; /* safe */ +} + +#else /* Verify that DEFAULT_CONSTRAINT_LEN is used properly and not tampered with. This isn't bullet-proof, but it should catch most genuine mistakes. */ @@ -1076,3 +1236,4 @@ constraint_len (const char *p, int genoutput_default_constraint_len) #undef DEFAULT_CONSTRAINT_LEN #define DEFAULT_CONSTRAINT_LEN(C,STR) 1 } +#endif diff --git a/gcc/genpreds.c b/gcc/genpreds.c index bfd681cc7b8b..9c0bb352e17a 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -27,57 +27,102 @@ Boston, MA 02110-1301, USA. */ #include "tm.h" #include "rtl.h" #include "errors.h" -#include "gensupport.h" #include "obstack.h" +#include "gensupport.h" -/* The new way to declare predicates is with (define_predicate) or - (define_special_predicate) expressions in the machine description. - This provides a function body as well as a name. */ -static void -process_define_predicate (rtx defn) +/* Given a predicate expression EXP, from form NAME at line LINENO, + verify that it does not contain any RTL constructs which are not + valid in predicate definitions. Returns true if EXP is + INvalid; issues error messages, caller need not. */ +static bool +validate_exp (rtx exp, const char *name, int lineno) { - struct pred_data *pred; - if (XEXP (defn, 1) == 0) + if (exp == 0) { - error ("%s: must give a predicate expression", XSTR (defn, 0)); - return; + message_with_line (lineno, "%s: must give a predicate expression", name); + return true; } - pred = XCNEW (struct pred_data); - pred->name = XSTR (defn, 0); - pred->exp = XEXP (defn, 1); - pred->c_block = XSTR (defn, 2); + switch (GET_CODE (exp)) + { + /* Ternary, binary, unary expressions: recurse into subexpressions. */ + case IF_THEN_ELSE: + if (validate_exp (XEXP (exp, 2), name, lineno)) + return true; + /* else fall through */ + case AND: + case IOR: + if (validate_exp (XEXP (exp, 1), name, lineno)) + return true; + /* else fall through */ + case NOT: + return validate_exp (XEXP (exp, 0), name, lineno); - if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) - pred->special = true; + /* MATCH_CODE might have a syntax error in its path expression. */ + case MATCH_CODE: + { + const char *p; + for (p = XSTR (exp, 1); *p; p++) + { + if (!ISDIGIT (*p) && !ISLOWER (*p)) + { + message_with_line (lineno, "%s: invalid character in path " + "string '%s'", name, XSTR (exp, 1)); + have_error = 1; + return true; + } + } + } + /* fall through */ - add_predicate (pred); + /* These need no special checking. */ + case MATCH_OPERAND: + case MATCH_TEST: + return false; + + default: + message_with_line (lineno, + "%s: cannot use '%s' in a predicate expression", + name, GET_RTX_NAME (GET_CODE (exp))); + have_error = 1; + return true; + } } -/* Write tm-preds.h. Unfortunately, it is impossible to forward-declare - an enumeration in portable C, so we have to condition all these - prototypes on HAVE_MACHINE_MODES. */ +/* Predicates are defined with (define_predicate) or + (define_special_predicate) expressions in the machine description. */ static void -write_tm_preds_h (void) +process_define_predicate (rtx defn, int lineno) { - struct pred_data *p; + struct pred_data *pred; + const char *p; - printf ("\ -/* Generated automatically by the program '%s'\n\ - from the machine description file '%s'. */\n\n", progname, in_fname); + if (!ISALPHA (XSTR (defn, 0)[0]) && XSTR (defn, 0)[0] != '_') + goto bad_name; + for (p = XSTR (defn, 0) + 1; *p; p++) + if (!ISALNUM (*p) && *p != '_') + goto bad_name; + + if (validate_exp (XEXP (defn, 1), XSTR (defn, 0), lineno)) + return; - puts ("\ -#ifndef GCC_TM_PREDS_H\n\ -#define GCC_TM_PREDS_H\n\ -\n\ -#ifdef HAVE_MACHINE_MODES"); + pred = XCNEW (struct pred_data); + pred->name = XSTR (defn, 0); + pred->exp = XEXP (defn, 1); + pred->c_block = XSTR (defn, 2); - FOR_ALL_PREDICATES (p) - printf ("extern int %s (rtx, enum machine_mode);\n", p->name); + if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) + pred->special = true; - puts ("\ -#endif /* HAVE_MACHINE_MODES */\n\ -#endif /* tm-preds.h */"); + add_predicate (pred); + return; + + bad_name: + message_with_line (lineno, + "%s: predicate name must be a valid C function name", + XSTR (defn, 0)); + have_error = 1; + return; } /* Given a predicate, if it has an embedded C block, write the block @@ -146,6 +191,59 @@ write_predicate_subfunction (struct pred_data *p) fputs ("\n\n", stdout); } +/* Given a predicate expression EXP, from form NAME, determine whether + it refers to the variable given as VAR. */ +static bool +needs_variable (rtx exp, const char *var) +{ + switch (GET_CODE (exp)) + { + /* Ternary, binary, unary expressions need a variable if + any of their subexpressions do. */ + case IF_THEN_ELSE: + if (needs_variable (XEXP (exp, 2), var)) + return true; + /* else fall through */ + case AND: + case IOR: + if (needs_variable (XEXP (exp, 1), var)) + return true; + /* else fall through */ + case NOT: + return needs_variable (XEXP (exp, 0), var); + + /* MATCH_CODE uses "op", but nothing else. */ + case MATCH_CODE: + return !strcmp (var, "op"); + + /* MATCH_OPERAND uses "op" and may use "mode". */ + case MATCH_OPERAND: + if (!strcmp (var, "op")) + return true; + if (!strcmp (var, "mode") && GET_MODE (exp) == VOIDmode) + return true; + return false; + + /* MATCH_TEST uses var if XSTR (exp, 0) =~ /\b${var}\b/o; */ + case MATCH_TEST: + { + const char *p = XSTR (exp, 0); + const char *q = strstr (p, var); + if (!q) + return false; + if (q != p && (ISALNUM (q[-1]) || q[-1] == '_')) + return false; + q += strlen (var); + if (ISALNUM (q[0] || q[0] == '_')) + return false; + } + return true; + + default: + gcc_unreachable (); + } +} + /* Given an RTL expression EXP, find all subexpressions which we may assume to perform mode tests. Normal MATCH_OPERAND does; MATCH_CODE does if it applies to the whole expression and accepts @@ -214,8 +312,7 @@ mark_mode_tests (rtx exp) break; default: - error ("'%s' cannot be used in a define_predicate expression", - GET_RTX_NAME (GET_CODE (exp))); + gcc_unreachable (); } } @@ -325,10 +422,7 @@ write_extract_subexp (const char *path) else if (ISDIGIT (path[i])) fputs ("XEXP (", stdout); else - { - error ("bad character in path string '%s'", path); - return; - } + gcc_unreachable (); } fputs ("op", stdout); @@ -370,39 +464,39 @@ write_match_code (const char *path, const char *codes) /* EXP is an RTL (sub)expression for a predicate. Recursively descend the expression and write out an equivalent C expression. */ static void -write_predicate_expr (const char *name, rtx exp) +write_predicate_expr (rtx exp) { switch (GET_CODE (exp)) { case AND: putchar ('('); - write_predicate_expr (name, XEXP (exp, 0)); + write_predicate_expr (XEXP (exp, 0)); fputs (") && (", stdout); - write_predicate_expr (name, XEXP (exp, 1)); + write_predicate_expr (XEXP (exp, 1)); putchar (')'); break; case IOR: putchar ('('); - write_predicate_expr (name, XEXP (exp, 0)); + write_predicate_expr (XEXP (exp, 0)); fputs (") || (", stdout); - write_predicate_expr (name, XEXP (exp, 1)); + write_predicate_expr (XEXP (exp, 1)); putchar (')'); break; case NOT: fputs ("!(", stdout); - write_predicate_expr (name, XEXP (exp, 0)); + write_predicate_expr (XEXP (exp, 0)); putchar (')'); break; case IF_THEN_ELSE: putchar ('('); - write_predicate_expr (name, XEXP (exp, 0)); + write_predicate_expr (XEXP (exp, 0)); fputs (") ? (", stdout); - write_predicate_expr (name, XEXP (exp, 1)); + write_predicate_expr (XEXP (exp, 1)); fputs (") : (", stdout); - write_predicate_expr (name, XEXP (exp, 2)); + write_predicate_expr (XEXP (exp, 2)); putchar (')'); break; @@ -422,9 +516,7 @@ write_predicate_expr (const char *name, rtx exp) break; default: - error ("%s: cannot use '%s' in a predicate expression", - name, GET_RTX_NAME (GET_CODE (exp))); - putchar ('0'); + gcc_unreachable (); } } @@ -443,9 +535,651 @@ write_one_predicate_function (struct pred_data *p) printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n" "{\n return ", p->name); - write_predicate_expr (p->name, p->exp); + write_predicate_expr (p->exp); fputs (";\n}\n\n", stdout); } + +/* Constraints fall into two categories: register constraints + (define_register_constraint), and others (define_constraint, + define_memory_constraint, define_address_constraint). We + work out automatically which of the various old-style macros + they correspond to, and produce appropriate code. They all + go in the same hash table so we can verify that there are no + duplicate names. */ + +/* All data from one constraint definition. */ +struct constraint_data +{ + struct constraint_data *next_this_letter; + struct constraint_data *next_textual; + const char *name; + const char *c_name; /* same as .name unless mangling is necessary */ + size_t namelen; + const char *regclass; /* for register constraints */ + rtx exp; /* for other constraints */ + unsigned int lineno; /* line of definition */ + unsigned int is_register : 1; + unsigned int is_const_int : 1; + unsigned int is_const_dbl : 1; + unsigned int is_extra : 1; + unsigned int is_memory : 1; + unsigned int is_address : 1; +}; + +/* Overview of all constraints beginning with a given letter. */ + +static struct constraint_data * +constraints_by_letter_table[1<<CHAR_BIT]; + +/* For looking up all the constraints in the order that they appeared + in the machine description. */ +static struct constraint_data *first_constraint; +static struct constraint_data **last_constraint_ptr = &first_constraint; + +#define FOR_ALL_CONSTRAINTS(iter_) \ + for (iter_ = first_constraint; iter_; iter_ = iter_->next_textual) + +/* These letters, and all names beginning with them, are reserved for + generic constraints. */ +static const char generic_constraint_letters[] = "EFVXgimnoprs"; + +/* Machine-independent code expects that constraints with these + (initial) letters will allow only (a subset of all) CONST_INTs. */ + +static const char const_int_constraints[] = "IJKLMNOP"; + +/* Machine-independent code expects that constraints with these + (initial) letters will allow only (a subset of all) CONST_DOUBLEs. */ + +static const char const_dbl_constraints[] = "GH"; + +/* Summary data used to decide whether to output various functions and + macro definitions. */ +static unsigned int constraint_max_namelen; +static bool have_register_constraints; +static bool have_memory_constraints; +static bool have_address_constraints; +static bool have_extra_constraints; +static bool have_const_int_constraints; +static bool have_const_dbl_constraints; + +/* Convert NAME, which contains angle brackets and/or underscores, to + a string that can be used as part of a C identifier. The string + comes from the rtl_obstack. */ +static const char * +mangle (const char *name) +{ + for (; *name; name++) + switch (*name) + { + case '_': obstack_grow (rtl_obstack, "__", 2); break; + case '<': obstack_grow (rtl_obstack, "_l", 2); break; + case '>': obstack_grow (rtl_obstack, "_g", 2); break; + default: obstack_1grow (rtl_obstack, *name); break; + } + + obstack_1grow (rtl_obstack, '\0'); + return obstack_finish (rtl_obstack); +} + +/* Add one constraint, of any sort, to the tables. NAME is its name; + REGCLASS is the register class, if any; EXP is the expression to + test, if any; IS_MEMORY and IS_ADDRESS indicate memory and address + constraints, respectively; LINENO is the line number from the MD reader. + Not all combinations of arguments are valid; most importantly, REGCLASS + is mutually exclusive with EXP, and IS_MEMORY/IS_ADDRESS are only + meaningful for constraints with EXP. + + This function enforces all syntactic and semantic rules about what + constraints can be defined. */ + +static void +add_constraint (const char *name, const char *regclass, + rtx exp, bool is_memory, bool is_address, + int lineno) +{ + struct constraint_data *c, **iter, **slot; + const char *p; + bool need_mangled_name = false; + bool is_const_int; + bool is_const_dbl; + size_t namelen; + + if (exp && validate_exp (exp, name, lineno)) + return; + + if (!ISALPHA (name[0]) && name[0] != '_') + { + if (name[1] == '\0') + message_with_line (lineno, "constraint name '%s' is not " + "a letter or underscore", name); + else + message_with_line (lineno, "constraint name '%s' does not begin " + "with a letter or underscore", name); + have_error = 1; + return; + } + for (p = name; *p; p++) + if (!ISALNUM (*p)) + { + if (*p == '<' || *p == '>' || *p == '_') + need_mangled_name = true; + else + { + message_with_line (lineno, + "constraint name '%s' must be composed of " + "letters, digits, underscores, and " + "angle brackets", name); + have_error = 1; + return; + } + } + + if (strchr (generic_constraint_letters, name[0])) + { + if (name[1] == '\0') + message_with_line (lineno, "constraint letter '%s' cannot be " + "redefined by the machine description", name); + else + message_with_line (lineno, "constraint name '%s' cannot be defined by " + "the machine description, as it begins with '%c'", + name, name[0]); + have_error = 1; + return; + } + + + namelen = strlen (name); + slot = &constraints_by_letter_table[(unsigned int)name[0]]; + for (iter = slot; *iter; iter = &(*iter)->next_this_letter) + { + /* This causes slot to end up pointing to the + next_this_letter field of the last constraint with a name + of equal or greater length than the new constraint; hence + the new constraint will be inserted after all previous + constraints with names of the same length. */ + if ((*iter)->namelen >= namelen) + slot = iter; + + if (!strcmp ((*iter)->name, name)) + { + message_with_line (lineno, "redefinition of constraint '%s'", name); + message_with_line ((*iter)->lineno, "previous definition is here"); + have_error = 1; + return; + } + else if (!strncmp ((*iter)->name, name, (*iter)->namelen)) + { + message_with_line (lineno, "defining constraint '%s' here", name); + message_with_line ((*iter)->lineno, "renders constraint '%s' " + "(defined here) a prefix", (*iter)->name); + have_error = 1; + return; + } + else if (!strncmp ((*iter)->name, name, namelen)) + { + message_with_line (lineno, "constraint '%s' is a prefix", name); + message_with_line ((*iter)->lineno, "of constraint '%s' " + "(defined here)", (*iter)->name); + have_error = 1; + return; + } + } + + is_const_int = strchr (const_int_constraints, name[0]) != 0; + is_const_dbl = strchr (const_dbl_constraints, name[0]) != 0; + + if (is_const_int || is_const_dbl) + { + enum rtx_code appropriate_code + = is_const_int ? CONST_INT : CONST_DOUBLE; + + /* Consider relaxing this requirement in the future. */ + if (regclass + || GET_CODE (exp) != AND + || GET_CODE (XEXP (exp, 0)) != MATCH_CODE + || strcmp (XSTR (XEXP (exp, 0), 0), + GET_RTX_NAME (appropriate_code))) + { + if (name[1] == '\0') + message_with_line (lineno, "constraint letter '%c' is reserved " + "for %s constraints", + name[0], GET_RTX_NAME (appropriate_code)); + else + message_with_line (lineno, "constraint names beginning with '%c' " + "(%s) are reserved for %s constraints", + name[0], name, + GET_RTX_NAME (appropriate_code)); + + have_error = 1; + return; + } + + if (is_memory) + { + if (name[1] == '\0') + message_with_line (lineno, "constraint letter '%c' cannot be a " + "memory constraint", name[0]); + else + message_with_line (lineno, "constraint name '%s' begins with '%c', " + "and therefore cannot be a memory constraint", + name, name[0]); + + have_error = 1; + return; + } + else if (is_address) + { + if (name[1] == '\0') + message_with_line (lineno, "constraint letter '%c' cannot be a " + "memory constraint", name[0]); + else + message_with_line (lineno, "constraint name '%s' begins with '%c', " + "and therefore cannot be a memory constraint", + name, name[0]); + + have_error = 1; + return; + } + + /* Remove the redundant (and (match_code "const_(int|double)") + from the expression. */ + exp = XEXP (exp, 1); + } + + + c = obstack_alloc (rtl_obstack, sizeof (struct constraint_data)); + c->name = name; + c->c_name = need_mangled_name ? mangle (name) : name; + c->lineno = lineno; + c->namelen = namelen; + c->regclass = regclass; + c->exp = exp; + c->is_register = regclass != 0; + c->is_const_int = is_const_int; + c->is_const_dbl = is_const_dbl; + c->is_extra = !(regclass || is_const_int || is_const_dbl); + c->is_memory = is_memory; + c->is_address = is_address; + + c->next_this_letter = *slot; + *slot = c; + + /* Insert this constraint in the list of all constraints in textual + order. */ + c->next_textual = 0; + *last_constraint_ptr = c; + last_constraint_ptr = &c->next_textual; + + constraint_max_namelen = MAX (constraint_max_namelen, strlen (name)); + have_register_constraints |= c->is_register; + have_const_int_constraints |= c->is_const_int; + have_const_dbl_constraints |= c->is_const_dbl; + have_extra_constraints |= c->is_extra; + have_memory_constraints |= c->is_memory; + have_address_constraints |= c->is_address; +} + +/* Process a DEFINE_CONSTRAINT, DEFINE_MEMORY_CONSTRAINT, or + DEFINE_ADDRESS_CONSTRAINT expression, C. */ +static void +process_define_constraint (rtx c, int lineno) +{ + add_constraint (XSTR (c, 0), 0, XEXP (c, 2), + GET_CODE (c) == DEFINE_MEMORY_CONSTRAINT, + GET_CODE (c) == DEFINE_ADDRESS_CONSTRAINT, + lineno); +} + +/* Process a DEFINE_REGISTER_CONSTRAINT expression, C. */ +static void +process_define_register_constraint (rtx c, int lineno) +{ + add_constraint (XSTR (c, 0), XSTR (c, 1), 0, false, false, lineno); +} + +/* Write out an enumeration with one entry per machine-specific + constraint. */ +static void +write_enum_constraint_num (void) +{ + struct constraint_data *c; + + fputs ("enum constraint_num\n" + "{\n" + " CONSTRAINT__UNKNOWN = 0", stdout); + FOR_ALL_CONSTRAINTS (c) + printf (",\n CONSTRAINT_%s", c->c_name); + puts ("\n};\n"); +} + +/* Write out a function which looks at a string and determines what + constraint name, if any, it begins with. */ +static void +write_lookup_constraint (void) +{ + unsigned int i; + puts ("enum constraint_num\n" + "lookup_constraint (const char *str)\n" + "{\n" + " switch (str[0])\n" + " {"); + + for (i = 0; i < ARRAY_SIZE(constraints_by_letter_table); i++) + { + struct constraint_data *c = constraints_by_letter_table[i]; + if (!c) + continue; + + printf (" case '%c':\n", i); + if (c->namelen == 1) + printf (" return CONSTRAINT_%s;\n", c->c_name); + else + { + do + { + printf (" if (!strncmp (str, \"%s\", %lu))\n" + " return CONSTRAINT_%s;\n", + c->name, (unsigned long int) c->namelen, c->c_name); + c = c->next_this_letter; + } + while (c); + puts (" break;"); + } + } + + puts (" default: break;\n" + " }\n" + " return CONSTRAINT__UNKNOWN;\n" + "}\n"); +} + +/* Write out the function which computes constraint name lengths from + their enumerators. */ +static void +write_insn_constraint_len (void) +{ + struct constraint_data *c; + + if (constraint_max_namelen == 1) + return; + + puts ("unsigned int\n" + "insn_constraint_len (enum constraint_num c)\n" + "{\n" + " switch (c)\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (c->namelen > 1) + printf (" case CONSTRAINT_%s: return %lu;\n", c->c_name, + (unsigned long int) c->namelen); + + puts (" default: break;\n" + " }\n" + " return 1;\n" + "}\n"); +} + +/* Write out the function which computes the register class corresponding + to a register constraint. */ +static void +write_regclass_for_constraint (void) +{ + struct constraint_data *c; + + puts ("enum reg_class\n" + "regclass_for_constraint (enum constraint_num c)\n" + "{\n" + " switch (c)\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (c->is_register) + printf (" case CONSTRAINT_%s: return %s;\n", c->c_name, c->regclass); + + puts (" default: break;\n" + " }\n" + " return NO_REGS;\n" + "}\n"); +} + +/* Write out the functions which compute whether a given value matches + a given non-register constraint. */ +static void +write_satisfies_constraint_fns (void) +{ + struct constraint_data *c; + + /* A fair number of places include tm_p.h without including rtl.h. */ + puts ("#ifdef GCC_RTL_H\n"); + + FOR_ALL_CONSTRAINTS (c) + if (!c->is_register) + { + bool needs_ival = needs_variable (c->exp, "ival"); + bool needs_hval = needs_variable (c->exp, "hval"); + bool needs_lval = needs_variable (c->exp, "lval"); + bool needs_rval = needs_variable (c->exp, "rval"); + bool needs_mode = (needs_variable (c->exp, "mode") + || needs_hval || needs_lval || needs_rval); + + printf ("static inline bool\n" + "satisfies_constraint_%s (rtx op)\n" + "{\n", c->c_name); + if (needs_mode) + puts ("enum machine_mode mode = GET_MODE (op);"); + if (needs_ival) + puts (" HOST_WIDE_INT ival = 0;"); + if (needs_hval) + puts (" HOST_WIDE_INT hval = 0;"); + if (needs_lval) + puts (" unsigned HOST_WIDE_INT lval = 0;"); + if (needs_rval) + puts (" const REAL_VALUE_TYPE *rval = 0;"); + + if (needs_ival) + puts (" if (GET_CODE (op) == CONST_INT)\n" + " ival = INTVAL (op);"); + if (needs_hval) + puts (" if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)" + " hval = CONST_DOUBLE_HIGH (op);"); + if (needs_lval) + puts (" if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)" + " lval = CONST_DOUBLE_LOW (op);"); + if (needs_rval) + puts (" if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)" + " rval = CONST_DOUBLE_REAL_VALUE (op);"); + + fputs (" return ", stdout); + write_predicate_expr (c->exp); + fputs (";\n}\n", stdout); + } + + puts ("\n#endif /* rtl.h visible */\n"); +} + +/* Write out the wrapper function, constraint_satisfied_p, that maps + a CONSTRAINT_xxx constant to one of the predicate functions generated + above. */ +static void +write_constraint_satisfied_p (void) +{ + struct constraint_data *c; + + puts ("bool\n" + "constraint_satisfied_p (rtx op, enum constraint_num c)\n" + "{\n" + " switch (c)\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (!c->is_register) + printf (" case CONSTRAINT_%s: " + "return satisfies_constraint_%s (op);\n", + c->c_name, c->c_name); + + puts (" default: break;\n" + " }\n" + " return false;\n" + "}\n"); +} + +/* Write out the function which computes whether a given value matches + a given CONST_INT constraint. This doesn't just forward to + constraint_satisfied_p because caller passes the INTVAL, not the RTX. */ +static void +write_insn_const_int_ok_for_constraint (void) +{ + struct constraint_data *c; + + puts ("bool\n" + "insn_const_int_ok_for_constraint (HOST_WIDE_INT ival, " + "enum constraint_num c)\n" + "{\n" + " switch (c)\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (c->is_const_int) + { + printf (" case CONSTRAINT_%s:\n return ", c->c_name); + write_predicate_expr (c->exp); + fputs (";\n\n", stdout); + } + + puts (" default: break;\n" + " }\n" + " return false;\n" + "}\n"); +} + + +/* Write out the function which computes whether a given constraint is + a memory constraint. */ +static void +write_insn_extra_memory_constraint (void) +{ + struct constraint_data *c; + + puts ("bool\n" + "insn_extra_memory_constraint (enum constraint_num c)\n" + "{\n" + " switch (c)\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (c->is_memory) + printf (" case CONSTRAINT_%s:\n return true;\n\n", c->c_name); + + puts (" default: break;\n" + " }\n" + " return false;\n" + "}\n"); +} + +/* Write out the function which computes whether a given constraint is + an address constraint. */ +static void +write_insn_extra_address_constraint (void) +{ + struct constraint_data *c; + + puts ("bool\n" + "insn_extra_address_constraint (enum constraint_num c)\n" + "{\n" + " switch (str[0])\n" + " {"); + + FOR_ALL_CONSTRAINTS (c) + if (c->is_address) + printf (" case CONSTRAINT_%s:\n return true;\n\n", c->c_name); + + puts (" default: break;\n" + " }\n" + " return false;\n" + "}\n"); +} + + +/* Write tm-preds.h. Unfortunately, it is impossible to forward-declare + an enumeration in portable C, so we have to condition all these + prototypes on HAVE_MACHINE_MODES. */ +static void +write_tm_preds_h (void) +{ + struct pred_data *p; + + printf ("\ +/* Generated automatically by the program '%s'\n\ + from the machine description file '%s'. */\n\n", progname, in_fname); + + puts ("\ +#ifndef GCC_TM_PREDS_H\n\ +#define GCC_TM_PREDS_H\n\ +\n\ +#ifdef HAVE_MACHINE_MODES"); + + FOR_ALL_PREDICATES (p) + printf ("extern int %s (rtx, enum machine_mode);\n", p->name); + + puts ("#endif /* HAVE_MACHINE_MODES */\n"); + + if (constraint_max_namelen > 0) + { + write_enum_constraint_num (); + puts ("extern enum constraint_num lookup_constraint (const char *);\n" + "extern bool constraint_satisfied_p (rtx, enum constraint_num);\n"); + + if (constraint_max_namelen > 1) + puts ("extern size_t insn_constraint_len (enum constraint_num);\n" + "#define CONSTRAINT_LEN(c_,s_) " + "insn_constraint_len (lookup_constraint (s_))\n"); + else + puts ("#define CONSTRAINT_LEN(c_,s_) 1\n"); + if (have_register_constraints) + puts ("extern enum reg_class regclass_for_constraint " + "(enum constraint_num);\n" + "#define REG_CLASS_FROM_CONSTRAINT(c_,s_) \\\n" + " regclass_for_constraint (lookup_constraint (s_))\n"); + else + puts ("#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS"); + if (have_const_int_constraints) + puts ("extern bool insn_const_int_ok_for_constraint " + "(HOST_WIDE_INT, enum constraint_num);\n" + "#define CONST_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n" + " insn_const_int_ok_for_constraint (v_, " + "lookup_constraint (s_))\n"); + if (have_const_dbl_constraints) + puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n" + " constraint_satisfied_p (v_, lookup_constraint (s_))\n"); + else + puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) 0\n"); + if (have_extra_constraints) + puts ("#define EXTRA_CONSTRAINT_STR(v_,c_,s_) \\\n" + " constraint_satisfied_p (v_, lookup_constraint (s_))\n"); + if (have_memory_constraints) + puts ("extern bool " + "insn_extra_memory_constraint (enum constraint_num);\n" + "#define EXTRA_MEMORY_CONSTRAINT(c_,s_) " + "insn_extra_memory_constraint (lookup_constraint (s_))\n"); + else + puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) false\n"); + if (have_address_constraints) + puts ("extern bool " + "insn_extra_address_constraint (enum constraint_num)" + "#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) " + "insn_extra_address_constraint (lookup_constraint (s_))\n"); + else + puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) false\n"); + + if (have_const_int_constraints || have_const_dbl_constraints + || have_extra_constraints) + write_satisfies_constraint_fns (); + } + + puts ("#endif /* tm-preds.h */"); +} /* Write insn-preds.c. N.B. the list of headers to include was copied from genrecog; it @@ -486,6 +1220,24 @@ write_insn_preds_c (void) FOR_ALL_PREDICATES (p) write_one_predicate_function (p); + + if (constraint_max_namelen > 0) + { + write_lookup_constraint (); + write_regclass_for_constraint (); + write_constraint_satisfied_p (); + + if (constraint_max_namelen > 1) + write_insn_constraint_len (); + + if (have_const_int_constraints) + write_insn_const_int_ok_for_constraint (); + + if (have_memory_constraints) + write_insn_extra_memory_constraint (); + if (have_address_constraints) + write_insn_extra_address_constraint (); + } } /* Argument parsing. */ @@ -516,11 +1268,26 @@ main (int argc, char **argv) return FATAL_EXIT_CODE; while ((defn = read_md_rtx (&pattern_lineno, &next_insn_code)) != 0) - { - if (GET_CODE (defn) == DEFINE_PREDICATE - || GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) - process_define_predicate (defn); - } + switch (GET_CODE (defn)) + { + case DEFINE_PREDICATE: + case DEFINE_SPECIAL_PREDICATE: + process_define_predicate (defn, pattern_lineno); + break; + + case DEFINE_CONSTRAINT: + case DEFINE_MEMORY_CONSTRAINT: + case DEFINE_ADDRESS_CONSTRAINT: + process_define_constraint (defn, pattern_lineno); + break; + + case DEFINE_REGISTER_CONSTRAINT: + process_define_register_constraint (defn, pattern_lineno); + break; + + default: + break; + } if (gen_header) write_tm_preds_h (); diff --git a/gcc/gensupport.c b/gcc/gensupport.c index bbac33a2c886..a880b111c0fd 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -287,6 +287,10 @@ process_rtx (rtx desc, int lineno) case DEFINE_PREDICATE: case DEFINE_SPECIAL_PREDICATE: + case DEFINE_CONSTRAINT: + case DEFINE_REGISTER_CONSTRAINT: + case DEFINE_MEMORY_CONSTRAINT: + case DEFINE_ADDRESS_CONSTRAINT: queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno); break; diff --git a/gcc/recog.c b/gcc/recog.c index 9d937ed04480..e3cdfd799148 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -2664,6 +2664,10 @@ reg_fits_class_p (rtx operand, enum reg_class cl, int offset, enum machine_mode mode) { int regno = REGNO (operand); + + if (cl == NO_REGS) + return 0; + if (regno < FIRST_PSEUDO_REGISTER && TEST_HARD_REG_BIT (reg_class_contents[(int) cl], regno + offset)) diff --git a/gcc/rtl.def b/gcc/rtl.def index 8710f54890f4..84b24bc543bb 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -874,6 +874,61 @@ DEF_RTL_EXPR(DEFINE_COND_EXEC, "define_cond_exec", "Ess", RTX_EXTRA) DEF_RTL_EXPR(DEFINE_PREDICATE, "define_predicate", "ses", RTX_EXTRA) DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", RTX_EXTRA) +/* Definition of a register operand constraint. This simply maps the + constraint string to a register class. + + Operand: + 0: The name of the constraint (often, but not always, a single letter). + 1: A C expression which evaluates to the appropriate register class for + this constraint. If this is not just a constant, it should look only + at -m switches and the like. + 2: A docstring for this constraint, in Texinfo syntax; not currently + used, in future will be incorporated into the manual's list of + machine-specific operand constraints. */ +DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sss", RTX_EXTRA) + +/* Definition of a non-register operand constraint. These look at the + operand and decide whether it fits the constraint. + + DEFINE_CONSTRAINT gets no special treatment if it fails to match. + It is appropriate for constant-only constraints, and most others. + + DEFINE_MEMORY_CONSTRAINT tells reload that this constraint can be made + to match, if it doesn't already, by converting the operand to the form + (mem (reg X)) where X is a base register. It is suitable for constraints + that describe a subset of all memory references. + + DEFINE_ADDRESS_CONSTRAINT tells reload that this constraint can be made + to match, if it doesn't already, by converting the operand to the form + (reg X) where X is a base register. It is suitable for constraints that + describe a subset of all address references. + + When in doubt, use plain DEFINE_CONSTRAINT. + + Operand: + 0: The name of the constraint (often, but not always, a single letter). + 1: A docstring for this constraint, in Texinfo syntax; not currently + used, in future will be incorporated into the manual's list of + machine-specific operand constraints. + 2: A boolean expression which computes whether or not the constraint + matches. It should follow the same rules as a define_predicate + expression, including the bit about specifying the set of RTX codes + that could possibly match. MATCH_TEST subexpressions may make use of + these variables: + `op' - the RTL object defining the operand. + `mode' - the mode of `op'. + `ival' - INTVAL(op), if op is a CONST_INT. + `hval' - CONST_DOUBLE_HIGH(op), if op is an integer CONST_DOUBLE. + `lval' - CONST_DOUBLE_LOW(op), if op is an integer CONST_DOUBLE. + `rval' - CONST_DOUBLE_REAL_VALUE(op), if op is a floating-point + CONST_DOUBLE. + Do not use ival/hval/lval/rval if op is not the appropriate kind of + RTL object. */ +DEF_RTL_EXPR(DEFINE_CONSTRAINT, "define_constraint", "sse", RTX_EXTRA) +DEF_RTL_EXPR(DEFINE_MEMORY_CONSTRAINT, "define_memory_constraint", "sse", RTX_EXTRA) +DEF_RTL_EXPR(DEFINE_ADDRESS_CONSTRAINT, "define_address_constraint", "sse", RTX_EXTRA) + + /* Constructions for CPU pipeline description described by NDFAs. */ /* (define_cpu_unit string [string]) describes cpu functional -- GitLab