您的位置:首页 > 其它

GCC后端及汇编发布(9)

2011-04-30 08:59 375 查看

4.

genemit
工具

4.1.

代码输出的准备

这个工具从机器描述文件生成文件
insn-emit.c

Insn-emit.c
定义了,从机器描述文件中的模式定义生成的,以给定操作数作为参数的模式匹配函数。

775

int

776

main (int argc, char **argv)
in
genemit.c

777

{

778

rtx desc;

779

780

progname = "genemit";

781

782

if (argc <= 1)

783

fatal ("no input file name");

784

785

if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)

786

return
(FATAL_EXIT_CODE);

787

788

/* Assign sequential codes to all entries in the
machine description

789

i
n parallel with the tables in
insn-output.c.
*/

790

791

insn_code_number = 0;

792

insn_index_number = 0;

793

794

printf ("/* Generated automatically by the program `genemit'/n/

795

from the machine description file `md'.

*//n/n");

796

797

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

798

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

799

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

800

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

801

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

802

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

803

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

804

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

805

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

806

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

807

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

808

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

809

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

810

printf ("#include /"hard-reg-set.h/"/n");

811

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

812

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

813

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

814

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

815

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

816

printf ("#define
FAIL return (end_sequence (), _val)/n");

817

printf ("#define DONE return (_val = get_insns (), end_sequence (),
_val)/n/n");

开始看起来都是类似的。在
785
行,
init_md_reader_args

读入机器描述文件,并构建对应的
rtx
对象。我们以
genconditions工具

中的
define_insn_and_split
为例,它将被分裂成两个
rtx
对象。

4225

(define_insn_and_split
"*fix_truncsi_1"
in
i386.md

4226

[(set (match_operand:SI 0 "nonimmediate_operand"
"=m,?r")

4227

(fix:SI (match_operand 1
"register_operand" "f,f")))]

4228

"TARGET_80387 && FLOAT_MODE_P
(GET_MODE (operands[1]))

4229

&& !reload_completed &&
!reload_in_progress

4230

&& !SSE_FLOAT_MODE_P (GET_MODE
(operands[1]))"

4231

"#"

4232

"&& 1"

4233

[(const_int 0)]

4234

{

4235

ix86_optimize_mode_switching = 1;

4236

operands[2] = assign_386_stack_local (HImode,
1);

4237

operands[3] = assign_386_stack_local (HImode,
2);

4238

if (memory_operand (operands[0], VOIDmode))

4239

emit_insn (gen_fix_truncsi_memory
(operands[0], operands[1],

4240

operands[2], operands[3]));

4241

else

4242

{

4243

operands[4] = assign_386_stack_local
(SImode, 0);

4244

emit_insn (gen_fix_truncsi_nomemory (operands[0],
operands[1],

4245

operands[2], operands[3],

4246

operands[4]));

4247

}

4248

DONE;

4249

}

4250

[(set_attr "type"
"fistp")

4251

(set_attr "mode" "SI")])

那么在下面,在
main

中我们将处理这个
rtx
对象。

main (continued)

819

/* Read the machine description.
*/

820

821

while
(1)

822

{

823

int line_no;

824

825

desc = read_md_rtx
(&line_no,
&insn_code_number);

826

if (desc == NULL)

827

break
;

828

829

switch
(GET_CODE (desc))

830

{

831

case
DEFINE_INSN:

832

gen_insn
(desc, line_no);

833

break
;

834

835

case
DEFINE_EXPAND:

836

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

837

gen_expand (desc);

838

break
;

839

840

case
DEFINE_SPLIT:

841

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

842

gen_split

(desc);

843

break
;

844

845

case
DEFINE_PEEPHOLE2:

846

printf ("/* %s:%d *//n", read_rtx_filename, line_no);

847

gen_split

(desc);

848

break
;

849

850

default
:

851

break
;

852

}

853

++insn_index_number;

854

}

855

856

/* Write out the routines to add CLOBBERs to a
pattern and say whether they

857

clobber a hard reg.
*/

858

output_add_clobbers ();

859

output_added_clobbers_hard_reg_p ();

860

861

fflush (stdout);

862

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

863

}

4.1.


define_insn
产生代码

对于我们
define_insn_and_split
模式的例子,其
define_insn
部分如下。




29


genemit - define_insn_and_split
模式
– insn
部分

这是一个
define_insn

rtx
对象,因此
gen_insn

将被调用。

287

static
void

288

gen_ins

n (rtx insn, int lineno)

in genemit.c

289

{

290

int operands;

291

int i;

292

293

/* See if the pattern for this insn ends with
a group of CLOBBERs of (hard)

294

registers or MATCH_SCRATCHes. If so, store
away the information for

295

later.

*/

296

297

if (XVEC (insn, 1))

298

{

299

int has_hard_reg = 0;

300

301

for
(i = XVECLEN (insn, 1) - 1; i > 0; i--)

302

{

303

if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)

304

break
;

305

306

if (GET_CODE (XEXP
(XVECEXP (insn, 1, i), 0)) ==
REG)

307

has_hard_reg = 1;

308

else if (GET_CODE (XEXP
(XVECEXP (insn, 1, i), 0))
!= MATCH_SCRATCH)

309

break
;

310

}

对于我们上面的例子,它在
304
行跳出循环,因为这个模式不破坏任何寄存器。

gen_insn (continued)

312

if (i != XVECLEN (insn, 1) - 1)

313

{

314

struct
clobber_pat
*p;

315

struct
clobber_ent
*link = xmalloc (sizeof
(struct
clobber_ent));

316

int j;

317

318

link->code_number = insn_code_number

;

319

320

/* See if any previous CLOBBER_LIST entry is
the same as this

321

one.

*/

322

323

for
(p = clobber_list

; p; p = p->next)

324

{

325

if (p->first_clobber != i + 1

326

|| XVECLEN (p->pattern, 1) !=
XVECLEN (insn, 1))

327

continue
;

328

329

for
(j = i + 1; j < XVECLEN (insn,
1); j++)

330

{

331

rtx old = XEXP
(XVECEXP (p->pattern, 1, j), 0);

332

rtx new = XEXP
(XVECEXP (insn, 1, j), 0);

333

334

/* OLD
and NEW are the same if both are to be a SCRATCH

335

of the same mode,

336

or if both are registers of the
same mode and number.
*/

337

if (! (GET_MODE (old) == GET_MODE
(new)

338

&& ((GET_CODE (old) ==
MATCH_SCRATCH

339

&& GET_CODE (new) ==
MATCH_SCRATCH)

340

|| (GET_CODE (old) == REG &&
GET_CODE (new) == REG

341

&& REGNO (old) == REGNO
(new)))))

342

break
;

343

}

344

345

if (j == XVECLEN (insn, 1))

346

break
;

347

}

348

349

if (p == 0)

350

{

351

p = xmalloc (sizeof
(struct
clobber_pat));

352

353

p->insns = 0;

354

p->pattern = insn;

355

p->first_clobber = i + 1;

356

p->next = clobber_list

;

357

p->has_hard_reg = has_hard_reg;

358

clobber_list

= p;

359

}

360

361

link->next = p->insns;

362

p->insns = link;

363

}

364

}

上面。对于将破坏寄存器的模式,这个相关的信息必须被保存在
clobber_list
中。它具有如下的定义:

42

struct
clobber_pat
in
genemit.c

43

{

44

struct
clobber_ent
*insns;

45

rtx pattern;

46

int first_clobber;

47

struct
clobber_pat *next;

48

int has_hard_reg;

49

} *clobber_list;

50

51

/* Records one
insn that uses the clobber list.
*/

52

53

struct
clobber_ent

54

{

55

int code_number;
/* Counts only insns.

*/

56

struct
clobber_ent *next;

57

};

clobber_pat
为具有相同形式的模式保存
clobber
信息的记录,换而言之,对于两个具有不同形式的模式,它们将属于不同的
clobber_pat
实例。因此
has_hard_reg


first_clobber

对于
clobber_ent

中的所有成员都是有意义的,其中
first_clobber

表示在哪一步这个指定的寄存器将被破坏,而
has_hard_reg

指出是否涉及真实的寄存器。


clobber_ent
中的
code_number

区分模式,因为它来自
insn_code_number

,对于指定的模式它是唯一且不变的。显然,
clobber_ent
是与模式对应的。对于我们的例子,没有收集
clobber
信息。

gen_insn (continued)

366

/* Don't mention instructions whose names are
the null string

367

or begin with '*'. They are in the machine
description just

368

to be recognized.
*/

369

if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')

370

return
;

371

372

printf ("/* %s:%d *//n", read_rtx_filename

, lineno);

373

374

/* Find out how many operands this function
has.
*/

375

operands = max_operand_vec
(insn, 1);

376

if (max_dup_opno

>= operands)

377

fatal ("match_dup operand number has no match_operand");

378

/* Output the function name and argument
declarations.
*/

379

printf ("rtx/ngen_%s (", XSTR (insn, 0));

380

if (operands)

381

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

382

if (i)

383

printf (",/n/trtx operand%d ATTRIBUTE_UNUSED", i);

384

else

385

printf ("rtx operand%d ATTRIBUTE_UNUSED", i);

386

else

387

printf ("void");

388

printf (")/n");

389

printf ("{/n");

不过,我们的例子在其名字的开头有“
*
”,这意味着这个指令模式不用于产生
RTL
代码,并且这样的一个名字仅用于在
RTL
转储(
dump
)中识别该指令。因此在真实世界里,它将在
370
行返回,而不做任何事。

现在,我们假定这个‘
*

压根没有出现过。在
372
行,给出我们来自那里的信息。在
375
行,
max_operand_vec

找出在该模式中操作数的个数。这个函数相当简单。对于我们的例子,
max_opno

将是
2


108

static
int

109

max_operand_vec
(rtx insn, int arg)
in
genemit.c

110

{

111

int len = XVECLEN (insn, arg);

112

int i;

113

114

max_opno

= -1;

115

max_dup_opno

= -1;

116

max_scratch_opno

= -1;

117

118

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

119

max_operand_1

(XVECEXP (insn, arg, i));

120

121

return
max_opno

+ 1;

122

}

72

static
void

73

max_operand_1
(rtx x)

in
genemit.c

74

{

75

RTX_CODE code;

76

int i;

77

int len;

78

const
char *fmt;

79

80

if (x == 0)

81

return
;

82

83

code = GET_CODE (x);

84

85

if (code == MATCH_OPERAND || code == MATCH_OPERATOR

86

|| code == MATCH_PARALLEL)

87

max_opno

= MAX (max_opno

,
XINT (x, 0));

88

if (code == MATCH_DUP ||
code == MATCH_OP_DUP || code == MATCH_PAR_DUP)

89

max_dup_opno

= MAX (max_dup_opno

,
XINT (x, 0));

90

if (code == MATCH_SCRATCH)

91

max_scratch_opno

= MAX (max_scratch_opno

,
XINT (x, 0));

92

93

fmt = GET_RTX_FORMAT (code);

94

len = GET_RTX_LENGTH (code);

95

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

96

{

97

if (fmt[i] == 'e' || fmt[i] ==
'u')

98

max_operand_1
(XEXP
(x,
i));

99

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

100

{

101

int j;

102

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

103

max_operand_1
(XVECEXP (x, i, j));

104

}

105

}

106

}

那么,从上面的代码片段,我们将得到如下函数的定义(假定模式名字是
fix_truncsi_1
,而不是
*fix_truncsi_1
)。

rtx

gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,

rtx
operand1 ATTRIBUTE_UNUSED,

rtx
operand2 ATTRIBUTE_UNUSED)

{

gen_insn (continued)

392

/* Output code to construct and return the rtl
for the instruction body.
*/

393

394

if (XVECLEN (insn, 1) == 1)

395

{

396

printf ("
return ");

397

gen_exp
(XVECEXP (insn, 1, 0), DEFINE_INSN,
NULL);

398

printf (";/n}/n/n");

399

}

400

else

401

{

402

printf ("
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec
(%d",

403

XVECLEN (insn, 1));

404

405

for
(i = 0; i < XVECLEN (insn, 1); i++)

406

{

407

printf (",/n/t/t");

408

gen_exp

(XVECEXP (insn, 1, i), DEFINE_INSN,
NULL);

409

}

410

printf ("));/n}/n/n");

411

}

412

}


define_pattern

rtx
格式中,
RTL
模板具有格式‘
E
’——
rtx
对象的向量。在上面
394
行的
XVECLEN

给出了这个向量的大小,而在
408

XVECEXP

给出该向量中的元素。对于
gen_exp

的参数
x

,它指向以下的
RTL
模板。

4225

[(set (match_operand:SI 0
"nonimmediate_operand" "=m,?r")

4226

(fix:SI (match_operand 1
"register_operand" "f,f")))]

148

static
void

149

gen_exp (rtx x, enum
rtx_code subroutine_type, char *used)
in genemit.c

150

{

151

RTX_CODE code;

152

int i;

153

int len;

154

const
char *fmt;

155

156

if (x == 0)

157

{

158

printf ("NULL_RTX");

159

return
;

160

}

161

162

code = GET_CODE (x);

163

164

switch
(code)

165

{

166

case
MATCH_OPERAND:

167

case
MATCH_DUP:

168

if (used)

169

{

170

if (used[XINT (x, 0)])

171

{

172

printf ("copy_rtx
(operand%d)", XINT (x, 0));

173

return
;

174

}

175

used[XINT (x, 0)] = 1;

176

}

177

printf ("operand%d", XINT (x, 0));

178

return
;

179

180

case
MATCH_OP_DUP:

181

printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));

182

if (GET_MODE (x) == VOIDmode)

183

printf ("GET_MODE (operand%d)", XINT (x, 0));

184

else

185

printf ("%smode", GET_MODE_NAME (GET_MODE (x)));

186

for
(i = 0; i < XVECLEN (x, 1); i++)

187

{

188

printf (",/n/t/t");

189

gen_exp
(XVECEXP (x, 1, i), subroutine_type,
used);

190

}

191

printf (")");

192

return
;

193

194

case
MATCH_OPERATOR:

195

printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));

196

printf (", %smode", GET_MODE_NAME (GET_MODE (x)));

197

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

198

{

199

printf (",/n/t/t");

200

gen_exp
(XVECEXP (x, 2, i), subroutine_type,
used);

201

}

202

printf (")");

203

return
;

204

205

case
MATCH_PARALLEL:

206

case
MATCH_PAR_DUP:

207

printf ("operand%d", XINT (x, 0));

208

return
;

209

210

case
MATCH_SCRATCH:

211

gen_rtx_scratch (x, subroutine_type);

212

return
;

213

214

case
ADDRESS:

215

fatal ("ADDRESS expression code used in named instruction
pattern");

216

217

case
PC:

218

printf ("pc_rtx");

219

return
;

220

221

case
CC0:

222

printf ("cc0_rtx");

223

return
;

224

225

case
CONST_INT:

226

if (INTVAL (x) == 0)

227

printf ("const0_rtx");

228

else if (INTVAL (x) == 1)

229

printf ("const1_rtx");

230

else if (INTVAL (x) == -1)

231

printf ("constm1_rtx");

232

else if (INTVAL (x) == STORE_FLAG_VALUE)

233

printf ("const_true_rtx");

234

else

235

{

236

printf ("GEN_INT (");

237

printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));

238

printf (")");

239

}

240

return
;

241

242

case
CONST_DOUBLE:

243

/* These shouldn't be written in MD files. Instead,
the appropriate

244

routines in varasm.c should be called.
*/

245

abort ();

246

247

default
:

248

break
;

249

}

250

251

printf ("gen_rtx_");

252

print_code (code);

253

printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));

对于我们这里的例子,编码是
SET
,因此我们直接跑到
251
行。因为这个
set
模式没有带
mode
信息,这个
mode
默认的是
VIODmode
。现在我们得到:

rtx

gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,

rtx
operand1 ATTRIBUTE_UNUSED,

rtx
operand2 ATTRIBUTE_UNUSED)

{

return gen_rtx_set (VOIDmode,

对于
set
模式,其
rtl
格式是“
ee
”,因此在
263

gen_exp

递归入其孩子。

gen_exp (continued)

255

fmt = GET_RTX_FORMAT (code);

256

len = GET_RTX_LENGTH (code);

257

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

258

{

259

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

260

break
;

261

printf (",/n/t");

262

if (fmt[i] == 'e' || fmt[i] == 'u')

263

gen_exp
(XEXP
(x, i),
subroutine_type, used);

264

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

265

printf ("%u", XINT (x, i));

266

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

267

printf ("/"%s/"", XSTR (x, i));

268

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

269

{

270

int j;

271

printf ("gen_rtvec
(%d", XVECLEN (x, i));

272

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

273

{

274

printf (",/n/t/t");

275

gen_exp
(XVECEXP (x, i, j), subroutine_type,
used);

276

}

277

printf (")");

278

}

279

else

280

abort ();

281

}

282

printf (")");

283

}

这个
set
模式的第一个孩子是
match_operand

,我们将进入
166
行。注意到
gen_exp

的参数
used


null
,因此我们得到:

rtx

gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,

rtx
operand1 ATTRIBUTE_UNUSED,

rtx
operand2 ATTRIBUTE_UNUSED)

{

return

gen_rtx_set (VOIDmode,

operand0

模式
set
的第二个孩子是
fix

,其
rtl
格式是‘
e
’。再次,我们直接跳到
251
行。并且也将使用
gen_exp

递归其第一个孩子
match_operand

。因此,对于这个
set
模式,我们得到以下代码片段。

rtx

gen_fix_truncsi_1(rtx operand0
ATTRIBUTE_UNUSED,

rtx
operand1 ATTRIBUTE_UNUSED,

rtx
operand2 ATTRIBUTE_UNUSED)

{

return

gen_rtx_SET (VOIDmode,

operand0,

gen_rtx_FIX (SImode,

operand1));

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