您的位置:首页 > 其它

GCC后端及汇编发布(6)

2011-04-23 09:30 387 查看

3.3.

构建识别树

3.3.3.

创建识别树

对于每个指令描述模式(正如我们看到有
3
个类型的模式在使用——
define_insn

define_split

define_peephole2
。但是它们被分别处理,因此有
3
种树对应这
3
个类型的模式),将构建形如


13

的树。为了从这些树,以高效、方便的方式,产生
insn-recog.c
,我们需要把这些树合并成一棵大的树。这正是
merge_trees

.
的目的。对于所有的描述,
merge_trees

应该构建一棵如下的树。





14



merge_trees
创建的描述树



14

的树(目标树)从指令的第一棵描述树,通过加入其它描述树,生长起来。对于这些树,它们将与目标树,从根节点开始,进行比较。在那些目标树中的节点不同于描述树节点的位置,该描述树节点将被作为目标树节点的兄弟节点加入。而如果目标树节点被发现与描述树节点相同,就进入这两棵树的下一级节点(在这两棵树中,深度由
decision
节点的
position

域,以我们在上面看到的方式,来显示),然后重复比较,合并或深入的步骤。

显然,每个指令与目标树的某个叶子匹配,注意到叶子与指令是一一对应的。从根节点到特定的叶子,其路径代表了用于选择该指令的条件测试。

1397

static
void

1398

merge_trees (struct
decision_head
*oldh, struct
decision_head *addh)
in genrecog.c

1399

{

1400

struct
decision
*next, *add;

1401

1402

if (addh->first == 0)

1403

return
;

1404

if (oldh->first == 0)

1405

{

1406

*oldh = *addh;

1407

return
;

1408

}

1409

1410

/* Trying to merge
bits at different positions isn't possible.

*/

1411

if (strcmp (oldh->first->position,
addh->first->position))

1412

abort ();

1413

1414

for
(add =
addh->first; add ; add = next)

1415

{

1416

struct
decision
*old, *insert_before = NULL;

1417

1418

next = add->next;

1419

1420

/* The semantics
of pattern matching state that the tests are

1421

done in the order given in the MD file so
that if an insn

1422

matches two patterns, the first one will
be used. However,

1423

i
n practice, most, if not all, patterns are unambiguous so

1424

that their order is independent. In that
case, we can merge

1425

identical tests and group all similar
modes and codes together.

1426

1427

Scan starting from the end of OLDH until
we reach a point

1428

where we reach the head of the list or
where we pass a

1429

pattern that could also be true if NEW is
true. If we find

1430

an identical pattern, we can merge them.
Also, record the

1431

last node that tests the same code and
mode and the last one

1432

that tests just the same mode.

1433

1434

If we have no match, place NEW after the
closest match we found.
*/

1435

1436

for
(old =
oldh->last; old; old = old->prev)

1437

{

1438

if (nodes_identical
(old, add))

1439

{

1440

merge_accept_insn
(old, add);

1441

merge_trees
(&old->success, &add->success);

1442

goto
merged_nodes;

1443

}

1444

1445

if (maybe_both_true
(old, add, 0))

1446

break
;

1447

1448

/* Insert the nodes in DT test type order,
which is roughly

1449

how expensive/important the test is.
Given that the tests

1450

are also ordered within the list,
examining the first is

1451

sufficient.
*/

1452

if ((int) add->tests->type <
(int) old->tests->type)

1453

insert_before = old;

1454

}

1455

1456

if (insert_before == NULL)

1457

{

1458

add->next = NULL;

1459

add->prev = oldh->last;

1460

oldh->last->next = add;

1461

oldh->last = add;

1462

}

1463

else

1464

{

1465

if ((add->prev =
insert_before->prev) != NULL)

1466

add->prev->next = add;

1467

else

1468

oldh->first = add;

1469

add->next = insert_before;

1470

insert_before->prev = add;

1471

}

1472

1473

merged_nodes:
;

1474

}

1475

}

这是一个非常复杂的过程,让我们一步一步来。在
main

中的调用点,我们看到该函数的第一个参数
oldh

指向我们例子的
recog_tree

,而第二个参数
addh

指向


13

所示的树。首先,它将检查以下的节点。




15


merge_tree
函数,图
1


1438
行,函数
nodes_identical

将检查上面的
decision
节点,来确定它们是否是相同的对象。而现在在
1436

oldh


prev

域,及在
1418

addh


next

域,都是
null


