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
118
119
120
121
122
123
124
125
|
#include "optimizer.h"
using namespace cashew;
IString ASM_FLOAT_ZERO;
IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"),
SIMD_INT16X8_CHECK("SIMD_Int16x8_check"),
SIMD_INT32X4_CHECK("SIMD_Int32x4_check"),
SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"),
SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check");
bool isInteger(double x) {
return fmod(x, 1) == 0;
}
bool isInteger32(double x) {
return isInteger(x) && (x == (int32_t)x || x == (uint32_t)x);
}
int parseInt(const char *str) {
int ret = *str - '0';
while (*(++str)) {
ret *= 10;
ret += *str - '0';
}
return ret;
}
HeapInfo parseHeap(const char *name) {
HeapInfo ret;
if (name[0] != 'H' || name[1] != 'E' || name[2] != 'A' || name[3] != 'P') {
ret.valid = false;
return ret;
}
ret.valid = true;
ret.unsign = name[4] == 'U';
ret.floaty = name[4] == 'F';
ret.bits = parseInt(name + (ret.unsign || ret.floaty ? 5 : 4));
ret.type = !ret.floaty ? ASM_INT : (ret.bits == 64 ? ASM_DOUBLE : ASM_FLOAT);
return ret;
}
AsmType detectType(Ref node, AsmData *asmData, bool inVarDef) {
switch (node[0]->getCString()[0]) {
case 'n': {
if (node[0] == NUM) {
if (!isInteger(node[1]->getNumber())) return ASM_DOUBLE;
return ASM_INT;
} else if (node[0] == NAME) {
if (asmData) {
AsmType ret = asmData->getType(node[1]->getCString());
if (ret != ASM_NONE) return ret;
}
if (!inVarDef) {
if (node[1] == INF || node[1] == NaN) return ASM_DOUBLE;
if (node[1] == TEMP_RET0) return ASM_INT;
return ASM_NONE;
}
// We are in a variable definition, where Math_fround(0) optimized into a global constant becomes f0 = Math_fround(0)
if (ASM_FLOAT_ZERO.isNull()) ASM_FLOAT_ZERO = node[1]->getIString();
else assert(node[1] == ASM_FLOAT_ZERO);
return ASM_FLOAT;
}
break;
}
case 'u': {
if (node[0] == UNARY_PREFIX) {
switch (node[1]->getCString()[0]) {
case '+': return ASM_DOUBLE;
case '-': return detectType(node[2], asmData, inVarDef);
case '!': case '~': return ASM_INT;
}
break;
}
break;
}
case 'c': {
if (node[0] == CALL) {
if (node[1][0] == NAME) {
IString name = node[1][1]->getIString();
if (name == MATH_FROUND) return ASM_FLOAT;
else if (name == SIMD_FLOAT32X4 || name == SIMD_FLOAT32X4_CHECK) return ASM_FLOAT32X4;
else if (name == SIMD_FLOAT64X2 || name == SIMD_FLOAT64X2_CHECK) return ASM_FLOAT64X2;
else if (name == SIMD_INT8X16 || name == SIMD_INT8X16_CHECK) return ASM_INT8X16;
else if (name == SIMD_INT16X8 || name == SIMD_INT16X8_CHECK) return ASM_INT16X8;
else if (name == SIMD_INT32X4 || name == SIMD_INT32X4_CHECK) return ASM_INT32X4;
}
return ASM_NONE;
} else if (node[0] == CONDITIONAL) {
return detectType(node[2], asmData, inVarDef);
}
break;
}
case 'b': {
if (node[0] == BINARY) {
switch (node[1]->getCString()[0]) {
case '+': case '-':
case '*': case '/': case '%': return detectType(node[2], asmData, inVarDef);
case '|': case '&': case '^': case '<': case '>': // handles <<, >>, >>=, <=, >=
case '=': case '!': { // handles ==, !=
return ASM_INT;
}
}
}
break;
}
case 's': {
if (node[0] == SEQ) {
return detectType(node[2], asmData, inVarDef);
} else if (node[0] == SUB) {
assert(node[1][0] == NAME);
HeapInfo info = parseHeap(node[1][1]->getCString());
if (info.valid) return ASM_NONE;
return info.floaty ? ASM_DOUBLE : ASM_INT; // XXX ASM_FLOAT?
}
break;
}
}
//dump("horrible", node);
//assert(0);
return ASM_NONE;
}
|