您的位置:首页 > 其它

GCC后端及汇编发布(5)

2011-04-23 09:16 399 查看

3.2.3.

向决策序列加入模式的
RTL
模板

对于上面我们的
define_insn
例子,在
2467
行,被传给
add_to_sequence

的类型是
RECOG
。而参数
pattern

是这个
define_insn
模式的
RTL
模板。对于我们的例子是:

[(set (reg 17)

(compare
(match_operand:DI 0 "nonimmediate_operand" "r,?mr")

(match_operand:DI 1 "const0_operand"
"n,n")))]

767

static
struct
decision
*

768

add_to_sequence
(rtx pattern, struct
decision_head
*last,
in genrecog.c

769

const
char *position, enum
routine_type insn_type, int top)

770

{

771

RTX_CODE code;

772

struct
decision
*this, *sub;

773

struct
decision_test
*test;

774

struct
decision_test
**place;

775

char *subpos;

776

size_t i;

777

const
char *fmt;

778

int depth = strlen (position);

779

int len;

780

enum
machine_mode mode;

781

782

if (depth > max_depth

)

783

max_depth

= depth;

784

785

subpos = xmalloc (depth + 2);

786

strcpy (subpos, position);

787

subpos[depth + 1] = 0;

788

789

sub = this = new_decision
(position, last);

790

place = &this->tests;

791

792

restart:

793

mode = GET_MODE (pattern);

794

code = GET_CODE (pattern);

795

796

switch
(code)

797

{

798

case
PARALLEL:



819

break
;

820

821

case
MATCH_PARALLEL:



831

case
MATCH_OPERAND:

832

case
MATCH_SCRATCH:

833

case
MATCH_OPERATOR:

834

case
MATCH_INSN:

835

{



915

}

916

917

case
MATCH_OP_DUP:



932

goto
fini;

933

934

case
MATCH_DUP:

935

case
MATCH_PAR_DUP:

936

code = UNKNOWN;

937

938

test = new_decision_test
(DT_dup,
&place);

939

test->u.dup = XINT (pattern, 0);

940

goto
fini;

941

942

case
ADDRESS:

943

pattern = XEXP (pattern, 0);

944

goto
restart;

945

946

default
:

947

break
;

948

}

当以
SET
码进入这个函数时,它将进入
946
行的
default
语句。在这个层次上,参数
position

是一个空字符串(
“”
)。并且注意到在
789
行,变量
sub


test

指向相同的新分配的决策实例。参见下面的
new_decision



316

static
struct
decision
*

317

new_decision (const
char *position, struct
decision_head *last)
in
genrecog.c

318

{

319

struct
decision
*new = xcalloc (1, sizeof
(struct
decision));

320

321

new->success = *last;

322

new->position = xstrdup (position);

323

new->number = next_number

++;

324

325

last->first = last->last = new;

326

return
new;

327

}


789
行,传递给
new_decision

的第二个参数是在
make_insn_sequence


2421
行声明的变量
head

。这个新的
decision
从头部链入,正如下图所示。




5


向决策序列加入
RTL
模板,图
1

add_to_sequence (continued)

950

fmt = GET_RTX_FORMAT (code);

951

len = GET_RTX_LENGTH (code);

952

953

/* Do tests against the current node
first.

*/

954

for
(i = 0; i < (size_t) len; i++)

955

{

956

if (fmt[i] == 'i')

957

{

958

if (i == 0)

959

{

960

test = new_decision_test
(DT_elt_zero_int, &place);

961

test->u.intval = XINT
(pattern, i);

962

}

963

else if (i == 1)

964

{

965

test = new_decision_test
(DT_elt_one_int, &place);

966

test->u.intval = XINT
(pattern, i);

967

}

968

else

969

abort ();

970

}

971

else if (fmt[i] == 'w')

972

{

973

/* If this value actually fits in an int, we
can use a switch

974

statement here, so indicate that.
*/

975

enum
decision_type
type

976

= ((int) XWINT
(pattern, i) == XWINT
(pattern, i))

977

? DT_elt_zero_wide_safe :
DT_elt_zero_wide;

978

979

if (i != 0)

980

abort ();

981

982

test = new_decision_test
(type,
&place);

983

test->u.intval = XWINT
(pattern, i);

984

}

985

else if (fmt[i] == 'E')

986

{

987

if (i != 0)

988

abort ();

989

990

test = new_decision_test
(DT_veclen,
&place);

991

test->u.veclen = XVECLEN (pattern, i);

992

}

993

}

在这里,我们再一次根据其格式处理模式。对于格式中的每个元素,通过
new_decision_test

构建了一个
decision_test
的实例。它定义了将要进行的测试。

331

static
struct
decision_test
*
in
genrecog.c

332

new_decision_test
(enum
decision_type
type, struct
decision_test
***pplace)

333

{

334

struct
decision_test
**place = *pplace;

335

struct
decision_test
*test;

336

337

test = xmalloc (sizeof
(*test));

338

test->next = *place;

339

test->type = type;

340

*place = test;

341

342

place = &test->next;

343

*pplace = place;

344

345

return
test;

346

}

上面,在这里传递给
new_decision_test

的第二个参数——声明在
add_to_sequence


790
行的变量
place

,指向变量
this


tests

域,这个变量是在
add_to_sequence


789
行构建的一个
decision
实例,同时在
make_insn_sequence


2421

this

链入以变量
head

开头的链表。

这个函数看起来有点晕,让我们一步一步来看。




6


new_decision_test
,步骤
1

直到
339
行,我们可以得到如上图所示的数据。看到新构建的
decision_test

next

域指向旧的
decision_test
。那么在
440
行,
pplace


place


this->tests

都指向这个新节点,如下图所示。




7


new_decision_test
,步骤
2


new_decision_test

的余下部分,
place


pplace

将指向新节点的
next

域的地址,如下图所示。




8


new_decision_test
,步骤
3

然后对于下一个加入的节点(黄色),直到
340
行,我们可以得到以下图形。




9


new_decision_test
,步骤
4

最后,
pplace


place

将指向这个新加入的节点(黄色)。




10


new_decision_test
,步骤
5

从这些图形,我们可以看到对于进一步加入的节点,它们将被插入到初始节点与上一个被加入节点之间。这意味着对于加入节点序列
1

2

3



n
,我们将得到以下的列表:

This
à

tests
à

1
à

2
à

3…
à

n
à

初始节点

对于我们的情形,
rtx
对象
SET
具有格式‘
ee
’,
954

993
行的
FOR
块将不做任何事。

add_to_sequence (continued)

995

/* Now test our sub-patterns.

*/

996

for
(i = 0; i < (size_t) len; i++)

997

{

998

switch
(fmt[i])

999

{

1000

case
'e':
case
'u':

1001

subpos[depth] = '0' + i;

1002

sub = add_to_sequence
(XEXP
(pattern, i), &sub->success,

1003

subpos, insn_type,
0);

1004

break
;

1005

1006

case
'E':

1007

{

1008

int j;

1009

for
(j = 0; j < XVECLEN (pattern, i);
j++)

1010

{

1011

subpos[depth] = 'a' + j;

1012

sub = add_to_sequence
(XVECEXP (pattern, i, j),

1013

&sub->success, subpos, insn_type, 0);

1014

}

1015

break
;

1016

}

1017

1018

case
'i':
case
'w':

1019

/* Handled
above.
*/

1020

break
;

1021

case
'0':

1022

break
;

1023

1024

default
:

1025

abort ();

1026

}

1027

}


954
行的
FOR

块之后,是另一个
FOR

块。对于我们的例子,它将进入
1000
行的
CASE

块。在
1001
行的
subpos

保存了这个递归的深度信息。它包含了形如“
0123abc45ab
”的信息,其中数字用于显示格式元素的序列,而字母用于显示对应某些格式(即‘
E
’,‘
V
’)的
rtx
向量的序列。然后为这个
SET
对象的两个孩子调用
add_to_sequence



对于第一个孩子
reg

对象,在
add_to_sequence

中,它直接跑到
fini

标签处。因为其编码是
REG
,在
1035
行构建了一个新的
decision_test
,并在
decision

中,链入在其父亲的之后。而且对于我们的
reg

对象,其
mode

VOIDmode
,正如我们之前看到的。

对于第二个孩子
compare

对象,它的处理路径与
set

对象相同。在
1000
行它为其孩子调用
add_to_sequence



add_to_sequence (continued)

1029

fini:

1030

/* Insert nodes
testing mode and code, if they're still relevant,

1031

before any of the nodes we may have added
above.
*/

1032

if (code != UNKNOWN)

1033

{

1034

place = &this->tests;

1035

test = new_decision_test
(DT_code, &place);

1036

test->u.code = code;

1037

}

1038

1039

if
(mode != VOIDmode)

1040

{

1041

place = &this->tests;

1042

test = new_decision_test
(DT_mode, &place);

1043

test->u.mode = mode;

1044

}

1045

1046

/* If we didn't
insert any tests or accept nodes, hork.

*/

1047

if (this->tests == NULL)

1048

abort ();

1049

1050

ret:

1051

free (subpos);

1052

return
sub;

1053

}

