| // Inferno utils/cc/com64.c |
| // http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c |
| // |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
| // Portions Copyright © 1997-1999 Vita Nuova Limited |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) |
| // Portions Copyright © 2004,2006 Bruce Ellis |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| #include <u.h> |
| #include "cc.h" |
| |
| /* |
| * this is machine depend, but it is totally |
| * common on all of the 64-bit symulating machines. |
| */ |
| |
| #define FNX 100 /* botch -- redefinition */ |
| |
| Node* nodaddv; |
| Node* nodsubv; |
| Node* nodmulv; |
| Node* noddivv; |
| Node* noddivvu; |
| Node* nodmodv; |
| Node* nodmodvu; |
| Node* nodlshv; |
| Node* nodrshav; |
| Node* nodrshlv; |
| Node* nodandv; |
| Node* nodorv; |
| Node* nodxorv; |
| Node* nodnegv; |
| Node* nodcomv; |
| |
| Node* nodtestv; |
| Node* nodeqv; |
| Node* nodnev; |
| Node* nodlev; |
| Node* nodltv; |
| Node* nodgev; |
| Node* nodgtv; |
| Node* nodhiv; |
| Node* nodhsv; |
| Node* nodlov; |
| Node* nodlsv; |
| |
| Node* nodf2v; |
| Node* nodd2v; |
| Node* nodp2v; |
| Node* nodsi2v; |
| Node* nodui2v; |
| Node* nodsl2v; |
| Node* nodul2v; |
| Node* nodsh2v; |
| Node* noduh2v; |
| Node* nodsc2v; |
| Node* noduc2v; |
| |
| Node* nodv2f; |
| Node* nodv2d; |
| Node* nodv2ui; |
| Node* nodv2si; |
| Node* nodv2ul; |
| Node* nodv2sl; |
| Node* nodv2uh; |
| Node* nodv2sh; |
| Node* nodv2uc; |
| Node* nodv2sc; |
| |
| Node* nodvpp; |
| Node* nodppv; |
| Node* nodvmm; |
| Node* nodmmv; |
| |
| Node* nodvasop; |
| |
| char etconv[NALLTYPES]; /* for _vasop */ |
| Init initetconv[] = |
| { |
| TCHAR, 1, 0, |
| TUCHAR, 2, 0, |
| TSHORT, 3, 0, |
| TUSHORT, 4, 0, |
| TLONG, 5, 0, |
| TULONG, 6, 0, |
| TVLONG, 7, 0, |
| TUVLONG, 8, 0, |
| TINT, 9, 0, |
| TUINT, 10, 0, |
| -1, 0, 0, |
| }; |
| |
| Node* |
| fvn(char *name, int type) |
| { |
| Node *n; |
| |
| n = new(ONAME, Z, Z); |
| n->sym = slookup(name); |
| n->sym->sig = SIGINTERN; |
| if(fntypes[type] == 0) |
| fntypes[type] = typ(TFUNC, types[type]); |
| n->type = fntypes[type]; |
| n->etype = type; |
| n->class = CGLOBL; |
| n->addable = 10; |
| n->complex = 0; |
| return n; |
| } |
| |
| void |
| com64init(void) |
| { |
| Init *p; |
| |
| nodaddv = fvn("_addv", TVLONG); |
| nodsubv = fvn("_subv", TVLONG); |
| nodmulv = fvn("_mulv", TVLONG); |
| noddivv = fvn("_divv", TVLONG); |
| noddivvu = fvn("_divvu", TVLONG); |
| nodmodv = fvn("_modv", TVLONG); |
| nodmodvu = fvn("_modvu", TVLONG); |
| nodlshv = fvn("_lshv", TVLONG); |
| nodrshav = fvn("_rshav", TVLONG); |
| nodrshlv = fvn("_rshlv", TVLONG); |
| nodandv = fvn("_andv", TVLONG); |
| nodorv = fvn("_orv", TVLONG); |
| nodxorv = fvn("_xorv", TVLONG); |
| nodnegv = fvn("_negv", TVLONG); |
| nodcomv = fvn("_comv", TVLONG); |
| |
| nodtestv = fvn("_testv", TLONG); |
| nodeqv = fvn("_eqv", TLONG); |
| nodnev = fvn("_nev", TLONG); |
| nodlev = fvn("_lev", TLONG); |
| nodltv = fvn("_ltv", TLONG); |
| nodgev = fvn("_gev", TLONG); |
| nodgtv = fvn("_gtv", TLONG); |
| nodhiv = fvn("_hiv", TLONG); |
| nodhsv = fvn("_hsv", TLONG); |
| nodlov = fvn("_lov", TLONG); |
| nodlsv = fvn("_lsv", TLONG); |
| |
| nodf2v = fvn("_f2v", TVLONG); |
| nodd2v = fvn("_d2v", TVLONG); |
| nodp2v = fvn("_p2v", TVLONG); |
| nodsi2v = fvn("_si2v", TVLONG); |
| nodui2v = fvn("_ui2v", TVLONG); |
| nodsl2v = fvn("_sl2v", TVLONG); |
| nodul2v = fvn("_ul2v", TVLONG); |
| nodsh2v = fvn("_sh2v", TVLONG); |
| noduh2v = fvn("_uh2v", TVLONG); |
| nodsc2v = fvn("_sc2v", TVLONG); |
| noduc2v = fvn("_uc2v", TVLONG); |
| |
| nodv2f = fvn("_v2f", TFLOAT); |
| nodv2d = fvn("_v2d", TDOUBLE); |
| nodv2sl = fvn("_v2sl", TLONG); |
| nodv2ul = fvn("_v2ul", TULONG); |
| nodv2si = fvn("_v2si", TINT); |
| nodv2ui = fvn("_v2ui", TUINT); |
| nodv2sh = fvn("_v2sh", TSHORT); |
| nodv2uh = fvn("_v2ul", TUSHORT); |
| nodv2sc = fvn("_v2sc", TCHAR); |
| nodv2uc = fvn("_v2uc", TUCHAR); |
| |
| nodvpp = fvn("_vpp", TVLONG); |
| nodppv = fvn("_ppv", TVLONG); |
| nodvmm = fvn("_vmm", TVLONG); |
| nodmmv = fvn("_mmv", TVLONG); |
| |
| nodvasop = fvn("_vasop", TVLONG); |
| |
| for(p = initetconv; p->code >= 0; p++) |
| etconv[p->code] = p->value; |
| } |
| |
| int |
| com64(Node *n) |
| { |
| Node *l, *r, *a, *t; |
| int lv, rv; |
| |
| if(n->type == 0) |
| return 0; |
| |
| l = n->left; |
| r = n->right; |
| |
| lv = 0; |
| if(l && l->type && typev[l->type->etype]) |
| lv = 1; |
| rv = 0; |
| if(r && r->type && typev[r->type->etype]) |
| rv = 1; |
| |
| if(lv) { |
| switch(n->op) { |
| case OEQ: |
| a = nodeqv; |
| goto setbool; |
| case ONE: |
| a = nodnev; |
| goto setbool; |
| case OLE: |
| a = nodlev; |
| goto setbool; |
| case OLT: |
| a = nodltv; |
| goto setbool; |
| case OGE: |
| a = nodgev; |
| goto setbool; |
| case OGT: |
| a = nodgtv; |
| goto setbool; |
| case OHI: |
| a = nodhiv; |
| goto setbool; |
| case OHS: |
| a = nodhsv; |
| goto setbool; |
| case OLO: |
| a = nodlov; |
| goto setbool; |
| case OLS: |
| a = nodlsv; |
| goto setbool; |
| |
| case OANDAND: |
| case OOROR: |
| if(machcap(n)) |
| return 1; |
| |
| if(rv) { |
| r = new(OFUNC, nodtestv, r); |
| n->right = r; |
| r->complex = FNX; |
| r->op = OFUNC; |
| r->type = types[TLONG]; |
| } |
| |
| case OCOND: |
| case ONOT: |
| if(machcap(n)) |
| return 1; |
| |
| l = new(OFUNC, nodtestv, l); |
| n->left = l; |
| l->complex = FNX; |
| l->op = OFUNC; |
| l->type = types[TLONG]; |
| n->complex = FNX; |
| return 1; |
| } |
| } |
| |
| if(rv) { |
| if(machcap(n)) |
| return 1; |
| switch(n->op) { |
| case OANDAND: |
| case OOROR: |
| r = new(OFUNC, nodtestv, r); |
| n->right = r; |
| r->complex = FNX; |
| r->op = OFUNC; |
| r->type = types[TLONG]; |
| return 1; |
| } |
| } |
| |
| if(typev[n->type->etype]) { |
| if(machcap(n)) |
| return 1; |
| switch(n->op) { |
| default: |
| diag(n, "unknown vlong %O", n->op); |
| case OFUNC: |
| n->complex = FNX; |
| case ORETURN: |
| case OAS: |
| case OIND: |
| return 1; |
| case OADD: |
| a = nodaddv; |
| goto setbop; |
| case OSUB: |
| a = nodsubv; |
| goto setbop; |
| case OMUL: |
| case OLMUL: |
| a = nodmulv; |
| goto setbop; |
| case ODIV: |
| a = noddivv; |
| goto setbop; |
| case OLDIV: |
| a = noddivvu; |
| goto setbop; |
| case OMOD: |
| a = nodmodv; |
| goto setbop; |
| case OLMOD: |
| a = nodmodvu; |
| goto setbop; |
| case OASHL: |
| a = nodlshv; |
| goto setbop; |
| case OASHR: |
| a = nodrshav; |
| goto setbop; |
| case OLSHR: |
| a = nodrshlv; |
| goto setbop; |
| case OAND: |
| a = nodandv; |
| goto setbop; |
| case OOR: |
| a = nodorv; |
| goto setbop; |
| case OXOR: |
| a = nodxorv; |
| goto setbop; |
| case OPOSTINC: |
| a = nodvpp; |
| goto setvinc; |
| case OPOSTDEC: |
| a = nodvmm; |
| goto setvinc; |
| case OPREINC: |
| a = nodppv; |
| goto setvinc; |
| case OPREDEC: |
| a = nodmmv; |
| goto setvinc; |
| case ONEG: |
| a = nodnegv; |
| goto setfnx; |
| case OCOM: |
| a = nodcomv; |
| goto setfnx; |
| case OCAST: |
| switch(l->type->etype) { |
| case TCHAR: |
| a = nodsc2v; |
| goto setfnxl; |
| case TUCHAR: |
| a = noduc2v; |
| goto setfnxl; |
| case TSHORT: |
| a = nodsh2v; |
| goto setfnxl; |
| case TUSHORT: |
| a = noduh2v; |
| goto setfnxl; |
| case TINT: |
| a = nodsi2v; |
| goto setfnx; |
| case TUINT: |
| a = nodui2v; |
| goto setfnx; |
| case TLONG: |
| a = nodsl2v; |
| goto setfnx; |
| case TULONG: |
| a = nodul2v; |
| goto setfnx; |
| case TFLOAT: |
| a = nodf2v; |
| goto setfnx; |
| case TDOUBLE: |
| a = nodd2v; |
| goto setfnx; |
| case TIND: |
| a = nodp2v; |
| goto setfnx; |
| } |
| diag(n, "unknown %T->vlong cast", l->type); |
| return 1; |
| case OASADD: |
| a = nodaddv; |
| goto setasop; |
| case OASSUB: |
| a = nodsubv; |
| goto setasop; |
| case OASMUL: |
| case OASLMUL: |
| a = nodmulv; |
| goto setasop; |
| case OASDIV: |
| a = noddivv; |
| goto setasop; |
| case OASLDIV: |
| a = noddivvu; |
| goto setasop; |
| case OASMOD: |
| a = nodmodv; |
| goto setasop; |
| case OASLMOD: |
| a = nodmodvu; |
| goto setasop; |
| case OASASHL: |
| a = nodlshv; |
| goto setasop; |
| case OASASHR: |
| a = nodrshav; |
| goto setasop; |
| case OASLSHR: |
| a = nodrshlv; |
| goto setasop; |
| case OASAND: |
| a = nodandv; |
| goto setasop; |
| case OASOR: |
| a = nodorv; |
| goto setasop; |
| case OASXOR: |
| a = nodxorv; |
| goto setasop; |
| } |
| } |
| |
| if(typefd[n->type->etype] && l && l->op == OFUNC) { |
| switch(n->op) { |
| case OASADD: |
| case OASSUB: |
| case OASMUL: |
| case OASLMUL: |
| case OASDIV: |
| case OASLDIV: |
| case OASMOD: |
| case OASLMOD: |
| case OASASHL: |
| case OASASHR: |
| case OASLSHR: |
| case OASAND: |
| case OASOR: |
| case OASXOR: |
| if(l->right && typev[l->right->etype]) { |
| diag(n, "sorry float <asop> vlong not implemented\n"); |
| } |
| } |
| } |
| |
| if(n->op == OCAST) { |
| if(l->type && typev[l->type->etype]) { |
| if(machcap(n)) |
| return 1; |
| switch(n->type->etype) { |
| case TDOUBLE: |
| a = nodv2d; |
| goto setfnx; |
| case TFLOAT: |
| a = nodv2f; |
| goto setfnx; |
| case TLONG: |
| a = nodv2sl; |
| goto setfnx; |
| case TULONG: |
| a = nodv2ul; |
| goto setfnx; |
| case TINT: |
| a = nodv2si; |
| goto setfnx; |
| case TUINT: |
| a = nodv2ui; |
| goto setfnx; |
| case TSHORT: |
| a = nodv2sh; |
| goto setfnx; |
| case TUSHORT: |
| a = nodv2uh; |
| goto setfnx; |
| case TCHAR: |
| a = nodv2sc; |
| goto setfnx; |
| case TUCHAR: |
| a = nodv2uc; |
| goto setfnx; |
| case TIND: // small pun here |
| a = nodv2ul; |
| goto setfnx; |
| } |
| diag(n, "unknown vlong->%T cast", n->type); |
| return 1; |
| } |
| } |
| |
| return 0; |
| |
| setbop: |
| n->left = a; |
| n->right = new(OLIST, l, r); |
| n->complex = FNX; |
| n->op = OFUNC; |
| return 1; |
| |
| setfnxl: |
| l = new(OCAST, l, 0); |
| l->type = types[TLONG]; |
| l->complex = l->left->complex; |
| |
| setfnx: |
| n->left = a; |
| n->right = l; |
| n->complex = FNX; |
| n->op = OFUNC; |
| return 1; |
| |
| setvinc: |
| n->left = a; |
| l = new(OADDR, l, Z); |
| l->type = typ(TIND, l->left->type); |
| n->right = new(OLIST, l, r); |
| n->complex = FNX; |
| n->op = OFUNC; |
| return 1; |
| |
| setbool: |
| if(machcap(n)) |
| return 1; |
| n->left = a; |
| n->right = new(OLIST, l, r); |
| n->complex = FNX; |
| n->op = OFUNC; |
| n->type = types[TLONG]; |
| return 1; |
| |
| setasop: |
| if(l->op == OFUNC) { |
| l = l->right; |
| goto setasop; |
| } |
| |
| t = new(OCONST, 0, 0); |
| t->vconst = etconv[l->type->etype]; |
| t->type = types[TLONG]; |
| t->addable = 20; |
| r = new(OLIST, t, r); |
| |
| t = new(OADDR, a, 0); |
| t->type = typ(TIND, a->type); |
| r = new(OLIST, t, r); |
| |
| t = new(OADDR, l, 0); |
| t->type = typ(TIND, l->type); |
| r = new(OLIST, t, r); |
| |
| n->left = nodvasop; |
| n->right = r; |
| n->complex = FNX; |
| n->op = OFUNC; |
| |
| return 1; |
| } |
| |
| void |
| bool64(Node *n) |
| { |
| Node *n1; |
| |
| if(machcap(Z)) |
| return; |
| if(typev[n->type->etype]) { |
| n1 = new(OXXX, 0, 0); |
| *n1 = *n; |
| |
| n->right = n1; |
| n->left = nodtestv; |
| n->complex = FNX; |
| n->addable = 0; |
| n->op = OFUNC; |
| n->type = types[TLONG]; |
| } |
| } |
| |
| /* |
| * more machine depend stuff. |
| * this is common for 8,16,32,64 bit machines. |
| * this is common for ieee machines. |
| */ |
| double |
| convvtof(vlong v) |
| { |
| double d; |
| |
| d = v; /* BOTCH */ |
| return d; |
| } |
| |
| vlong |
| convftov(double d) |
| { |
| vlong v; |
| |
| |
| v = d; /* BOTCH */ |
| return v; |
| } |
| |
| double |
| convftox(double d, int et) |
| { |
| |
| if(!typefd[et]) |
| diag(Z, "bad type in castftox %s", tnames[et]); |
| return d; |
| } |
| |
| vlong |
| convvtox(vlong c, int et) |
| { |
| int n; |
| |
| n = 8 * ewidth[et]; |
| c &= MASK(n); |
| if(!typeu[et]) |
| if(c & SIGN(n)) |
| c |= ~MASK(n); |
| return c; |
| } |