/builtins.c
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
- /*
- * Copyright (c) 2005 - 2009, Nils R. Weller
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * Parsing of, and icode generation for, builtin functions.
- * This stuff is mostly kinda ad-hoc and ugly :-(
- *
- * Maybe parsing and code generation should be separated as this
- * file keeps growing.
- *
- * Implemented builtins:
- *
- * __builtin_va_start
- * __builtin_va_stdarg_start
- * __builtin_va_arg
- * __builtin_va_next_arg
- * __builtin_va_end
- * __builtin_memcpy
- * __builtin_memset
- * __builtin_constant_p
- * __builtin_va_expect
- * NOTE: This one is just ignored
- * __builtin_va_alloca
- * NOTE: This one uses malloc()/free() instead of the stack. Also,
- * it does not honor block scope, so every allocated block
- * is kept until the current function is left
- * __builtin_va_copy
- * NOTE: No typechecking
- */
- #include "builtins.h"
- #include <string.h>
- #include <stdlib.h>
- #include "icode.h"
- #include "token.h"
- #include "error.h"
- #include "subexpr.h"
- #include "icode.h"
- #include "functions.h"
- #include "backend.h"
- #include "expr.h"
- #include "type.h"
- #include "symlist.h"
- #include "scope.h"
- #include "typemap.h"
- #include "amd64_gen.h"
- #include "token.h"
- #include "backend.h"
- #include "cc1_main.h"
- #include "decl.h"
- #include "reg.h"
- #include "x87_nonsense.h"
- #include "n_libc.h"
- struct type *builtin_va_list_type;
- /*
- * 08/22/07: This stuff was nonsense for va_arg()s first argument, but
- * seems to still make some sense for va_start()
- */
- static char *
- get_ident(struct expr *ex) {
- struct token *idtok;
- if (ex->op != 0) {
- return NULL;
- }
- if (ex->data->meat != NULL) {
- idtok = ex->data->meat;
- } else if (ex->data->is_expr) {
- if (ex->data->is_expr->op != 0) {
- return NULL;
- } else if (ex->data->is_expr->data->meat != NULL) {
- idtok = ex->data->is_expr->data->meat;
- } else {
- return NULL;
- }
- } else {
- return NULL;
- }
- return idtok->ascii;
- }
- static int
- builtin_parse_va_start(struct token **tok, struct fcall_data *fdat) {
- struct token *t = *tok;
- struct decl *dec;
- struct expr *ex;
- struct sym_entry *se;
- char *ident;
- int i;
- if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- fdat->builtin->args[1] = NULL;
- if (next_token(&t) != 0) {
- return -1;
- }
- if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
- return -1;
- }
- #if 0
- if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
- errorfl(t, "Bad second argument to va_start() - "
- "Identifier expected");
- return -1;
- }
- #endif
- if ((ident = get_ident(ex)) == NULL) {
- errorfl(t, "Bad second argument to va_start() - "
- "Identifier expected");
- return -1;
- }
- if ((dec = lookup_symbol(curfunc->scope, ident, 0)) == NULL) {
- errorfl(t, "Undeclared identifier `%s'", ident);
- return -1;
- }
- for (i = 0, se = curfunc->scope->slist; se != NULL; se = se->next) {
- ++i;
- if (i == curfunc->proto->dtype->tlist->tfunc->nargs) {
- break;
- }
- }
- if (se == NULL || se->dec != dec) {
- errorfl(t, "Second argument to va_start() is not %s "
- "parameter of `%s'",
- se == NULL? "a": "last",
- curfunc->proto->dtype->name);
- return -1;
- }
- if (t->type != TOK_PAREN_CLOSE) {
- errorfl(t, "Syntax error at `%s'", t->ascii);
- return -1;
- }
- *tok = t;
- return 0;
- }
- static int
- builtin_parse_next_arg(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- struct token *t = *tok;
- (void) fdat;
- if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
- return -1;
- }
- if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
- errorfl(t, "Bad second argument to va_start() - "
- "Identifier expected");
- return -1;
- }
- *tok = t;
- return 0;
- }
- static int
- builtin_parse_va_end(struct token **tok, struct fcall_data *fdat) {
- struct token *t = *tok;
- struct expr *ex;
- (void) fdat;
- if ((ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0 ,1)) == NULL) {
- return -1;
- }
- if (ex->op != 0 || ex->data->meat->type != TOK_IDENTIFIER) {
- errorfl(t, "Bad second argument to va_start() - "
- "Identifier expected");
- return -1;
- }
- *tok = t;
- fdat->builtin->args[0] = ex;
- return 0;
- }
- static int
- builtin_parse_va_arg(struct token **tok, struct fcall_data *fdat) {
- struct decl **typedec;
- struct token *starttok;
- struct token *t = *tok;
- struct expr *ex;
- struct type *type;
- if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- if (next_token(&t) != 0) {
- return -1;
- }
- starttok = t;
- if ((typedec = parse_decl(&t, DECL_CAST)) == NULL) {
- return -1;
- }
- type = typedec[0]->dtype;
- free(typedec);
- fdat->builtin->args[1] = type;
- fdat->builtin->args[2] = NULL;
- #if 0
- if (is_basic_agg_type(type)) {
- unimpl();
- }
- #endif
- *tok = t;
- return 0;
- }
- static int
- builtin_parse_expect(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- struct expr *ex2;
- struct token *t = *tok;
- struct token *second_start;
- if ((ex = parse_expr(&t, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- /* hmm - gcc warns about first argument of pointer type */
- if (next_token(&t) != 0) {
- return -1;
- }
- second_start = t;
- if ((ex2 = parse_expr(&t, TOK_PAREN_CLOSE, 0, EXPR_CONST, 1)) == NULL) {
- return -1;
- }
- #if 0
- /* const_value is always null!?!??!?!?!?!?!??? :-( :-( :-( */
- if (!is_integral_type(ex2->const_value->type)) {
- /* hmm - gcc accepts stuff like 0.0f */
- errorfl(second_start,
- "Second argument of __builtin_expect not integer constant");
- return -1;
- }
- #endif
- fdat->builtin->args[0] = ex;
- fdat->builtin->args[1] = ex2;
- fdat->builtin->type = BUILTIN_EXPECT;
- *tok = t;
- return 0;
- }
- static int
- generic_builtin_parse_alloca(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- return 0;
- }
- static int
- generic_builtin_parse_va_copy(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- struct expr *ex2;
- if ((ex = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- if (next_token(tok) != 0) {
- return -1;
- }
- if ((ex2 = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- fdat->builtin->args[1] = ex2;
- return 0;
- }
- static int
- generic_builtin_parse_constant_p(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, EXPR_OPTCONSTSUBEXPR, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- return 0;
- }
- static int
- generic_builtin_parse_memcpy(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- struct expr *ex2;
- struct expr *ex3;
- if ((ex = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- if (next_token(tok) != 0) {
- return -1;
- }
- if ((ex2 = parse_expr(tok, TOK_OP_COMMA, 0, 0, 1)) == NULL) {
- return -1;
- }
- if (next_token(tok) != 0) {
- return -1;
- }
- if ((ex3 = parse_expr(tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) {
- return -1;
- }
- fdat->builtin->args[0] = ex;
- fdat->builtin->args[1] = ex2;
- fdat->builtin->args[2] = ex3;
- return 0;
- }
- static int
- generic_builtin_parse_offsetof(struct token **tok, struct fcall_data *fdat) {
- struct token *t = *tok;
- struct token *starttok = t;
- struct type *cur_struct_type;
- struct decl **typedec;
- unsigned long total_offset;
- struct expr *ex;
- /*static*/ struct token *tokens;
- static struct token *tag_location;
- static struct token *cast_location;
- struct token *origtokens;
- int i;
- static int dummy;
- int *ip;
- int not_constant;
- if ((typedec = parse_decl(&t, DECL_FUNCARG)) == NULL) {
- return -1;
- }
- if ((typedec[0]->dtype->code != TY_STRUCT && typedec[0]->dtype->code != TY_UNION)
- || typedec[0]->dtype->tlist != NULL) {
- errorfl(starttok, "First operand of __builtin_offsetof() "
- "is not structure type");
- return -1;
- }
- if (t->type != TOK_OPERATOR
- || *(int *)t->data != TOK_OP_COMMA) {
- errorfl(t, "Syntax error at `%s'", t->ascii);
- return -1;
- }
- if (next_token(&t) != 0) {
- return -1;
- }
- cur_struct_type = typedec[0]->dtype;
- total_offset = 0;
- /*
- * 07/16/08: Do it thoroughly; Don't just allow a single member
- * identifier, but arbitrary expressions.
- *
- * The operand may contain multiple struct member or array
- * subscript operators, so the easiest way is to construct the
- * traditional offsetof() implementation as a token list, parse
- * and evaluate it!
- */
- tokens = NULL;
- /*
- * Construct token list. It would be nice to cache these things, but
- * since the expression parsing routiens alter some tokens (cast,
- * indirection), it is just safer to start over every time
- */
- i = TOK_OP_AMB_BAND;
- store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
- store_token(&tokens, &dummy, TOK_PAREN_OPEN, 0, NULL);
- store_token(&tokens, &dummy, TOK_PAREN_OPEN, 0, NULL);
- /* & ( ( */
- cast_location = tokens->next->next;
- if (typedec[0]->dtype->code == TY_STRUCT) {
- store_token(&tokens, n_xstrdup("struct"), TOK_KEY_STRUCT, 0, NULL);
- } else {
- store_token(&tokens, n_xstrdup("union"), TOK_KEY_UNION, 0, NULL);
- }
- if (typedec[0]->dtype->tstruc->tag != NULL) {
- /* A well-behaved struct with tag */
- store_token(&tokens, typedec[0]->dtype->tstruc->tag, TOK_IDENTIFIER, 0, NULL);
- } else {
- /* A sinister anonymous struct type - use dummy tag */
- store_token(&tokens, typedec[0]->dtype->tstruc->dummytag, TOK_IDENTIFIER, 0, NULL);
- }
- /* & ( ( struct tag */
- tag_location = tokens->next->next->next->next;
- i = TOK_OP_AMB_MULTI;
- store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
- store_token(&tokens, &dummy, TOK_PAREN_CLOSE, 0, NULL);
- i = 0;
- ip = n_xmalloc(16); /* XXX */
- memcpy(ip, &i, sizeof i);
- store_token(&tokens, ip, TY_INT, 0, NULL);
- store_token(&tokens, &dummy, TOK_PAREN_CLOSE, 0, NULL);
- i = TOK_OP_STRUPMEMB;
- store_token(&tokens, n_xmemdup(&i, sizeof i), TOK_OPERATOR, 0, NULL);
- /*
- * Append member selection to token template
- *
- * & ( ( struct tag * ) 0 ) ->
- */
- tokens->next->next->next->next->next->next->next->next->next->next = t;
- origtokens = tokens;
- ex = parse_expr(&tokens, TOK_PAREN_CLOSE, 0, 0, 1);
- if (ex == NULL) {
- return -1;
- }
- if (ex->op != 0) {
- errorfl(ex->tok, "Parse error - Binary operator unexpected");
- return -1;
- }
- if (eval_const_expr(ex, EXPR_OPTCONSTSUBEXPR, ¬_constant) != -1) {
- cross_do_conv(ex->const_value, backend->get_size_t()->code, 1);
- total_offset = cross_to_host_size_t(ex->const_value);
- }
- /*
- * Continue where parse_expr() stopped
- */
- t = tokens;
- if (t->type != TOK_PAREN_CLOSE) {
- errorfl(t, "Syntax error at `%s' - expected closing parenthesis",
- t->ascii);
- return -1;
- }
- *tok = t;
- /*fdat->builtin->args[0] = n_xmemdup(&total_offset, sizeof total_offset);*/
- fdat->builtin->args[0] = ex;
- fdat->builtin->type = BUILTIN_OFFSETOF;
- return 0;
- }
- static int
- generic_builtin_parse_frame_address(struct token **tok, struct fcall_data *fdat) {
- struct expr *ex;
- struct token *t = *tok;
- size_t frameno;
- if ((ex = parse_expr(tok, TOK_PAREN_CLOSE, 0, EXPR_CONST, 1)) == NULL) {
- return -1;
- }
- if (ex->const_value == NULL) {
- errorfl(t, "Argument to __builtin_frame_address() not "
- "constant");
- return -1;
- }
- if (!is_integral_type(ex->const_value->type)) {
- errorfl(t, "Argument to __builtin_frame_address() not "
- "integral");
- return -1;
- }
- cross_do_conv(ex->const_value, TY_INT, 1);
- frameno = cross_to_host_size_t(ex->const_value); /* XXXX CROSS??? */
- if (frameno > 0) {
- errorfl(t, "__builtin_frame_address() currently only "
- "works with the current stack frame (argument 0)!");
- return -1;
- }
- fdat->builtin->args[0] = n_xmemdup(&frameno, sizeof frameno);
- return 0;
- }
- static struct vreg *
- generic_builtin_constant_p_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct expr *ex = fdat->builtin->args[0];
- int val;
- struct token *tok;
- val = ex->const_value != NULL; /*ex->is_const;*/
- tok = const_from_value(&val, NULL);
- vr = vreg_alloc(NULL, tok, NULL, NULL);
- return vr;
- }
- static struct vreg *
- generic_builtin_va_copy_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct vreg *arg0;
- struct vreg *arg1;
- struct vreg *tmpvr;
- struct expr *ex0 = fdat->builtin->args[0];
- struct expr *ex1 = fdat->builtin->args[1];
- struct icode_instr *ii;
- struct token *tok;
- int size;
- int va_list_is_array = 0;
- arg0 = expr_to_icode(ex0, NULL, il, 0, 0, eval);
- if (arg0 == NULL) {
- return NULL;
- }
- arg1 = expr_to_icode(ex1, NULL, il, 0, 0, eval);
- if (arg1 == NULL) {
- return NULL;
- }
- if (!eval) {
- /* XXX Could not hurt to type-check the operand results?!?!? */
- vreg_set_new_type(vr, make_basic_type(TY_VOID));
- return vr;
- }
- /*
- * XXX this is just a quick kludge... we will later want to do
- * full type-checking! Ideally use unary_to_icode() from
- * subexpr.c for this to determine whether the address can be
- * taken
- */
- size = backend->get_sizeof_type(arg0->type, NULL);
- if (backend->arch == ARCH_AMD64) {
- /*
- * XXX use backend->va_list_is_sysv_like?!?!
- * This must be done on Linux/PPC too
- */
- va_list_is_array = 1;
- vreg_faultin(NULL, NULL, arg0, il, 0);
- size = 24; /* XXX because the source really is an array! */
- } else {
- ii = icode_make_addrof(NULL, arg0, il);
- append_icode_list(il, ii);
- arg0 = vreg_disconnect(arg0);
- arg0->type = addrofify_type(arg0->type);
- arg0->size = backend->get_sizeof_type(arg0->type, NULL);
- vreg_map_preg(arg0, ii->dat);
- }
- reg_set_unallocatable(arg0->pregs[0]);
- if (!va_list_is_array) {
- ii = icode_make_addrof(NULL, arg1, il);
- append_icode_list(il, ii);
- arg1 = vreg_disconnect(arg1);
- arg1->type = addrofify_type(arg1->type);
- arg1->size = backend->get_sizeof_type(arg1->type, NULL);
- vreg_map_preg(arg1, ii->dat);
- } else {
- vreg_faultin(NULL, NULL, arg1, il, 0);
- }
- reg_set_unallocatable(arg1->pregs[0]);
- tok = const_from_value(&size, make_basic_type(TY_INT));
- tmpvr = vreg_alloc(NULL, tok, NULL, make_basic_type(TY_INT));
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
-
- reg_set_allocatable(arg0->pregs[0]);
- reg_set_allocatable(arg1->pregs[0]);
- icode_make_intrinsic_memcpy_or_memset(BUILTIN_MEMCPY,
- arg0, arg1, tmpvr, 0, il);
-
- #if 0
- vr->type = make_basic_type(TY_VOID);
- #endif
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments. Size assignment was missing
- */
- vreg_set_new_type(vr, make_basic_type(TY_VOID));
- return vr;
- }
- static struct vreg *
- generic_builtin_memcpy_or_memset_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
- struct vreg *resvr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct vreg *arg0;
- struct vreg *arg1;
- struct vreg *arg2;
- struct expr *ex0 = fdat->builtin->args[0];
- struct expr *ex1 = fdat->builtin->args[1];
- struct expr *ex2 = fdat->builtin->args[2];
- char *funcname = fdat->builtin->type == BUILTIN_MEMCPY?
- "memcpy": "memset";
- resvr->type = n_xmemdup(make_basic_type(TY_VOID), sizeof(struct type));
- append_typelist(resvr->type, TN_POINTER_TO, 0, NULL, NULL);
- resvr->size = backend->get_sizeof_type(resvr->type, NULL);
- arg0 = expr_to_icode(ex0, NULL, il, 0, 0, eval);
- if (arg0 == NULL) {
- return NULL;
- }
- if (arg0->type->tlist == NULL) {
- errorfl(ex0->tok, "First argument to __builtin_%s "
- "must be pointer", funcname);
- return NULL;
- }
- /*
- * Now save target address to stack (this is the return value
- * of __builtin_memcpy() and memcpy() generally.)
- */
- if (eval) {
- vreg_faultin(NULL, NULL, arg0, il, 0);
- vreg_map_preg(resvr, arg0->pregs[0]);
- free_preg(resvr->pregs[0], il, 0, 1); /* save, but don't invalidate */
- vreg_map_preg(arg0, resvr->pregs[0]);
- }
-
- arg1 = expr_to_icode(ex1, NULL, il, 0, 0, eval);
- if (arg1 == NULL) {
- return NULL;
- }
- /*
- * 03/26/08: Hmm, the faultin was missing, it only showed up
- * when dec->vreg was removed. We should recheck the guarantees
- * that expr_to_icode() gives us, apparently register residence
- * is not included. This makes sense too!
- */
- if (eval) {
- vreg_faultin(NULL, NULL, arg1, il, 0);
- }
- if (fdat->builtin->type == BUILTIN_MEMCPY) {
- if (arg1->type->tlist == NULL) {
- errorfl(ex1->tok, "Second argument to __builtin_%s "
- "must be pointer", funcname);
- return NULL;
- }
- } else {
- /* memset */
- if (!is_integral_type(arg1->type)) {
- errorfl(ex1->tok, "Second argument to __builtin_%s ",
- "must be integral", funcname);
- }
- if (eval) {
- arg1 = backend->icode_make_cast(arg1,
- make_basic_type(TY_UCHAR), il);
- }
- }
- arg2 = expr_to_icode(ex2, NULL, il, 0, 0, eval);
- if (arg2 == NULL) {
- return NULL;
- }
- /* 03/26/08: Faultin missing, see above */
- if (eval) {
- vreg_faultin(NULL, NULL, arg2, il, 0);
- }
- if (!is_integral_type(arg2->type)) {
- errorfl(ex2->tok, "Third argument to __builtin_%s "
- "must be integral type", funcname);
- return NULL;
- }
- if (eval) {
- icode_make_intrinsic_memcpy_or_memset(fdat->builtin->type,
- arg0, arg1, arg2, 0, il);
- }
- return resvr;
- }
- static struct vreg *
- generic_builtin_alloca_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct vreg *size_vr;
- struct type *ty;
- struct stack_block *sb;
- struct reg *r;
- struct expr *ex = fdat->builtin->args[0];
-
- size_vr = expr_to_icode(ex, NULL, il, 0, 0, eval);
- if (size_vr == NULL) {
- return NULL;
- }
- if (!is_integral_type(size_vr->type)) {
- errorfl(ex->tok, "Argument not of integral type");
- return NULL;
- }
- /* Result type is ``void *'' */
- ty = n_xmemdup(make_basic_type(TY_VOID), sizeof *ty);
- append_typelist(ty, TN_POINTER_TO, 0, NULL, NULL);
- vr->type = ty;
- vr->size = backend->get_sizeof_type(ty, NULL);
- if (!eval) {
- return vr;
- }
- /*
- * Now allocate a stack block in which to store the returned
- * pointer, so that we can free it upon return from the function.
- * As usual the offset is patched in gen_function()
- */
- sb = make_stack_block(0, vr->size);
- if (curfunc->alloca_head == NULL) {
- curfunc->alloca_head = curfunc->alloca_tail = sb;
- } else {
- curfunc->alloca_tail->next = sb;
- curfunc->alloca_tail = sb;
- }
- /* Get register to store result pointer */
- vreg_set_unallocatable(size_vr);
- /*
- * 11/12/07: ALLOC_GPR() is wrong here! We have to use the ABI's
- * malloc() return address register. This stuff is kludgedx XXX
- * XXXXXXXXXXXXXX
- */
- r = backend->get_abi_ret_reg(make_void_ptr_type());
- free_preg(r, il, 1, 1);
- #if 0
- r = ALLOC_GPR(curfunc, vr->size, il, 0);
- #endif
- icode_make_alloca(r, size_vr, sb, il);
- vreg_map_preg(vr, r);
- return vr;
- }
- static struct vreg *
- generic_builtin_offsetof_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
-
- struct vreg *vr;
- long val; /* XXX because const_from_type() is broken */
- struct token *tok;
- struct expr *ex = fdat->builtin->args[0];
- int not_constant = 0;
- if (eval) {
- if (ex->const_value != NULL) {
- val = cross_to_host_size_t(ex->const_value);
- } else {
- val = 0;
- not_constant = 1;
- }
- } else {
- val = 0;
- }
- if (not_constant) {
- vr = expr_to_icode(ex, NULL, il, 0, 0, eval);
- vr = backend->icode_make_cast(vr, backend->get_size_t(), il);
- } else {
- tok = alloc_token();
- tok->data = n_xmalloc(16); /* XXX */
- tok->type = backend->get_size_t()->code;
- cross_from_host_long(tok->data, val, tok->type);
- vr = vreg_alloc(NULL, tok, NULL, NULL);
- }
-
- return vr;
- }
- static struct vreg *
- generic_builtin_frame_address_to_icode(struct fcall_data *fdat,
- struct icode_list *il, int eval) {
- struct vreg *vr = vreg_alloc(NULL,NULL,NULL,NULL);
- struct type *ty;
- struct reg *r;
- struct reg *r2;
- ty = n_xmemdup(make_basic_type(TY_VOID), sizeof *ty);
- append_typelist(ty, TN_POINTER_TO, 0, NULL, NULL);
- vreg_set_new_type(vr, ty);
- if (!eval) {
- return vr;
- }
- /*
- * Allocate two GPRs to make walking up the stack possible
- */
- r = ALLOC_GPR(curfunc, vr->size, il, NULL);
- r2 = ALLOC_GPR(curfunc, vr->size, il, NULL);
- icode_make_builtin_frame_address(r, r2, fdat->builtin->args[0], il);
- free_preg(r2, il, 1, 0);
- vreg_map_preg(vr, r);
- return vr;
- }
- static struct vreg *
- x86_builtin_va_start_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct type *ty;
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct vreg *valist_vr;
- struct icode_instr *ii;
-
- if (eval) {
- ii = icode_make_addrof(NULL, NULL, il);
- append_icode_list(il, ii);
- }
- valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
- if (valist_vr == NULL) {
- return NULL;
- }
- if (eval) {
- vreg_map_preg(valist_vr, ii->dat);
- icode_make_store(curfunc, valist_vr, valist_vr, il);
- free_preg(valist_vr->pregs[0], il, 0, 0);
- }
- ty = make_basic_type(TY_VOID);
- vr->type = ty;
- vr->size = 0;
- return vr;
- }
- static struct vreg *
- x86_builtin_next_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct type *ty;
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct icode_instr *ii;
-
- (void) fdat;
- if (eval) {
- ii = icode_make_addrof(NULL, NULL, il);
- append_icode_list(il, ii);
-
- vreg_map_preg(vr, ii->dat);
- }
- ty = n_xmemdup(make_basic_type(TY_CHAR), sizeof *ty);
- ty->tlist = alloc_type_node();
- ty->tlist->type = TN_POINTER_TO;
- vr->type = ty;
- vr->size = backend->get_sizeof_type(ty, NULL);
- return vr;
- }
- static struct vreg *
- x86_builtin_va_end_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct type *ty;
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- /*
- * 07/21/08: This was not actually evaluating the operand to va_end()!
- * But that's needed because it may contain side effects
- */
- if (expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval) == NULL) {
- return NULL;
- }
- /* XXX type-checking for argument to va_end()!!!!!!!! */
- ty = make_basic_type(TY_VOID);
- vr->type = ty;
- vr->size = 0;
- return vr;
- }
- static struct vreg *
- x86_builtin_va_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct vreg *valist_vr;
- struct vreg *vr;
- struct type *argtype = fdat->builtin->args[1];
- int size;
- int intsize;
- int rightadjust = 0;
-
- /*
- * 08/22/07: Wow, this stuff used get_ident() and did not
- * generate icode for the first argument at all! Thus
- *
- * va_list *foo;
- * va_arg(*foo, type);
- *
- * ... didn't work because *foo was not loaded
- */
- valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
- if (valist_vr == NULL) {
- return NULL;
- } /* else {
- check type...
- } */
- if (eval) {
- vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
- }
- intsize = backend->get_sizeof_type(
- make_basic_type(backend->arch == ARCH_X86? TY_INT: TY_LONG),
- NULL);
- if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
- && argtype->tlist == NULL) {
- /* Struct/union passed by value */
- vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
- vr->type = fdat->builtin->args[1];
- vr->size = size = backend->get_sizeof_type(vr->type, NULL);
- if (fdat->lvalue != NULL) {
- /* Result is assigned - copy */
- if (eval) {
- /*
- * 07/21/08: invalidate_gprs() was missing
- * since copystruct will probably call memcpy()!
- */
- backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
- vreg_faultin_ptr(/*valist->vreg*/ valist_vr, il);
- vreg_faultin_ptr(fdat->lvalue, il);
- icode_make_copystruct(fdat->lvalue, vr, il);
- /*
- * 07/21/08: Invalidate va_list vreg for
- * offset addition below... Since memcpy
- * may have trashed it
- */
- free_preg(valist_vr->pregs[0], il, 1, 0);
- }
- vr->struct_ret = 1;
- }
- } else {
- /* XXX from_ptr?? check for indirection chain!!??! */
- vr = vreg_alloc(NULL, NULL, /*valist->vreg*/ valist_vr, NULL);
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments (is_multi_reg_obj was not set!)
- */
- vreg_set_new_type(vr, fdat->builtin->args[1]);
- size = vr->size;
- if (eval) {
- if (size < intsize
- && backend->arch == ARCH_POWER
- && backend->abi == ABI_POWER64) {
- /*
- * Right adjust small argument - Only
- * for PPC for now
- */
- rightadjust = calc_slot_rightadjust_bytes(size, intsize);
- if (rightadjust != 0) {
- add_const_to_vreg(valist_vr, rightadjust, il);
- }
- }
- if (is_x87_trash(vr)) {
- vr = x87_anonymify(vr, il);
- } else {
- vreg_faultin(NULL, NULL, vr, il, 0);
- vreg_anonymify(&vr, NULL, NULL, il);
- }
- }
- }
- if (!eval) {
- return vr;
- }
- if (size < intsize) {
- size = intsize;
- } else if (vr->type->code == TY_LDOUBLE) {
- if (backend->arch == ARCH_X86) {
- if (sysflag == OS_OSX) {
- #if 0
- size += 6;
- #endif
- } else {
- #if 0
- size += 2;
- #endif
- }
- } else if (backend->arch == ARCH_AMD64) {
- ; /* ... */
- } else if (backend->arch == ARCH_POWER) {
- #if _AIX
- #else
- /* size += 8;*/
- #endif
- }
- }
- /* 07/21/08: Align to multiple of 4
- * XXXX What to do with SPARC and PPC?
- */
- if ((vr->type->code == TY_STRUCT || vr->type->code == TY_UNION)
- && vr->type->tlist == NULL) {
- if (size & 3) {
- size += 4 - (size & 3);
- }
- }
- /*
- * 11/25/08: If the item was right-adjusted for a dword slot, we have
- * to take that into account
- */
- if (rightadjust != 0) {
- size -= rightadjust;
- }
- add_const_to_vreg(valist_vr, size, il);
- #if 0
- c = const_from_value(&size, NULL);
- tmpvr = vreg_alloc(NULL, c, NULL, NULL);
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- vreg_faultin_protected(tmpvr, NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
- ii = icode_make_add( /*valist->vreg*/valist_vr, tmpvr);
- append_icode_list(il, ii);
- icode_make_store(curfunc, /*valist->vreg*/valist_vr,
- /*valist->vreg*/valist_vr, il);
- #endif
- return vr;
- }
- static struct builtin builtins[] = {
- { "va_start", sizeof "va_start" - 1, BUILTIN_VA_START,
- builtin_parse_va_start, /*x86_builtin_va_start_to_icode*/0 },
- /* va_start and stdarg_start are equivalent */
- { "stdarg_start", sizeof "stdarg_start" - 1, BUILTIN_STDARG_START,
- builtin_parse_va_start, x86_builtin_va_start_to_icode },
- { "next_arg", sizeof "next_arg" - 1, BUILTIN_NEXT_ARG,
- builtin_parse_next_arg, x86_builtin_next_arg_to_icode },
- { "va_end", sizeof "va_end" - 1, BUILTIN_VA_END,
- builtin_parse_va_end, x86_builtin_va_end_to_icode },
- { "va_arg", sizeof "va_arg" - 1, BUILTIN_VA_ARG,
- builtin_parse_va_arg, x86_builtin_va_arg_to_icode },
- { "expect", sizeof "expect" - 1, BUILTIN_EXPECT,
- builtin_parse_expect, NULL },
- { "alloca", sizeof "alloca" - 1, BUILTIN_ALLOCA,
- generic_builtin_parse_alloca, generic_builtin_alloca_to_icode },
- { "va_copy", sizeof "va_copy" - 1, BUILTIN_VA_COPY,
- generic_builtin_parse_va_copy, generic_builtin_va_copy_to_icode },
- { "constant_p", sizeof "constant_p" - 1, BUILTIN_CONSTANT_P,
- generic_builtin_parse_constant_p, generic_builtin_constant_p_to_icode },
- { "memcpy", sizeof "memcpy" - 1, BUILTIN_MEMCPY,
- generic_builtin_parse_memcpy, generic_builtin_memcpy_or_memset_to_icode },
- { "memset", sizeof "memset" - 1, BUILTIN_MEMSET,
- generic_builtin_parse_memcpy, generic_builtin_memcpy_or_memset_to_icode },
- { "frame_address", sizeof "frame_address" - 1, BUILTIN_FRAME_ADDRESS,
- generic_builtin_parse_frame_address,
- generic_builtin_frame_address_to_icode },
- { "offsetof", sizeof "offsetof" - 1, BUILTIN_OFFSETOF,
- generic_builtin_parse_offsetof,
- generic_builtin_offsetof_to_icode },
- { "prefetch", sizeof "offsetof" - 1, 0, NULL, NULL },
- { NULL, 0, 0, NULL, NULL }
- };
- static struct vreg *
- mips_builtin_next_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- (void) fdat; (void) il; (void) eval;
- unimpl();
- return NULL;
- }
- /*
- * XXXXXXXXXX misses struct/union arguments!
- */
- static struct vreg *
- mips_builtin_va_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct vreg *valist_vr;
- struct vreg *vr;
- struct vreg *tmpvr;
- struct token *c;
- struct type *argtype = fdat->builtin->args[1];
- struct icode_instr *ii;
- int size;
- int intsize;
-
- /*
- * 08/22/07: Wow, this stuff used get_ident() and did not
- * generate icode for the first argument at all! Thus
- *
- * va_list *foo;
- * va_arg(*foo, type);
- *
- * ... didn't work because *foo was not loaded
- */
- valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
- if (valist_vr == NULL) {
- return NULL;
- } /* else {
- check type...
- } */
- if (eval) {
- vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
- if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
- && argtype->tlist == NULL) {
- unimpl();
- }
- }
-
- /* XXX from_ptr?? check for indirection chain!!??! */
- vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
- #if 0
- vr->type = fdat->builtin->args[1];
- vr->size = size = backend->get_sizeof_type(vr->type, NULL);
- #endif
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments (is_multi_reg_obj was not set!)
- */
- vreg_set_new_type(vr, fdat->builtin->args[1]);
- size = vr->size;
- if (!eval) {
- return vr;
- }
-
- #if 0
- vreg_faultin(NULL, NULL, vr, il, 0);
- #endif
- if ((argtype->code == TY_STRUCT || argtype->code == TY_UNION)
- && argtype->tlist == NULL) {
- /* Struct/union passed by value */
- #if 0
- vr = vreg_alloc(NULL, NULL, /*valist->vreg*/valist_vr, NULL);
- vr->type = fdat->builtin->args[1];
- vr->size = size = backend->get_sizeof_type(vr->type, NULL);
- #endif
- if (fdat->lvalue != NULL) {
- /* Result is assigned - copy */
- vreg_faultin_ptr(/*valist->vreg*/valist_vr, il);
- vreg_faultin_ptr(fdat->lvalue, il);
- /*
- * 07/21/08: invalidate_gprs() was missing
- * since copystruct will probably call memcpy()!
- */
- backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
- icode_make_copystruct(fdat->lvalue, vr, il);
- /*
- * 07/21/08: Invalidate va_list vreg for
- * offset addition below... Since memcpy
- * may have trashed it
- */
- free_preg(valist_vr->pregs[0], il, 1, 0);
- vr->struct_ret = 1;
- }
- } else {
- /*
- * Small arguments are passed as dwords.
- * XXX take fp into account!!
- * ... so let us load the dword, then just treat it as
- * the destination type
- */
- tmpvr = n_xmemdup(vr, sizeof *vr);
- if (!is_floating_type(vr->type)) {
- tmpvr->type = make_basic_type(TY_ULLONG);
- tmpvr->size = 8;
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- vreg_map_preg(vr, tmpvr->pregs[0]);
- vreg_anonymify(&vr, NULL, NULL, il);
- } else {
- tmpvr->type = make_basic_type(TY_DOUBLE);
- tmpvr->size = 8;
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- vreg_map_preg(vr, tmpvr->pregs[0]);
- vreg_anonymify(&vr, NULL, NULL, il);
- }
- }
- intsize = backend->
- get_sizeof_type(make_basic_type(TY_INT), NULL);
- if (size < intsize) {
- size = intsize;
- }
- if (size < 8) {
- /* Even small types are stored as dwords */
- size = 8;
- } else {
- /* 07/21/08: XXX handle struct alignment! */
- }
- c = const_from_value(&size, NULL);
- tmpvr = vreg_alloc(NULL, c, NULL, NULL);
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- vreg_faultin_protected(tmpvr, NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
- ii = icode_make_add(/*valist->vreg*/valist_vr, tmpvr);
- append_icode_list(il, ii);
- icode_make_store(curfunc, /*valist->vreg*/valist_vr,
- /*valist->vreg*/valist_vr, il);
- return vr;
- }
- static void
- get_member_vreg(struct decl *d, struct vreg **dest, struct vreg *parent) {
- struct vreg *vr;
- vr = vreg_alloc(NULL, NULL, NULL, d->dtype);
- vr->parent = parent;
- vr->memberdecl = d;
- vr->from_ptr = parent;
- *dest = vr;
- }
- static struct type *voidptr_type;
- static int
- calc_fp_start_offset(struct function *f) {
- struct sym_entry *se;
- int fp_regs_used = 0;
- for (se = f->scope->slist; se != NULL; se = se->next) {
- if (is_floating_type(se->dec->dtype)
- && se->dec->dtype->code != TY_LDOUBLE) {
- ++fp_regs_used;
- if (fp_regs_used == 8) {
- break;
- }
- }
- if (se->dec == f->proto->dtype->tlist->tfunc->lastarg) {
- break;
- }
- }
- return 48 + fp_regs_used * 8;
- }
- /*
- * typedef struct {
- * unsigned gp_offset;
- * unsigned fp_offset;
- * void *overflow_arg_area;
- * void *reg_save_area;
- * } va_list[1];
- *
- * - reg_save_area is recorded by fty->lastarg if some variadic args are
- * passed in registers
- * - if all variadic stuff is passed on the stack, lastarg points to the
- * beginning of the stack arguments
- * - if registers are used for arguments, fty->lastarg->stack_addr->from_reg
- * is non-null, and
- * (struct reg **)fty->lastarg->stack_addr->from_reg - amd64_argregs
- * is the number of gprs used, which, multiplied by 8, gives the gp_offset.
- * - XXX fp is UNIMPLEMENTED
- * phew ..
- */
- static struct vreg *
- amd64_builtin_va_start_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct type *ty;
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct vreg *valist_vr;
- struct sym_entry *se;
- struct icode_instr *ii;
- struct ty_func *fty;
- struct reg *r;
- struct decl *srcdec;
- struct vreg *srcvr;
- struct vreg *tempvr;
- struct amd64_va_patches *patches;
- static struct amd64_va_patches nullp;
- int fp_start_offset;
- if (eval) {
- patches = n_xmalloc(sizeof *patches);
- *patches = nullp;
- /* curfunc->patchme = patches;*/
- /*
- * 08/07/08: Allow for multiple va_start() per function
- * (oops)
- */
- patches->next = curfunc->patchme;
- curfunc->patchme = patches;
- }
- fty = curfunc->fty;
-
- valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
- if (valist_vr == NULL) {
- return NULL;
- }
- if (eval) {
- vreg_faultin(NULL, NULL, valist_vr, il, 0);
- }
- if (valist_vr->type->tlist == NULL
- || valist_vr->type->tlist->type != TN_POINTER_TO
- || valist_vr->type->tlist->next != NULL
- || valist_vr->type->code != TY_STRUCT
- || valist_vr->type->tstruc != builtin_va_list_type->tstruc) {
- errorfl(NULL /* XXX */, "Argument to va_start() has wrong "
- "type");
- return NULL;
- }
- if (!eval) {
- ty = make_basic_type(TY_VOID);
- vreg_set_new_type(vr, ty);
- return vr;
- }
- r = ALLOC_GPR(curfunc, 0, il, 0);
- se = valist_vr->type->tstruc->scope->slist;
- /* se = gp_offset */
- get_member_vreg(se->dec, &tempvr, valist_vr);
- ii = icode_make_setreg(r->composed_of[0], /*n*/0);
- append_icode_list(il, ii);
- patches->gp_offset = ii->dat;
- vreg_map_preg(tempvr, r->composed_of[0]);
- icode_make_store(curfunc, tempvr, tempvr, il);
- se = se->next;
- /* se = fp_offset */
- get_member_vreg(se->dec, &tempvr, valist_vr);
- /*
- * 07/31/08: Don't always begin at 48 (%xmm0), but also take non-
- * elliptic parameters into account, e.g. for
- *
- * void foo(double d, ...)
- *
- * ... set t the start offset to 48 + 1*8
- */
- fp_start_offset = calc_fp_start_offset(curfunc);
- ii = icode_make_setreg(r->composed_of[0], /*48*/ fp_start_offset); /* begins after gprs */
- append_icode_list(il, ii);
- patches->fp_offset = ii->dat;
- vreg_map_preg(tempvr, r->composed_of[0]);
- icode_make_store(curfunc, tempvr, tempvr, il);
- se = se->next;
- /* se = overflow_arg_area; */
- get_member_vreg(se->dec, &tempvr, valist_vr);
- srcdec = alloc_decl();
- /* XXX typing stuff is totally bogus?! untyped addres suffices?? */
- srcdec->dtype = voidptr_type;
- srcdec->stack_addr = make_stack_block(0, 8);
- patches->overflow_arg_area = srcdec->stack_addr;
- srcvr = vreg_alloc(srcdec, NULL, NULL, NULL);
- ii = icode_make_addrof(NULL, srcvr, il);
- append_icode_list(il, ii);
- vreg_map_preg(srcvr, ii->dat);
- icode_make_store(curfunc, srcvr, tempvr, il);
- free_preg(ii->dat, il, 0, 0);
- se = se->next;
- /* se = reg_save_area */
- get_member_vreg(se->dec, &tempvr, valist_vr);
- srcdec = alloc_decl();
- srcdec->dtype = voidptr_type;
- srcdec->stack_addr = make_stack_block(0, 8);
- patches->reg_save_area = srcdec->stack_addr;
- srcvr = vreg_alloc(srcdec, NULL, NULL, NULL);
- ii = icode_make_addrof(NULL, srcvr, il);
- append_icode_list(il, ii);
- vreg_map_preg(srcvr, ii->dat);
- icode_make_store(curfunc, srcvr, tempvr, il);
- free_preg(ii->dat, il, 0, 0);
- #if 0
- se->dec->stack_addr = make_stack_block(0, 8);
- patches->reg_save_area = se->dec->stack_addr;
- #endif
- ty = make_basic_type(TY_VOID);
- #if 0
- vr->type = ty;
- vr->size = 0;
- #endif
- /* 06/20/08: Use vreg_set_new_type() instead of ad-hoc assignments */
- vreg_set_new_type(vr, ty);
- free_preg(r, il, 0, 0);
- return vr;
- }
- static struct vreg *
- amd64_builtin_next_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct type *ty;
- struct vreg *vr = vreg_alloc(NULL, NULL, NULL, NULL);
- struct icode_instr *ii;
-
- (void) fdat;
- if (eval) {
- ii = icode_make_addrof(NULL, NULL, il);
- append_icode_list(il, ii);
-
- vreg_map_preg(vr, ii->dat);
- }
- ty = n_xmemdup(make_basic_type(TY_CHAR), sizeof *ty);
- ty->tlist = alloc_type_node();
- ty->tlist->type = TN_POINTER_TO;
- #if 0
- vr->type = ty;
- vr->size = backend->get_sizeof_type(ty, NULL);
- #endif
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments
- */
- vreg_set_new_type(vr, ty);
- return vr;
- }
- static struct vreg *
- amd64_builtin_va_arg_to_icode(
- struct fcall_data *fdat,
- struct icode_list *il,
- int eval) {
- struct vreg *valist_vr;
- struct vreg *vr;
- struct vreg *tmpvr;
- struct vreg *tempmembvr;
- struct vreg *pointer;
- struct vreg *limit_vreg;
- struct vreg *offset_vreg = NULL;
- struct token *c;
- struct icode_instr *ii;
- struct type *argtype = fdat->builtin->args[1];
- struct sym_entry *se;
- struct icode_instr *label;
- struct icode_instr *label2;
- struct token *fe_const;
- struct reg *r;
- long long_size;
- int size;
- int is_floating = 0;
- struct vreg *gp_offset_vreg;
- struct vreg *fp_offset_vreg;
- struct vreg *overflow_arg_area_vreg;
- struct vreg *reg_save_area_vreg;
- #define gp_offset se->dec
- #define fp_offset se->next->dec
- #define overflow_arg_area se->next->next->dec
- #define reg_save_area se->next->next->next->dec
- /*
- * 08/22/07: Wow, this stuff used get_ident() and did not
- * generate icode for the first argument at all! Thus
- *
- * va_list *foo;
- * va_arg(*foo, type);
- *
- * ... didn't work because *foo was not loaded
- */
- valist_vr = expr_to_icode(fdat->builtin->args[0], NULL, il, 0, 0, eval);
- if (valist_vr == NULL) {
- return NULL;
- } /* else {
- check type...
- } */
- pointer = vreg_alloc(NULL, NULL, NULL, voidptr_type);
- if (!eval) {
- vr = vreg_alloc(NULL, NULL, /*pointer,*/NULL, NULL);
- vr->from_ptr = pointer;
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments
- */
- vreg_set_new_type(vr, fdat->builtin->args[1]);
- return vr;
- }
- vreg_faultin(NULL, NULL, /*valist->vreg*/valist_vr, il, 0);
- #if 0
- /* Load va_list pointer into register */
- vreg_faultin(NULL, NULL, valist->vreg, il, 0);
- reg_set_unallocatable(valist->vreg->pregs[0]);
- #endif
- se = valist_vr->type->tstruc->scope->slist;
- /* All va_list members come from the va_list pointer */
- get_member_vreg(gp_offset, &tempmembvr, valist_vr);
- gp_offset_vreg = tempmembvr;
- get_member_vreg(fp_offset, &tempmembvr, valist_vr);
- fp_offset_vreg = tempmembvr;
- get_member_vreg(overflow_arg_area, &tempmembvr, valist_vr);
- overflow_arg_area_vreg = tempmembvr;
- get_member_vreg(reg_save_area, &tempmembvr, valist_vr);
- reg_save_area_vreg = tempmembvr;
- if ((argtype->code == TY_STRUCT
- || argtype->code == TY_UNION
- || argtype->code == TY_LDOUBLE)
- && argtype->tlist == NULL) {
- /* Struct/union/long double passed by value */
- struct vreg *oarea;
- vreg_faultin(NULL, NULL, overflow_arg_area_vreg, il, 0);
- oarea = vreg_disconnect(overflow_arg_area_vreg);
- oarea->type = n_xmemdup(argtype, sizeof *argtype);
- append_typelist(oarea->type, TN_POINTER_TO, 0, NULL, NULL);
- vr = vreg_alloc(NULL, NULL, NULL, NULL);
- vr->from_ptr = oarea;
- #if 0
- vr->type = argtype;
- vr->size = size = backend->get_sizeof_type(vr->type, NULL);
- #endif
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments
- */
- vreg_set_new_type(vr, argtype);
- size = vr->size;
- if (argtype->code == TY_LDOUBLE) {
- /*
- * 07/29/08: This used to unconditionally
- * anonymify, then fault-in the vreg. This is
- * wrong because it will cause two x87 FPR
- * loads (not quite sure why), which fills
- * up the register stack
- */
- vreg_anonymify(&vr, NULL, NULL, il);
- if (vr->pregs[0] == NULL
- || vr->pregs[0]->vreg != vr) {
- vreg_faultin_x87(NULL, NULL, vr, il, 0);
- }
- } else if (fdat->lvalue != NULL) {
- /* Result is assigned - copy */
- vreg_faultin_ptr(/*valist->vreg*/valist_vr, il);
- vreg_faultin_ptr(fdat->lvalue, il);
- /* Struct/union result */
- /*
- * 07/21/08: invalidate_gprs() was missing
- * since copystruct will probably call memcpy()!
- */
- backend->invalidate_gprs(il, 1, INV_FOR_FCALL);
- icode_make_copystruct(fdat->lvalue, vr, il);
- /*
- * 07/21/08: Invalidate va_list vreg for
- * offset addition below... Since memcpy
- * may have trashed it
- */
- free_preg(valist_vr->pregs[0], il, 1, 0);
- vr->struct_ret = 1;
- }
- while (size % 8) ++size;
- long_size = size;
- fe_const =
- const_from_value(&long_size, make_basic_type(TY_LONG));
- limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
- vreg_faultin_protected(oarea,
- NULL, NULL, limit_vreg, il, 0);
- ii = icode_make_add(oarea, limit_vreg);
- append_icode_list(il, ii);
- vreg_map_preg(overflow_arg_area_vreg, oarea->pregs[0]);
- icode_make_store(curfunc, overflow_arg_area_vreg,
- overflow_arg_area_vreg, il);
- return vr;
- } else if (argtype->tlist == NULL && IS_FLOATING(argtype->code)) {
- if (argtype->code == TY_LDOUBLE) {
- /* Passed on stack */
- } else {
- is_floating = 1;
- offset_vreg = fp_offset_vreg;
- long_size = 112; /* 48 gpr- + 64 fpr-bytes */
- }
- } else {
- offset_vreg = gp_offset_vreg;
- long_size = 48; /* 48 gpr bytes */
- }
- vreg_faultin(NULL, NULL, /*gp_offset->vreg*/offset_vreg, il, 0);
- fe_const = const_from_value(&long_size, make_basic_type(TY_LONG));
- limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
- vreg_faultin(NULL, NULL, limit_vreg, il, 0);
- ii = icode_make_cmp(/*gp_offset->vreg*/offset_vreg, limit_vreg);
- append_icode_list(il, ii);
- r = limit_vreg->pregs[0]; /* reuse register */
- label = icode_make_label(NULL);
- label2 = icode_make_label(NULL);
- ii = icode_make_branch(label, INSTR_BR_EQUAL, offset_vreg);
- append_icode_list(il, ii);
- /* offset is below 48 - use register save area */
- vreg_faultin(r, NULL, reg_save_area_vreg, il, 0);
- ii = icode_make_add(reg_save_area_vreg, offset_vreg);
- append_icode_list(il, ii);
- append_icode_list(il, icode_make_jump(label2));
- append_icode_list(il, label);
- /* offset is 48 - use overflow area */
- vreg_faultin(r, NULL, overflow_arg_area_vreg, il, 0);
- append_icode_list(il, label2);
- vreg_map_preg(pointer, r);
- reg_set_unallocatable(r);
- /* XXX from_ptr?? check for indirection chain!!??! */
- vr = vreg_alloc(NULL, NULL, /*pointer,*/NULL, NULL);
- vr->from_ptr = pointer;
- #if 0
- vr->type = fdat->builtin->args[1];
- vr->size = size = backend->get_sizeof_type(vr->type, NULL);
- #endif
- /*
- * 06/20/08: Use vreg_set_new_type() instead of ad-hoc
- * assignments
- */
- vreg_set_new_type(vr, fdat->builtin->args[1]);
- size = vr->size;
- vreg_faultin(NULL, NULL, vr, il, 0);
- vreg_anonymify(&vr, NULL, NULL, il);
- if (size < 8) {
- size = 8;
- }
- c = const_from_value(&size, NULL);
- tmpvr = vreg_alloc(NULL, c, NULL, NULL);
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- vreg_faultin(NULL, NULL, offset_vreg, il, 0);
- limit_vreg = vreg_alloc(NULL, fe_const, NULL, NULL);
- vreg_faultin(NULL, NULL, limit_vreg, il, 0);
- ii = icode_make_cmp(offset_vreg, limit_vreg);
- append_icode_list(il, ii);
- label = icode_make_label(NULL);
- label2 = icode_make_label(NULL);
- ii = icode_make_branch(label, INSTR_BR_EQUAL, offset_vreg);
- append_icode_list(il, ii);
- /* offset is below 48/112 - use register save area */
- vreg_faultin_protected(offset_vreg, NULL, NULL, tmpvr, il, 0);
- ii = icode_make_add(offset_vreg, tmpvr);
- append_icode_list(il, ii);
- icode_make_store(curfunc, offset_vreg, offset_vreg, il);
- append_icode_list(il, icode_make_jump(label2));
- append_icode_list(il, label);
- /* offset is 48/112 - use overflow area */
- vreg_faultin(NULL, NULL, overflow_arg_area_vreg, il, 0);
- vreg_faultin(NULL, NULL, tmpvr, il, 0);
- ii = icode_make_add(overflow_arg_area_vreg, tmpvr);
- append_icode_list(il, ii);
- icode_make_store(curfunc, overflow_arg_area_vreg,
- overflow_arg_area_vreg, il);
- append_icode_list(il, label2);
- free_preg(/*valist->vreg*/ valist_vr->pregs[0], il, 0, 0);
- free_preg(offset_vreg->pregs[0], il, 0, 0);
- free_preg(overflow_arg_area_vreg->pregs[0], il, 0, 0);
- free_preg(reg_save_area_vreg->pregs[0], il, 0, 0);
- free_preg(r, il, 0, 0);
- #undef gp_offset
- #undef fp_offset
- #undef overflow_arg_area
- #undef reg_save_area
- return vr;
- }
- static builtin_to_icode_func_t x86_icode_funcs[] = {
- x86_builtin_va_start_to_icode,
- x86_builtin_va_start_to_icode,
- x86_builtin_next_arg_to_icode,
- x86_builtin_va_end_to_icode,
- x86_builtin_va_arg_to_icode,
- NULL, /* expect */
- generic_builtin_alloca_to_icode,
- generic_builtin_va_copy_to_icode,
- generic_builtin_constant_p_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_frame_address_to_icode,
- generic_builtin_offsetof_to_icode
- };
- static builtin_to_icode_func_t mips_icode_funcs[] = {
- x86_builtin_va_start_to_icode,
- x86_builtin_va_start_to_icode,
- mips_builtin_next_arg_to_icode,
- x86_builtin_va_end_to_icode,
- mips_builtin_va_arg_to_icode,
- NULL, /* expect */
- generic_builtin_alloca_to_icode,
- generic_builtin_va_copy_to_icode,
- generic_builtin_constant_p_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_frame_address_to_icode,
- generic_builtin_offsetof_to_icode
- };
- static builtin_to_icode_func_t sparc_icode_funcs[] = {
- x86_builtin_va_start_to_icode,
- x86_builtin_va_start_to_icode,
- mips_builtin_next_arg_to_icode,
- x86_builtin_va_end_to_icode,
- mips_builtin_va_arg_to_icode,
- NULL, /* expect */
- generic_builtin_alloca_to_icode,
- generic_builtin_va_copy_to_icode,
- generic_builtin_constant_p_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_frame_address_to_icode,
- generic_builtin_offsetof_to_icode
- };
- static builtin_to_icode_func_t power_icode_funcs[] = {
- x86_builtin_va_start_to_icode,
- x86_builtin_va_start_to_icode,
- /*mips*/ x86_builtin_next_arg_to_icode,
- x86_builtin_va_end_to_icode,
- /*mips*/ x86_builtin_va_arg_to_icode,
- NULL, /* expect */
- generic_builtin_alloca_to_icode,
- generic_builtin_va_copy_to_icode,
- generic_builtin_constant_p_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_frame_address_to_icode,
- generic_builtin_offsetof_to_icode
- };
-
- static builtin_to_icode_func_t amd64_icode_funcs[] = {
- amd64_builtin_va_start_to_icode,
- amd64_builtin_va_start_to_icode,
- amd64_builtin_next_arg_to_icode,
- x86_builtin_va_end_to_icode,
- amd64_builtin_va_arg_to_icode,
- NULL, /* expect */
- generic_builtin_alloca_to_icode,
- generic_builtin_va_copy_to_icode,
- generic_builtin_constant_p_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_memcpy_or_memset_to_icode,
- generic_builtin_frame_address_to_icode,
- generic_builtin_offsetof_to_icode
- };
- /*
- * XXX the initialization below means that the ``builtins'' and
- * ``*_icode_funcs'' tables have to have the same ordering
- */
- static void
- init_builtin_functions(void) {
- builtin_to_icode_func_t *p = NULL;
- unsigned int i;
- if (backend->arch == ARCH_X86) {
- p = x86_icode_funcs;
- } else if (backend->arch == ARCH_AMD64) {
- p = amd64_icode_funcs;
- } else if (backend->arch == ARCH_MIPS) {
- p = mips_icode_funcs;
- } else if (backend->arch == ARCH_POWER) {
- p = power_icode_funcs;
- } else if (backend->arch == ARCH_SPARC) {
- p = sparc_icode_funcs;
- } else {
- unimpl();
- }
- for (i = 0; i < sizeof x86_icode_funcs /
- sizeof x86_icode_funcs[0]; ++i) {
- builtins[i].toicode = p[i];
- }
- }
- static struct builtin *
- lookup_builtin(const char *name) {
- size_t namelen = strlen(name);
- int i;
- /*
- * XXX test below is for alloca()
- */
- if (name[0] == '_') {
- name += sizeof "__builtin_" - 1;
- namelen -= sizeof "__builtin_" - 1;
- }
- for (i = 0; builtins[i].name != NULL; ++i) {
- if (builtins[i].namelen != namelen) {
- continue;
- }
- if (strcmp(builtins[i].name, name) == 0) {
- return &builtins[i];
- }
- }
- return NULL;
- }
- struct fcall_data *
- get_builtin(struct token **tok, struct token *nametok) {
- struct builtin *b;
- struct fcall_data *ret;
- sta…
Large files files are truncated, but you can click here to view the full file