gccint: Output Statement
1
1 17.6 C Statements for Assembler Output
1 ======================================
1
1 Often a single fixed template string cannot produce correct and
1 efficient assembler code for all the cases that are recognized by a
1 single instruction pattern. For example, the opcodes may depend on the
1 kinds of operands; or some unfortunate combinations of operands may
1 require extra machine instructions.
1
1 If the output control string starts with a '@', then it is actually a
1 series of templates, each on a separate line. (Blank lines and leading
1 spaces and tabs are ignored.) The templates correspond to the pattern's
1 constraint alternatives (⇒Multi-Alternative). For example, if a
1 target machine has a two-address add instruction 'addr' to add into a
1 register and another 'addm' to add a register to memory, you might write
1 this pattern:
1
1 (define_insn "addsi3"
1 [(set (match_operand:SI 0 "general_operand" "=r,m")
1 (plus:SI (match_operand:SI 1 "general_operand" "0,0")
1 (match_operand:SI 2 "general_operand" "g,r")))]
1 ""
1 "@
1 addr %2,%0
1 addm %2,%0")
1
1 If the output control string starts with a '*', then it is not an
1 output template but rather a piece of C program that should compute a
1 template. It should execute a 'return' statement to return the
1 template-string you want. Most such templates use C string literals,
1 which require doublequote characters to delimit them. To include these
1 doublequote characters in the string, prefix each one with '\'.
1
1 If the output control string is written as a brace block instead of a
1 double-quoted string, it is automatically assumed to be C code. In that
1 case, it is not necessary to put in a leading asterisk, or to escape the
1 doublequotes surrounding C string literals.
1
1 The operands may be found in the array 'operands', whose C data type is
1 'rtx []'.
1
1 It is very common to select different ways of generating assembler code
1 based on whether an immediate operand is within a certain range. Be
1 careful when doing this, because the result of 'INTVAL' is an integer on
1 the host machine. If the host machine has more bits in an 'int' than
1 the target machine has in the mode in which the constant will be used,
1 then some of the bits you get from 'INTVAL' will be superfluous. For
1 proper results, you must carefully disregard the values of those bits.
1
1 It is possible to output an assembler instruction and then go on to
1 output or compute more of them, using the subroutine 'output_asm_insn'.
1 This receives two arguments: a template-string and a vector of operands.
1 The vector may be 'operands', or it may be another array of 'rtx' that
1 you declare locally and initialize yourself.
1
1 When an insn pattern has multiple alternatives in its constraints,
1 often the appearance of the assembler code is determined mostly by which
1 alternative was matched. When this is so, the C code can test the
1 variable 'which_alternative', which is the ordinal number of the
1 alternative that was actually satisfied (0 for the first, 1 for the
1 second alternative, etc.).
1
1 For example, suppose there are two opcodes for storing zero, 'clrreg'
1 for registers and 'clrmem' for memory locations. Here is how a pattern
1 could use 'which_alternative' to choose between them:
1
1 (define_insn ""
1 [(set (match_operand:SI 0 "general_operand" "=r,m")
1 (const_int 0))]
1 ""
1 {
1 return (which_alternative == 0
1 ? "clrreg %0" : "clrmem %0");
1 })
1
1 The example above, where the assembler code to generate was _solely_
1 determined by the alternative, could also have been specified as
1 follows, having the output control string start with a '@':
1
1 (define_insn ""
1 [(set (match_operand:SI 0 "general_operand" "=r,m")
1 (const_int 0))]
1 ""
1 "@
1 clrreg %0
1 clrmem %0")
1
1 If you just need a little bit of C code in one (or a few) alternatives,
1 you can use '*' inside of a '@' multi-alternative template:
1
1 (define_insn ""
1 [(set (match_operand:SI 0 "general_operand" "=r,<,m")
1 (const_int 0))]
1 ""
1 "@
1 clrreg %0
1 * return stack_mem_p (operands[0]) ? \"push 0\" : \"clrmem %0\";
1 clrmem %0")
1