现在对于在这个
compare

对象的第二个孩子,其编码是
MATCH_OPERAND
,将进入
add_to_sequence

中以下部分的代码。

add_to_sequence (continued)

831

case
MATCH_OPERAND:

832

case
MATCH_SCRATCH:

833

case
MATCH_OPERATOR:

834

case
MATCH_INSN:

835

{

836

const
char *pred_name;

837

RTX_CODE was_code = code;

838

int allows_const_int = 1;

839

840

if (code == MATCH_SCRATCH)

841

{

842

pred_name =
"scratch_operand";

843

code = UNKNOWN;

844

}

845

else

846

{

847

pred_name = XSTR (pattern, 1);

848

if (code == MATCH_PARALLEL)

849

code = PARALLEL;

850

else

851

code = UNKNOWN;

852

}

853

854

if (pred_name[0] != 0)

855

{

856

test = new_decision_test
(DT_pred, &place);

857

test->u.pred.name = pred_name;

858

test->u.pred.mode = mode;

859

860

/* See if we
know about this predicate and save its number.

861

If we do, and it only accepts one
code, note that fact.

862

863

If we know that the predicate does
not allow CONST_INT,

864

we know that the only way the
predicate can match is if

865

the modes match (here we use the
kludge of relying on the

866

fact that "address_operand"
accepts CONST_INT; otherwise,

867

it would have to be a special case),
so we can test the

868

mode (but we need not). This fact
should considerably

869

simplify the generated code.
*/

870

871

for
(i
= 0; i < NUM_KNOWN_PREDS; i++)

872

if (! strcmp (preds

[i].name, pred_name))

873

break
;

874

875

if (i < NUM_KNOWN_PREDS)

876

{

877

int j;

878

879

test->u.pred.index = i;

880

881

if (preds

[i].codes[1] == 0 &&
code == UNKNOWN)

882

code = preds

[i].codes[0];

883

884

allows_const_int = 0;

885

for
(j = 0; preds

[i].codes[j]
!= 0; j++)

886

if (preds

[i].codes[j] == CONST_INT)

887

{

888

allows_const_int = 1;

889

break
;

890

}

891

}

892

else

893

test->u.pred.index = -1;

894

}

895

896

/* Can't enforce a mode if we allow
const_int.
*/

897

if (allows_const_int)

898

mode = VOIDmode;

899

900

/* Accept the
operand, ie. record it in `operands'.
*/

901

test = new_decision_test
(DT_accept_op, &place);

902

test->u.opno = XINT
(pattern, 0);

903

904

if (was_code == MATCH_OPERATOR ||
was_code == MATCH_PARALLEL)

905

{

906

char base = (was_code == MATCH_OPERATOR
? '0' : 'a');

907

for
(i
= 0; i < (size_t) XVECLEN (pattern, 2); i++)

908

{

909

subpos[depth] = i + base;

910

sub = add_to_sequence
(XVECEXP (pattern, 2, i),

911

&sub->success,
subpos, insn_type, 0);

912

}

913

}

914

goto
fini;

915

}

