您的位置:首页 > 其它

GCC后端及汇编发布(30)

2011-06-18 08:33 519 查看

9.6.

输出生成文件

9.6.1.

处理属性

9.6.1.1.

统一属性

虽然我们构建了生成最小化
DFA
所需的数据,但收集的属性尚未处理。我们需要把它们转换为统一的形式,并如下打包有用的信息。

main (continued)

6137

printf ("#include /"config.h/"/n");

6138

printf ("#include
/"system.h/"/n");

6139

printf ("#include
/"coretypes.h/"/n");

6140

printf ("#include
/"tm.h/"/n");

6141

printf ("#include
/"rtl.h/"/n");

6142

printf ("#include
/"tm_p.h/"/n");

6143

printf ("#include
/"insn-config.h/"/n");

6144

printf ("#include
/"recog.h/"/n");

6145

printf ("#include
/"regs.h/"/n");

6146

printf ("#include
/"real.h/"/n");

6147

printf ("#include
/"output.h/"/n");

6148

printf ("#include
/"insn-attr.h/"/n");

6149

printf ("#include
/"toplev.h/"/n");

6150

printf ("#include
/"flags.h/"/n");

6151

printf ("#include
/"function.h/"/n");

6152

printf ("/n");

6153

printf ("#define
operands recog_data.operand/n/n");

6154

6155

/* Make
`insn_alternatives'.
*/

6156

insn_alternatives

= oballoc (insn_code_number

* sizeof
(int));

6157

for
(id = defs

;
id; id = id->next)

6158

if (id->insn_code >=
0)

6159

insn_alternatives

[id->insn_code]
= (1 << id->num_alternatives) - 1;

6160

6161

/* Make
`insn_n_alternatives'.
*/

6162

insn_n_alternatives

= oballoc (insn_code_number

* sizeof
(int));

6163

for
(id = defs

;
id; id = id->next)

6164

if (id->insn_code >=
0)

6165

insn_n_alternatives

[id->insn_code]
= id->num_alternatives;

6166

6167

/* Prepare to write out attribute subroutines by
checking everything stored

6168

away
and building the attribute cases.
*/

6169

6170

check_defs

();

上面在
6159
行,
insn_alternatives

保存着,对于每个指令编码,一个位图,每个可能的替代对应其中的一个比特。而在
6162
行,
insn_n_alternatives

保存着,对于每个指令编码,约束替代的数目。在
6170

check_defs

扫描所有的定义,检查有效性,并把所有的
SET_ATTR

SET_ATTR_ALTERNATIVE
表达式转换为对应的
SET
表达式。

首先,看一下
SET_ATTR

SET_ATTR_ALTERNATIVE
表达式,以下摘自注释


DEFINE_INSN

DEFINE_PEEPHOLE
最后的操作数中,这可以被用于,根据被匹配的替代,指出将被用在赋值的属性值。

以下的三个表达式是等效的:

(set
(attr "att") (cond [(eq_attrq "alternative" "1")
(const_string "a1")

(eq_attrq "alternative"
"2") (const_string "a2")]

(const_string "a3")))

(set_attr_alternative "att" [(const_string "a1")
(const_string "a2")

(const_string "a3")])

(set_attr "att" "a1,a2,a3")

check_defs

将把后两个形式转换为第一个形式。

1313

static
void

1314

check_defs

(void)

in
genattrtab.c

1315

{

1316

struct
insn_def
*id;

1317

struct
attr_desc
*attr;

1318

int i;

1319

rtx value;

1320

1321

for
(id = defs

;
id; id = id->next)

1322

{

1323

if (XVEC (id->def, id->vec_idx) ==
NULL)

1324

continue
;

1325

1326

for
(i = 0;
i < XVECLEN (id->def, id->vec_idx); i++)

1327

{

1328

value = XVECEXP (id->def, id->vec_idx,
i);

1329

switch
(GET_CODE (value))

1330

{

1331

case
SET:

1332

if (GET_CODE (XEXP
(value, 0)) != ATTR)

1333

{

1334

message_with_line (id->lineno, "bad
attribute set");

1335

have_error

= 1;

1336

value = NULL_RTX;

1337

}

1338

break
;

1339

1340

case
SET_ATTR_ALTERNATIVE:

1341

value = convert_set_attr_alternative
(value,
id);

1342

break
;

1343

1344

case
SET_ATTR:

1345

value = convert_set_attr
(value, id);

1346

break
;

1347

1348

default
:

1349

message_with_line (id->lineno,
"invalid attribute code %s",

1350

GET_RTX_NAME (GET_CODE (value)));

1351

have_error

= 1;

1352

value = NULL_RTX;

1353

}

1354

if
(value == NULL_RTX)

1355

continue
;

1356

1357

if
((attr = find_attr
(&XSTR (XEXP
(value, 0), 0), 0)) == NULL)

1358

{

1359

message_with_line (id->lineno,
"unknown attribute %s",

1360

XSTR (XEXP
(value, 0),
0));

1361

have_error

= 1;

1362

continue
;

1363

}

1364

1365

XVECEXP (id->def, id->vec_idx, i) =
value;

1366

XEXP
(value, 1) = check_attr_value
(XEXP
(value, 1), attr);

1367

}

1368

}

1369

}

上面在
1323
行,
def

指向这个
insn_def

所属的
rtx
对象,
vec_idx

显示属性向量在这个
def

中的位置,这个值是硬编码的。对于
define_insn
,它是
4
。对于
define_peephole
,它是
3
。对于
define_asm_attribute
,它是
0
。模式中的属性部分是可选的,如果不存在,意味着使用该属性的缺省值。

SET_ATTR_ALTERNATIVE

RTL
格式是

sE

。使用以下的例子,

(set_attr_alternative
"att" [(const_string "a1") (const_string "a2")

(const_string "a3")])

其中“
att
”是格式的“
s
”部分,而“
[…]
”是“
E
”部分,它是应该含有
3
个元素的向量。正如我们已知的,格式“
s
”对应
CONST_STRING

rtx
对象,而格式“
E
”对应
RTVEC

rtx
对象。

1244

static
rtx

1245

convert_set_attr_alternative

(rtx exp, struct

insn_def

*id)

in
genattrtab.c

1246

{

1247

int num_alt = id->num_alternatives;

1248

rtx condexp;

1249

int i;

1250

1251

if (XVECLEN (exp, 1) != num_alt)

1252

{

1253

message_with_line (id->lineno,

1254

"bad number of entries in
SET_ATTR_ALTERNATIVE");

1255

have_error

= 1;

1256

return
NULL_RTX;

1257

}

1258

1259

/* Make a COND with
all tests but the last. Select the last value via the

1260

default.

*/

1261

condexp = rtx_alloc (COND);

1262

XVEC (condexp, 0) = rtvec_alloc ((num_alt -
1) * 2);

1263

1264

for
(i = 0; i
< num_alt - 1; i++)

1265

{

1266

const
char
*p;

1267

p = attr_numeral (i);

1268

1269

XVECEXP (condexp, 0, 2 * i) =
attr_eq

(alternative_name

,
p);

1270

XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP
(exp, 1, i);

1271

}

1272

1273

XEXP

(condexp, 1) = XVECEXP (exp, 1, i);

1274

1275

return

attr_rtx

(SET,
attr_rtx

(ATTR, XSTR (exp, 0)), condexp);

1276

}

SET_ATTR

RTL
格式是“
ss
”。所有以下的例子,
(set_attr "att" "a1,a2,a3")

。其中,“
ss
”对应“
att
”,及“
a1, a2, a3”

。首先把这个
SET_ATTR
对象转换到对应的
SET_ATTR_ALTERNATIVE
对象。然后通过上面的
convert_set_attr_alternatives

,这个
SET_ATTR_ALTERNATIVE
对象进一步转换到
SET
对象。

1281

static
rtx

1282

convert_set_attr

(rtx exp, struct

insn_def

*id)
in
genattrtab.c

1283

{

1284

rtx newexp;

1285

const
char
*name_ptr;

1286

char *p;

1287

int n;

1288

1289

/* See how many
alternative specified.
*/

1290

n = n_comma_elts (XSTR (exp, 1));

1291

if (n == 1)

1292

return

attr_rtx

(SET,

1293

attr_rtx

(ATTR, XSTR (exp, 0)),

1294

attr_rtx

(CONST_STRING, XSTR (exp, 1)));

1295

1296

newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);

1297

XSTR (newexp, 0) = XSTR (exp, 0);

1298

XVEC (newexp, 1) = rtvec_alloc (n);

1299

1300

/* Process each
comma-separated name.
*/

1301

name_ptr = XSTR (exp, 1);

1302

n = 0;

1303

while
((p =
next_comma_elt (&name_ptr)) != NULL)

1304

XVECEXP (newexp, 1, n++) =
attr_rtx

(CONST_STRING, p);

1305

1306

return

convert_set_attr_alternative

(newexp, id);

1307

}

现在,因为由于处理
SET_ATTR_ALTERNATIVE

SET_ATTR
对象,某些属性被改变了,因此需要下面
6175
行的
check_attr_value

来再一次验证属性。

main (continued)

6172

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

6173

for
(attr =
attrs

[i];
attr; attr = attr->next)

6174

attr->default_val->value

6175

= check_attr_value
(attr->default_val->value, attr);

6176

6177

if (have_error

)

6178

return
FATAL_EXIT_CODE;

6179

6180

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

6181

for
(attr =
attrs

[i];
attr; attr = attr->next)

6182

fill_attr

(attr);

6183

6184

/* Construct extra
attributes for `length'.
*/

6185

make_length_attrs

();

6186

6187

/* Perform any possible optimizations to
speed up compilation.

*/

6188

optimize_attrs
();

9.6.1.2.

完成属性

对于数值属性,在其模式定义中,它必须具有空的
LIST-OF-VALUE
部分(至于
define_attr
的细节,可以参考
读入

DEFINE_ATTR模式

一节)。

对于这些数值属性,
fill_attr

用于从模式中收集这些值。除此之外,对于所有的属性,这个函数将构建一个列表,它把所有使用同一个属性的指令链接起来。

2263

static
void

2264

fill_attr

(struct

attr_desc

*attr)
in
genattrtab.c

2265

{

2266

struct

attr_value

*av;

2267

struct

insn_ent

*ie;

2268

struct

insn_def

*id;

2269

int i;

2270

rtx value;

2271

2272

/* Don't fill
constant attributes. The value is independent of

2273

any particular insn.
*/

2274

if (attr->is_const)

2275

return
;

2276

2277

for
(id = defs

;
id; id = id->next)

2278

{

2279

/* If no value is
specified for this insn for this attribute, use the

2280

default.

*/

2281

value = NULL;

2282

if (XVEC (id->def, id->vec_idx))

2283

for
(i = 0; i < XVECLEN (id->def,
id->vec_idx); i++)

2284

if (! strcmp_check (XSTR (
XEXP

(XVECEXP (id->def, id->vec_idx, i), 0), 0),

2285

attr->name))

2286

value =
XEXP

(XVECEXP (id->def,
id->vec_idx, i), 1);

2287

2288

if (value == NULL)

2289

av = attr->default_val;

2290

else

2291

av =
get_attr_value

(value, attr, id->insn_code);

2292

2293

ie = oballoc (sizeof
(struct

insn_ent

));

2294

ie->insn_code
= id->insn_code;

2295

ie->insn_index = id->insn_code;

2296

insert_insn_ent
(av, ie);

2297

}

2298

}


fill_attr


2274


属性视为常量

如果其值是
SYMBOL_REF

CONST_INT
。在
2277
行,
defs

已经链接了所有的
define_insn

define_peephole

define_asm_attributes
(参见
gen_insn

)。因此在
2283
行的
FOR

循环遍历模式的属性部分,并调用
get_attr_value

来向属性的值列表加入新发现的值(注意对于具有以星号(
*
)开头,由系统产生的属性,它们将以相同的值,为每个指令所添加。这是因为,首先没有指令会包含匹配这个名字的属性,其次,所有这些属性由
make_internal_attr

构建,并具有单个的值)。而在
2296
行,
insert_insn_ent

的定义如下,它把使用相同属性值的指令链接起来。

2632

static
void

2633

insert_insn_ent

(struct

attr_value

*av, struct

insn_ent

*ie)

in genattrtab.c

2634

{

2635

ie->next = av->first_insn;

2636

av->first_insn = ie;

2637

av->num_insns++;

2638

if (ie->insn_code == -1)

2639

av->has_asm_insn = 1;

2640

2641

num_insn_ents

++;

2642

}

insn_ent
构成了具有相同属性值指令的链表,它具有如下定义。

161

struct
insn_ent

in genattrtab.c

162

{

163

struct
insn_ent *next;
/* Next in
chain.
*/

164

int insn_code;
/* Instruction number.

*/

165

int insn_index;
/* Index of definition in file */

166

int lineno;
/* Line number.
*/

167

};

继续
main

,为了更好地了解
6185
行的
make_length_attr

,首先看一下以下摘自
gccint
的段落。

对于许多机器而言,它们提供了多种跳转指令,每个对应不同跳转偏移。在绝大多数情形下,汇编器将选择使用正确的指令。不过,当汇编器做不到这一点时,
GCC
可以,当一个特殊的属性——‘
length

’属性被定义时。这个属性必须,通过在其‘
define_attr

’中指定一个空字符串,来定义为具有数字值。

就‘

length

’属性而言,允许在测试表达式中使用另外两个形式的算术项:

(match_dup
N)

这指向当前指令操作数
N

的地址,它必须是一个‘
label_re.

’。

(pc)

这指向当前指令的地址。其他的用法把它作为下一个指令的地址可能更符合,不过因为当前指令的长度会被计入,这可能会让人困扰。

对于普通的指令,长度将由‘
length

’属性的值来决定。在‘
addr_vec

’及‘
addr_diff_vec

’指令模式中,其长度通过向量的数量乘以每个向量的大小来计算。

长度以可取址储存单元(
byte

)为单位来计量。

下面的宏可以用于细化长度计算:

ADJUST_INSN_LENGTH
(INSN, LENGTH)

如果定义了,作为一个其所被应用的上下文中的一个函数,修改赋予指令
INSN

的长度。
LENGTH

是一个左值(
lvalue

),它包含了该指令初始计算的长度,并将为该指令正确的长度所更新。

这个宏通常是不要求的。要求它的一个情形是
ROMP

。在这个机器中,一个‘
addr_vec

’指令的长度必须加上
2
,来补偿可能要求对齐的这个事实。

返回‘
get_attr_length

’(‘
length

’属性的值)的函数,可以被输出函数所使用,来确定所要写出的跳转指令的形式,如下面例子所显示的。

作为一个可变长度跳转说明的例子,考虑
IBM 360

。如果我们采用约定,一个寄存器将被设置为一个函数的起始地址,我们可以,使用一个
4
字节指令,跳转到距起始地址
4k
内的
label

。否则,我们需要一个
6
字节序列,来从内存载入地址,然后跳转到这个地址。

在这样的一个机器上,一个用于一个跳转指令的模式可能被详细说明如下:

(define_insn
"jump"

[(set (pc)

(label_ref (match_operand 0 "" "")))]

""

{

return (get_attr_length (insn) == 4

?
"b %l0" : "l r15,=a(%l0); br r15");

}

[(set (attr
"length")

(if_then_else
(lt (minus (pc) (match_dup 0) (const_int 4096))

(const_int 4)

(const_int 6)))])

事实上,对于每个
define_insn

define_peephole

define_asm_attribute
模式,如果它不显式设置一个属性,它将使用该属性的缺省值。在这里
make_length

为每个模式,根据其“
length
”属性,构建了
3
个额外的属性。它们是:

*insn_default_length

这是在调用
shorten_branches

之前,由返回的
get_attr_length

指令的长度。在长度依赖于相对地址的情形下,使用最大可能的那个。

*insn_variable_length_p

这返回
1
,如果该指令的长度依赖于相对地址;否则返回
0


*insn_current_length

仅当已知该指令具有一个可变长度时,这才被调用,并基于相对地址返回当前长度。

2379

static
void

2380

make_length_attrs

(void)
in
genattrtab.c

2381

{

2382

static
const
char *new_names[] =

2383

{

2384

"*insn_default_length",

2385

"*insn_variable_length_p",

2386

"*insn_current_length"

2387

};

2388

static
rtx (*const
no_address_fn[]) (rtx) = {identity_fn, zero_fn,
zero_fn};

2389

static
rtx (*const
address_fn[]) (rtx) = {max_fn, one_fn,
identity_fn};

2390

size_t i;

2391

struct

attr_desc

*length_attr, *new_attr;

2392

struct

attr_value

*av, *new_av;

2393

struct

insn_ent

*ie, *new_ie;

2394

2395

/* See if length
attribute is defined. If so, it must be numeric. Make

2396

it special so we don't output anything for
it.
*/

2397

length_attr =
find_attr

(&length_str

,
0);

2398

if (length_attr == 0)

2399

return
;

2400

2401

if (! length_attr->is_numeric)

2402

fatal ("length attribute must be
numeric");

2403

2404

length_attr->is_const = 0;

2405

length_attr->is_special = 1;

2406

2407

/* Make each new
attribute, in turn.
*/

2408

for
(i = 0; i
< ARRAY_SIZE (new_names); i++)

2409

{

2410

make_internal_attr

(new_names[i],

2411

substitute_address

(length_attr->default_val->value,

2412

no_address_fn[i], address_fn[i]),

2413

ATTR_NONE);

2414

new_attr =
find_attr

(&new_names[i], 0);

2415

for
(av =
length_attr->first_value; av; av = av->next)

2416

for
(ie =
av->first_insn; ie; ie = ie->next)

2417

{

2418

new_av =
get_attr_value

(
substitute_address

(av->value,

2419

no_address_fn[i],

2420

address_fn[i]),

2421

new_attr,
ie->insn_code);

2422

new_ie = oballoc (sizeof
(struct

insn_ent

));

2423

new_ie->insn_code = ie->insn_code;

2424

new_ie->insn_index =
ie->insn_index;

2425

insert_insn_ent

(new_av, new_ie);

2426

}

2427

}

2428

}

上面在
2411
行,
substitute_address

,给定一个表达式
exp

,查看它是否是一个具有检查指令相对位置(使用
MATCH_DUP

PC
)测试的
COND

IF_THEN_ELSE
。如果是,使用通过把该表达式传递给
address_fn

所得到的结果来替代之。如果不是,但它是一个
COND

IF_THEN_ELSE
,在每个值上递归调用这个函数(包括缺省值)。否则,返回由应用在
exp

上的
no_address_fn

所返回的值。

2307

static
rtx

2308

substitute_address

(rtx exp, rtx
(*no_address_fn) (rtx),

in genattrtab.c

2309

rtx (*address_fn) (rtx))

2310

{

2311

int i;

2312

rtx newexp;

2313

2314

if (GET_CODE (exp) == COND)

2315

{

2316

/* See if any
tests use addresses.
*/

2317

address_used

= 0;

2318

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

2319

walk_attr_value

(XVECEXP (exp, 0, i));

2320

2321

if (address_used

)

2322

return
(*address_fn) (exp);

2323

2324

/* Make a new
copy of this COND, replacing each element.

*/

2325

newexp = rtx_alloc (COND);

2326

XVEC (newexp, 0) = rtvec_alloc (XVECLEN
(exp, 0));

2327

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

2328

{

2329

XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);

2330

XVECEXP (newexp, 0, i + 1)

2331

=
substitute_address

(XVECEXP (exp, 0, i + 1),

2332

no_address_fn,
address_fn);

2333

}

2334

2335

XEXP

(newexp, 1) =
substitute_address

(
XEXP

(exp, 1),

2336

no_address_fn,
address_fn);

2337

2338

return
newexp;

2339

}

2340

2341

else if (GET_CODE (exp) == IF_THEN_ELSE)

2342

{

2343

address_used

= 0;

2344

walk_attr_value

(
XEXP

(exp, 0));

2345

if (address_used

)

2346

return
(*address_fn) (exp);

2347

2348

return

attr_rtx

(IF_THEN_ELSE,

2349

substitute_address

(
XEXP

(exp, 0),

2350

no_address_fn,
address_fn),

2351

substitute_address

(
XEXP

(exp, 1),

2352

no_address_fn, address_fn),

2353

substitute_address

(
XEXP

(exp, 2),

2354

no_address_fn,
address_fn));

2355

}

2356

2357

return
(*no_address_fn)
(exp);

2358

}

walk_attr_value

扫描属性值,这可能是个条件值(一个例外是下面
4979
行的
ATTR_FLAG
),并记录将要求什么动作来对它进行条件测试。

4934

static
void

4935

walk_attr_value

(rtx exp)

in genattrtab.c

4936

{

4937

int i, j;

4938

const
char
*fmt;

4939

RTX_CODE code;

4940

4941

if (exp == NULL)

4942

return
;

4943

4944

code = GET_CODE (exp);

4945

switch
(code)

4946

{

4947

case
SYMBOL_REF:

4948

if (!
ATTR_IND_SIMPLIFIED_P

(exp))

4949

/* Since this
is an arbitrary expression, it can look at anything.

4950

However, constant expressions do not
depend on any particular

4951

insn.

*/

4952

must_extract

= must_constrain

= 1;

4953

return
;

4954

4955

case
MATCH_OPERAND:

4956

must_extract

= 1;

4957

return
;

4958

4959

case
EQ_ATTR_ALT:

4960

must_extract

= must_constrain

= 1;

4961

break
;

4962

4963

case
EQ_ATTR:

4964

if (XSTR (exp, 0) == alternative_name

)

4965

must_extract

= must_constrain

= 1;

4966

else if (strcmp_check (XSTR (exp, 0), length_str

)
== 0)

4967

length_used

= 1;

4968

return
;

4969

4970

case
MATCH_DUP:

4971

must_extract

= 1;

4972

address_used

= 1;

4973

return
;

4974

4975

case
PC:

4976

address_used

= 1;

4977

return
;

4978

4979

case
ATTR_FLAG:

4980

return
;

4981

4982

default
:

4983

break
;

4984

}

4985

4986

for
(i = 0,
fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)

4987

switch
(*fmt++)

4988

{

4989

case
'e':

4990

case
'u':

4991

walk_attr_value

(
XEXP

(exp, i));

4992

break
;

4993

4994

case
'E':

4995

if (XVEC (exp, i) != NULL)

4996

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

4997

walk_attr_value

(XVECEXP (exp, i, j));

4998

break
;

4999

}

5000

}


4952
行,
must_extract

表示我们是否需要提取指令的操作数,
must_constrain

表示我们是否必须计算编译器变量
which_alternative

。在
4967
行,
length_used

表示,是否使用了一个
(eq_attr
"length" ...)
,而在
4972
行,
address_used

显示是否使用了一个地址表达式。

最后,对两种指令类型的结果显示如下。

no_address_fn
result of fn on exp
attribute attached


identity_fn
exp
"*insn_default_length"

zero_fn
rtx
object of 0
"*insn_variable_length_p"

zero_fn
rtx
object of 0
"*insn_current_length"


1

:为其它指令构建的属性

address_fn
result of fn on exp
attribute attached


max_fn
rtx
object of max value in exp
"*insn_default_length"

one_fn
rtx
object of 1
"*insn_variable_length_p"

identify_fn
exp
"*insn_current_length"


2

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