aboutsummaryrefslogtreecommitdiffhomepage
path: root/ir/fold.c
blob: bad0373e79f1913d56b814a2f640cecb71b774a5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "ir.h"

static union ref
foldint(enum op op, enum irclass k, union ref lr, union ref rr)
{
   vlong x;
   union {
      vlong s;
      uvlong u;
   } l = {.s = intconval(lr)}, r = {.s = intconval(rr)};
   bool w = cls2siz[k] == 8;
   if (in_range(op, Odiv, Ourem)) assert(r.u != 0);
   switch (op) {
   case Ocopy: x = l.s; break;
   case Oneg:  x = -l.s; break;
   case Onot:  x = ~l.s; break;
   case Ocvtf4s: x = (int)(float)fltconval(lr); break;
   case Ocvtf4u: x = (uint)(float)fltconval(lr); break;
   case Ocvtf8s: x = (vlong)fltconval(lr); break;
   case Ocvtf8u: x = (uvlong)fltconval(lr); break;
   case Oexts1: x = (schar)l.s; break;
   case Oextu1: x = (uchar)l.s; break;
   case Oexts2: x = (short)l.s; break;
   case Oextu2: x = (ushort)l.s; break;
   case Oexts4: x = (int)l.s; break;
   case Oextu4: x = (uint)l.s; break;
   case Oadd:  x = l.u + r.u; break;
   case Osub:  x = l.u - r.u; break;
   case Omul:  x = l.u * r.u; break;
   case Oumul: x = l.u * r.u; break;
   case Odiv:  x = w ? l.s / r.s : (int)l.s / (int)r.s; break;
   case Oudiv: x = w ? l.u / r.u : (uint)l.u / (uint)r.u; break;
   case Orem:  x = w ? l.s % r.s : (int)l.s % (int)r.s; break;
   case Ourem: x = w ? l.u % r.u : (uint)l.u % (uint)r.u; break;
   case Oand:  x = l.u & r.u; break;
   case Oior:  x = l.u | r.u; break;
   case Oxor:  x = l.u ^ r.u; break;
   case Oshl:  x = l.u << (r.u & (w ? 63 : 31)); break;
   case Oslr:  x = w ? l.u >> (r.u&63) : (int)l.s >> (r.u&31); break;
   case Osar:  x = w ? l.s >> (r.u&63) : (int)l.s >> (r.u&31); break;
   case Oequ:  x = l.s == r.s; break;
   case Oneq:  x = l.s != r.s; break;
   case Olth:  x = l.s < r.s; break;
   case Ogth:  x = l.s > r.s; break;
   case Olte:  x = l.s <= r.s; break;
   case Ogte:  x = l.s >= r.s; break;
   case Oulth: x = l.u < r.u; break;
   case Ougth: x = l.u > r.u; break;
   case Oulte: x = l.u <= r.u; break;
   case Ougte: x = l.u >= r.u; break;
   default: assert(0);
   }
   return mkintcon(k, x);
}

static union ref
foldflt(enum op op, enum irclass k, union ref lr, union ref rr)
{
   int xi;
   double x, l = fltconval(lr), r = fltconval(rr);
   bool w = k == KF64;
   if (in_range(op, Odiv, Ourem)) assert(r != 0.0);
   switch (op) {
   case Ocopy: x = l; break;
   case Oneg:  x = -l; break;
   case Ocvtf4f8: x = (float)l; break;
   case Ocvtf8f4: x = (float)l; break;
   case Ocvts4f:  x = (int)intconval(lr); break;
   case Ocvtu4f:  x = (int)intconval(lr); break;
   case Ocvts8f:  x = (vlong)intconval(lr); break;
   case Ocvtu8f:  x = (uvlong)intconval(lr); break;
   case Oadd: x = l + r; break;
   case Osub: x = l - r; break;
   case Omul: x = l * r; break;
   case Odiv: x = l / r; break;
   case Oequ: xi = l == r; break;
   case Oneq: xi = l != r; break;
   case Olth: xi = l < r; break;
   case Ogth: xi = l > r; break;
   case Olte: xi = l <= r; break;
   case Ogte: xi = l >= r; break;
   default: assert(0);
   }
   if (oiscmp(op)) return mkref(RICON, xi);
   if (!w) x = (float)x;
   return mkfltcon(k, x);
}

bool
foldbinop(union ref *to, enum op op, enum irclass k, union ref l, union ref r)
{
   if (!isnumcon(l) || !isnumcon(r)) return 0;
   if (in_range(op, Odiv, Ourem) && (kisint(k) ? intconval(r) == 0 : fltconval(r) == 0))
      return 0;
   if (!oisarith(op))
      return 0;
   if (kisint(k))
      *to = foldint(op, k, l, r);
   else
      *to = foldflt(op, k, l, r);
   return 1;
}

bool
foldunop(union ref *to, enum op op, enum irclass k, union ref a)
{
   if (!isnumcon(a)) return 0;
   if (op != Ocopy && !oisarith(op))
      return 0;
   if (kisint(k))
      *to = foldint(op, k, a, ZEROREF);
   else
      *to = foldflt(op, k, a, ZEROREF);
   return 1;
}

/* vim:set ts=3 sw=3 expandtab: */