这个代码类似于
validate_pattern

的那部分。当我们的例子模式通过这个函数时,我们可以得到以下的树。




11

:向决策序列加入
RTL
模板,图
2

然后我们从
add_to_sequence

返回到
make_insn_sequence

。在
2469
行的
last

指向,由
add_to_sequence

返回的,上图中
poistion

域是“
11
”的
decision



make_insn_sequence (continued)

2465

/* Find the end of
the test chain on the last node.
*/

2466

for
(test =
last->tests; test->next; test = test->next)

2467

continue
;

2468

place = &test->next;

2469

2470

/* Skip the C test
if it's known to be true at compile time.

*/

2471

if (truth == -1)

2472

{

2473

/* Need a new
node if we have another test to add.
*/

2474

if (test->type == DT_accept_op)

2475

{

2476

last = new_decision
(c_test_pos, &last->success);

2477

place = &last->tests;

2478

}

2479

test = new_decision_test
(DT_c_test, &place);

2480

test->u.c_test = c_test;

2481

}

2482

2483

test = new_decision_test
(DT_accept_insn, &place);

2484

test->u.insn.code_number = next_insn_code

;

2485

test->u.insn.lineno = pattern_lineno

;

2486

test->u.insn.num_clobbers_to_add = 0;


2475
行,
truth


2418
行的
maybe_eval_c_test

的结果。正如我们已经在
genconditions
中看到的,
maybe_eval_c_test

将返回
-1
,如果条件测试部分不是编译时常量。对于我们的例子,这个条件测试部分是:

"TARGET_64BIT && ix86_match_ccmode (insn,
CCNOmode)"

函数
ix86_match_ccmode

不是编译时的常量,因此
truth

在这里将是
-1
(参见
2475
行)。注意到在
2471
行,
place