1317

static
int

1318

nodes_identical (struct
decision
*d1, struct
decision
*d2)

in
genrecog.c

1319

{

1320

struct

decision_test

*t1, *t2;

1321

1322

for
(t1 = d1->tests, t2 = d2->tests; t1
&& t2; t1 = t1->next, t2 = t2->next)

1323

{

1324

if (t1->type != t2->type)

1325

return
0;

1326

if (! nodes_identical_1 (t1, t2))

1327

return
0;

1328

}

1329

1330

/* For success,
they should now both be null.
*/

1331

if (t1 != t2)

1332

return
0;

1333

1334

/* Check that their
subnodes are at the same position, as any one set

1335

of sibling decisions must be at the same
position. Allowing this

1336

requires complications to find_afterward
and when change_state is

1337

invoked.

*/

1338

if (d1->success.first

1339

&& d2->success.first

1340

&& strcmp
(d1->success.first->position, d2->success.first->position))

1341

return
0;

1342

1343

return
1;

1344

}

上面,在
1326
行,在比较了类型之后,
nodes_identical_1

进一步检查内容是否匹配。接着在
1338
行,要完全相同,跟随它们的节点的
position

也必须是相同的。显然我们例子中所关注的节点是相同的。

给定两个声明完全相同的节点,在
1440
行的函数
merge_accept_insn

拷贝这两个指令的接受状态。下面的
DT_accept_insn
表示一旦通过这个
decision_test
,对应的指令被匹配。即,这个
decision_test
节点是匹配这个指令的最后一个测试。

1353

static
void

1354

merge_accept_insn (struct
decision
*oldd, struct
decision
*addd)
in
genrecog.c

1355

{

1356

struct
decision_test
*old, *add;

1357

1358

for
(old =
oldd->tests; old; old = old->next)

1359

if (old->type == DT_accept_insn)

1360

break
;

1361

if (old == NULL)

1362

return
;

1363

1364

for
(add =
addd->tests; add; add = add->next)

1365

if (add->type == DT_accept_insn)

1366

break
;

1367

if (add == NULL)

1368

return
;

1369

1370

/* If one node is
for a normal insn and the second is for the base

1371

insn with clobbers stripped off, the second
node should be ignored.
*/

1372

1373

if (old->u.insn.num_clobbers_to_add == 0

1374

&&
add->u.insn.num_clobbers_to_add > 0)

1375

{

1376

/* Nothing to do
here.
*/

1377

}

1378

else if (old->u.insn.num_clobbers_to_add
> 0

1379

&& add->u.insn.num_clobbers_to_add == 0)

1380

{

1381

/* In this case,
replace OLD with ADD.
*/

1382

old->u.insn = add->u.insn;

1383

}

1384

else

1385

{

1386

message_with_line (add->u.insn.lineno,
"`%s' matches `%s'",

1387

get_insn_name
(add->u.insn.code_number),

1388

get_insn_name
(old->u.insn.code_number));

1389

message_with_line (old->u.insn.lineno,
"previous definition of `%s'",

1390

get_insn_name
(old->u.insn.code_number));

1391

error_count

++;

1392

}

1393

}

上面的
num_clobbers_to_add

,在
make_insn_sequence

中,设置为
PARALLEL
对象中元素数目的记录。如果它们在是否带
clobber
上不相同,那么这个冲突是由
make_insn_sequence

造成的,我们可以丢掉带有
clobber
的版本。如果这两个节点不能通过
clobber
来区分,我们在机器描述文件中找到了一个二义性错误。这个机制用于筛选更有效率的指令。

对于两个相同的节点,那样
merge_trees

沿着链,递归入下一个节点。我们可以看到,对于这两个链,接着的节点也是相同的,直到来到以下节点。




16


merge_tree
函数,图
2

对于这两个节点,
nodes_identical


DT_Code
类型的
decision_test
的子节点处返回
0
。然后函数
maybe_both_true

将被调用。这个函数把描述树的节点与目标树的兄弟节点比较,如果任一兄弟节点匹配这个节点就返回
1
,如果没有找到这样的兄弟节点就返回
0
,不确定则返回
-1


1202

static
int

1203

maybe_both_true (struct
decision
*d1, struct
decision
*d2,
in
genrecog.c

1204

int toplevel)

1205

