20
20
var LABEL_ENDERS = set('branch', 'return', 'switch');
21
21
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
22
22
var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam');
23
var I64_DOUBLE_FLIP = { i64: 'double', double: 'i64' };
101
102
delete item.items;
103
this.forwardItem(item, 'CastAway');
107
// CastAway - try to remove bitcasts of double<-->i64, which LLVM sometimes generates unnecessarily
108
// (load a double, convert to i64, use as i64).
109
// We optimize this by checking if there are such bitcasts. If so we create a shadow
110
// variable that is of the other type, and use that in the relevant places. (As SSA, this is valid, and
111
// variable elimination later will remove the double load if it is no longer needed.)
113
// Note that aside from being an optimization, this is needed for correctness in some cases: If code
114
// assumes it can bitcast a double to an i64 and back and forth without loss, that may be violated
115
// due to NaN canonicalization.
116
substrate.addActor('CastAway', {
117
processItem: function(item) {
102
118
this.forwardItem(item, 'Legalizer');
119
if (USE_TYPED_ARRAYS != 2) return;
121
item.functions.forEach(function(func) {
123
func.labels.forEach(function(label) {
124
var lines = label.lines;
125
for (var i = 0; i < lines.length; i++) {
127
if (line.intertype == 'bitcast' && line.type in I64_DOUBLE_FLIP) {
133
// there are i64<-->double bitcasts, create shadows for everything
135
func.labels.forEach(function(label) {
136
var lines = label.lines;
138
while (i < lines.length) {
139
var lines = label.lines;
141
if (line.intertype == 'load' && line.type in I64_DOUBLE_FLIP) {
142
if (line.pointer.intertype != 'value') { i++; continue } // TODO
143
shadowed[line.assignTo] = 1;
144
var shadow = line.assignTo + '$$SHADOW';
145
var flip = I64_DOUBLE_FLIP[line.type];
146
lines.splice(i + 1, 0, { // if necessary this element will be legalized in the next phase
149
lineNum: line.lineNum + 0.5,
152
pointerType: flip + '*',
157
ident: line.pointer.ident,
163
// note: no need to update func.lines, it is generated in a later pass
169
// use shadows where possible
170
func.labels.forEach(function(label) {
171
var lines = label.lines;
172
for (var i = 0; i < lines.length; i++) {
174
if (line.intertype == 'bitcast' && line.type in I64_DOUBLE_FLIP && line.ident in shadowed) {
175
var shadow = line.ident + '$$SHADOW';
176
line.params[0].ident = shadow;
177
line.params[0].type = line.type;
178
line.type2 = line.type;
174
254
var factor = (next - prev)/(4*toAdd.length+3);
175
255
for (var k = 0; k < toAdd.length; k++) {
176
256
toAdd[k].lineNum = prev + ((k+1)*factor);
257
assert(k == 0 || toAdd[k].lineNum > toAdd[k-1].lineNum);
179
260
function removeAndAdd(lines, i, toAdd) {
180
261
var item = lines[i];
181
262
interpLines(lines, i, toAdd);
182
263
Array.prototype.splice.apply(lines, [i, 1].concat(toAdd));
264
if (i > 0) assert(lines[i].lineNum > lines[i-1].lineNum);
265
if (i + toAdd.length < lines.length) assert(lines[i + toAdd.length - 1].lineNum < lines[i + toAdd.length].lineNum);
183
266
return toAdd.length;
185
268
function legalizeFunctionParameters(params) {
328
411
// legalize parameters
329
412
legalizeFunctionParameters(value.params);
330
413
// legalize return value, if any
331
if (value.assignTo && isIllegalType(item.type)) {
332
bits = getBits(value.type);
414
var returnType = getReturnType(item.type);
415
if (value.assignTo && isIllegalType(returnType)) {
416
bits = getBits(returnType);
333
417
var elements = getLegalVars(item.assignTo, bits);
334
418
// legalize return value
335
419
value.assignTo = elements[0].ident;