|
58 | 58 | return x && ((x & (x - 1)) === 0);
|
59 | 59 | }
|
60 | 60 |
|
61 |
| - function wordAlignment(x) { |
62 |
| - return (x + 3) & ~0x3; |
63 |
| - } |
64 |
| - |
65 | 61 | function log2(x) {
|
66 | 62 | assert (isPowerOfTwo(x), "Value " + x + " is not a power of two.");
|
67 | 63 | return Math.log(x) / Math.LN2;
|
|
72 | 68 | return x / 4;
|
73 | 69 | }
|
74 | 70 |
|
| 71 | + function isAlignedTo(offset, alignment) { |
| 72 | + return offset & ~(alignment - 1); |
| 73 | + } |
| 74 | + |
75 | 75 | function alignTo(offset, alignment) {
|
76 |
| - return (((offset - 1) / alignment + 1) | 0) * alignment; |
| 76 | + return (offset + (alignment - 1)) & ~(alignment - 1); |
77 | 77 | }
|
78 | 78 |
|
79 | 79 | function extend(old, props) {
|
|
234 | 234 | const wordTy = u32ty;
|
235 | 235 | const voidTy = new PrimitiveType("void", 0, 0, undefined);
|
236 | 236 | const bytePointerTy = new PointerType(u8ty);
|
| 237 | + const spTy = new PointerType(u32ty); |
237 | 238 |
|
238 | 239 | const mallocTy = new ArrowType([u32ty], bytePointerTy);
|
239 | 240 | const freeTy = new ArrowType([bytePointerTy], voidTy);
|
240 |
| - const memcpyTy = new ArrowType([bytePointerTy, bytePointerTy, u32ty], bytePointerTy); |
241 |
| - const memsetTy = new ArrowType([bytePointerTy, u32ty, u32ty], voidTy); |
| 241 | + |
| 242 | + function createMemcpyType(pointerTy) { |
| 243 | + return new ArrowType([pointerTy, pointerTy, u32ty], pointerTy); |
| 244 | + } |
| 245 | + |
| 246 | + function createMemsetType(pointerTy) { |
| 247 | + return new ArrowType([pointerTy, pointerTy.base, u32ty], voidTy); |
| 248 | + } |
| 249 | + |
| 250 | + const memcpyTy = createMemcpyType(bytePointerTy); |
| 251 | + const memcpy2Ty = createMemcpyType(new PointerType(u16ty)); |
| 252 | + const memcpy4Ty = createMemcpyType(new PointerType(u32ty)); |
| 253 | + const memsetTy = createMemsetType(bytePointerTy); |
| 254 | + const memset2Ty = createMemsetType(new PointerType(u16ty)); |
| 255 | + const memset4Ty = createMemsetType(new PointerType(u32ty)); |
242 | 256 |
|
243 | 257 | u8ty.integral = u8ty.numeric = true;
|
244 | 258 | i8ty.integral = i8ty.numeric = true;
|
|
391 | 405 | return this.frame.FREE();
|
392 | 406 | };
|
393 | 407 |
|
394 |
| - Scope.prototype.MEMCPY = function MEMCPY() { |
395 |
| - return this.frame.MEMCPY(); |
| 408 | + Scope.prototype.MEMCPY = function MEMCPY(size) { |
| 409 | + return this.frame.MEMCPY(size); |
396 | 410 | };
|
397 | 411 |
|
398 |
| - Scope.prototype.MEMSET = function MEMSET() { |
399 |
| - return this.frame.MEMSET(); |
| 412 | + Scope.prototype.MEMSET = function MEMSET(size) { |
| 413 | + return this.frame.MEMSET(size); |
400 | 414 | };
|
401 | 415 |
|
402 | 416 | Scope.prototype.toString = Scope.prototype.toJSON = function () {
|
|
442 | 456 | return getCachedLocal(this, "free", freeTy);
|
443 | 457 | };
|
444 | 458 |
|
445 |
| - Frame.prototype.MEMCPY = function MEMCPY() { |
446 |
| - return getCachedLocal(this, "memcpy", memcpyTy); |
| 459 | + Frame.prototype.MEMCPY = function MEMCPY(size) { |
| 460 | + assert(size === 1 || size === 2 || size === 4); |
| 461 | + var name, ty; |
| 462 | + switch (size) { |
| 463 | + case 1: name = "memcpy"; ty = memcpyTy; break; |
| 464 | + case 2: name = "memcpy2"; ty = memcpy2Ty; break; |
| 465 | + case 4: name = "memcpy4"; ty = memcpy4Ty; break; |
| 466 | + } |
| 467 | + return getCachedLocal(this, name, ty); |
447 | 468 | };
|
448 | 469 |
|
449 |
| - Frame.prototype.MEMSET = function MEMSET() { |
450 |
| - return getCachedLocal(this, "memset", memsetTy); |
| 470 | + Frame.prototype.MEMSET = function MEMSET(size) { |
| 471 | + assert(size === 1 || size === 2 || size === 4); |
| 472 | + var name, ty; |
| 473 | + switch (size) { |
| 474 | + case 1: name = "memset"; ty = memsetTy; break; |
| 475 | + case 2: name = "memset2"; ty = memset2Ty; break; |
| 476 | + case 4: name = "memset4"; ty = memset4Ty; break; |
| 477 | + } |
| 478 | + return getCachedLocal(this, name, ty); |
451 | 479 | };
|
452 | 480 |
|
453 | 481 | Frame.prototype.getView = function getView(ty) {
|
|
460 | 488 |
|
461 | 489 | Frame.prototype.SP = function SP() {
|
462 | 490 | if (!this.cachedSP) {
|
463 |
| - this.cachedSP = cast(new Identifier(this.freshVariable("$SP").name), |
464 |
| - new PointerType(u32ty)); |
| 491 | + this.cachedSP = cast(new Identifier(this.freshVariable("$SP").name), spTy); |
465 | 492 | }
|
466 | 493 | return this.cachedSP;
|
467 | 494 | };
|
468 | 495 |
|
469 | 496 | Frame.prototype.realSP = function realSP() {
|
470 |
| - return cast(new MemberExpression(this.getView(builtinTypes.uint), new Literal(1), true), |
471 |
| - new PointerType(u32ty)); |
| 497 | + return cast(new MemberExpression(this.getView(builtinTypes.uint), new Literal(1), true), spTy); |
472 | 498 | };
|
473 | 499 |
|
474 | 500 | Frame.prototype.close = function close() {
|
| 501 | + const wordSize = wordTy.size; |
475 | 502 | var wordOffset = 0;
|
476 | 503 | var mangles = this.mangles;
|
| 504 | + // The SP and frame sizes are in *words*, since we expect most accesses |
| 505 | + // are to ints, but the alignment is by *double word*, to fit doubles. |
477 | 506 | for (var name in mangles) {
|
478 | 507 | var variable = mangles[name];
|
479 | 508 | if (mangles[name].isStackAllocated) {
|
480 | 509 | variable.wordOffset = wordOffset;
|
481 |
| - wordOffset += wordAlignment(variable.type.align.size) / 4; |
| 510 | + wordOffset += alignTo(variable.type.size, wordSize * 2) / wordSize; |
482 | 511 | }
|
483 | 512 | }
|
484 | 513 |
|
|
1182 | 1211 | quote(tystr(rty, 0)) + " to " + quote(tystr(lty, 0)));
|
1183 | 1212 |
|
1184 | 1213 | if (lty instanceof StructType) {
|
1185 |
| - return cast(new CallExpression(scope.MEMCPY(), [this.left, this.right, lty.size]), lty); |
| 1214 | + // Emit a memcpy using the largest alignment size we can. |
| 1215 | + var mc, size; |
| 1216 | + if (isAlignedTo(lty.size, 4)) { |
| 1217 | + mc = scope.MEMCPY(4); |
| 1218 | + size = lty.size / 4; |
| 1219 | + } else if (isAlignedTo(lty.size, 2)) { |
| 1220 | + mc = scope.MEMCPY(2); |
| 1221 | + size = lty.size / 2; |
| 1222 | + } else { |
| 1223 | + mc = scope.MEMCPY(1); |
| 1224 | + size = lty.size; |
| 1225 | + } |
| 1226 | + return cast(new CallExpression(mc, [this.left, this.right, new Literal(size)]), lty); |
1186 | 1227 | } else {
|
1187 | 1228 | this.right = cast(this.right, lty);
|
1188 | 1229 | return cast(this, lty);
|
|
1266 | 1307 | return expr;
|
1267 | 1308 | }
|
1268 | 1309 |
|
1269 |
| - var lalign = this.base.align.size; |
1270 |
| - var ralign = rty.base.align.size; |
| 1310 | + return realign(expr, this.base.align.size); |
| 1311 | + }; |
| 1312 | + |
| 1313 | + StructType.prototype.convert = function (expr) { |
| 1314 | + return expr; |
| 1315 | + }; |
| 1316 | + |
| 1317 | + ArrowType.prototype.convert = function (expr) { |
| 1318 | + return expr; |
| 1319 | + }; |
| 1320 | + |
| 1321 | + function realign(expr, lalign) { |
| 1322 | + assert(expr.ty instanceof PointerType); |
| 1323 | + var ralign = expr.ty.base.align.size; |
1271 | 1324 |
|
1272 | 1325 | if (lalign === ralign) {
|
1273 | 1326 | return expr;
|
|
1283 | 1336 | }
|
1284 | 1337 |
|
1285 | 1338 | return new BinaryExpression(op, expr, new Literal(log2(ratio)));
|
1286 |
| - }; |
1287 |
| - |
1288 |
| - StructType.prototype.convert = function (expr) { |
1289 |
| - return expr; |
1290 |
| - }; |
1291 |
| - |
1292 |
| - ArrowType.prototype.convert = function (expr) { |
1293 |
| - return expr; |
1294 |
| - }; |
| 1339 | + } |
1295 | 1340 |
|
1296 | 1341 | function alignAddress(base, byteOffset, ty) {
|
1297 |
| - var address = base; |
| 1342 | + var address = realign(base, ty.align.size); |
1298 | 1343 | if (byteOffset !== 0) {
|
1299 |
| - assert(byteOffset % ty.align.size === 0, "Unaligned byte offset " + byteOffset + " for type " + quote(ty) + " with alignment " + ty.align.size); |
| 1344 | + assert(isAlignedTo(byteOffset, ty.align.size), "unaligned byte offset " + byteOffset + |
| 1345 | + " for type " + quote(ty) + " with alignment " + ty.align.size); |
1300 | 1346 | var offset = byteOffset / ty.align.size;
|
1301 | 1347 | address = new BinaryExpression("+", address, new Literal(offset));
|
1302 | 1348 | }
|
|
1306 | 1352 | function dereference(address, byteOffset, ty, scope) {
|
1307 | 1353 | assert(scope);
|
1308 | 1354 | address = alignAddress(address, byteOffset, ty);
|
1309 |
| - return new MemberExpression(scope.getView(ty), address, true); |
| 1355 | + var expr = new MemberExpression(scope.getView(ty), address, true); |
| 1356 | + // Remember (coerce) the type so we can realign, but *do not* cast. |
| 1357 | + expr.ty = ty; |
| 1358 | + return expr; |
1310 | 1359 | }
|
1311 | 1360 |
|
1312 | 1361 | function createPrologue(node, o) {
|
|
1429 | 1478 | }
|
1430 | 1479 | };
|
1431 | 1480 |
|
| 1481 | + VariableDeclaration.prototype.lowerNode = function (o) { |
| 1482 | + if (this.declarations.length === 0) { |
| 1483 | + return null; |
| 1484 | + } |
| 1485 | + }; |
| 1486 | + |
1432 | 1487 | VariableDeclarator.prototype.lowerNode = function (o) {
|
1433 | 1488 | if (!(this.id instanceof Identifier)) {
|
1434 | 1489 | if (this.init) {
|
|
0 commit comments