{

1206

struct
decision
*p1, *p2;

1207

int cmp;

1208

1209

/* Don't compare strings on the different
positions in insn. Doing so

1210

is incorrect and results in false matches
from constructs like

1211

1212

[(set (subreg:HI (match_operand:SI
"register_operand" "r") 0)

1213

(subreg:HI (match_operand:SI
"register_operand" "r") 0))]

1214

vs

1215

[(set (match_operand:HI
"register_operand" "r")

1216

(match_operand:HI "register_operand"
"r"))]

1217

1218

If we are presented with such, we are
recursing through the remainder

1219

of a node's success nodes (from the loop at
the end of this function).

1220

Skip forward until we come to a position
that matches.

1221

1222

Due to the way position strings are
constructed, we know that iterating

1223

forward from the lexically lower position
(e.g. "00") will run into

1224

the lexically higher position (e.g.
"1") and not the other way around.

1225

This saves a bit of effort.
*/

1226

1227

cmp = strcmp (d1->position,
d2->position);

1228

if (cmp != 0)

1229

{

1230

if (toplevel)

1231

abort ();

1232

1233

/* If the
d2->position was lexically lower, swap.

*/

1234

if (cmp > 0)

1235

p1
= d1, d1 = d2, d2 = p1;

1236

1237

if (d1->success.first == 0)

1238

return
1;

1239

for
(p1 =
d1->success.first; p1; p1 = p1->next)

1240

if (maybe_both_true
(p1, d2, 0))

1241

return
1;

1242

1243

return
0;

1244

}

1245

1246

/* Test the current
level.
*/

1247

cmp = maybe_both_true_1
(d1->tests, d2->tests);

1248

if (cmp >= 0)

1249

return
cmp;

1250

1251

/* We can't prove that D1 and D2 cannot both
be true. If we are only

1252

to check the top level, return 1.
Otherwise, see if we can prove

1253

that all choices in both successors are
mutually exclusive. If

1254

either does not have any successors, we
can't prove they can't both

1255

be true.

*/

1256

1257

if (toplevel || d1->success.first == 0 ||
d2->success.first == 0)

1258

return
1;

1259

1260

for
(p1 =
d1->success.first; p1; p1 = p1->next)

1261

for
(p2 =
d2->success.first; p2; p2 = p2->next)

1262

if (maybe_both_true
(p1, p2, 0))

1263

return
1;

1264

1265

return
0;

1266

}

然后
merge_trees

开始处理
position(‘10’)
的节点。对于这些节点,在
1227
行的测试将可通过。它们具有相同的位置。接着函数
maybe_both_true_1

测试属于这两个节点的
decision_test
,来确保这些测试集是相同的。如果匹配,它将返回
1
,可能匹配则返回
-1
,不匹配则返回
0


1168

static
int

1169

maybe_both_true_1 (struct
decision_test
*d1, struct
decision_test
*d2)
in genrecog.c

1170

{

1171

struct
decision_test
*t1, *t2;

1172

1173

/* A match_operand
with no predicate can match anything. Recognize

1174

this by the existence of alone DT_accept_op
test.

*/

1175

if
(d1->type == DT_accept_op || d2->type == DT_accept_op)

1176

return
1;

1177

1178

/* Eliminate pairs
of tests while they can exactly match.

*/

1179

while
(d1
&& d2 && d1->type == d2->type)

1180

{

1181

if (maybe_both_true_2
(d1, d2) == 0)

1182

return
0;

1183

d1 = d1->next, d2 = d2->next;

1184

}

1185

1186

/* After that, consider
all pairs.

*/

1187

for
(t1 = d1; t1 ; t1 = t1->next)

1188

for
(t2 = d2; t2 ; t2 = t2->next)

1189

if (maybe_both_true_2
(t1, t2) == 0)

1190

return
0;

1191

1192

return
-1;

1193

}

maybe_both_true_2

处理测试集中的具体测试。如果两个测试是相同的,它返回
1
;如果不同,则返回
0
;如果不能证明它们是相同的,就返回
-1


1058

static
int

1059

maybe_both_true_2 (struct
decision_test
*d1, struct
decision_test
*d2)
in genrecog.c

1060

