| 1 | /* $Id: builtins.c,v 1.18.2.2 2011/03/29 15:56:24 ragge Exp $ */
|
|---|
| 2 | /*
|
|---|
| 3 | * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
|
|---|
| 4 | * All rights reserved.
|
|---|
| 5 | *
|
|---|
| 6 | * Redistribution and use in source and binary forms, with or without
|
|---|
| 7 | * modification, are permitted provided that the following conditions
|
|---|
| 8 | * are met:
|
|---|
| 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|---|
| 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|---|
| 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|---|
| 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|---|
| 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|---|
| 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|---|
| 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|---|
| 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|---|
| 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|---|
| 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|---|
| 25 | */
|
|---|
| 26 |
|
|---|
| 27 | # include "pass1.h"
|
|---|
| 28 |
|
|---|
| 29 | #ifndef MIN
|
|---|
| 30 | #define MIN(a,b) (((a)<(b))?(a):(b))
|
|---|
| 31 | #endif
|
|---|
| 32 | #ifndef MAX
|
|---|
| 33 | #define MAX(a,b) (((a)>(b))?(a):(b))
|
|---|
| 34 | #endif
|
|---|
| 35 |
|
|---|
| 36 | #ifndef NO_C_BUILTINS
|
|---|
| 37 | /*
|
|---|
| 38 | * replace an alloca function with direct allocation on stack.
|
|---|
| 39 | * return a destination temp node.
|
|---|
| 40 | */
|
|---|
| 41 | static NODE *
|
|---|
| 42 | builtin_alloca(NODE *f, NODE *a, TWORD rt)
|
|---|
| 43 | {
|
|---|
| 44 | struct symtab *sp;
|
|---|
| 45 | NODE *t, *u;
|
|---|
| 46 |
|
|---|
| 47 | #ifdef notyet
|
|---|
| 48 | if (xnobuiltins)
|
|---|
| 49 | return NULL;
|
|---|
| 50 | #endif
|
|---|
| 51 | sp = f->n_sp;
|
|---|
| 52 |
|
|---|
| 53 | t = tempnode(0, VOID|PTR, 0, MKAP(INT) /* XXX */);
|
|---|
| 54 | u = tempnode(regno(t), VOID|PTR, 0, MKAP(INT) /* XXX */);
|
|---|
| 55 | spalloc(t, a, SZCHAR);
|
|---|
| 56 | tfree(f);
|
|---|
| 57 | return u;
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | /*
|
|---|
| 61 | * See if there is a goto in the tree.
|
|---|
| 62 | * XXX this function is a hack for a flaw in handling of
|
|---|
| 63 | * compound expressions and inline functions and should not be
|
|---|
| 64 | * needed.
|
|---|
| 65 | */
|
|---|
| 66 | static int
|
|---|
| 67 | hasgoto(NODE *p)
|
|---|
| 68 | {
|
|---|
| 69 | int o = coptype(p->n_op);
|
|---|
| 70 |
|
|---|
| 71 | if (o == LTYPE)
|
|---|
| 72 | return 0;
|
|---|
| 73 | if (p->n_op == GOTO)
|
|---|
| 74 | return 1;
|
|---|
| 75 | if (o == UTYPE)
|
|---|
| 76 | return hasgoto(p->n_left);
|
|---|
| 77 | if (hasgoto(p->n_left))
|
|---|
| 78 | return 1;
|
|---|
| 79 | return hasgoto(p->n_right);
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | /*
|
|---|
| 83 | * Determine if a value is known to be constant at compile-time and
|
|---|
| 84 | * hence that PCC can perform constant-folding on expressions involving
|
|---|
| 85 | * that value.
|
|---|
| 86 | */
|
|---|
| 87 | static NODE *
|
|---|
| 88 | builtin_constant_p(NODE *f, NODE *a, TWORD rt)
|
|---|
| 89 | {
|
|---|
| 90 | void putjops(NODE *p, void *arg);
|
|---|
| 91 | int isconst;
|
|---|
| 92 |
|
|---|
| 93 | tfree(f);
|
|---|
| 94 | walkf(a, putjops, 0);
|
|---|
| 95 | for (f = a; f->n_op == COMOP; f = f->n_right)
|
|---|
| 96 | ;
|
|---|
| 97 | isconst = nncon(f);
|
|---|
| 98 | tfree(a);
|
|---|
| 99 | return bcon(isconst);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | /*
|
|---|
| 103 | * Hint to the compiler whether this expression will evaluate true or false.
|
|---|
| 104 | * Just ignored for now.
|
|---|
| 105 | */
|
|---|
| 106 | static NODE *
|
|---|
| 107 | builtin_expect(NODE *f, NODE *a, TWORD rt)
|
|---|
| 108 | {
|
|---|
| 109 |
|
|---|
| 110 | tfree(f);
|
|---|
| 111 | if (a && a->n_op == CM) {
|
|---|
| 112 | tfree(a->n_right);
|
|---|
| 113 | f = a->n_left;
|
|---|
| 114 | nfree(a);
|
|---|
| 115 | a = f;
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | return a;
|
|---|
| 119 | }
|
|---|
| 120 |
|
|---|
| 121 | /*
|
|---|
| 122 | * Take integer absolute value.
|
|---|
| 123 | * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
|
|---|
| 124 | */
|
|---|
| 125 | static NODE *
|
|---|
| 126 | builtin_abs(NODE *f, NODE *a, TWORD rt)
|
|---|
| 127 | {
|
|---|
| 128 | NODE *p, *q, *r, *t, *t2, *t3;
|
|---|
| 129 | int tmp1, tmp2, shift;
|
|---|
| 130 |
|
|---|
| 131 | if (a->n_type != INT)
|
|---|
| 132 | a = cast(a, INT, 0);
|
|---|
| 133 |
|
|---|
| 134 | tfree(f);
|
|---|
| 135 |
|
|---|
| 136 | if (a->n_op == ICON) {
|
|---|
| 137 | if (a->n_lval < 0)
|
|---|
| 138 | a->n_lval = -a->n_lval;
|
|---|
| 139 | p = a;
|
|---|
| 140 | } else {
|
|---|
| 141 | t = tempnode(0, a->n_type, a->n_df, a->n_ap);
|
|---|
| 142 | tmp1 = regno(t);
|
|---|
| 143 | p = buildtree(ASSIGN, t, a);
|
|---|
| 144 |
|
|---|
| 145 | t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
|
|---|
| 146 | shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1;
|
|---|
| 147 | q = buildtree(RS, t, bcon(shift));
|
|---|
| 148 |
|
|---|
| 149 | t2 = tempnode(0, a->n_type, a->n_df, a->n_ap);
|
|---|
| 150 | tmp2 = regno(t2);
|
|---|
| 151 | q = buildtree(ASSIGN, t2, q);
|
|---|
| 152 |
|
|---|
| 153 | t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
|
|---|
| 154 | t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
|
|---|
| 155 | t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
|
|---|
| 156 | r = buildtree(MINUS, buildtree(ER, t, t2), t3);
|
|---|
| 157 |
|
|---|
| 158 | p = buildtree(COMOP, p, buildtree(COMOP, q, r));
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | return p;
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | /*
|
|---|
| 165 | * Get size of object, if possible.
|
|---|
| 166 | * Currently does nothing,
|
|---|
| 167 | */
|
|---|
| 168 | static NODE *
|
|---|
| 169 | builtin_object_size(NODE *f, NODE *a, TWORD rt)
|
|---|
| 170 | {
|
|---|
| 171 | int v = icons(a->n_right);
|
|---|
| 172 | if (v < 0 || v > 3)
|
|---|
| 173 | uerror("arg2 must be between 0 and 3");
|
|---|
| 174 |
|
|---|
| 175 | tfree(f);
|
|---|
| 176 | f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, rt));
|
|---|
| 177 | nfree(a);
|
|---|
| 178 | return f;
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 | #ifndef TARGET_STDARGS
|
|---|
| 182 | static NODE *
|
|---|
| 183 | builtin_stdarg_start(NODE *f, NODE *a, TWORD rt)
|
|---|
| 184 | {
|
|---|
| 185 | NODE *p, *q;
|
|---|
| 186 | int sz;
|
|---|
| 187 |
|
|---|
| 188 | /* must first deal with argument size; use int size */
|
|---|
| 189 | p = a->n_right;
|
|---|
| 190 | if (p->n_type < INT) {
|
|---|
| 191 | sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap));
|
|---|
| 192 | } else
|
|---|
| 193 | sz = 1;
|
|---|
| 194 |
|
|---|
| 195 | /* do the real job */
|
|---|
| 196 | p = buildtree(ADDROF, p, NIL); /* address of last arg */
|
|---|
| 197 | #ifdef BACKAUTO
|
|---|
| 198 | p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
|
|---|
| 199 | #else
|
|---|
| 200 | p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
|
|---|
| 201 | #endif
|
|---|
| 202 | q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */
|
|---|
| 203 | q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
|
|---|
| 204 | p = q->n_right;
|
|---|
| 205 | nfree(q->n_left);
|
|---|
| 206 | nfree(q);
|
|---|
| 207 | p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
|
|---|
| 208 | tfree(f);
|
|---|
| 209 | nfree(a);
|
|---|
| 210 | return p;
|
|---|
| 211 | }
|
|---|
| 212 |
|
|---|
| 213 | static NODE *
|
|---|
| 214 | builtin_va_arg(NODE *f, NODE *a, TWORD rt)
|
|---|
| 215 | {
|
|---|
| 216 | NODE *p, *q, *r, *rv;
|
|---|
| 217 | int sz, nodnum;
|
|---|
| 218 |
|
|---|
| 219 | /* create a copy to a temp node of current ap */
|
|---|
| 220 | p = ccopy(a->n_left);
|
|---|
| 221 | q = tempnode(0, p->n_type, p->n_df, p->n_ap);
|
|---|
| 222 | nodnum = regno(q);
|
|---|
| 223 | rv = buildtree(ASSIGN, q, p);
|
|---|
| 224 |
|
|---|
| 225 | r = a->n_right;
|
|---|
| 226 | sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR;
|
|---|
| 227 | /* add one to ap */
|
|---|
| 228 | #ifdef BACKAUTO
|
|---|
| 229 | rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
|
|---|
| 230 | #else
|
|---|
| 231 | #error fix wrong eval order in builtin_va_arg
|
|---|
| 232 | ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
|
|---|
| 233 | #endif
|
|---|
| 234 |
|
|---|
| 235 | nfree(a->n_right);
|
|---|
| 236 | nfree(a);
|
|---|
| 237 | nfree(f);
|
|---|
| 238 | r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap);
|
|---|
| 239 | return buildtree(COMOP, rv, buildtree(UMUL, r, NIL));
|
|---|
| 240 |
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | static NODE *
|
|---|
| 244 | builtin_va_end(NODE *f, NODE *a, TWORD rt)
|
|---|
| 245 | {
|
|---|
| 246 | tfree(f);
|
|---|
| 247 | tfree(a);
|
|---|
| 248 | return bcon(0); /* nothing */
|
|---|
| 249 | }
|
|---|
| 250 |
|
|---|
| 251 | static NODE *
|
|---|
| 252 | builtin_va_copy(NODE *f, NODE *a, TWORD rt)
|
|---|
| 253 | {
|
|---|
| 254 | tfree(f);
|
|---|
| 255 | f = buildtree(ASSIGN, a->n_left, a->n_right);
|
|---|
| 256 | nfree(a);
|
|---|
| 257 | return f;
|
|---|
| 258 | }
|
|---|
| 259 | #endif /* TARGET_STDARGS */
|
|---|
| 260 |
|
|---|
| 261 | /*
|
|---|
| 262 | * For unimplemented "builtin" functions, try to invoke the
|
|---|
| 263 | * non-builtin name
|
|---|
| 264 | */
|
|---|
| 265 | static NODE *
|
|---|
| 266 | binhelp(NODE *f, NODE *a, TWORD rt, char *n)
|
|---|
| 267 | {
|
|---|
| 268 | f->n_sp = lookup(addname(n), SNORMAL);
|
|---|
| 269 | if (f->n_sp->sclass == SNULL) {
|
|---|
| 270 | f->n_sp->sclass = EXTERN;
|
|---|
| 271 | f->n_sp->stype = INCREF(rt)+(FTN-PTR);
|
|---|
| 272 | }
|
|---|
| 273 | f->n_type = f->n_sp->stype;
|
|---|
| 274 | f = clocal(f);
|
|---|
| 275 | return buildtree(CALL, f, a);
|
|---|
| 276 | }
|
|---|
| 277 |
|
|---|
| 278 | static NODE *
|
|---|
| 279 | builtin_unimp(NODE *f, NODE *a, TWORD rt)
|
|---|
| 280 | {
|
|---|
| 281 | char *n = f->n_sp->sname;
|
|---|
| 282 |
|
|---|
| 283 | if (strncmp("__builtin_", n, 10) == 0)
|
|---|
| 284 | n += 10;
|
|---|
| 285 | return binhelp(f, a, rt, n);
|
|---|
| 286 | }
|
|---|
| 287 |
|
|---|
| 288 | static NODE *
|
|---|
| 289 | builtin_unimp_f(NODE *f, NODE *a, TWORD rt)
|
|---|
| 290 | {
|
|---|
| 291 | return binhelp(f, a, rt, f->n_sp->sname);
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | #ifndef TARGET_ISMATH
|
|---|
| 295 | /*
|
|---|
| 296 | * Handle the builtin macros for the math functions is*
|
|---|
| 297 | * To get something that is be somewhat generic assume that
|
|---|
| 298 | * isnan() is a real function and that cast of a NaN type
|
|---|
| 299 | * to double will still be a NaN.
|
|---|
| 300 | */
|
|---|
| 301 | static NODE *
|
|---|
| 302 | mtisnan(NODE *p)
|
|---|
| 303 | {
|
|---|
| 304 | NODE *q = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
|
|---|
| 305 |
|
|---|
| 306 | return binhelp(q, cast(ccopy(p), DOUBLE, 0), INT, "isnan");
|
|---|
| 307 | }
|
|---|
| 308 |
|
|---|
| 309 | static TWORD
|
|---|
| 310 | mtcheck(NODE *p)
|
|---|
| 311 | {
|
|---|
| 312 | TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type;
|
|---|
| 313 |
|
|---|
| 314 | if ((t1 >= FLOAT && t1 <= LDOUBLE) ||
|
|---|
| 315 | (t2 >= FLOAT && t2 <= LDOUBLE))
|
|---|
| 316 | return MAX(t1, t2);
|
|---|
| 317 | return 0;
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | static NODE *
|
|---|
| 321 | builtin_isunordered(NODE *f, NODE *a, TWORD rt)
|
|---|
| 322 | {
|
|---|
| 323 | NODE *p;
|
|---|
| 324 |
|
|---|
| 325 | if (mtcheck(a) == 0)
|
|---|
| 326 | return bcon(0);
|
|---|
| 327 |
|
|---|
| 328 | p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
|
|---|
| 329 | tfree(f);
|
|---|
| 330 | tfree(a);
|
|---|
| 331 | return p;
|
|---|
| 332 | }
|
|---|
| 333 | static NODE *
|
|---|
| 334 | builtin_isany(NODE *f, NODE *a, TWORD rt, int cmpt)
|
|---|
| 335 | {
|
|---|
| 336 | NODE *p, *q;
|
|---|
| 337 | TWORD t;
|
|---|
| 338 |
|
|---|
| 339 | if ((t = mtcheck(a)) == 0)
|
|---|
| 340 | return bcon(0);
|
|---|
| 341 | p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
|
|---|
| 342 | p = buildtree(NOT, p, NIL);
|
|---|
| 343 | q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0),
|
|---|
| 344 | cast(ccopy(a->n_right), t, 0));
|
|---|
| 345 | p = buildtree(ANDAND, p, q);
|
|---|
| 346 | tfree(f);
|
|---|
| 347 | tfree(a);
|
|---|
| 348 | return p;
|
|---|
| 349 | }
|
|---|
| 350 | static NODE *
|
|---|
| 351 | builtin_isgreater(NODE *f, NODE *a, TWORD rt)
|
|---|
| 352 | {
|
|---|
| 353 | return builtin_isany(f, a, rt, GT);
|
|---|
| 354 | }
|
|---|
| 355 | static NODE *
|
|---|
| 356 | builtin_isgreaterequal(NODE *f, NODE *a, TWORD rt)
|
|---|
| 357 | {
|
|---|
| 358 | return builtin_isany(f, a, rt, GE);
|
|---|
| 359 | }
|
|---|
| 360 | static NODE *
|
|---|
| 361 | builtin_isless(NODE *f, NODE *a, TWORD rt)
|
|---|
| 362 | {
|
|---|
| 363 | return builtin_isany(f, a, rt, LT);
|
|---|
| 364 | }
|
|---|
| 365 | static NODE *
|
|---|
| 366 | builtin_islessequal(NODE *f, NODE *a, TWORD rt)
|
|---|
| 367 | {
|
|---|
| 368 | return builtin_isany(f, a, rt, LE);
|
|---|
| 369 | }
|
|---|
| 370 | static NODE *
|
|---|
| 371 | builtin_islessgreater(NODE *f, NODE *a, TWORD rt)
|
|---|
| 372 | {
|
|---|
| 373 | NODE *p, *q, *r;
|
|---|
| 374 | TWORD t;
|
|---|
| 375 |
|
|---|
| 376 | if ((t = mtcheck(a)) == 0)
|
|---|
| 377 | return bcon(0);
|
|---|
| 378 | p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
|
|---|
| 379 | p = buildtree(NOT, p, NIL);
|
|---|
| 380 | q = buildtree(GT, cast(ccopy(a->n_left), t, 0),
|
|---|
| 381 | cast(ccopy(a->n_right), t, 0));
|
|---|
| 382 | r = buildtree(LT, cast(ccopy(a->n_left), t, 0),
|
|---|
| 383 | cast(ccopy(a->n_right), t, 0));
|
|---|
| 384 | q = buildtree(OROR, q, r);
|
|---|
| 385 | p = buildtree(ANDAND, p, q);
|
|---|
| 386 | tfree(f);
|
|---|
| 387 | tfree(a);
|
|---|
| 388 | return p;
|
|---|
| 389 | }
|
|---|
| 390 | #endif
|
|---|
| 391 |
|
|---|
| 392 | /*
|
|---|
| 393 | * Math-specific builtins that expands to constants.
|
|---|
| 394 | * Versins here is for IEEE FP, vax needs its own versions.
|
|---|
| 395 | */
|
|---|
| 396 | #ifdef RTOLBYTES
|
|---|
| 397 | static char vFLOAT[] = { 0, 0, 0x80, 0x7f };
|
|---|
| 398 | static char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
|
|---|
| 399 | #ifdef LDBL_128
|
|---|
| 400 | static char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
|
|---|
| 401 | #else /* LDBL_80 */
|
|---|
| 402 | static char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
|
|---|
| 403 | #endif
|
|---|
| 404 | static char nFLOAT[] = { 0, 0, 0xc0, 0x7f };
|
|---|
| 405 | static char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
|
|---|
| 406 | #ifdef LDBL_128
|
|---|
| 407 | static char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
|
|---|
| 408 | #else /* LDBL_80 */
|
|---|
| 409 | static char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 };
|
|---|
| 410 | #endif
|
|---|
| 411 | #else
|
|---|
| 412 | static char vFLOAT[] = { 0x7f, 0x80, 0, 0 };
|
|---|
| 413 | static char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
|
|---|
| 414 | #ifdef LDBL_128
|
|---|
| 415 | static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
|
|---|
| 416 | #else /* LDBL_80 */
|
|---|
| 417 | static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 };
|
|---|
| 418 | #endif
|
|---|
| 419 | static char nFLOAT[] = { 0x7f, 0xc0, 0, 0 };
|
|---|
| 420 | static char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
|
|---|
| 421 | #ifdef LDBL_128
|
|---|
| 422 | static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
|
|---|
| 423 | #else /* LDBL_80 */
|
|---|
| 424 | static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 };
|
|---|
| 425 | #endif
|
|---|
| 426 | #endif
|
|---|
| 427 |
|
|---|
| 428 | #define VALX(typ,TYP) { \
|
|---|
| 429 | typ d; \
|
|---|
| 430 | int x; \
|
|---|
| 431 | x = MIN(sizeof(n ## TYP), sizeof(d)); \
|
|---|
| 432 | memcpy(&d, v ## TYP, x); \
|
|---|
| 433 | nfree(f); \
|
|---|
| 434 | f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP)); \
|
|---|
| 435 | f->n_dcon = d; \
|
|---|
| 436 | return f; \
|
|---|
| 437 | }
|
|---|
| 438 |
|
|---|
| 439 | static NODE *
|
|---|
| 440 | builtin_huge_valf(NODE *f, NODE *a, TWORD rt) VALX(float,FLOAT)
|
|---|
| 441 | static NODE *
|
|---|
| 442 | builtin_huge_val(NODE *f, NODE *a, TWORD rt) VALX(double,DOUBLE)
|
|---|
| 443 | static NODE *
|
|---|
| 444 | builtin_huge_vall(NODE *f, NODE *a, TWORD rt) VALX(long double,LDOUBLE)
|
|---|
| 445 |
|
|---|
| 446 | #define builtin_inff builtin_huge_valf
|
|---|
| 447 | #define builtin_inf builtin_huge_val
|
|---|
| 448 | #define builtin_infl builtin_huge_vall
|
|---|
| 449 |
|
|---|
| 450 | #define NANX(typ,TYP) { \
|
|---|
| 451 | typ d; \
|
|---|
| 452 | int x; \
|
|---|
| 453 | if ((a->n_op == ICON && a->n_sp && a->n_sp->sname[0] == '\0') ||\
|
|---|
| 454 | (a->n_op == ADDROF && a->n_left->n_op == NAME && \
|
|---|
| 455 | a->n_left->n_sp && a->n_left->n_sp->sname[0] == '\0')) { \
|
|---|
| 456 | x = MIN(sizeof(n ## TYP), sizeof(d)); \
|
|---|
| 457 | memcpy(&d, n ## TYP, x); \
|
|---|
| 458 | tfree(a); tfree(f); \
|
|---|
| 459 | f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP)); \
|
|---|
| 460 | f->n_dcon = d; \
|
|---|
| 461 | return f; \
|
|---|
| 462 | } \
|
|---|
| 463 | return buildtree(CALL, f, a); \
|
|---|
| 464 | }
|
|---|
| 465 |
|
|---|
| 466 | /*
|
|---|
| 467 | * Return NANs, if reasonable.
|
|---|
| 468 | */
|
|---|
| 469 | static NODE *
|
|---|
| 470 | builtin_nanf(NODE *f, NODE *a, TWORD rt) NANX(float,FLOAT)
|
|---|
| 471 | static NODE *
|
|---|
| 472 | builtin_nan(NODE *f, NODE *a, TWORD rt) NANX(double,DOUBLE)
|
|---|
| 473 | static NODE *
|
|---|
| 474 | builtin_nanl(NODE *f, NODE *a, TWORD rt) NANX(long double,LDOUBLE)
|
|---|
| 475 |
|
|---|
| 476 | /*
|
|---|
| 477 | * Target defines, to implement target versions of the generic builtins
|
|---|
| 478 | */
|
|---|
| 479 | #ifndef TARGET_MEMCMP
|
|---|
| 480 | #define builtin_memcmp builtin_unimp
|
|---|
| 481 | #endif
|
|---|
| 482 | #ifndef TARGET_MEMCPY
|
|---|
| 483 | #define builtin_memcpy builtin_unimp
|
|---|
| 484 | #endif
|
|---|
| 485 | #ifndef TARGET_MEMSET
|
|---|
| 486 | #define builtin_memset builtin_unimp
|
|---|
| 487 | #endif
|
|---|
| 488 |
|
|---|
| 489 | /* Reasonable type of size_t */
|
|---|
| 490 | #ifndef SIZET
|
|---|
| 491 | #if SZINT == SZSHORT
|
|---|
| 492 | #define SIZET UNSIGNED
|
|---|
| 493 | #elif SZLONG > SZINT
|
|---|
| 494 | #define SIZET ULONG
|
|---|
| 495 | #else
|
|---|
| 496 | #define SIZET UNSIGNED
|
|---|
| 497 | #endif
|
|---|
| 498 | #endif
|
|---|
| 499 |
|
|---|
| 500 | static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT };
|
|---|
| 501 | static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT };
|
|---|
| 502 | static TWORD allocat[] = { SIZET };
|
|---|
| 503 | static TWORD expectt[] = { LONG, LONG };
|
|---|
| 504 | static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR };
|
|---|
| 505 | static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT };
|
|---|
| 506 | static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT };
|
|---|
| 507 | static TWORD strchrt[] = { CHAR|PTR, INT };
|
|---|
| 508 | static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR };
|
|---|
| 509 | static TWORD nant[] = { CHAR|PTR };
|
|---|
| 510 | static TWORD bitt[] = { UNSIGNED };
|
|---|
| 511 | static TWORD bitlt[] = { ULONG };
|
|---|
| 512 | static TWORD ffst[] = { INT };
|
|---|
| 513 |
|
|---|
| 514 | static const struct bitable {
|
|---|
| 515 | char *name;
|
|---|
| 516 | NODE *(*fun)(NODE *f, NODE *a, TWORD);
|
|---|
| 517 | int narg;
|
|---|
| 518 | TWORD *tp;
|
|---|
| 519 | TWORD rt;
|
|---|
| 520 | } bitable[] = {
|
|---|
| 521 | { "__builtin___memcpy_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
|
|---|
| 522 | { "__builtin___memmove_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
|
|---|
| 523 | { "__builtin___memset_chk", builtin_unimp, 4, memsett, VOID|PTR },
|
|---|
| 524 |
|
|---|
| 525 | { "__builtin___strcat_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
|
|---|
| 526 | { "__builtin___strcpy_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
|
|---|
| 527 | { "__builtin___strncat_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
|
|---|
| 528 | { "__builtin___strncpy_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
|
|---|
| 529 |
|
|---|
| 530 | { "__builtin___printf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 531 | { "__builtin___fprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 532 | { "__builtin___sprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 533 | { "__builtin___snprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 534 | { "__builtin___vprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 535 | { "__builtin___vfprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 536 | { "__builtin___vsprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 537 | { "__builtin___vsnprintf_chk", builtin_unimp, -1, 0, INT },
|
|---|
| 538 |
|
|---|
| 539 | { "__builtin_alloca", builtin_alloca, 1, allocat },
|
|---|
| 540 | { "__builtin_abs", builtin_abs, 1 },
|
|---|
| 541 | { "__builtin_clz", builtin_unimp_f, 1, bitt, INT },
|
|---|
| 542 | { "__builtin_ctz", builtin_unimp_f, 1, bitt, INT },
|
|---|
| 543 | { "__builtin_clzl", builtin_unimp_f, 1, bitlt, INT },
|
|---|
| 544 | { "__builtin_ctzl", builtin_unimp_f, 1, bitlt, INT },
|
|---|
| 545 | { "__builtin_ffs", builtin_unimp, 1, ffst, INT },
|
|---|
| 546 |
|
|---|
| 547 | { "__builtin_constant_p", builtin_constant_p, 1 },
|
|---|
| 548 | { "__builtin_expect", builtin_expect, 2, expectt },
|
|---|
| 549 | { "__builtin_memcmp", builtin_memcmp, 3, memcpyt, INT },
|
|---|
| 550 | { "__builtin_memcpy", builtin_memcpy, 3, memcpyt, VOID|PTR },
|
|---|
| 551 | { "__builtin_memset", builtin_memset, 3, memsett, VOID|PTR },
|
|---|
| 552 | { "__builtin_huge_valf", builtin_huge_valf, 0 },
|
|---|
| 553 | { "__builtin_huge_val", builtin_huge_val, 0 },
|
|---|
| 554 | { "__builtin_huge_vall", builtin_huge_vall, 0 },
|
|---|
| 555 | { "__builtin_inff", builtin_inff, 0 },
|
|---|
| 556 | { "__builtin_inf", builtin_inf, 0 },
|
|---|
| 557 | { "__builtin_infl", builtin_infl, 0 },
|
|---|
| 558 | { "__builtin_isgreater", builtin_isgreater, 2, NULL, INT },
|
|---|
| 559 | { "__builtin_isgreaterequal", builtin_isgreaterequal, 2, NULL, INT },
|
|---|
| 560 | { "__builtin_isless", builtin_isless, 2, NULL, INT },
|
|---|
| 561 | { "__builtin_islessequal", builtin_islessequal, 2, NULL, INT },
|
|---|
| 562 | { "__builtin_islessgreater", builtin_islessgreater, 2, NULL, INT },
|
|---|
| 563 | { "__builtin_isunordered", builtin_isunordered, 2, NULL, INT },
|
|---|
| 564 | { "__builtin_nanf", builtin_nanf, 1, nant, FLOAT },
|
|---|
| 565 | { "__builtin_nan", builtin_nan, 1, nant, DOUBLE },
|
|---|
| 566 | { "__builtin_nanl", builtin_nanl, 1, nant, LDOUBLE },
|
|---|
| 567 | { "__builtin_object_size", builtin_object_size, 2, memsett, SIZET },
|
|---|
| 568 | { "__builtin_strcmp", builtin_unimp, 2, strcmpt, INT },
|
|---|
| 569 | { "__builtin_strcpy", builtin_unimp, 2, strcmpt, CHAR|PTR },
|
|---|
| 570 | { "__builtin_strchr", builtin_unimp, 2, strchrt, CHAR|PTR },
|
|---|
| 571 | { "__builtin_strlen", builtin_unimp, 1, strcmpt, SIZET },
|
|---|
| 572 | { "__builtin_strrchr", builtin_unimp, 2, strchrt, CHAR|PTR },
|
|---|
| 573 | { "__builtin_strncpy", builtin_unimp, 3, strncpyt, CHAR|PTR },
|
|---|
| 574 | { "__builtin_strncat", builtin_unimp, 3, strncpyt, CHAR|PTR },
|
|---|
| 575 | { "__builtin_strcspn", builtin_unimp, 2, strcspnt, SIZET },
|
|---|
| 576 | #ifndef TARGET_STDARGS
|
|---|
| 577 | { "__builtin_stdarg_start", builtin_stdarg_start, 2 },
|
|---|
| 578 | { "__builtin_va_start", builtin_stdarg_start, 2 },
|
|---|
| 579 | { "__builtin_va_arg", builtin_va_arg, 2 },
|
|---|
| 580 | { "__builtin_va_end", builtin_va_end, 1 },
|
|---|
| 581 | { "__builtin_va_copy", builtin_va_copy, 2 },
|
|---|
| 582 | #endif
|
|---|
| 583 | #ifdef TARGET_BUILTINS
|
|---|
| 584 | TARGET_BUILTINS
|
|---|
| 585 | #endif
|
|---|
| 586 | };
|
|---|
| 587 |
|
|---|
| 588 | /*
|
|---|
| 589 | * Check and cast arguments for builtins.
|
|---|
| 590 | */
|
|---|
| 591 | static int
|
|---|
| 592 | acnt(NODE *a, int narg, TWORD *tp)
|
|---|
| 593 | {
|
|---|
| 594 | NODE *q;
|
|---|
| 595 | TWORD t;
|
|---|
| 596 |
|
|---|
| 597 | if (a == NIL)
|
|---|
| 598 | return narg;
|
|---|
| 599 | for (; a->n_op == CM; a = a->n_left, narg--) {
|
|---|
| 600 | if (tp == NULL)
|
|---|
| 601 | continue;
|
|---|
| 602 | q = a->n_right;
|
|---|
| 603 | t = tp[narg-1];
|
|---|
| 604 | if (q->n_type == t)
|
|---|
| 605 | continue;
|
|---|
| 606 | a->n_right = ccast(q, t, 0, NULL, MKAP(BTYPE(t)));
|
|---|
| 607 | }
|
|---|
| 608 |
|
|---|
| 609 | /* Last arg is ugly to deal with */
|
|---|
| 610 | if (narg == 1 && tp != NULL) {
|
|---|
| 611 | q = talloc();
|
|---|
| 612 | *q = *a;
|
|---|
| 613 | q = ccast(q, tp[0], 0, NULL, MKAP(BTYPE(tp[0])));
|
|---|
| 614 | *a = *q;
|
|---|
| 615 | nfree(q);
|
|---|
| 616 | }
|
|---|
| 617 | return narg != 1;
|
|---|
| 618 | }
|
|---|
| 619 |
|
|---|
| 620 | NODE *
|
|---|
| 621 | builtin_check(NODE *f, NODE *a)
|
|---|
| 622 | {
|
|---|
| 623 | const struct bitable *bt;
|
|---|
| 624 | int i;
|
|---|
| 625 |
|
|---|
| 626 | for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
|
|---|
| 627 | bt = &bitable[i];
|
|---|
| 628 | if (strcmp(bt->name, f->n_sp->sname))
|
|---|
| 629 | continue;
|
|---|
| 630 | if (bt->narg >= 0 && acnt(a, bt->narg, bt->tp)) {
|
|---|
| 631 | uerror("wrong argument count to %s", bt->name);
|
|---|
| 632 | return bcon(0);
|
|---|
| 633 | }
|
|---|
| 634 | return (*bt->fun)(f, a, bt->rt);
|
|---|
| 635 | }
|
|---|
| 636 | return NIL;
|
|---|
| 637 | }
|
|---|
| 638 | #endif
|
|---|