diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 8b8951d7b14aa1a8858fdc24bf6f9dd3d927d5ea..601173338a9068f7694867c8e6e78f9b10f32a17 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -366,7 +366,7 @@ (define_constants ;; As a convenience, "fp_q" means "fp" + the ability to move between ;; Q registers and is equivalent to "simd". -(define_enum "arches" [ any rcpc8_4 fp fp_q simd sve fp16]) +(define_enum "arches" [ any rcpc8_4 fp fp_q simd nosimd sve fp16]) (define_enum_attr "arch" "arches" (const_string "any")) @@ -397,6 +397,9 @@ (define_attr "arch_enabled" "no,yes" (and (eq_attr "arch" "fp_q, simd") (match_test "TARGET_SIMD")) + (and (eq_attr "arch" "nosimd") + (match_test "!TARGET_SIMD")) + (and (eq_attr "arch" "fp16") (match_test "TARGET_FP_F16INST")) @@ -1206,44 +1209,27 @@ (define_expand "mov" ) (define_insn "*mov_aarch64" - [(set (match_operand:SHORT 0 "nonimmediate_operand" "=r,r, w,r ,r,w, m,m,r,w,w") - (match_operand:SHORT 1 "aarch64_mov_operand" " r,M,D,Usv,m,m,rZ,w,w,rZ,w"))] + [(set (match_operand:SHORT 0 "nonimmediate_operand") + (match_operand:SHORT 1 "aarch64_mov_operand"))] "(register_operand (operands[0], mode) || aarch64_reg_or_zero (operands[1], mode))" -{ - switch (which_alternative) - { - case 0: - return "mov\t%w0, %w1"; - case 1: - return "mov\t%w0, %1"; - case 2: - return aarch64_output_scalar_simd_mov_immediate (operands[1], - mode); - case 3: - return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]); - case 4: - return "ldr\t%w0, %1"; - case 5: - return "ldr\t%0, %1"; - case 6: - return "str\t%w1, %0"; - case 7: - return "str\t%1, %0"; - case 8: - return TARGET_SIMD ? "umov\t%w0, %1.[0]" : "fmov\t%w0, %s1"; - case 9: - return TARGET_SIMD ? "dup\t%0., %w1" : "fmov\t%s0, %w1"; - case 10: - return TARGET_SIMD ? "dup\t%0, %1.[0]" : "fmov\t%s0, %s1"; - default: - gcc_unreachable (); - } -} - ;; The "mov_imm" type for CNT is just a placeholder. - [(set_attr "type" "mov_reg,mov_imm,neon_move,mov_imm,load_4,load_4,store_4, - store_4,neon_to_gp,neon_from_gp,neon_dup") - (set_attr "arch" "*,*,simd,sve,*,*,*,*,*,*,*")] + {@ [cons: =0, 1; attrs: type, arch] + [r , r ; mov_reg , * ] mov\t%w0, %w1 + [r , M ; mov_imm , * ] mov\t%w0, %1 + [w , D; neon_move , simd ] << aarch64_output_scalar_simd_mov_immediate (operands[1], mode); + /* The "mov_imm" type for CNT is just a placeholder. */ + [r , Usv ; mov_imm , sve ] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]); + [r , m ; load_4 , * ] ldr\t%w0, %1 + [w , m ; load_4 , * ] ldr\t%0, %1 + [m , rZ ; store_4 , * ] str\\t%w1, %0 + [m , w ; store_4 , * ] str\t%1, %0 + [r , w ; neon_to_gp , simd ] umov\t%w0, %1.[0] + [r , w ; neon_to_gp , nosimd] fmov\t%w0, %s1 /*foo */ + [w , rZ ; neon_from_gp, simd ] dup\t%0., %w1 + [w , rZ ; neon_from_gp, nosimd] fmov\t%s0, %w1 + [w , w ; neon_dup , simd ] dup\t%0, %1.[0] + [w , w ; neon_dup , nosimd] fmov\t%s0, %s1 + } ) (define_expand "mov" @@ -1280,79 +1266,71 @@ (define_expand "mov" ) (define_insn_and_split "*movsi_aarch64" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r, r,w, m, m, r, r, r, w,r,w, w") - (match_operand:SI 1 "aarch64_mov_operand" " r,r,k,M,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Ds"))] + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] "(register_operand (operands[0], SImode) || aarch64_reg_or_zero (operands[1], SImode))" - "@ - mov\\t%w0, %w1 - mov\\t%w0, %w1 - mov\\t%w0, %w1 - mov\\t%w0, %1 - # - * return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]); - ldr\\t%w0, %1 - ldr\\t%s0, %1 - str\\t%w1, %0 - str\\t%s1, %0 - adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1] - adr\\t%x0, %c1 - adrp\\t%x0, %A1 - fmov\\t%s0, %w1 - fmov\\t%w0, %s1 - fmov\\t%s0, %s1 - * return aarch64_output_scalar_simd_mov_immediate (operands[1], SImode);" + {@ [cons: =0, 1; attrs: type, arch, length] + [r , r ; mov_reg , * , 4] mov\t%w0, %w1 + [k , r ; mov_reg , * , 4] ^ + [r , k ; mov_reg , * , 4] ^ + [r , M ; mov_imm , * , 4] mov\t%w0, %1 + [r , n ; mov_imm , * ,16] # + /* The "mov_imm" type for CNT is just a placeholder. */ + [r , Usv; mov_imm , sve , 4] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]); + [r , m ; load_4 , * , 4] ldr\t%w0, %1 + [w , m ; load_4 , fp , 4] ldr\t%s0, %1 + [m , rZ ; store_4 , * , 4] str\t%w1, %0 + [m , w ; store_4 , fp , 4] str\t%s1, %0 + [r , Usw; load_4 , * , 8] adrp\t%x0, %A1;ldr\t%w0, [%x0, %L1] + [r , Usa; adr , * , 4] adr\t%x0, %c1 + [r , Ush; adr , * , 4] adrp\t%x0, %A1 + [w , rZ ; f_mcr , fp , 4] fmov\t%s0, %w1 + [r , w ; f_mrc , fp , 4] fmov\t%w0, %s1 + [w , w ; fmov , fp , 4] fmov\t%s0, %s1 + [w , Ds ; neon_move, simd, 4] << aarch64_output_scalar_simd_mov_immediate (operands[1], SImode); + } "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), SImode) && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))" - [(const_int 0)] - "{ - aarch64_expand_mov_immediate (operands[0], operands[1]); - DONE; - }" - ;; The "mov_imm" type for CNT is just a placeholder. - [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm,load_4, - load_4,store_4,store_4,load_4,adr,adr,f_mcr,f_mrc,fmov,neon_move") - (set_attr "arch" "*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd") - (set_attr "length" "4,4,4,4,*, 4,4, 4,4, 4,8,4,4, 4, 4, 4, 4") -] + [(const_int 0)] + { + aarch64_expand_mov_immediate (operands[0], operands[1]); + DONE; + } ) (define_insn_and_split "*movdi_aarch64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,k,r,r,r,r, r,w, m,m, r, r, r, w,r,w, w") - (match_operand:DI 1 "aarch64_mov_operand" " r,r,k,O,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Dd"))] + [(set (match_operand:DI 0 "nonimmediate_operand") + (match_operand:DI 1 "aarch64_mov_operand"))] "(register_operand (operands[0], DImode) || aarch64_reg_or_zero (operands[1], DImode))" - "@ - mov\\t%x0, %x1 - mov\\t%0, %x1 - mov\\t%x0, %1 - * return aarch64_is_mov_xn_imm (INTVAL (operands[1])) ? \"mov\\t%x0, %1\" : \"mov\\t%w0, %1\"; - # - * return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]); - ldr\\t%x0, %1 - ldr\\t%d0, %1 - str\\t%x1, %0 - str\\t%d1, %0 - * return TARGET_ILP32 ? \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %L1]\" : \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %L1]\"; - adr\\t%x0, %c1 - adrp\\t%x0, %A1 - fmov\\t%d0, %x1 - fmov\\t%x0, %d1 - fmov\\t%d0, %d1 - * return aarch64_output_scalar_simd_mov_immediate (operands[1], DImode);" - "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), DImode) - && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))" - [(const_int 0)] - "{ - aarch64_expand_mov_immediate (operands[0], operands[1]); - DONE; - }" - ;; The "mov_imm" type for CNTD is just a placeholder. - [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm, - load_8,load_8,store_8,store_8,load_8,adr,adr,f_mcr,f_mrc, - fmov,neon_move") - (set_attr "arch" "*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd") - (set_attr "length" "4,4,4,4,*, 4,4, 4,4, 4,8,4,4, 4, 4, 4, 4")] + {@ [cons: =0, 1; attrs: type, arch, length] + [r , r ; mov_reg , * , 4] mov\t%x0, %x1 + [k , r ; mov_reg , * , 4] mov\t%0, %x1 + [r , k ; mov_reg , * , 4] mov\t%x0, %1 + [r , O ; mov_imm , * , 4] << aarch64_is_mov_xn_imm (INTVAL (operands[1])) ? "mov\t%x0, %1" : "mov\t%w0, %1"; + [r , n ; mov_imm , * ,16] # + /* The "mov_imm" type for CNT is just a placeholder. */ + [r , Usv; mov_imm , sve , 4] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]); + [r , m ; load_8 , * , 4] ldr\t%x0, %1 + [w , m ; load_8 , fp , 4] ldr\t%d0, %1 + [m , rZ ; store_8 , * , 4] str\t%x1, %0 + [m , w ; store_8 , fp , 4] str\t%d1, %0 + [r , Usw; load_8 , * , 8] << TARGET_ILP32 ? "adrp\t%0, %A1;ldr\t%w0, [%0, %L1]" : "adrp\t%0, %A1;ldr\t%0, [%0, %L1]"; + [r , Usa; adr , * , 4] adr\t%x0, %c1 + [r , Ush; adr , * , 4] adrp\t%x0, %A1 + [w , rZ ; f_mcr , fp , 4] fmov\t%d0, %x1 + [r , w ; f_mrc , fp , 4] fmov\t%x0, %d1 + [w , w ; fmov , fp , 4] fmov\t%d0, %d1 + [w , Dd ; neon_move, simd, 4] << aarch64_output_scalar_simd_mov_immediate (operands[1], DImode); + } + "CONST_INT_P (operands[1]) && !aarch64_move_imm (INTVAL (operands[1]), DImode) + && REG_P (operands[0]) && GP_REGNUM_P (REGNO (operands[0]))" + [(const_int 0)] + { + aarch64_expand_mov_immediate (operands[0], operands[1]); + DONE; + } ) (define_insn "insv_imm" diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 2c7249f01937eafcab175e73149881b06a929872..254cd8cdfef9067f2d053f6a9197f31b2b87323c 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -924,27 +924,28 @@ (define_peephole2 ;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will ;; put the duplicated register first, and not try the commutative version. (define_insn_and_split "*arm_addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=rk,l,l ,l ,r ,k ,r,k ,r ,k ,r ,k,k,r ,k ,r") - (plus:SI (match_operand:SI 1 "s_register_operand" "%0 ,l,0 ,l ,rk,k ,r,r ,rk,k ,rk,k,r,rk,k ,rk") - (match_operand:SI 2 "reg_or_int_operand" "rk ,l,Py,Pd,rI,rI,k,rI,Pj,Pj,L ,L,L,PJ,PJ,?n")))] - "TARGET_32BIT" - "@ - add%?\\t%0, %0, %2 - add%?\\t%0, %1, %2 - add%?\\t%0, %1, %2 - add%?\\t%0, %1, %2 - add%?\\t%0, %1, %2 - add%?\\t%0, %1, %2 - add%?\\t%0, %2, %1 - add%?\\t%0, %1, %2 - addw%?\\t%0, %1, %2 - addw%?\\t%0, %1, %2 - sub%?\\t%0, %1, #%n2 - sub%?\\t%0, %1, #%n2 - sub%?\\t%0, %1, #%n2 - subw%?\\t%0, %1, #%n2 - subw%?\\t%0, %1, #%n2 - #" + [(set (match_operand:SI 0 "s_register_operand") + (plus:SI (match_operand:SI 1 "s_register_operand") + (match_operand:SI 2 "reg_or_int_operand")))] + "TARGET_32BIT" + {@ [cons: =0, 1, 2; attrs: length, predicable_short_it, arch] + [rk, %0, rk; 2, yes, t2] add%?\\t%0, %0, %2 + [l, l, l ; 4, yes, t2] add%?\\t%0, %1, %2 + [l, 0, Py; 4, yes, t2] add%?\\t%0, %1, %2 + [l, l, Pd; 4, yes, t2] add%?\\t%0, %1, %2 + [r, rk, rI; 4, no, * ] add%?\\t%0, %1, %2 + [k, k, rI; 4, no, * ] add%?\\t%0, %1, %2 + [r, r, k ; 4, no, * ] add%?\\t%0, %2, %1 + [k, r, rI; 4, no, a ] add%?\\t%0, %1, %2 + [r, rk, Pj; 4, no, t2] addw%?\\t%0, %1, %2 + [k, k, Pj; 4, no, t2] addw%?\\t%0, %1, %2 + [r, rk, L ; 4, no, * ] sub%?\\t%0, %1, #%n2 + [k, k, L ; 4, no, * ] sub%?\\t%0, %1, #%n2 + [k, r, L ; 4, no, a ] sub%?\\t%0, %1, #%n2 + [r, rk, PJ; 4, no, t2] subw%?\\t%0, %1, #%n2 + [k, k, PJ; 4, no, t2] subw%?\\t%0, %1, #%n2 + [r, rk, ?n; 16, no, * ] # + } "TARGET_32BIT && CONST_INT_P (operands[2]) && !const_ok_for_op (INTVAL (operands[2]), PLUS) @@ -956,10 +957,10 @@ (define_insn_and_split "*arm_addsi3" operands[1], 0); DONE; " - [(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,16") + [(set_attr "length") (set_attr "predicable" "yes") - (set_attr "predicable_short_it" "yes,yes,yes,yes,no,no,no,no,no,no,no,no,no,no,no,no") - (set_attr "arch" "t2,t2,t2,t2,*,*,*,a,t2,t2,*,*,a,t2,t2,*") + (set_attr "predicable_short_it") + (set_attr "arch") (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "") (const_string "alu_imm") (const_string "alu_sreg"))) diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 6a435eb44610960513e9739ac9ac1e8a27182c10..1437ab55b260ab5c876e92d59ba39d24bffc6276 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -27,6 +27,7 @@ See the next chapter for information on the C header file. from such an insn. * Output Statement:: For more generality, write C code to output the assembler code. +* Compact Syntax:: Compact syntax for writing Machine descriptors. * Predicates:: Controlling what kinds of operands can be used for an insn. * Constraints:: Fine-tuning operand selection. @@ -713,6 +714,213 @@ you can use @samp{*} inside of a @samp{@@} multi-alternative template: @end group @end smallexample +@node Compact Syntax +@section Compact Syntax +@cindex compact syntax + +In cases where the number of alternatives in a @code{define_insn} or +@code{define_insn_and_split} are large then it may be beneficial to use the +compact syntax when specifying alternatives. + +This syntax puts the constraints and attributes on the same horizontal line as +the instruction assembly template. + +As an example + +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r") + (match_operand:SI 1 "aarch64_mov_operand" " r,r,k,M,n,Usv"))] + "" + "@@ + mov\\t%w0, %w1 + mov\\t%w0, %w1 + mov\\t%w0, %w1 + mov\\t%w0, %1 + # + * return aarch64_output_sve_cnt_immediate ('cnt', '%x0', operands[1]);" + "&& true" + [(const_int 0)] + @{ + aarch64_expand_mov_immediate (operands[0], operands[1]); + DONE; + @} + [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm") + (set_attr "arch" "*,*,*,*,*,sve") + (set_attr "length" "4,4,4,4,*, 4") +] +) +@end group +@end smallexample + +can be better expressed as: + +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] + "" + @{@@ [cons: =0, 1; attrs: type, arch, length] + [r , r ; mov_reg , * , 4] mov\t%w0, %w1 + [k , r ; mov_reg , * , 4] ^ + [r , k ; mov_reg , * , 4] ^ + [r , M ; mov_imm , * , 4] mov\t%w0, %1 + [r , n ; mov_imm , * , *] # + [r , Usv; mov_imm , sve , 4] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]); + @} + "&& true" + [(const_int 0)] + @{ + aarch64_expand_mov_immediate (operands[0], operands[1]); + DONE; + @} +) +@end group +@end smallexample + +The syntax rules are as follows: +@itemize @bullet +@item +Template must start with "@{@@" to use the new syntax. + +@item +"@{@@" is followed by a layout in parentheses which is @samp{"cons:"} followed by +a list of @code{match_operand}/@code{match_scratch} comma operand numbers, then a +semicolon, followed by the same for attributes (@samp{"attrs:"}). Operand +modifiers can be placed in this section group as well. Both sections +are optional (so you can use only @samp{cons}, or only @samp{attrs}, or both), +and @samp{cons} must come before @samp{attrs} if present. + +@item +Each alternative begins with any amount of whitespace. + +@item +Following the whitespace is a comma-separated list of @samp{constraints} and/or +@samp{attributes} within brackets @code{[]}, with sections separated by a +semicolon. + +@item +Should you want to copy the previous asm line, the symbol @code{^} can be used. +This allows less copy pasting between alternative and reduces the number of +lines to update on changes. + +@item +When using C functions for output, the idiom @code{* return ;} can be +replaced with the shorthand @code{<< ;}. + +@item +Following the closing ']' is any amount of whitespace, and then the actual asm +output. + +@item +Spaces are allowed in the list (they will simply be removed). + +@item +All alternatives should be specified: a blank list should be "[,,]", "[,,;,]" +etc., not "[]" or "". + +@item +Within an @{@@ block both multiline and singleline C comments are allowed, but +when used outside of a C block they must be the only non-whitespace blocks on +the line. + +@item +Any unexpanded iterators within the block will result in a compile time error +rather than accepting the generating the @code{<..>} in the output asm. If the +literal @code{<..>} is required it should be escaped as @code{\<..\>}. + +@item +Within an @{@@ block, any iterators that do not get expanded will result in an +error. If for some reason it is required to have @code{<>} in the output then +these must be escaped using @backslashchar{}. + +@item +The actual constraint string in the @code{match_operand} or +@code{match_scratch}, and the attribute string in the @code{set_attr}, must be +blank or an empty string (you can't combine the old and new syntaxes). + +@item +@code{set_attr} are optional. If a @code{set_attr} is defined in the +@samp{attrs} section then that declaration can be both definition and +declaration. If both @samp{attrs} and @code{set_attr} are defined for the same +entry then the attribute string must be empty or blank. + +@item +Additional @code{set_attr} can be specified other than the ones in the +@samp{attrs} list. These must use the @samp{normal} syntax and must be defined +after all @samp{attrs} specified. + +In other words, the following are valid: +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] + "" + @{@@ [cons: 0, 1; attrs: type, arch, length]@} + ... + [(set_attr "type")] + [(set_attr "arch")] + [(set_attr "length")] + [(set_attr "foo" "mov_imm")] +) +@end group +@end smallexample + +and + +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] + "" + @{@@ [cons: 0, 1; attrs: type, arch, length]@} + ... + [(set_attr "foo" "mov_imm")] +) +@end group +@end smallexample + +but these are not valid: +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] + "" + @{@@ [cons: 0, 1; attrs: type, arch, length]@} + ... + [(set_attr "type")] + [(set_attr "arch")] + [(set_attr "foo" "mov_imm")] +) +@end group +@end smallexample + +and + +@smallexample +@group +(define_insn_and_split "" + [(set (match_operand:SI 0 "nonimmediate_operand") + (match_operand:SI 1 "aarch64_mov_operand"))] + "" + @{@@ [cons: 0, 1; attrs: type, arch, length]@} + ... + [(set_attr "type")] + [(set_attr "foo" "mov_imm")] + [(set_attr "arch")] + [(set_attr "length")] +) +@end group +@end smallexample + +because the order of the entries don't match and new entries must be last. +@end itemize + @node Predicates @section Predicates @cindex predicates diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc index 163e8dfef4ca2c2c92ce1cf001ee6be40a54ca3e..8ac62dc37edf4c095d694e5c7caa4499cf201334 100644 --- a/gcc/genoutput.cc +++ b/gcc/genoutput.cc @@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see #include "errors.h" #include "read-md.h" #include "gensupport.h" +#include /* No instruction can have more operands than this. Sorry for this arbitrary limit, but what machine will have an instruction with @@ -157,6 +158,7 @@ public: int n_alternatives; /* Number of alternatives in each constraint */ int operand_number; /* Operand index in the big array. */ int output_format; /* INSN_OUTPUT_FORMAT_*. */ + bool compact_syntax_p; struct operand_data operand[MAX_MAX_OPERANDS]; }; @@ -700,12 +702,57 @@ process_template (class data *d, const char *template_code) if (sp != ep) message_at (d->loc, "trailing whitespace in output template"); - while (cp < sp) + /* Check for any unexpanded iterators. */ + if (bp[0] != '*' && d->compact_syntax_p) { - putchar (*cp); - cp++; + const char *p = cp; + const char *last_bracket = nullptr; + while (p < sp) + { + if (*p == '\\' && p + 1 < sp) + { + putchar (*p); + putchar (*(p+1)); + p += 2; + continue; + } + + if (*p == '>' && last_bracket && *last_bracket == '<') + { + size_t len = p - last_bracket; + char *iter = XNEWVEC (char, len); + memcpy (iter, last_bracket+1, (size_t)(len - 1)); + char *nl = strchr (const_cast (cp), '\n'); + if (nl) + *nl ='\0'; + iter[len - 1] = '\0'; + fatal_at (d->loc, "unresolved iterator '%s' in '%s'", + iter, cp); + } + else if (*p == '<' || *p == '>') + last_bracket = p; + + putchar (*p); + p += 1; + } + + if (last_bracket) + { + char *nl = strchr (const_cast (cp), '\n'); + if (nl) + *nl ='\0'; + fatal_at (d->loc, "unmatched angle brackets, likely an " + "error in iterator syntax in %s", cp); + } + } + else + { + while (cp < sp) + putchar (*(cp++)); } + cp = sp; + if (!found_star) puts ("\","); else if (*bp != '*') @@ -881,6 +928,8 @@ gen_insn (md_rtx_info *info) else d->name = 0; + d->compact_syntax_p = compact_syntax.contains (insn); + /* Build up the list in the same order as the insns are seen in the machine description. */ d->next = 0; diff --git a/gcc/gensupport.h b/gcc/gensupport.h index a1edfbd71908b6244b40f801c6c01074de56777e..7925e22ed418767576567cad583bddf83c0846b1 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_GENSUPPORT_H #define GCC_GENSUPPORT_H +#include "hash-set.h" #include "read-md.h" struct obstack; @@ -218,6 +219,8 @@ struct pattern_stats int num_operand_vars; }; +extern hash_set compact_syntax; + extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec); extern void compute_test_codes (rtx, file_location, char *); extern file_location get_file_location (rtx); diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index f9efc6eb7572a44b8bb154b0b22be3815bd0d244..f1d6b512356844da5d1dadbc69e08c16ef7a3abd 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -27,12 +27,17 @@ #include "read-md.h" #include "gensupport.h" #include "vec.h" +#include +#include +#include #define MAX_OPERANDS 40 static rtx operand_data[MAX_OPERANDS]; static rtx match_operand_entries_in_pattern[MAX_OPERANDS]; static char used_operands_numbers[MAX_OPERANDS]; +/* List of entries which are part of the new syntax. */ +hash_set compact_syntax; /* In case some macros used by files we include need it, define this here. */ @@ -545,6 +550,569 @@ gen_rewrite_sequence (rtvec vec) return new_vec; } +/* The following is for handling the compact syntax for constraints and + attributes. + + The normal syntax looks like this: + + ... + (match_operand: 0 "s_register_operand" "r,I,k") + (match_operand: 2 "s_register_operand" "r,k,I") + ... + "@ + + + " + ... + (set_attr "length" "4,8,8") + + The compact syntax looks like this: + + ... + (match_operand: 0 "s_register_operand") + (match_operand: 2 "s_register_operand") + ... + {@ [cons: 0, 2; attrs: length] + [r,r; 4] + [I,k; 8] + [k,I; 8] + } + ... + (set_attr "length") + + This is the only place where this syntax needs to be handled. Relevant + patterns are transformed from compact to the normal syntax before they are + queued, so none of the gen* programs need to know about this syntax at all. + + Conversion process (convert_syntax): + + 0) Check that pattern actually uses new syntax (check for {@ ... }). + + 1) Get the "layout", i.e. the "(cons: 0 2; attrs: length)" from the above + example. cons must come first; both are optional. Set up two vecs, + convec and attrvec, for holding the results of the transformation. + + 2) For each alternative: parse the list of constraints and/or attributes, + and enqueue them in the relevant lists in convec and attrvec. By the end + of this process, convec[N].con and attrvec[N].con should contain regular + syntax constraint/attribute lists like "r,I,k". Copy the asm to a string + as we go. + + 3) Search the rtx and write the constraint and attribute lists into the + correct places. Write the asm back into the template. */ + +/* Helper class for shuffling constraints/attributes in convert_syntax and + add_constraints/add_attributes. This includes commas but not whitespace. */ + +class conlist { +private: + std::string con; + +public: + std::string name; + std::string modifier; + int idx = -1; + + conlist () + { + } + + /* [ns..ns + len) should be a string with the id of the rtx to match + i.e. if rtx is the relevant match_operand or match_scratch then + [ns..ns + len) should equal itoa (XINT (rtx, 0)), and if set_attr then + [ns..ns + len) should equal XSTR (rtx, 0). */ + conlist (const char *ns, unsigned int len, bool numeric) + { + /* Trim leading whitespaces. */ + while (*ns == ' ' || *ns == '\t') + { + ns++; + len--; + } + + /* Trim trailing whitespace. */ + for (int i = len - 1; i >= 0; i++, len--) + if (ns[len] != ' ' && ns[len] != '\t') + break; + + /* Parse off any modifiers. */ + while (!isalnum (*ns)) + { + modifier += *(ns++); + len--; + } + + /* What remains is the name. */ + name.assign (ns, len); + if (numeric) + idx = std::stoi(name); + } + + /* Adds a character to the end of the string. */ + void add (char c) + { + con += c; + } + + /* Output the string in the form of a brand-new char *, then effectively + clear the internal string by resetting len to 0. */ + char * out () + { + /* Final character is always a trailing comma, so strip it out. */ + char * q; + if (modifier.empty ()) + q = xstrndup (con.c_str (), con.size () - 1); + else + { + int len = con.size () + modifier.size (); + q = XNEWVEC (char, len); + strncpy (q, modifier.c_str (), modifier.size ()); + strncpy (q + modifier.size (), con.c_str (), con.size ()); + q[len -1] = '\0'; + } + + con.clear (); + modifier.clear (); + return q; + } +}; + +typedef std::vector vec_conlist; + +/* Add constraints to an rtx. The match_operand/match_scratch that are matched + must be in depth-first order i.e. read from top to bottom in the pattern. + index is the index of the conlist we are up to so far. + This function is similar to remove_constraints. + Errors if adding the constraints would overwrite existing constraints. + Returns 1 + index of last conlist to be matched. */ + +static unsigned int +add_constraints (rtx part, file_location loc, unsigned int index, + vec_conlist &cons) +{ + const char *format_ptr; + + if (part == NULL_RTX || index == cons.size ()) + return index; + + /* If match_op or match_scr, check if we have the right one, and if so, copy + over the constraint list. */ + if (GET_CODE (part) == MATCH_OPERAND || GET_CODE (part) == MATCH_SCRATCH) + { + int field = GET_CODE (part) == MATCH_OPERAND ? 2 : 1; + int id = XINT (part, 0); + + if (XSTR (part, field)[0] != '\0') + { + error_at (loc, "can't mix normal and compact constraint syntax"); + return cons.size (); + } + XSTR (part, field) = cons[id].out (); + + ++index; + } + + format_ptr = GET_RTX_FORMAT (GET_CODE (part)); + + /* Recursively search the rtx. */ + for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) + switch (*format_ptr++) + { + case 'e': + case 'u': + index = add_constraints (XEXP (part, i), loc, index, cons); + break; + case 'E': + if (XVEC (part, i) != NULL) + for (int j = 0; j < XVECLEN (part, i); j++) + index = add_constraints (XVECEXP (part, i, j), loc, index, cons); + break; + default: + continue; + } + + return index; +} + +/* Add attributes to an rtx. The attributes that are matched must be in order + i.e. read from top to bottom in the pattern. + Errors if adding the attributes would overwrite existing attributes. + Returns 1 + index of last conlist to be matched. */ + +static unsigned int +add_attributes (rtx x, file_location loc, vec_conlist &attrs) +{ + unsigned int attr_index = GET_CODE (x) == DEFINE_INSN ? 4 : 3; + unsigned int index = 0; + + if (XVEC (x, attr_index) == NULL) + return index; + + for (int i = 0; i < XVECLEN (x, attr_index); ++i) + { + rtx part = XVECEXP (x, attr_index, i); + + if (GET_CODE (part) != SET_ATTR) + continue; + + if (attrs[index].name.compare (XSTR (part, 0)) == 0) + { + if (XSTR (part, 1) && XSTR (part, 1)[0] != '\0') + { + error_at (loc, "can't mix normal and compact attribute syntax"); + break; + } + XSTR (part, 1) = attrs[index].out (); + + ++index; + if (index == attrs.size ()) + break; + } + } + + return index; +} + +/* Modify the attributes list to make space for the implicitly declared + attributes in the attrs: list. */ + +static void +create_missing_attributes (rtx x, file_location /* loc */, vec_conlist &attrs) +{ + if (attrs.empty ()) + return; + + unsigned int attr_index = GET_CODE (x) == DEFINE_INSN ? 4 : 3; + vec_conlist missing; + + /* This is an O(n*m) loop but it's fine, both n and m will always be very + small. */ + for (conlist cl : attrs) + { + bool found = false; + for (int i = 0; XVEC (x, attr_index) && i < XVECLEN (x, attr_index); ++i) + { + rtx part = XVECEXP (x, attr_index, i); + + if (GET_CODE (part) != SET_ATTR + || cl.name.compare (XSTR (part, 0)) == 0) + { + found = true; + break; + } + } + + if (!found) + missing.push_back (cl); + } + + rtvec orig = XVEC (x, attr_index); + size_t n_curr = orig ? XVECLEN (x, attr_index) : 0; + rtvec copy = rtvec_alloc (n_curr + missing.size ()); + + /* Create a shallow copy of existing entries. */ + memcpy (©->elem[missing.size ()], &orig->elem[0], sizeof (rtx) * n_curr); + XVEC (x, attr_index) = copy; + + /* Create the new elements. */ + for (unsigned i = 0; i < missing.size (); i++) + { + rtx attr = rtx_alloc (SET_ATTR); + XSTR (attr, 0) = xstrdup (attrs[i].name.c_str ()); + XSTR (attr, 1) = NULL; + XVECEXP (x, attr_index, i) = attr; + } + + return; +} + +/* Consumes spaces and tabs. */ + +static inline void +skip_spaces (const char **str) +{ + while (**str == ' ' || **str == '\t') + (*str)++; +} + +/* Consumes the given character, if it's there. */ + +static inline bool +expect_char (const char **str, char c) +{ + if (**str != c) + return false; + (*str)++; + return true; +} + +/* Parses the section layout that follows a "{@}" if using new syntax. Builds + a vector for a single section. E.g. if we have "attrs: length arch)..." + then list will have two elements, the first for "length" and the second + for "arch". */ + +static void +parse_section_layout (const char **templ, const char *label, + vec_conlist &list, bool numeric) +{ + const char *name_start; + size_t label_len = strlen (label); + if (strncmp (label, *templ, label_len) == 0) + { + *templ += label_len; + + /* Gather the names. */ + while (**templ != ';' && **templ != ']') + { + skip_spaces (templ); + name_start = *templ; + int len = 0; + char val = (*templ)[len]; + while (val != ',' && val != ';' && val != ']') + val = (*templ)[++len]; + *templ += len; + if (val == ',') + (*templ)++; + list.push_back (conlist (name_start, len, numeric)); + } + } +} + +/* Parse a section, a section is defined as a named space separated list, e.g. + + foo: a b c + + is a section named "foo" with entries a,b and c. */ + +static void +parse_section (const char **templ, unsigned int n_elems, unsigned int alt_no, + vec_conlist &list, file_location loc, const char *name) +{ + unsigned int i; + + /* Go through the list, one character at a time, adding said character + to the correct string. */ + for (i = 0; **templ != ']' && **templ != ';'; (*templ)++) + { + if (**templ != ' ' && **templ != '\t') + { + list[i].add(**templ); + if (**templ == ',') + { + ++i; + if (i == n_elems) + fatal_at (loc, "too many %ss in alternative %d: expected %d", + name, alt_no, n_elems); + } + } + } + + if (i + 1 < n_elems) + fatal_at (loc, "too few %ss in alternative %d: expected %d, got %d", + name, alt_no, n_elems, i); + + list[i].add(','); +} + +/* The compact syntax has more convience syntaxes. As such we post process + the lines to get them back to something the normal syntax understands. */ + +static void +preprocess_compact_syntax (file_location loc, int alt_no, std::string &line, + std::string &last_line) +{ + /* Check if we're copying the last statement. */ + if (line.find ("^") == 0 && line.size () == 1) + { + if (last_line.empty ()) + fatal_at (loc, "found instruction to copy previous line (^) in" + "alternative %d but no previous line to copy", alt_no); + line = last_line; + return; + } + + std::string result; + std::string buffer; + /* Check if we have << which means return c statement. */ + if (line.find ("<<") == 0) + { + result.append ("* return "); + result.append (line.substr (3)); + } + else + result.append (line); + + line = result; + return; +} + +/* Converts an rtx from compact syntax to normal syntax if possible. */ + +static void +convert_syntax (rtx x, file_location loc) +{ + int alt_no; + unsigned int index, templ_index; + const char *templ; + vec_conlist tconvec, convec, attrvec; + + templ_index = GET_CODE (x) == DEFINE_INSN ? 3 : 2; + + templ = XTMPL (x, templ_index); + + /* Templates with constraints start with "{@". */ + if (strncmp ("*{@", templ, 3)) + return; + + /* Get the layout for the template. */ + templ += 3; + skip_spaces (&templ); + + if (!expect_char (&templ, '[')) + fatal_at (loc, "expecing `[' to begin section list"); + + parse_section_layout (&templ, "cons:", tconvec, true); + convec.resize (tconvec.size ()); + + /* Check for any duplicate cons entries and sort based on i. */ + for (unsigned i = 0; i < tconvec.size (); i++) + { + int idx = tconvec[i].idx; + if (convec[idx].idx >= 0) + fatal_at (loc, "duplicate cons number found: %d", idx); + convec[idx] = tconvec[i]; + } + tconvec.clear (); + + + if (*templ != ']') + { + if (*templ == ';') + skip_spaces (&(++templ)); + parse_section_layout (&templ, "attrs:", attrvec, false); + create_missing_attributes (x, loc, attrvec); + } + + if (!expect_char (&templ, ']')) + { + fatal_at (loc, "expecting `]` to end section list - section list " + "must have cons first, attrs second"); + } + + /* We will write the un-constrainified template into new_templ. */ + std::string new_templ; + new_templ.append ("@"); + + /* Skip to the first proper line. */ + while (*templ++ != '\n'); + alt_no = 0; + + std::string last_line; + + /* Process the alternatives. */ + while (*(templ - 1) != '\0') + { + /* Copy leading whitespace. */ + std::string buffer; + while (*templ == ' ' || *templ == '\t') + buffer += *templ++; + + /* Check if we're at the end. */ + if (templ[0] == '}' && templ[1] == '\0') + break; + + new_templ += '\n'; + new_templ.append (buffer); + + if (expect_char (&templ, '[')) + { + /* Parse the constraint list, then the attribute list. */ + if (convec.size () > 0) + parse_section (&templ, convec.size (), alt_no, convec, loc, + "constraint"); + + if (attrvec.size () > 0) + { + if (convec.size () > 0 && !expect_char (&templ, ';')) + fatal_at (loc, "expected `;' to separate constraints " + "and attributes in alternative %d", alt_no); + + parse_section (&templ, attrvec.size (), alt_no, + attrvec, loc, "attribute"); + } + + if (!expect_char (&templ, ']')) + fatal_at (loc, "expected end of constraint/attribute list but " + "missing an ending `]' in alternative %d", alt_no); + } + else if (templ[0] == '/' && templ[1] == '/') + { + templ+=2; + /* Glob till newline or end of string. */ + while (*templ != '\n' || *templ != '\0') + templ++; + } + else if (templ[0] == '/' && templ[1] == '*') + { + templ+=2; + /* Glob till newline or end of multiline comment. */ + while (templ[0] != '*' && templ[1] != '/') + templ++; + templ++; + } + else + fatal_at (loc, "expected constraint/attribute list at beginning of " + "alternative %d but missing a starting `['", alt_no); + + /* Skip whitespace between list and asm. */ + ++templ; + skip_spaces (&templ); + + /* Copy asm to new template. */ + std::string line; + while (*templ != '\n' && *templ != '\0') + line += *templ++; + + /* Apply any pre-processing needed to the line. */ + preprocess_compact_syntax (loc, alt_no, line, last_line); + new_templ.append (line); + last_line = line; + + /* The processing is very sensitive to whitespace, so preserve + all but the trailing ones. */ + if (templ[0] == '\n') + *templ++; + ++alt_no; + } + + /* Write the constraints and attributes into their proper places. */ + if (convec.size () > 0) + { + index = add_constraints (x, loc, 0, convec); + if (index < convec.size ()) + fatal_at (loc, "could not find match_operand/scratch with id %d", + convec[index].idx); + } + + if (attrvec.size () > 0) + { + index = add_attributes (x, loc, attrvec); + if (index < attrvec.size ()) + fatal_at (loc, "could not find set_attr for attribute %s", + attrvec[index].name.c_str ()); + } + + /* Copy over the new un-constrainified template. */ + XTMPL (x, templ_index) = xstrdup (new_templ.c_str ()); + + /* Register for later checks during iterator expansions. */ + compact_syntax.add (x); + +#if DEBUG + print_rtl_single (stderr, x); +#endif +} + /* Process a top level rtx in some way, queuing as appropriate. */ static void @@ -553,10 +1121,12 @@ process_rtx (rtx desc, file_location loc) switch (GET_CODE (desc)) { case DEFINE_INSN: + convert_syntax (desc, loc); queue_pattern (desc, &define_insn_tail, loc); break; case DEFINE_COND_EXEC: + convert_syntax (desc, loc); queue_pattern (desc, &define_cond_exec_tail, loc); break; @@ -631,6 +1201,7 @@ process_rtx (rtx desc, file_location loc) attr = XVEC (desc, split_code + 1); PUT_CODE (desc, DEFINE_INSN); XVEC (desc, 4) = attr; + convert_syntax (desc, loc); /* Queue them. */ insn_elem = queue_pattern (desc, &define_insn_tail, loc);