{

1061

if (d1->type == d2->type)

1062

{

1063

switch
(d1->type)

1064

{

1065

case
DT_mode:

1066

return
d1->u.mode == d2->u.mode;

1067

1068

case
DT_code:

1069

return
d1->u.code == d2->u.code;

1070

1071

case
DT_veclen:

1072

return
d1->u.veclen == d2->u.veclen;

1073

1074

case
DT_elt_zero_int:

1075

case
DT_elt_one_int:

1076

case
DT_elt_zero_wide:

1077

case
DT_elt_zero_wide_safe:

1078

return
d1->u.intval == d2->u.intval;

1079

1080

default
:

1081

break
;

1082

}

1083

}

1084

1085

/* If either has a
predicate that we know something about, set

1086

things up so that D1 is the one that always
has a known

1087

predicate. Then see if they have any codes
in common.
*/

1088

1089

if (d1->type == DT_pred || d2->type ==
DT_pred)

1090

{

1091

if (d2->type == DT_pred)

1092

{

1093

struct
decision_test
*tmp;

1094

tmp = d1, d1 = d2, d2 = tmp;

1095

}

1096

1097

/* If D2 tests a mode, see if it matches
D1.
*/

1098

if (d1->u.pred.mode != VOIDmode)

1099

{

1100

if (d2->type == DT_mode)

1101

{

1102

if (d1->u.pred.mode != d2->u.mode

1103

/* The mode of an
address_operand predicate is the

1104

mode of the memory, not the
operand. It can only

1105

be used for testing the predicate,
so we must

1106

ignore it here.
*/

1107

&& strcmp (d1->u.pred.name,
"address_operand") != 0)

1108

return
0;

1109

}

1110

/* Don't check
two predicate modes here, because if both predicates

1111

accept CONST_INT, then both can still
be true even if the modes

1112

are different. If they don't accept
CONST_INT, there will be a

1113

separate DT_mode that will make
maybe_both_true_1 return 0.
*/

1114

}

1115

1116

if (d1->u.pred.index >= 0)

1117

{

1118

/* If D2 tests
a code, see if it is in the list of valid

1119

codes for D1's predicate.
*/

1120

if (d2->type == DT_code)

1121

{

1122

const
RTX_CODE *c = &preds

[d1->u.pred.index].codes[0];

1123

while
(*c != 0)

1124

{

1125

if (*c == d2->u.code)

1126

break
;

1127

++c;

1128

}

1129

if (*c == 0)

1130

return
0;

1131

}

1132

1133

/* Otherwise
see if the predicates have any codes in common.

*/

1134

else if (d2->type == DT_pred
&& d2->u.pred.index >= 0)

1135

{

1136

const
RTX_CODE *c1 = &preds

[d1->u.pred.index].codes[0];

1137

int common = 0;

1138

1139

while
(*c1 != 0 && !common)

1140

{

1141

const
RTX_CODE *c2 = &preds

[d2->u.pred.index].codes[0];

1142

while
(*c2
!= 0 && !common)

1143

{

1144

common = (*c1 == *c2);

1145

++c2;

1146

}

1147

++c1;

1148

}

1149

1150

if (!common)

1151

return
0;

1152

}

1153

}

1154

}

1155

1156

/* Tests vs veclen
may be known when strict equality is involved.

*/

1157

if
(d1->type == DT_veclen && d2->type == DT_veclen_ge)

1158

return
d1->u.veclen >= d2->u.veclen;

1159

if
(d1->type == DT_veclen_ge && d2->type == DT_veclen)

1160

return
d2->u.veclen >= d1->u.veclen;

1161

1162

return
-1;

1163

}

对于这里感兴趣的节点,
maybe_both_true_2

将对第二个子节点返回
0
,它进而使得在
1182
行的
maybe_both_true_1

返回
0
。接着函数
maybe_both_true


1249
行也返回
0


那么回到
merge_trees

,在
1445
行,因为
maybe_both_true

返回
0
。在
1452
行的代码执行在两个相等的类型上。那么在
1456
行,
insert_before

当前是
null
。在执行了
1456
行的
IF

块之后,我们可以得到如下的节点。两个位置是“
10
”的节点被链接为兄弟节点。




17


merge_tree
函数,图
3

从这个图中,我们可以看到,向
recog_tree

加入了一个分枝。看到事实上从
addh

剥除了公共的部分,对
recog_tree

的根节点,它们不可到达。

main (continued)

2662

if (error_count

)

2663

return
FATAL_EXIT_CODE;

2664

2665

puts ("/n/n");

2666

2667

process_tree
(&recog_tree, RECOG);

2668

process_tree
(&split_tree, SPLIT);

2669

process_tree
(&peephole2_tree, PEEPHOLE2);

2670

2671

fflush (stdout);

2672

return
(ferror (stdout) !=
0 ?
FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);

2673

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