FUNCTIONS TO GENERATE RTX
typical calling sequence to generate expression
c_expand_body()<c-decl.c>
expand_stmt()<c-semantics.c>
genrtl_expr_stmt_value()<c-semantics.c>
expand_expr_stmt_value()stmt.c>
expand_expr()expr.c>
crucial code of expand_expr:
rtx expand_expr (tree exp, …) {
enum tree_code code = TREE_CODE (exp);
optab this_optab;
switch (code) {
case MODIFY_EXPR:
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
expand_assignment (lhs, rhs, …); // <expr.c>
case PLUS_EXPR:
this_optab = …? addv_optab : add_optab;
goto binop2 或 both_summands;
both_summands:
gen_rtx_PLUS(…)
}
binop2:
expand_binop (mode, this_optab, op0, op1, …); // <optab.c>
}
calling sequence beyond gen_rtx_PLUS()
gen_rtx_PLUS() <genrtl.h>
gen_rtx_fmt_ee() <genrtl.c>
ggc_alloc_rtx()
genrtl.c, genrtl.h are generated by gengenrtl.exe
OPERATION TABLES
keypoint of mapping standard name (tree node) to define_insn (define_expand)
standard names are hard-coded in the compiler
Data Structure
optabs.h
struct optab
enum optab_index
#define add_optab (optab_table[OTI_add])
optabs.c
optab optab_table[OTI_MAX];
Initailization
main()<main.c>
toplev_main()<toplev.c>
do_compile()<toplev.c>
lang_dependent_init()<toplev.c>
init_optabs()<optabs.c>
init_optab()<optabs.c>
init_all_optabs()<insn_opinit.c>
init_optab() – construct structure
init_all_optabs() – fill data
machine-dependent
Example Rtx
(define_expand "addsi3"
[(parallel[(set(match_operand:SI 0 "nonimmediate_operand" "")
(plus:SI(match_operand:SI 1 "nonimmediate_operand" "")
(match_operand:SI 2 "general_operand" "")))
(clobber (reg:CC 17))])]
""
"ix86_expand_binary_operator (PLUS, SImode, operands); DONE;")
(define_insn "divqi3"
[(set(match_operand:QI 0 "register_operand" "=a")
(div:QI(match_operand:HI 1 "register_operand" "0")
(match_operand:QI 2 "nonimmediate_operand" "qm")))
(clobber (reg:CC 17))]
"TARGET_QIMODE_MATH"
"idiv{b}\t%2"
[(set_attr "type" "idiv")
(set_attr "mode" "QI")
(set_attr "ppro_uops" "few")])
Function init_all_optabs()
in <insn_opinit.c>
crucial code of init_all_optans:
add_optab->handlers[(int) SImode].insn_code = CODE_FOR_addsi3;
if (HAVE_divqi3)
sdiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_divqi3;
CODE_FOR_xxx
in <insn-codes.h>
numbering for define_expand & named define_insn
index of insn_data[]
CODE_FOR_divqi3 = 187,
CODE_FOR_addsi3 = 933,
HAVE_xxx
in <insn-flaags.h>
according to 3rd argument of define_expand & named define_insn
#define HAVE_divqi3 (TARGET_QIMODE_MATH)
#define HAVE_addsi3 1
RTX GENERATION
ARRAY insn_data[] & operand_data[]
in <insn_output.c>
const struct insn_data insn_data[] = {// defined in <recog.h>
{ //\\ insn_data[187] <i386.md:7118>
"divqi3",// char *const name;
"idiv{b}\t%2",// PTR output; (useless for rtx-gen)
(insn_gen_fn) gen_divqi3,// insn_gen_fn genfun;
&operand_data[378],// struct insn_operand_data *operand;
3,// char n_operands
0,// char n_dups; (useless for rtx-gen)
1,// char n_alternatives; (useless for rtx-gen)
1// char output_format; (useless for rtx-gen)
},
{ //\\ insn_data[933] <i386.md:4789>
"addsi3",0,(insn_gen_fn) gen_addsi3,&operand_data[1592],3,0, 0, 0
},
}
static const struct insn_operand_data operand_data[] = {// defined in <recog.h>
{ //\\ operand_data[378]
register_operand,// insn_operand_predicate_fn predicate;
"=a",// char *const constraint; (useless for rtx-gen)
QImode,// ENUM_BITFIELD(machine_mode) mode : 16;
0,// char strict_low; (useless for rtx-gen)
1// char eliminable; (useless for rtx-gen)
},
{ //\\ operand_data[379]
register_operand,"0",HImode,0,1
},
{ //\\ operand_data[380]
nonimmediate_operand,"qm",QImode,0,1
},
{ //\\ operand_data[1592]
nonimmediate_operand,"",SImode,0,1
},
{ //\\ operand_data[1593]
nonimmediate_operand,"",SImode,0,1
},
{ //\\ operand_data[1594]
general_operand,"",SImode,0,1
},
}
FUNCTION expand_binop()
crucial code of expand_binop()
rtxexpand_binop (optab binoptab, rtx op0, rtx op1, rtx target, …) {
int icode = (int) binoptab->handlers[(int) mode].insn_code;
... insn_data[icode].operand[1].mode ...
if ((*insn_data[icode].operand[1].predicate) (xop0, mode0)… )
…
GEN_FCN (icode) (temp, xop0, xop1);
}
#define GEN_FCN(CODE) (*insn_data[(int) (CODE)].genfun)
in <optabs.h>
for example, addsi3
icode = 933
(*insn_data[icode].operand[1].predicate) = nonimmediate_operand
in <recog.c>
GEN_FCN(CODE) = (*insn_data[(int) (CODE)].genfun) = gen_addsi3
in <insn-emit.c>
FUNCTION gen_divqi3
example of define_insn
generate rtx according to 2nd argument (rtx template) of define_insn of divqi3
FUNCTION gen_addsi3
example of define_expand
do 4th argument of define_expand of addsi3
may DONE or FAIL
generate rtx according to 2nd argument (rtx template) of define_expand of addsi3
RELATED MD-RTX
DEF_RTL_EXPR(DEFINE_INSN, "define_insn", "sEsTV", 'x')
s – insn name
standard name: normal string
non-standard name: string beginning with *, null string
E – rtx template (pattern)
embedded in gen_xxx()
s –condition about target-machine-typefor recognizing this pattern
HAVE_xxx
T – useless for rtx-gen
V – attributes (optional)
DEF_RTL_EXPR(DEFINE_EXPAND, "define_expand", "sEss", 'x')
s – insn name
must be standard name
E –rtx template
embedded in gen_xxx(), low priority
s –condition about target-machine-type for recognizing this pattern
HAVE_xxx
s –preparation statement, extra C code to execute before generating the insns
embedded in gen_xxx(), high priority
Rtx Template
incomplete RTL expression
DEF_RTL_EXPR(MATCH_OPERAND, "match_operand", "iss", 'm')
i – operand index
counting from 0
s – function name, a predicate
s – register allocator restrictions
'=' write-only
'+' read & write
'i' immediate data
'r' register
'm' memory
GCC Internals 13.4, 13.7, 13.8
HOMEWORK
reading Gcc Internals Chapter 13 (Machine Descriptions)
trace rtx-generation for "if statement"