指向最后一个
test
节点
next

域的地址,在执行了上面的代码后,我们可以得到下面的树。




12


向决策序列加入
RTL
模板,图
3

make_insn_sequence (continued)

2492

switch
(type)

2493

{

2494

case
RECOG:

2495

/* If this is a
DEFINE_INSN and X is a PARALLEL, see if it ends

2496

with a group of CLOBBERs of (hard)
registers or MATCH_SCRATCHes.

2497

If so, set up to recognize the pattern
without these CLOBBERs.
*/

2498

2499

if (GET_CODE (x) == PARALLEL)

2500

{

2501

int i;

2502

2503

/* Find the last non-clobber in the parallel.

*/

2504

for
(i = XVECLEN (x, 0); i > 0; i--)

2505

{

2506

rtx y = XVECEXP (x, 0, i - 1);

2507

if (GET_CODE
(y) != CLOBBER

2508

|| (GET_CODE (XEXP (y, 0)) != REG

2509

&& GET_CODE (XEXP (y, 0)) !=
MATCH_SCRATCH))

2510

break
;

2511

}

2512

2513

if (i != XVECLEN (x, 0))

2514

{

2515

rtx new;

2516

struct
decision_head clobber_head;

2517

2518

/* Build a
similar insn without the clobbers.
*/

2519

if (i == 1)

2520

new = XVECEXP (x, 0, 0);

2521

else

2522

{

2523

int
j;

2524

2525

new = rtx_alloc (PARALLEL);

2526

XVEC (new, 0) = rtvec_alloc (i);

2527

for
(j = i -
1; j >= 0; j--)

2528

XVECEXP (new, 0, j) = XVECEXP (x, 0,
j);

2529

}

2530

2531

/* Recognize
it.
*/

2532

memset (&clobber_head, 0, sizeof
(clobber_head));

2533

last = add_to_sequence
(new, &clobber_head, "", type, 1);

2534

2535

/* Find the end of
the test chain on the last node.
*/

2536

for
(test =
last->tests; test->next; test = test->next)

2537

continue
;

2538

2539

/* We definitely
have a new test to add -- create a new

2540

node if needed.
*/

2541

place = &test->next;

2542

if
(test->type == DT_accept_op)

2543

{

2544

last = new_decision ("",
&last->success);

2545

place
= &last->tests;

2546

}

2547

2548

/* Skip the C test
if it's known to be true at compile

2549

time.

*/

2550

if (truth == -1)

2551

{

2552

test =
new_decision_test
(DT_c_test, &place);

2553

test->u.c_test = c_test;

2554

}

2555

2556

test = new_decision_test
(DT_accept_insn, &place);

2557

test->u.insn.code_number = next_insn_code

;

2558

test->u.insn.lineno = pattern_lineno

;

2559

test->u.insn.num_clobbers_to_add = XVECLEN
(x, 0) - i;

2560

2561

merge_trees
(&head, &clobber_head);

2562

}

2563

}

2564

break
;

2565

2566

case
SPLIT:

2567

/* Define the
subroutine we will call below and emit in genemit.
*/

2568

printf ("extern rtx gen_split_%d
(rtx *);/n", next_insn_code

);

2569

break
;

2570

2571

case
PEEPHOLE2:

2572

/* Define the
subroutine we will call below and emit in genemit.
*/

2573

printf ("extern rtx gen_peephole2_%d
(rtx, rtx *);/n",

2574

next_insn_code);

2575

break
;

2576

}

2577

2578

return
head;

2579

}

对于我们的例子模式,其类型是
RECOG
,并且其编码是
SET
,因此在函数余下部分不做任何事。

回到
main

,在
make_insn_sequence

返回了这棵树的根节点后,这个根节点作为第二个参数传递给
merge_trees

。我们的例子模式是
i386.md
中的第一个
define_insn
模式,因此
recog_tree

全是
0
,并在
1407
行返回。

为了更贴近地看
merge_trees

可以为我们做什么,我们需要另一个模式。在
i386.md
里,跟着我们例子的下一个
define_insn
模式是:

497

(define_insn "*cmpdi_minus_1_rex64"

498

[(set (reg 17)

499

(compare (minus:DI (match_operand:DI
0 "nonimmediate_operand" "rm,r")

500

(match_operand:DI
1 "x86_64_general_operand" "re,mr"))

501

(const_int 0)))]

502

"TARGET_64BIT
&& ix86_match_ccmode (insn, CCGOCmode)"

503

"cmp{q}/t{%1, %0|%0, %1}"

504

[(set_attr "type" "icmp")

505

(set
_attr
"mode" "DI")])

而在
make_insn_sequence

处理之后,对于该模式我们可以得到以下的树。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: