PageRenderTime 62ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/builtins.c

https://bitbucket.org/hiyuh/nwcc
C | 2216 lines | 1633 code | 266 blank | 317 comment | 346 complexity | 58d96e63d94bd05dff578e1fe8da1b7b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2005 - 2009, Nils R. Weller
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. * Parsing of, and icode generation for, builtin functions.
  28. * This stuff is mostly kinda ad-hoc and ugly :-(
  29. *
  30. * Maybe parsing and code generation should be separated as this
  31. * file keeps growing.
  32. *
  33. * Implemented builtins:
  34. *
  35. * __builtin_va_start
  36. * __builtin_va_stdarg_start
  37. * __builtin_va_arg
  38. * __builtin_va_next_arg
  39. * __builtin_va_end
  40. * __builtin_memcpy
  41. * __builtin_memset
  42. * __builtin_constant_p
  43. * __builtin_va_expect
  44. * NOTE: This one is just ignored
  45. * __builtin_va_alloca
  46. * NOTE: This one uses malloc()/free() instead of the stack. Also,
  47. * it does not honor block scope, so every allocated block
  48. * is kept until the current function is left
  49. * __builtin_va_copy
  50. * NOTE: No typechecking
  51. */
  52. #include "builtins.h"
  53. #include <string.h>
  54. #include <stdlib.h>
  55. #include "icode.h"
  56. #include "token.h"
  57. #include "error.h"
  58. #include "subexpr.h"
  59. #include "icode.h"
  60. #include "functions.h"
  61. #include "backend.h"
  62. #include "expr.h"
  63. #include "type.h"
  64. #include "symlist.h"
  65. #include "scope.h"
  66. #include "typemap.h"
  67. #include "amd64_gen.h"
  68. #include "token.h"
  69. #include "backend.h"
  70. #include "cc1_main.h"
  71. #include "decl.h"
  72. #include "reg.h"
  73. #include "x87_nonsense.h"
  74. #include "n_libc.h"
  75. struct type *builtin_va_list_type;
  76. /*
  77. * 08/22/07: This stuff was nonsense for va_arg()s first argument, but
  78. * seems to still make some sense for va_start()
  79. */
  80. static char *
  81. get_ident(struct expr *ex) {
  82. struct token *idtok;
  83. if (ex->op != 0) {
  84. return NULL;
  85. }
  86. if (ex->data->meat != NULL) {
  87. idtok = ex->data->meat;
  88. } else if (ex->data->is_expr) {
  89. if (ex->data->is_expr->op != 0) {
  90. return NULL;
  91. } else if (ex->data->is_expr->data->meat != NULL) {
  92. idtok = ex->data->is_expr->data->meat;
  93. } else {
  94. return NULL;
  95. }
  96. } else {
  97. return NULL;
  98. }
  99. return idtok->ascii;
  100. }
  101. static int
  102. builtin_parse_va_start(struct token **tok, struct fcall_data *fdat) {
  103. struct token *t = *tok;
  104. struct decl *dec;
  105. struct expr *ex;
  106. struct sym_entry *se;
  107. char *ident;
  108. int i;
  109. if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  110. return -1;
  111. }
  112. fdat->builtin->args[0] = ex;
  113. fdat->builtin->args[1] = NULL;
  114. if (next_token(&t) != 0) {
  115. return -1;
  116. }
  117. if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
  118. return -1;
  119. }
  120. #if 0
  121. if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
  122. errorfl(t, "Bad second argument to va_start() - "
  123. "Identifier expected");
  124. return -1;
  125. }
  126. #endif
  127. if ((ident = get_ident(ex)) == NULL) {
  128. errorfl(t, "Bad second argument to va_start() - "
  129. "Identifier expected");
  130. return -1;
  131. }
  132. if ((dec = lookup_symbol(curfunc->scope, ident, 0)) == NULL) {
  133. errorfl(t, "Undeclared identifier `%s'", ident);
  134. return -1;
  135. }
  136. for (i = 0, se = curfunc->scope->slist; se != NULL; se = se->next) {
  137. ++i;
  138. if (i == curfunc->proto->dtype->tlist->tfunc->nargs) {
  139. break;
  140. }
  141. }
  142. if (se == NULL || se->dec != dec) {
  143. errorfl(t, "Second argument to va_start() is not %s "
  144. "parameter of `%s'",
  145. se == NULL? "a": "last",
  146. curfunc->proto->dtype->name);
  147. return -1;
  148. }
  149. if (t->type != TOK_PAREN_CLOSE) {
  150. errorfl(t, "Syntax error at `%s'", t->ascii);
  151. return -1;
  152. }
  153. *tok = t;
  154. return 0;
  155. }
  156. static int
  157. builtin_parse_next_arg(struct token **tok, struct fcall_data *fdat) {
  158. struct expr *ex;
  159. struct token *t = *tok;
  160. (void) fdat;
  161. if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
  162. return -1;
  163. }
  164. if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
  165. errorfl(t, "Bad second argument to va_start() - "
  166. "Identifier expected");
  167. return -1;
  168. }
  169. *tok = t;
  170. return 0;
  171. }
  172. static int
  173. builtin_parse_va_end(struct token **tok, struct fcall_data *fdat) {
  174. struct token *t = *tok;
  175. struct expr *ex;
  176. (void) fdat;
  177. if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0 ,1)) == NULL) {
  178. return -1;
  179. }
  180. if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
  181. errorfl(t, "Bad second argument to va_start() - "
  182. "Identifier expected");
  183. return -1;
  184. }
  185. *tok = t;
  186. fdat->builtin->args[0] = ex;
  187. return 0;
  188. }
  189. static int
  190. builtin_parse_va_arg(struct token **tok, struct fcall_data *fdat) {
  191. struct decl **typedec;
  192. struct token *starttok;
  193. struct token *t = *tok;
  194. struct expr *ex;
  195. struct type *type;
  196. if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  197. return -1;
  198. }
  199. fdat->builtin->args[0] = ex;
  200. if (next_token(&t) != 0) {
  201. return -1;
  202. }
  203. starttok = t;
  204. if ((typedec = parse_decl(&t, DECL_CAST)) == NULL) {
  205. return -1;
  206. }
  207. type = typedec[0]->dtype;
  208. free(typedec);
  209. fdat->builtin->args[1] = type;
  210. fdat->builtin->args[2] = NULL;
  211. #if 0
  212. if (is_basic_agg_type(type)) {
  213. unimpl();
  214. }
  215. #endif
  216. *tok = t;
  217. return 0;
  218. }
  219. static int
  220. builtin_parse_expect(struct token **tok, struct fcall_data *fdat) {
  221. struct expr *ex;
  222. struct expr *ex2;
  223. struct token *t = *tok;
  224. struct token *second_start;
  225. if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  226. return -1;
  227. }
  228. /* hmm - gcc warns about first argument of pointer type */
  229. if (next_token(&t) != 0) {
  230. return -1;
  231. }
  232. second_start = t;
  233. if ((ex2 = parse_expr(&t, TOK_PAREN_CLOSE, 0, EXPR_CONST, 1)) == NULL) {
  234. return -1;
  235. }
  236. #if 0
  237. /* const_value is always null!?!??!?!?!?!?!??? :-( :-( :-( */
  238. if (!is_integral_type(ex2->const_value->type)) {
  239. /* hmm - gcc accepts stuff like 0.0f */
  240. errorfl(second_start,
  241. "Second argument of __builtin_expect not integer constant");
  242. return -1;
  243. }
  244. #endif
  245. fdat->builtin->args[0] = ex;
  246. fdat->builtin->args[1] = ex2;
  247. fdat->builtin->type = BUILTIN_EXPECT;
  248. *tok = t;
  249. return 0;
  250. }
  251. static int
  252. generic_builtin_parse_alloca(struct token **tok, struct fcall_data *fdat) {
  253. struct expr *ex;
  254. if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
  255. return -1;
  256. }
  257. fdat->builtin->args[0] = ex;
  258. return 0;
  259. }
  260. static int
  261. generic_builtin_parse_va_copy(struct token **tok, struct fcall_data *fdat) {
  262. struct expr *ex;
  263. struct expr *ex2;
  264. if ((ex = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  265. return -1;
  266. }
  267. if (next_token(tok) != 0) {
  268. return -1;
  269. }
  270. if ((ex2 = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
  271. return -1;
  272. }
  273. fdat->builtin->args[0] = ex;
  274. fdat->builtin->args[1] = ex2;
  275. return 0;
  276. }
  277. static int
  278. generic_builtin_parse_constant_p(struct token **tok, struct fcall_data *fdat) {
  279. struct expr *ex;
  280. if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, EXPR_OPTCONSTSUBEXPR, 1)) == NULL) {
  281. return -1;
  282. }
  283. fdat->builtin->args[0] = ex;
  284. return 0;
  285. }
  286. static int
  287. generic_builtin_parse_memcpy(struct token **tok, struct fcall_data *fdat) {
  288. struct expr *ex;
  289. struct expr *ex2;
  290. struct expr *ex3;
  291. if ((ex = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  292. return -1;
  293. }
  294. if (next_token(tok) != 0) {
  295. return -1;
  296. }
  297. if ((ex2 = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
  298. return -1;
  299. }
  300. if (next_token(tok) != 0) {
  301. return -1;
  302. }
  303. if ((ex3 = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
  304. return -1;
  305. }
  306. fdat->builtin->args[0] = ex;
  307. fdat->builtin->args[1] = ex2;
  308. fdat->builtin->args[2] = ex3;
  309. return 0;
  310. }
  311. static int
  312. generic_builtin_parse_offsetof(struct token **tok, struct fcall_data *fdat) {
  313. struct token *t = *tok;
  314. struct token *starttok = t;
  315. struct type *cur_struct_type;
  316. struct decl **typedec;
  317. unsigned long total_offset;
  318. struct expr *ex;
  319. /*static*/ struct token *tokens;
  320. static struct token *tag_location;
  321. static struct token *cast_location;
  322. struct token *origtokens;
  323. int i;
  324. static int dummy;
  325. int *ip;
  326. int not_constant;
  327. if ((typedec = parse_decl(&t, DECL_FUNCARG)) == NULL) {
  328. return -1;
  329. }
  330. if ((typedec[0]->dtype->code != TY_STRUCT && typedec[0]->dtype->code != TY_UNION)
  331. || typedec[0]->dtype->tlist != NULL) {
  332. errorfl(starttok, "First operand of __builtin_offsetof() "
  333. "is not structure type");
  334. return -1;
  335. }
  336. if (t->type != TOK_OPERATOR
  337. || *(int *)t->data != TOK_OP_COMMA) {
  338. errorfl(t, "Syntax error at `%s'", t->ascii);
  339. return -1;
  340. }
  341. if (next_token(&t) != 0) {
  342. return -1;
  343. }
  344. cur_struct_type = typedec[0]->dtype;
  345. total_offset = 0;
  346. /*
  347. * 07/16/08: Do it thoroughly; Don't just allow a single member
  348. * identifier, but arbitrary expressions.
  349. *
  350. * The operand may contain multiple struct member or array
  351. * subscript operators, so the easiest way is to construct the
  352. * traditional offsetof() implementation as a token list, parse
  353. * and evaluate it!
  354. */
  355. tokens = NULL;
  356. /*
  357. * Construct token list. It would be nice to cache these things, but
  358. * since the expression parsing routiens alter some tokens (cast,
  359. * indirection), it is just safer to start over every time
  360. */
  361. i = TOK_OP_AMB_BAND;
  362. store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
  363. store_token(&tokens, &dummy, TOK_PAREN_OPEN, 0, NULL);
  364. store_token(&tokens, &dummy, TOK_PAREN_OPEN, 0, NULL);
  365. /* & ( ( */
  366. cast_location = tokens->next->next;
  367. if (typedec[0]->dtype->code == TY_STRUCT) {
  368. store_token(&tokens, n_xstrdup("struct"), TOK_KEY_STRUCT, 0, NULL);
  369. } else {
  370. store_token(&tokens, n_xstrdup("union"), TOK_KEY_UNION, 0, NULL);
  371. }
  372. if (typedec[0]->dtype->tstruc->tag != NULL) {
  373. /* A well-behaved struct with tag */
  374. store_token(&tokens, typedec[0]->dtype->tstruc->tag, TOK_IDENTIFIER, 0, NULL);
  375. } else {
  376. /* A sinister anonymous struct type - use dummy tag */
  377. store_token(&tokens, typedec[0]->dtype->tstruc->dummytag, TOK_IDENTIFIER, 0, NULL);
  378. }
  379. /* & ( ( struct tag */
  380. tag_location = tokens->next->next->next->next;
  381. i = TOK_OP_AMB_MULTI;
  382. store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
  383. store_token(&tokens, &dummy, TOK_PAREN_CLOSE, 0, NULL);
  384. i = 0;
  385. ip = n_xmalloc(16); /* XXX */
  386. memcpy(ip, &i, sizeof i);
  387. store_token(&tokens, ip, TY_INT, 0, NULL);
  388. store_token(&tokens, &dummy, TOK_PAREN_CLOSE, 0, NULL);
  389. i = TOK_OP_STRUPMEMB;
  390. store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
  391. /*
  392. * Append member selection to token template
  393. *
  394. * & ( ( struct tag * ) 0 ) ->
  395. */
  396. tokens->next->next->next->next->next->next->next->next->next->next = t;
  397. origtokens = tokens;
  398. ex = parse_expr(&tokens, TOK_PAREN_CLOSE, 0, 0, 1);
  399. if (ex == NULL) {
  400. return -1;
  401. }
  402. if (ex->op != 0) {
  403. errorfl(ex->tok, "Parse error - Binary operator unexpected");
  404. return -1;
  405. }
  406. if (eval_const_expr(ex, EXPR_OPTCONSTSUBEXPR, &not_constant) != -1) {
  407. cross_do_conv(ex->const_value, backend->get_size_t()->code, 1);
  408. total_offset = cross_to_host_size_t(ex->const_value);
  409. }
  410. /*
  411. * Continue where parse_expr() stopped
  412. */
  413. t = tokens;
  414. if (t->type != TOK_PAREN_CLOSE) {
  415. errorfl(t, "Syntax error at `%s' - expected closing parenthesis",
  416. t->ascii);
  417. return -1;
  418. }
  419. *tok = t;
  420. /*fdat->builtin->args[0] = n_xmemdup(&total_offset, sizeof total_offset);*/
  421. fdat->builtin->args[0] = ex;
  422. fdat->builtin->type = BUILTIN_OFFSETOF;
  423. return 0;
  424. }
  425. static int
  426. generic_builtin_parse_frame_address(struct token **tok, struct fcall_data *fdat) {
  427. struct expr *ex;
  428. struct token *t = *tok;
  429. size_t frameno;
  430. if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, EXPR_CONST, 1)) == NULL) {
  431. return -1;
  432. }
  433. if (ex->const_value == NULL) {
  434. errorfl(t, "Argument to __builtin_frame_address() not "
  435. "constant");
  436. return -1;
  437. }
  438. if (!is_integral_type(ex->const_value->type)) {
  439. errorfl(t, "Argument to __builtin_frame_address() not "
  440. "integral");
  441. return -1;
  442. }
  443. cross_do_conv(ex->const_value, TY_INT, 1);
  444. frameno = cross_to_host_size_t(ex->const_value); /* XXXX CROSS??? */
  445. if (frameno > 0) {
  446. errorfl(t, "__builtin_frame_address() currently only "
  447. "works with the current stack frame (argument 0)!");
  448. return -1;
  449. }
  450. fdat->builtin->args[0] = n_xmemdup(&frameno, sizeof frameno);
  451. return 0;
  452. }
  453. static struct vreg *
  454. generic_builtin_constant_p_to_icode(struct fcall_data *fdat,
  455. struct icode_list *il, int eval) {
  456. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  457. struct expr *ex = fdat->builtin->args[0];
  458. int val;
  459. struct token *tok;
  460. val = ex->const_value != NULL; /*ex->is_const;*/
  461. tok = const_from_value(&val, NULL);
  462. vr = vreg_alloc(NULL, tok, NULL, NULL);
  463. return vr;
  464. }
  465. static struct vreg *
  466. generic_builtin_va_copy_to_icode(struct fcall_data *fdat,
  467. struct icode_list *il, int eval) {
  468. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  469. struct vreg *arg0;
  470. struct vreg *arg1;
  471. struct vreg *tmpvr;
  472. struct expr *ex0 = fdat->builtin->args[0];
  473. struct expr *ex1 = fdat->builtin->args[1];
  474. struct icode_instr *ii;
  475. struct token *tok;
  476. int size;
  477. int va_list_is_array = 0;
  478. arg0 = expr_to_icode(ex0, NULL, il, 0, 0, eval);
  479. if (arg0 == NULL) {
  480. return NULL;
  481. }
  482. arg1 = expr_to_icode(ex1, NULL, il, 0, 0, eval);
  483. if (arg1 == NULL) {
  484. return NULL;
  485. }
  486. if (!eval) {
  487. /* XXX Could not hurt to type-check the operand results?!?!? */
  488. vreg_set_new_type(vr, make_basic_type(TY_VOID));
  489. return vr;
  490. }
  491. /*
  492. * XXX this is just a quick kludge... we will later want to do
  493. * full type-checking! Ideally use unary_to_icode() from
  494. * subexpr.c for this to determine whether the address can be
  495. * taken
  496. */
  497. size = backend->get_sizeof_type(arg0->type, NULL);
  498. if (backend->arch == ARCH_AMD64) {
  499. /*
  500. * XXX use backend->va_list_is_sysv_like?!?!
  501. * This must be done on Linux/PPC too
  502. */
  503. va_list_is_array = 1;
  504. vreg_faultin(NULL, NULL, arg0, il, 0);
  505. size = 24; /* XXX because the source really is an array! */
  506. } else {
  507. ii = icode_make_addrof(NULL, arg0, il);
  508. append_icode_list(il, ii);
  509. arg0 = vreg_disconnect(arg0);
  510. arg0->type = addrofify_type(arg0->type);
  511. arg0->size = backend->get_sizeof_type(arg0->type, NULL);
  512. vreg_map_preg(arg0, ii->dat);
  513. }
  514. reg_set_unallocatable(arg0->pregs[0]);
  515. if (!va_list_is_array) {
  516. ii = icode_make_addrof(NULL, arg1, il);
  517. append_icode_list(il, ii);
  518. arg1 = vreg_disconnect(arg1);
  519. arg1->type = addrofify_type(arg1->type);
  520. arg1->size = backend->get_sizeof_type(arg1->type, NULL);
  521. vreg_map_preg(arg1, ii->dat);
  522. } else {
  523. vreg_faultin(NULL, NULL, arg1, il, 0);
  524. }
  525. reg_set_unallocatable(arg1->pregs[0]);
  526. tok = const_from_value(&size, make_basic_type(TY_INT));
  527. tmpvr = vreg_alloc(NULL, tok, NULL, make_basic_type(TY_INT));
  528. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  529. reg_set_allocatable(arg0->pregs[0]);
  530. reg_set_allocatable(arg1->pregs[0]);
  531. icode_make_intrinsic_memcpy_or_memset(BUILTIN_MEMCPY,
  532. arg0, arg1, tmpvr, 0, il);
  533. #if 0
  534. vr->type = make_basic_type(TY_VOID);
  535. #endif
  536. /*
  537. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  538. * assignments. Size assignment was missing
  539. */
  540. vreg_set_new_type(vr, make_basic_type(TY_VOID));
  541. return vr;
  542. }
  543. static struct vreg *
  544. generic_builtin_memcpy_or_memset_to_icode(struct fcall_data *fdat,
  545. struct icode_list *il, int eval) {
  546. struct vreg *resvr = vreg_alloc(NULL, NULL, NULL, NULL);
  547. struct vreg *arg0;
  548. struct vreg *arg1;
  549. struct vreg *arg2;
  550. struct expr *ex0 = fdat->builtin->args[0];
  551. struct expr *ex1 = fdat->builtin->args[1];
  552. struct expr *ex2 = fdat->builtin->args[2];
  553. char *funcname = fdat->builtin->type == BUILTIN_MEMCPY?
  554. "memcpy": "memset";
  555. resvr->type = n_xmemdup(make_basic_type(TY_VOID), sizeof(struct type));
  556. append_typelist(resvr->type, TN_POINTER_TO, 0, NULL, NULL);
  557. resvr->size = backend->get_sizeof_type(resvr->type, NULL);
  558. arg0 = expr_to_icode(ex0, NULL, il, 0, 0, eval);
  559. if (arg0 == NULL) {
  560. return NULL;
  561. }
  562. if (arg0->type->tlist == NULL) {
  563. errorfl(ex0->tok, "First argument to __builtin_%s "
  564. "must be pointer", funcname);
  565. return NULL;
  566. }
  567. /*
  568. * Now save target address to stack (this is the return value
  569. * of __builtin_memcpy() and memcpy() generally.)
  570. */
  571. if (eval) {
  572. vreg_faultin(NULL, NULL, arg0, il, 0);
  573. vreg_map_preg(resvr, arg0->pregs[0]);
  574. free_preg(resvr->pregs[0], il, 0, 1); /* save, but don't invalidate */
  575. vreg_map_preg(arg0, resvr->pregs[0]);
  576. }
  577. arg1 = expr_to_icode(ex1, NULL, il, 0, 0, eval);
  578. if (arg1 == NULL) {
  579. return NULL;
  580. }
  581. /*
  582. * 03/26/08: Hmm, the faultin was missing, it only showed up
  583. * when dec->vreg was removed. We should recheck the guarantees
  584. * that expr_to_icode() gives us, apparently register residence
  585. * is not included. This makes sense too!
  586. */
  587. if (eval) {
  588. vreg_faultin(NULL, NULL, arg1, il, 0);
  589. }
  590. if (fdat->builtin->type == BUILTIN_MEMCPY) {
  591. if (arg1->type->tlist == NULL) {
  592. errorfl(ex1->tok, "Second argument to __builtin_%s "
  593. "must be pointer", funcname);
  594. return NULL;
  595. }
  596. } else {
  597. /* memset */
  598. if (!is_integral_type(arg1->type)) {
  599. errorfl(ex1->tok, "Second argument to __builtin_%s ",
  600. "must be integral", funcname);
  601. }
  602. if (eval) {
  603. arg1 = backend->icode_make_cast(arg1,
  604. make_basic_type(TY_UCHAR), il);
  605. }
  606. }
  607. arg2 = expr_to_icode(ex2, NULL, il, 0, 0, eval);
  608. if (arg2 == NULL) {
  609. return NULL;
  610. }
  611. /* 03/26/08: Faultin missing, see above */
  612. if (eval) {
  613. vreg_faultin(NULL, NULL, arg2, il, 0);
  614. }
  615. if (!is_integral_type(arg2->type)) {
  616. errorfl(ex2->tok, "Third argument to __builtin_%s "
  617. "must be integral type", funcname);
  618. return NULL;
  619. }
  620. if (eval) {
  621. icode_make_intrinsic_memcpy_or_memset(fdat->builtin->type,
  622. arg0, arg1, arg2, 0, il);
  623. }
  624. return resvr;
  625. }
  626. static struct vreg *
  627. generic_builtin_alloca_to_icode(struct fcall_data *fdat,
  628. struct icode_list *il, int eval) {
  629. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  630. struct vreg *size_vr;
  631. struct type *ty;
  632. struct stack_block *sb;
  633. struct reg *r;
  634. struct expr *ex = fdat->builtin->args[0];
  635. size_vr = expr_to_icode(ex, NULL, il, 0, 0, eval);
  636. if (size_vr == NULL) {
  637. return NULL;
  638. }
  639. if (!is_integral_type(size_vr->type)) {
  640. errorfl(ex->tok, "Argument not of integral type");
  641. return NULL;
  642. }
  643. /* Result type is ``void *'' */
  644. ty = n_xmemdup(make_basic_type(TY_VOID), sizeof *ty);
  645. append_typelist(ty, TN_POINTER_TO, 0, NULL, NULL);
  646. vr->type = ty;
  647. vr->size = backend->get_sizeof_type(ty, NULL);
  648. if (!eval) {
  649. return vr;
  650. }
  651. /*
  652. * Now allocate a stack block in which to store the returned
  653. * pointer, so that we can free it upon return from the function.
  654. * As usual the offset is patched in gen_function()
  655. */
  656. sb = make_stack_block(0, vr->size);
  657. if (curfunc->alloca_head == NULL) {
  658. curfunc->alloca_head = curfunc->alloca_tail = sb;
  659. } else {
  660. curfunc->alloca_tail->next = sb;
  661. curfunc->alloca_tail = sb;
  662. }
  663. /* Get register to store result pointer */
  664. vreg_set_unallocatable(size_vr);
  665. /*
  666. * 11/12/07: ALLOC_GPR() is wrong here! We have to use the ABI's
  667. * malloc() return address register. This stuff is kludgedx XXX
  668. * XXXXXXXXXXXXXX
  669. */
  670. r = backend->get_abi_ret_reg(make_void_ptr_type());
  671. free_preg(r, il, 1, 1);
  672. #if 0
  673. r = ALLOC_GPR(curfunc, vr->size, il, 0);
  674. #endif
  675. icode_make_alloca(r, size_vr, sb, il);
  676. vreg_map_preg(vr, r);
  677. return vr;
  678. }
  679. static struct vreg *
  680. generic_builtin_offsetof_to_icode(struct fcall_data *fdat,
  681. struct icode_list *il, int eval) {
  682. struct vreg *vr;
  683. long val; /* XXX because const_from_type() is broken */
  684. struct token *tok;
  685. struct expr *ex = fdat->builtin->args[0];
  686. int not_constant = 0;
  687. if (eval) {
  688. if (ex->const_value != NULL) {
  689. val = cross_to_host_size_t(ex->const_value);
  690. } else {
  691. val = 0;
  692. not_constant = 1;
  693. }
  694. } else {
  695. val = 0;
  696. }
  697. if (not_constant) {
  698. vr = expr_to_icode(ex, NULL, il, 0, 0, eval);
  699. vr = backend->icode_make_cast(vr, backend->get_size_t(), il);
  700. } else {
  701. tok = alloc_token();
  702. tok->data = n_xmalloc(16); /* XXX */
  703. tok->type = backend->get_size_t()->code;
  704. cross_from_host_long(tok->data, val, tok->type);
  705. vr = vreg_alloc(NULL, tok, NULL, NULL);
  706. }
  707. return vr;
  708. }
  709. static struct vreg *
  710. generic_builtin_frame_address_to_icode(struct fcall_data *fdat,
  711. struct icode_list *il, int eval) {
  712. struct vreg *vr = vreg_alloc(NULL,NULL,NULL,NULL);
  713. struct type *ty;
  714. struct reg *r;
  715. struct reg *r2;
  716. ty = n_xmemdup(make_basic_type(TY_VOID), sizeof *ty);
  717. append_typelist(ty, TN_POINTER_TO, 0, NULL, NULL);
  718. vreg_set_new_type(vr, ty);
  719. if (!eval) {
  720. return vr;
  721. }
  722. /*
  723. * Allocate two GPRs to make walking up the stack possible
  724. */
  725. r = ALLOC_GPR(curfunc, vr->size, il, NULL);
  726. r2 = ALLOC_GPR(curfunc, vr->size, il, NULL);
  727. icode_make_builtin_frame_address(r, r2, fdat->builtin->args[0], il);
  728. free_preg(r2, il, 1, 0);
  729. vreg_map_preg(vr, r);
  730. return vr;
  731. }
  732. static struct vreg *
  733. x86_builtin_va_start_to_icode(
  734. struct fcall_data *fdat,
  735. struct icode_list *il,
  736. int eval) {
  737. struct type *ty;
  738. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  739. struct vreg *valist_vr;
  740. struct icode_instr *ii;
  741. if (eval) {
  742. ii = icode_make_addrof(NULL, NULL, il);
  743. append_icode_list(il, ii);
  744. }
  745. valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
  746. if (valist_vr == NULL) {
  747. return NULL;
  748. }
  749. if (eval) {
  750. vreg_map_preg(valist_vr, ii->dat);
  751. icode_make_store(curfunc, valist_vr, valist_vr, il);
  752. free_preg(valist_vr->pregs[0], il, 0, 0);
  753. }
  754. ty = make_basic_type(TY_VOID);
  755. vr->type = ty;
  756. vr->size = 0;
  757. return vr;
  758. }
  759. static struct vreg *
  760. x86_builtin_next_arg_to_icode(
  761. struct fcall_data *fdat,
  762. struct icode_list *il,
  763. int eval) {
  764. struct type *ty;
  765. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  766. struct icode_instr *ii;
  767. (void) fdat;
  768. if (eval) {
  769. ii = icode_make_addrof(NULL, NULL, il);
  770. append_icode_list(il, ii);
  771. vreg_map_preg(vr, ii->dat);
  772. }
  773. ty = n_xmemdup(make_basic_type(TY_CHAR), sizeof *ty);
  774. ty->tlist = alloc_type_node();
  775. ty->tlist->type = TN_POINTER_TO;
  776. vr->type = ty;
  777. vr->size = backend->get_sizeof_type(ty, NULL);
  778. return vr;
  779. }
  780. static struct vreg *
  781. x86_builtin_va_end_to_icode(
  782. struct fcall_data *fdat,
  783. struct icode_list *il,
  784. int eval) {
  785. struct type *ty;
  786. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  787. /*
  788. * 07/21/08: This was not actually evaluating the operand to va_end()!
  789. * But that's needed because it may contain side effects
  790. */
  791. if (expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval) == NULL) {
  792. return NULL;
  793. }
  794. /* XXX type-checking for argument to va_end()!!!!!!!! */
  795. ty = make_basic_type(TY_VOID);
  796. vr->type = ty;
  797. vr->size = 0;
  798. return vr;
  799. }
  800. static struct vreg *
  801. x86_builtin_va_arg_to_icode(
  802. struct fcall_data *fdat,
  803. struct icode_list *il,
  804. int eval) {
  805. struct vreg *valist_vr;
  806. struct vreg *vr;
  807. struct type *argtype = fdat->builtin->args[1];
  808. int size;
  809. int intsize;
  810. int rightadjust = 0;
  811. /*
  812. * 08/22/07: Wow, this stuff used get_ident() and did not
  813. * generate icode for the first argument at all! Thus
  814. *
  815. * va_list *foo;
  816. * va_arg(*foo, type);
  817. *
  818. * ... didn't work because *foo was not loaded
  819. */
  820. valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
  821. if (valist_vr == NULL) {
  822. return NULL;
  823. } /* else {
  824. check type...
  825. } */
  826. if (eval) {
  827. vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
  828. }
  829. intsize = backend->get_sizeof_type(
  830. make_basic_type(backend->arch == ARCH_X86? TY_INT: TY_LONG),
  831. NULL);
  832. if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
  833. && argtype->tlist == NULL) {
  834. /* Struct/union passed by value */
  835. vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
  836. vr->type = fdat->builtin->args[1];
  837. vr->size = size = backend->get_sizeof_type(vr->type, NULL);
  838. if (fdat->lvalue != NULL) {
  839. /* Result is assigned - copy */
  840. if (eval) {
  841. /*
  842. * 07/21/08: invalidate_gprs() was missing
  843. * since copystruct will probably call memcpy()!
  844. */
  845. backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
  846. vreg_faultin_ptr(/*valist->vreg*/ valist_vr, il);
  847. vreg_faultin_ptr(fdat->lvalue, il);
  848. icode_make_copystruct(fdat->lvalue, vr, il);
  849. /*
  850. * 07/21/08: Invalidate va_list vreg for
  851. * offset addition below... Since memcpy
  852. * may have trashed it
  853. */
  854. free_preg(valist_vr->pregs[0], il, 1, 0);
  855. }
  856. vr->struct_ret = 1;
  857. }
  858. } else {
  859. /* XXX from_ptr?? check for indirection chain!!??! */
  860. vr = vreg_alloc(NULL, NULL, /*valist->vreg*/ valist_vr, NULL);
  861. /*
  862. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  863. * assignments (is_multi_reg_obj was not set!)
  864. */
  865. vreg_set_new_type(vr, fdat->builtin->args[1]);
  866. size = vr->size;
  867. if (eval) {
  868. if (size < intsize
  869. && backend->arch == ARCH_POWER
  870. && backend->abi == ABI_POWER64) {
  871. /*
  872. * Right adjust small argument - Only
  873. * for PPC for now
  874. */
  875. rightadjust = calc_slot_rightadjust_bytes(size, intsize);
  876. if (rightadjust != 0) {
  877. add_const_to_vreg(valist_vr, rightadjust, il);
  878. }
  879. }
  880. if (is_x87_trash(vr)) {
  881. vr = x87_anonymify(vr, il);
  882. } else {
  883. vreg_faultin(NULL, NULL, vr, il, 0);
  884. vreg_anonymify(&vr, NULL, NULL, il);
  885. }
  886. }
  887. }
  888. if (!eval) {
  889. return vr;
  890. }
  891. if (size < intsize) {
  892. size = intsize;
  893. } else if (vr->type->code == TY_LDOUBLE) {
  894. if (backend->arch == ARCH_X86) {
  895. if (sysflag == OS_OSX) {
  896. #if 0
  897. size += 6;
  898. #endif
  899. } else {
  900. #if 0
  901. size += 2;
  902. #endif
  903. }
  904. } else if (backend->arch == ARCH_AMD64) {
  905. ; /* ... */
  906. } else if (backend->arch == ARCH_POWER) {
  907. #if _AIX
  908. #else
  909. /* size += 8;*/
  910. #endif
  911. }
  912. }
  913. /* 07/21/08: Align to multiple of 4
  914. * XXXX What to do with SPARC and PPC?
  915. */
  916. if ((vr->type->code == TY_STRUCT || vr->type->code == TY_UNION)
  917. && vr->type->tlist == NULL) {
  918. if (size & 3) {
  919. size += 4 - (size & 3);
  920. }
  921. }
  922. /*
  923. * 11/25/08: If the item was right-adjusted for a dword slot, we have
  924. * to take that into account
  925. */
  926. if (rightadjust != 0) {
  927. size -= rightadjust;
  928. }
  929. add_const_to_vreg(valist_vr, size, il);
  930. #if 0
  931. c = const_from_value(&size, NULL);
  932. tmpvr = vreg_alloc(NULL, c, NULL, NULL);
  933. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  934. vreg_faultin_protected(tmpvr, NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
  935. ii = icode_make_add( /*valist->vreg*/valist_vr, tmpvr);
  936. append_icode_list(il, ii);
  937. icode_make_store(curfunc, /*valist->vreg*/valist_vr,
  938. /*valist->vreg*/valist_vr, il);
  939. #endif
  940. return vr;
  941. }
  942. static struct builtin builtins[] = {
  943. { "va_start", sizeof "va_start" - 1, BUILTIN_VA_START,
  944. builtin_parse_va_start, /*x86_builtin_va_start_to_icode*/0 },
  945. /* va_start and stdarg_start are equivalent */
  946. { "stdarg_start", sizeof "stdarg_start" - 1, BUILTIN_STDARG_START,
  947. builtin_parse_va_start, x86_builtin_va_start_to_icode },
  948. { "next_arg", sizeof "next_arg" - 1, BUILTIN_NEXT_ARG,
  949. builtin_parse_next_arg, x86_builtin_next_arg_to_icode },
  950. { "va_end", sizeof "va_end" - 1, BUILTIN_VA_END,
  951. builtin_parse_va_end, x86_builtin_va_end_to_icode },
  952. { "va_arg", sizeof "va_arg" - 1, BUILTIN_VA_ARG,
  953. builtin_parse_va_arg, x86_builtin_va_arg_to_icode },
  954. { "expect", sizeof "expect" - 1, BUILTIN_EXPECT,
  955. builtin_parse_expect, NULL },
  956. { "alloca", sizeof "alloca" - 1, BUILTIN_ALLOCA,
  957. generic_builtin_parse_alloca, generic_builtin_alloca_to_icode },
  958. { "va_copy", sizeof "va_copy" - 1, BUILTIN_VA_COPY,
  959. generic_builtin_parse_va_copy, generic_builtin_va_copy_to_icode },
  960. { "constant_p", sizeof "constant_p" - 1, BUILTIN_CONSTANT_P,
  961. generic_builtin_parse_constant_p, generic_builtin_constant_p_to_icode },
  962. { "memcpy", sizeof "memcpy" - 1, BUILTIN_MEMCPY,
  963. generic_builtin_parse_memcpy, generic_builtin_memcpy_or_memset_to_icode },
  964. { "memset", sizeof "memset" - 1, BUILTIN_MEMSET,
  965. generic_builtin_parse_memcpy, generic_builtin_memcpy_or_memset_to_icode },
  966. { "frame_address", sizeof "frame_address" - 1, BUILTIN_FRAME_ADDRESS,
  967. generic_builtin_parse_frame_address,
  968. generic_builtin_frame_address_to_icode },
  969. { "offsetof", sizeof "offsetof" - 1, BUILTIN_OFFSETOF,
  970. generic_builtin_parse_offsetof,
  971. generic_builtin_offsetof_to_icode },
  972. { "prefetch", sizeof "offsetof" - 1, 0, NULL, NULL },
  973. { NULL, 0, 0, NULL, NULL }
  974. };
  975. static struct vreg *
  976. mips_builtin_next_arg_to_icode(
  977. struct fcall_data *fdat,
  978. struct icode_list *il,
  979. int eval) {
  980. (void) fdat; (void) il; (void) eval;
  981. unimpl();
  982. return NULL;
  983. }
  984. /*
  985. * XXXXXXXXXX misses struct/union arguments!
  986. */
  987. static struct vreg *
  988. mips_builtin_va_arg_to_icode(
  989. struct fcall_data *fdat,
  990. struct icode_list *il,
  991. int eval) {
  992. struct vreg *valist_vr;
  993. struct vreg *vr;
  994. struct vreg *tmpvr;
  995. struct token *c;
  996. struct type *argtype = fdat->builtin->args[1];
  997. struct icode_instr *ii;
  998. int size;
  999. int intsize;
  1000. /*
  1001. * 08/22/07: Wow, this stuff used get_ident() and did not
  1002. * generate icode for the first argument at all! Thus
  1003. *
  1004. * va_list *foo;
  1005. * va_arg(*foo, type);
  1006. *
  1007. * ... didn't work because *foo was not loaded
  1008. */
  1009. valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
  1010. if (valist_vr == NULL) {
  1011. return NULL;
  1012. } /* else {
  1013. check type...
  1014. } */
  1015. if (eval) {
  1016. vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
  1017. if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
  1018. && argtype->tlist == NULL) {
  1019. unimpl();
  1020. }
  1021. }
  1022. /* XXX from_ptr?? check for indirection chain!!??! */
  1023. vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
  1024. #if 0
  1025. vr->type = fdat->builtin->args[1];
  1026. vr->size = size = backend->get_sizeof_type(vr->type, NULL);
  1027. #endif
  1028. /*
  1029. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  1030. * assignments (is_multi_reg_obj was not set!)
  1031. */
  1032. vreg_set_new_type(vr, fdat->builtin->args[1]);
  1033. size = vr->size;
  1034. if (!eval) {
  1035. return vr;
  1036. }
  1037. #if 0
  1038. vreg_faultin(NULL, NULL, vr, il, 0);
  1039. #endif
  1040. if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
  1041. && argtype->tlist == NULL) {
  1042. /* Struct/union passed by value */
  1043. #if 0
  1044. vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
  1045. vr->type = fdat->builtin->args[1];
  1046. vr->size = size = backend->get_sizeof_type(vr->type, NULL);
  1047. #endif
  1048. if (fdat->lvalue != NULL) {
  1049. /* Result is assigned - copy */
  1050. vreg_faultin_ptr(/*valist->vreg*/valist_vr, il);
  1051. vreg_faultin_ptr(fdat->lvalue, il);
  1052. /*
  1053. * 07/21/08: invalidate_gprs() was missing
  1054. * since copystruct will probably call memcpy()!
  1055. */
  1056. backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
  1057. icode_make_copystruct(fdat->lvalue, vr, il);
  1058. /*
  1059. * 07/21/08: Invalidate va_list vreg for
  1060. * offset addition below... Since memcpy
  1061. * may have trashed it
  1062. */
  1063. free_preg(valist_vr->pregs[0], il, 1, 0);
  1064. vr->struct_ret = 1;
  1065. }
  1066. } else {
  1067. /*
  1068. * Small arguments are passed as dwords.
  1069. * XXX take fp into account!!
  1070. * ... so let us load the dword, then just treat it as
  1071. * the destination type
  1072. */
  1073. tmpvr = n_xmemdup(vr, sizeof *vr);
  1074. if (!is_floating_type(vr->type)) {
  1075. tmpvr->type = make_basic_type(TY_ULLONG);
  1076. tmpvr->size = 8;
  1077. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  1078. vreg_map_preg(vr, tmpvr->pregs[0]);
  1079. vreg_anonymify(&vr, NULL, NULL, il);
  1080. } else {
  1081. tmpvr->type = make_basic_type(TY_DOUBLE);
  1082. tmpvr->size = 8;
  1083. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  1084. vreg_map_preg(vr, tmpvr->pregs[0]);
  1085. vreg_anonymify(&vr, NULL, NULL, il);
  1086. }
  1087. }
  1088. intsize = backend->
  1089. get_sizeof_type(make_basic_type(TY_INT), NULL);
  1090. if (size < intsize) {
  1091. size = intsize;
  1092. }
  1093. if (size < 8) {
  1094. /* Even small types are stored as dwords */
  1095. size = 8;
  1096. } else {
  1097. /* 07/21/08: XXX handle struct alignment! */
  1098. }
  1099. c = const_from_value(&size, NULL);
  1100. tmpvr = vreg_alloc(NULL, c, NULL, NULL);
  1101. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  1102. vreg_faultin_protected(tmpvr, NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
  1103. ii = icode_make_add(/*valist->vreg*/valist_vr, tmpvr);
  1104. append_icode_list(il, ii);
  1105. icode_make_store(curfunc, /*valist->vreg*/valist_vr,
  1106. /*valist->vreg*/valist_vr, il);
  1107. return vr;
  1108. }
  1109. static void
  1110. get_member_vreg(struct decl *d, struct vreg **dest, struct vreg *parent) {
  1111. struct vreg *vr;
  1112. vr = vreg_alloc(NULL, NULL, NULL, d->dtype);
  1113. vr->parent = parent;
  1114. vr->memberdecl = d;
  1115. vr->from_ptr = parent;
  1116. *dest = vr;
  1117. }
  1118. static struct type *voidptr_type;
  1119. static int
  1120. calc_fp_start_offset(struct function *f) {
  1121. struct sym_entry *se;
  1122. int fp_regs_used = 0;
  1123. for (se = f->scope->slist; se != NULL; se = se->next) {
  1124. if (is_floating_type(se->dec->dtype)
  1125. && se->dec->dtype->code != TY_LDOUBLE) {
  1126. ++fp_regs_used;
  1127. if (fp_regs_used == 8) {
  1128. break;
  1129. }
  1130. }
  1131. if (se->dec == f->proto->dtype->tlist->tfunc->lastarg) {
  1132. break;
  1133. }
  1134. }
  1135. return 48 + fp_regs_used * 8;
  1136. }
  1137. /*
  1138. * typedef struct {
  1139. * unsigned gp_offset;
  1140. * unsigned fp_offset;
  1141. * void *overflow_arg_area;
  1142. * void *reg_save_area;
  1143. * } va_list[1];
  1144. *
  1145. * - reg_save_area is recorded by fty->lastarg if some variadic args are
  1146. * passed in registers
  1147. * - if all variadic stuff is passed on the stack, lastarg points to the
  1148. * beginning of the stack arguments
  1149. * - if registers are used for arguments, fty->lastarg->stack_addr->from_reg
  1150. * is non-null, and
  1151. * (struct reg **)fty->lastarg->stack_addr->from_reg - amd64_argregs
  1152. * is the number of gprs used, which, multiplied by 8, gives the gp_offset.
  1153. * - XXX fp is UNIMPLEMENTED
  1154. * phew ..
  1155. */
  1156. static struct vreg *
  1157. amd64_builtin_va_start_to_icode(
  1158. struct fcall_data *fdat,
  1159. struct icode_list *il,
  1160. int eval) {
  1161. struct type *ty;
  1162. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  1163. struct vreg *valist_vr;
  1164. struct sym_entry *se;
  1165. struct icode_instr *ii;
  1166. struct ty_func *fty;
  1167. struct reg *r;
  1168. struct decl *srcdec;
  1169. struct vreg *srcvr;
  1170. struct vreg *tempvr;
  1171. struct amd64_va_patches *patches;
  1172. static struct amd64_va_patches nullp;
  1173. int fp_start_offset;
  1174. if (eval) {
  1175. patches = n_xmalloc(sizeof *patches);
  1176. *patches = nullp;
  1177. /* curfunc->patchme = patches;*/
  1178. /*
  1179. * 08/07/08: Allow for multiple va_start() per function
  1180. * (oops)
  1181. */
  1182. patches->next = curfunc->patchme;
  1183. curfunc->patchme = patches;
  1184. }
  1185. fty = curfunc->fty;
  1186. valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
  1187. if (valist_vr == NULL) {
  1188. return NULL;
  1189. }
  1190. if (eval) {
  1191. vreg_faultin(NULL, NULL, valist_vr, il, 0);
  1192. }
  1193. if (valist_vr->type->tlist == NULL
  1194. || valist_vr->type->tlist->type != TN_POINTER_TO
  1195. || valist_vr->type->tlist->next != NULL
  1196. || valist_vr->type->code != TY_STRUCT
  1197. || valist_vr->type->tstruc != builtin_va_list_type->tstruc) {
  1198. errorfl(NULL /* XXX */, "Argument to va_start() has wrong "
  1199. "type");
  1200. return NULL;
  1201. }
  1202. if (!eval) {
  1203. ty = make_basic_type(TY_VOID);
  1204. vreg_set_new_type(vr, ty);
  1205. return vr;
  1206. }
  1207. r = ALLOC_GPR(curfunc, 0, il, 0);
  1208. se = valist_vr->type->tstruc->scope->slist;
  1209. /* se = gp_offset */
  1210. get_member_vreg(se->dec, &tempvr, valist_vr);
  1211. ii = icode_make_setreg(r->composed_of[0], /*n*/0);
  1212. append_icode_list(il, ii);
  1213. patches->gp_offset = ii->dat;
  1214. vreg_map_preg(tempvr, r->composed_of[0]);
  1215. icode_make_store(curfunc, tempvr, tempvr, il);
  1216. se = se->next;
  1217. /* se = fp_offset */
  1218. get_member_vreg(se->dec, &tempvr, valist_vr);
  1219. /*
  1220. * 07/31/08: Don't always begin at 48 (%xmm0), but also take non-
  1221. * elliptic parameters into account, e.g. for
  1222. *
  1223. * void foo(double d, ...)
  1224. *
  1225. * ... set t the start offset to 48 + 1*8
  1226. */
  1227. fp_start_offset = calc_fp_start_offset(curfunc);
  1228. ii = icode_make_setreg(r->composed_of[0], /*48*/ fp_start_offset); /* begins after gprs */
  1229. append_icode_list(il, ii);
  1230. patches->fp_offset = ii->dat;
  1231. vreg_map_preg(tempvr, r->composed_of[0]);
  1232. icode_make_store(curfunc, tempvr, tempvr, il);
  1233. se = se->next;
  1234. /* se = overflow_arg_area; */
  1235. get_member_vreg(se->dec, &tempvr, valist_vr);
  1236. srcdec = alloc_decl();
  1237. /* XXX typing stuff is totally bogus?! untyped addres suffices?? */
  1238. srcdec->dtype = voidptr_type;
  1239. srcdec->stack_addr = make_stack_block(0, 8);
  1240. patches->overflow_arg_area = srcdec->stack_addr;
  1241. srcvr = vreg_alloc(srcdec, NULL, NULL, NULL);
  1242. ii = icode_make_addrof(NULL, srcvr, il);
  1243. append_icode_list(il, ii);
  1244. vreg_map_preg(srcvr, ii->dat);
  1245. icode_make_store(curfunc, srcvr, tempvr, il);
  1246. free_preg(ii->dat, il, 0, 0);
  1247. se = se->next;
  1248. /* se = reg_save_area */
  1249. get_member_vreg(se->dec, &tempvr, valist_vr);
  1250. srcdec = alloc_decl();
  1251. srcdec->dtype = voidptr_type;
  1252. srcdec->stack_addr = make_stack_block(0, 8);
  1253. patches->reg_save_area = srcdec->stack_addr;
  1254. srcvr = vreg_alloc(srcdec, NULL, NULL, NULL);
  1255. ii = icode_make_addrof(NULL, srcvr, il);
  1256. append_icode_list(il, ii);
  1257. vreg_map_preg(srcvr, ii->dat);
  1258. icode_make_store(curfunc, srcvr, tempvr, il);
  1259. free_preg(ii->dat, il, 0, 0);
  1260. #if 0
  1261. se->dec->stack_addr = make_stack_block(0, 8);
  1262. patches->reg_save_area = se->dec->stack_addr;
  1263. #endif
  1264. ty = make_basic_type(TY_VOID);
  1265. #if 0
  1266. vr->type = ty;
  1267. vr->size = 0;
  1268. #endif
  1269. /* 06/20/08: Use vreg_set_new_type() instead of ad-hoc assignments */
  1270. vreg_set_new_type(vr, ty);
  1271. free_preg(r, il, 0, 0);
  1272. return vr;
  1273. }
  1274. static struct vreg *
  1275. amd64_builtin_next_arg_to_icode(
  1276. struct fcall_data *fdat,
  1277. struct icode_list *il,
  1278. int eval) {
  1279. struct type *ty;
  1280. struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
  1281. struct icode_instr *ii;
  1282. (void) fdat;
  1283. if (eval) {
  1284. ii = icode_make_addrof(NULL, NULL, il);
  1285. append_icode_list(il, ii);
  1286. vreg_map_preg(vr, ii->dat);
  1287. }
  1288. ty = n_xmemdup(make_basic_type(TY_CHAR), sizeof *ty);
  1289. ty->tlist = alloc_type_node();
  1290. ty->tlist->type = TN_POINTER_TO;
  1291. #if 0
  1292. vr->type = ty;
  1293. vr->size = backend->get_sizeof_type(ty, NULL);
  1294. #endif
  1295. /*
  1296. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  1297. * assignments
  1298. */
  1299. vreg_set_new_type(vr, ty);
  1300. return vr;
  1301. }
  1302. static struct vreg *
  1303. amd64_builtin_va_arg_to_icode(
  1304. struct fcall_data *fdat,
  1305. struct icode_list *il,
  1306. int eval) {
  1307. struct vreg *valist_vr;
  1308. struct vreg *vr;
  1309. struct vreg *tmpvr;
  1310. struct vreg *tempmembvr;
  1311. struct vreg *pointer;
  1312. struct vreg *limit_vreg;
  1313. struct vreg *offset_vreg = NULL;
  1314. struct token *c;
  1315. struct icode_instr *ii;
  1316. struct type *argtype = fdat->builtin->args[1];
  1317. struct sym_entry *se;
  1318. struct icode_instr *label;
  1319. struct icode_instr *label2;
  1320. struct token *fe_const;
  1321. struct reg *r;
  1322. long long_size;
  1323. int size;
  1324. int is_floating = 0;
  1325. struct vreg *gp_offset_vreg;
  1326. struct vreg *fp_offset_vreg;
  1327. struct vreg *overflow_arg_area_vreg;
  1328. struct vreg *reg_save_area_vreg;
  1329. #define gp_offset se->dec
  1330. #define fp_offset se->next->dec
  1331. #define overflow_arg_area se->next->next->dec
  1332. #define reg_save_area se->next->next->next->dec
  1333. /*
  1334. * 08/22/07: Wow, this stuff used get_ident() and did not
  1335. * generate icode for the first argument at all! Thus
  1336. *
  1337. * va_list *foo;
  1338. * va_arg(*foo, type);
  1339. *
  1340. * ... didn't work because *foo was not loaded
  1341. */
  1342. valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
  1343. if (valist_vr == NULL) {
  1344. return NULL;
  1345. } /* else {
  1346. check type...
  1347. } */
  1348. pointer = vreg_alloc(NULL, NULL, NULL, voidptr_type);
  1349. if (!eval) {
  1350. vr = vreg_alloc(NULL, NULL, /*pointer,*/NULL, NULL);
  1351. vr->from_ptr = pointer;
  1352. /*
  1353. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  1354. * assignments
  1355. */
  1356. vreg_set_new_type(vr, fdat->builtin->args[1]);
  1357. return vr;
  1358. }
  1359. vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
  1360. #if 0
  1361. /* Load va_list pointer into register */
  1362. vreg_faultin(NULL, NULL, valist->vreg, il, 0);
  1363. reg_set_unallocatable(valist->vreg->pregs[0]);
  1364. #endif
  1365. se = valist_vr->type->tstruc->scope->slist;
  1366. /* All va_list members come from the va_list pointer */
  1367. get_member_vreg(gp_offset, &tempmembvr, valist_vr);
  1368. gp_offset_vreg = tempmembvr;
  1369. get_member_vreg(fp_offset, &tempmembvr, valist_vr);
  1370. fp_offset_vreg = tempmembvr;
  1371. get_member_vreg(overflow_arg_area, &tempmembvr, valist_vr);
  1372. overflow_arg_area_vreg = tempmembvr;
  1373. get_member_vreg(reg_save_area, &tempmembvr, valist_vr);
  1374. reg_save_area_vreg = tempmembvr;
  1375. if ((argtype->code == TY_STRUCT
  1376. || argtype->code == TY_UNION
  1377. || argtype->code == TY_LDOUBLE)
  1378. && argtype->tlist == NULL) {
  1379. /* Struct/union/long double passed by value */
  1380. struct vreg *oarea;
  1381. vreg_faultin(NULL, NULL, overflow_arg_area_vreg, il, 0);
  1382. oarea = vreg_disconnect(overflow_arg_area_vreg);
  1383. oarea->type = n_xmemdup(argtype, sizeof *argtype);
  1384. append_typelist(oarea->type, TN_POINTER_TO, 0, NULL, NULL);
  1385. vr = vreg_alloc(NULL, NULL, NULL, NULL);
  1386. vr->from_ptr = oarea;
  1387. #if 0
  1388. vr->type = argtype;
  1389. vr->size = size = backend->get_sizeof_type(vr->type, NULL);
  1390. #endif
  1391. /*
  1392. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  1393. * assignments
  1394. */
  1395. vreg_set_new_type(vr, argtype);
  1396. size = vr->size;
  1397. if (argtype->code == TY_LDOUBLE) {
  1398. /*
  1399. * 07/29/08: This used to unconditionally
  1400. * anonymify, then fault-in the vreg. This is
  1401. * wrong because it will cause two x87 FPR
  1402. * loads (not quite sure why), which fills
  1403. * up the register stack
  1404. */
  1405. vreg_anonymify(&vr, NULL, NULL, il);
  1406. if (vr->pregs[0] == NULL
  1407. || vr->pregs[0]->vreg != vr) {
  1408. vreg_faultin_x87(NULL, NULL, vr, il, 0);
  1409. }
  1410. } else if (fdat->lvalue != NULL) {
  1411. /* Result is assigned - copy */
  1412. vreg_faultin_ptr(/*valist->vreg*/valist_vr, il);
  1413. vreg_faultin_ptr(fdat->lvalue, il);
  1414. /* Struct/union result */
  1415. /*
  1416. * 07/21/08: invalidate_gprs() was missing
  1417. * since copystruct will probably call memcpy()!
  1418. */
  1419. backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
  1420. icode_make_copystruct(fdat->lvalue, vr, il);
  1421. /*
  1422. * 07/21/08: Invalidate va_list vreg for
  1423. * offset addition below... Since memcpy
  1424. * may have trashed it
  1425. */
  1426. free_preg(valist_vr->pregs[0], il, 1, 0);
  1427. vr->struct_ret = 1;
  1428. }
  1429. while (size % 8) ++size;
  1430. long_size = size;
  1431. fe_const =
  1432. const_from_value(&long_size, make_basic_type(TY_LONG));
  1433. limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
  1434. vreg_faultin_protected(oarea,
  1435. NULL, NULL, limit_vreg, il, 0);
  1436. ii = icode_make_add(oarea, limit_vreg);
  1437. append_icode_list(il, ii);
  1438. vreg_map_preg(overflow_arg_area_vreg, oarea->pregs[0]);
  1439. icode_make_store(curfunc, overflow_arg_area_vreg,
  1440. overflow_arg_area_vreg, il);
  1441. return vr;
  1442. } else if (argtype->tlist == NULL && IS_FLOATING(argtype->code)) {
  1443. if (argtype->code == TY_LDOUBLE) {
  1444. /* Passed on stack */
  1445. } else {
  1446. is_floating = 1;
  1447. offset_vreg = fp_offset_vreg;
  1448. long_size = 112; /* 48 gpr- + 64 fpr-bytes */
  1449. }
  1450. } else {
  1451. offset_vreg = gp_offset_vreg;
  1452. long_size = 48; /* 48 gpr bytes */
  1453. }
  1454. vreg_faultin(NULL, NULL, /*gp_offset->vreg*/offset_vreg, il, 0);
  1455. fe_const = const_from_value(&long_size, make_basic_type(TY_LONG));
  1456. limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
  1457. vreg_faultin(NULL, NULL, limit_vreg, il, 0);
  1458. ii = icode_make_cmp(/*gp_offset->vreg*/offset_vreg, limit_vreg);
  1459. append_icode_list(il, ii);
  1460. r = limit_vreg->pregs[0]; /* reuse register */
  1461. label = icode_make_label(NULL);
  1462. label2 = icode_make_label(NULL);
  1463. ii = icode_make_branch(label, INSTR_BR_EQUAL, offset_vreg);
  1464. append_icode_list(il, ii);
  1465. /* offset is below 48 - use register save area */
  1466. vreg_faultin(r, NULL, reg_save_area_vreg, il, 0);
  1467. ii = icode_make_add(reg_save_area_vreg, offset_vreg);
  1468. append_icode_list(il, ii);
  1469. append_icode_list(il, icode_make_jump(label2));
  1470. append_icode_list(il, label);
  1471. /* offset is 48 - use overflow area */
  1472. vreg_faultin(r, NULL, overflow_arg_area_vreg, il, 0);
  1473. append_icode_list(il, label2);
  1474. vreg_map_preg(pointer, r);
  1475. reg_set_unallocatable(r);
  1476. /* XXX from_ptr?? check for indirection chain!!??! */
  1477. vr = vreg_alloc(NULL, NULL, /*pointer,*/NULL, NULL);
  1478. vr->from_ptr = pointer;
  1479. #if 0
  1480. vr->type = fdat->builtin->args[1];
  1481. vr->size = size = backend->get_sizeof_type(vr->type, NULL);
  1482. #endif
  1483. /*
  1484. * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
  1485. * assignments
  1486. */
  1487. vreg_set_new_type(vr, fdat->builtin->args[1]);
  1488. size = vr->size;
  1489. vreg_faultin(NULL, NULL, vr, il, 0);
  1490. vreg_anonymify(&vr, NULL, NULL, il);
  1491. if (size < 8) {
  1492. size = 8;
  1493. }
  1494. c = const_from_value(&size, NULL);
  1495. tmpvr = vreg_alloc(NULL, c, NULL, NULL);
  1496. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  1497. vreg_faultin(NULL, NULL, offset_vreg, il, 0);
  1498. limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
  1499. vreg_faultin(NULL, NULL, limit_vreg, il, 0);
  1500. ii = icode_make_cmp(offset_vreg, limit_vreg);
  1501. append_icode_list(il, ii);
  1502. label = icode_make_label(NULL);
  1503. label2 = icode_make_label(NULL);
  1504. ii = icode_make_branch(label, INSTR_BR_EQUAL, offset_vreg);
  1505. append_icode_list(il, ii);
  1506. /* offset is below 48/112 - use register save area */
  1507. vreg_faultin_protected(offset_vreg, NULL, NULL, tmpvr, il, 0);
  1508. ii = icode_make_add(offset_vreg, tmpvr);
  1509. append_icode_list(il, ii);
  1510. icode_make_store(curfunc, offset_vreg, offset_vreg, il);
  1511. append_icode_list(il, icode_make_jump(label2));
  1512. append_icode_list(il, label);
  1513. /* offset is 48/112 - use overflow area */
  1514. vreg_faultin(NULL, NULL, overflow_arg_area_vreg, il, 0);
  1515. vreg_faultin(NULL, NULL, tmpvr, il, 0);
  1516. ii = icode_make_add(overflow_arg_area_vreg, tmpvr);
  1517. append_icode_list(il, ii);
  1518. icode_make_store(curfunc, overflow_arg_area_vreg,
  1519. overflow_arg_area_vreg, il);
  1520. append_icode_list(il, label2);
  1521. free_preg(/*valist->vreg*/ valist_vr->pregs[0], il, 0, 0);
  1522. free_preg(offset_vreg->pregs[0], il, 0, 0);
  1523. free_preg(overflow_arg_area_vreg->pregs[0], il, 0, 0);
  1524. free_preg(reg_save_area_vreg->pregs[0], il, 0, 0);
  1525. free_preg(r, il, 0, 0);
  1526. #undef gp_offset
  1527. #undef fp_offset
  1528. #undef overflow_arg_area
  1529. #undef reg_save_area
  1530. return vr;
  1531. }
  1532. static builtin_to_icode_func_t x86_icode_funcs[] = {
  1533. x86_builtin_va_start_to_icode,
  1534. x86_builtin_va_start_to_icode,
  1535. x86_builtin_next_arg_to_icode,
  1536. x86_builtin_va_end_to_icode,
  1537. x86_builtin_va_arg_to_icode,
  1538. NULL, /* expect */
  1539. generic_builtin_alloca_to_icode,
  1540. generic_builtin_va_copy_to_icode,
  1541. generic_builtin_constant_p_to_icode,
  1542. generic_builtin_memcpy_or_memset_to_icode,
  1543. generic_builtin_memcpy_or_memset_to_icode,
  1544. generic_builtin_frame_address_to_icode,
  1545. generic_builtin_offsetof_to_icode
  1546. };
  1547. static builtin_to_icode_func_t mips_icode_funcs[] = {
  1548. x86_builtin_va_start_to_icode,
  1549. x86_builtin_va_start_to_icode,
  1550. mips_builtin_next_arg_to_icode,
  1551. x86_builtin_va_end_to_icode,
  1552. mips_builtin_va_arg_to_icode,
  1553. NULL, /* expect */
  1554. generic_builtin_alloca_to_icode,
  1555. generic_builtin_va_copy_to_icode,
  1556. generic_builtin_constant_p_to_icode,
  1557. generic_builtin_memcpy_or_memset_to_icode,
  1558. generic_builtin_memcpy_or_memset_to_icode,
  1559. generic_builtin_frame_address_to_icode,
  1560. generic_builtin_offsetof_to_icode
  1561. };
  1562. static builtin_to_icode_func_t sparc_icode_funcs[] = {
  1563. x86_builtin_va_start_to_icode,
  1564. x86_builtin_va_start_to_icode,
  1565. mips_builtin_next_arg_to_icode,
  1566. x86_builtin_va_end_to_icode,
  1567. mips_builtin_va_arg_to_icode,
  1568. NULL, /* expect */
  1569. generic_builtin_alloca_to_icode,
  1570. generic_builtin_va_copy_to_icode,
  1571. generic_builtin_constant_p_to_icode,
  1572. generic_builtin_memcpy_or_memset_to_icode,
  1573. generic_builtin_memcpy_or_memset_to_icode,
  1574. generic_builtin_frame_address_to_icode,
  1575. generic_builtin_offsetof_to_icode
  1576. };
  1577. static builtin_to_icode_func_t power_icode_funcs[] = {
  1578. x86_builtin_va_start_to_icode,
  1579. x86_builtin_va_start_to_icode,
  1580. /*mips*/ x86_builtin_next_arg_to_icode,
  1581. x86_builtin_va_end_to_icode,
  1582. /*mips*/ x86_builtin_va_arg_to_icode,
  1583. NULL, /* expect */
  1584. generic_builtin_alloca_to_icode,
  1585. generic_builtin_va_copy_to_icode,
  1586. generic_builtin_constant_p_to_icode,
  1587. generic_builtin_memcpy_or_memset_to_icode,
  1588. generic_builtin_memcpy_or_memset_to_icode,
  1589. generic_builtin_frame_address_to_icode,
  1590. generic_builtin_offsetof_to_icode
  1591. };
  1592. static builtin_to_icode_func_t amd64_icode_funcs[] = {
  1593. amd64_builtin_va_start_to_icode,
  1594. amd64_builtin_va_start_to_icode,
  1595. amd64_builtin_next_arg_to_icode,
  1596. x86_builtin_va_end_to_icode,
  1597. amd64_builtin_va_arg_to_icode,
  1598. NULL, /* expect */
  1599. generic_builtin_alloca_to_icode,
  1600. generic_builtin_va_copy_to_icode,
  1601. generic_builtin_constant_p_to_icode,
  1602. generic_builtin_memcpy_or_memset_to_icode,
  1603. generic_builtin_memcpy_or_memset_to_icode,
  1604. generic_builtin_frame_address_to_icode,
  1605. generic_builtin_offsetof_to_icode
  1606. };
  1607. /*
  1608. * XXX the initialization below means that the ``builtins'' and
  1609. * ``*_icode_funcs'' tables have to have the same ordering
  1610. */
  1611. static void
  1612. init_builtin_functions(void) {
  1613. builtin_to_icode_func_t *p = NULL;
  1614. unsigned int i;
  1615. if (backend->arch == ARCH_X86) {
  1616. p = x86_icode_funcs;
  1617. } else if (backend->arch == ARCH_AMD64) {
  1618. p = amd64_icode_funcs;
  1619. } else if (backend->arch == ARCH_MIPS) {
  1620. p = mips_icode_funcs;
  1621. } else if (backend->arch == ARCH_POWER) {
  1622. p = power_icode_funcs;
  1623. } else if (backend->arch == ARCH_SPARC) {
  1624. p = sparc_icode_funcs;
  1625. } else {
  1626. unimpl();
  1627. }
  1628. for (i = 0; i < sizeof x86_icode_funcs /
  1629. sizeof x86_icode_funcs[0]; ++i) {
  1630. builtins[i].toicode = p[i];
  1631. }
  1632. }
  1633. static struct builtin *
  1634. lookup_builtin(const char *name) {
  1635. size_t namelen = strlen(name);
  1636. int i;
  1637. /*
  1638. * XXX test below is for alloca()
  1639. */
  1640. if (name[0] == '_') {
  1641. name += sizeof "__builtin_" - 1;
  1642. namelen -= sizeof "__builtin_" - 1;
  1643. }
  1644. for (i = 0; builtins[i].name != NULL; ++i) {
  1645. if (builtins[i].namelen != namelen) {
  1646. continue;
  1647. }
  1648. if (strcmp(builtins[i].name, name) == 0) {
  1649. return &builtins[i];
  1650. }
  1651. }
  1652. return NULL;
  1653. }
  1654. struct fcall_data *
  1655. get_builtin(struct token **tok, struct token *nametok) {
  1656. struct builtin *b;
  1657. struct fcall_data *ret;
  1658. sta

Large files files are truncated, but you can click here to view the full file