8000 Emit memcpy{2,4} if pointers are halfword- and word-aligned · repos-javascript-compilers/LLJS@102d4a3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 102d4a3

Browse files
committed
Emit memcpy{2,4} if pointers are halfword- and word-aligned
1 parent 0d4149b commit 102d4a3

File tree

1 file changed

+90
-35
lines changed

1 file changed

+90
-35
lines changed

src/compiler.js

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@
5858
return x && ((x & (x - 1)) === 0);
5959
}
6060

61-
function wordAlignment(x) {
62-
return (x + 3) & ~0x3;
63-
}
64-
6561
function log2(x) {
6662
assert (isPowerOfTwo(x), "Value " + x + " is not a power of two.");
6763
return Math.log(x) / Math.LN2;
@@ -72,8 +68,12 @@
7268
return x / 4;
7369
}
7470

71+
function isAlignedTo(offset, alignment) {
72+
return offset & ~(alignment - 1);
73+
}
74+
7575
function alignTo(offset, alignment) {
76-
return (((offset - 1) / alignment + 1) | 0) * alignment;
76+
return (offset + (alignment - 1)) & ~(alignment - 1);
7777
}
7878

7979
function extend(old, props) {
@@ -234,11 +234,25 @@
234234
const wordTy = u32ty;
235235
const voidTy = new PrimitiveType("void", 0, 0, undefined);
236236
const bytePointerTy = new PointerType(u8ty);
237+
const spTy = new PointerType(u32ty);
237238

238239
const mallocTy = new ArrowType([u32ty], bytePointerTy);
239240
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));
242256

243257
u8ty.integral = u8ty.numeric = true;
244258
i8ty.integral = i8ty.numeric = true;
@@ -391,12 +405,12 @@
391405
return this.frame.FREE();
392406
};
393407

394-
Scope.prototype.MEMCPY = function MEMCPY() {
395-
return this.frame.MEMCPY();
408+
Scope.prototype.MEMCPY = function MEMCPY(size) {
409+
return this.frame.MEMCPY(size);
396410
};
397411

398-
Scope.prototype.MEMSET = function MEMSET() {
399-
return this.frame.MEMSET();
412+
Scope.prototype.MEMSET = function MEMSET(size) {
413+
return this.frame.MEMSET(size);
400414
};
401415

402416
Scope.prototype.toString = Scope.prototype.toJSON = function () {
@@ -442,12 +456,26 @@
442456
return getCachedLocal(this, "free", freeTy);
443457
};
444458

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);
447468
};
448469

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);
451479
};
452480

453481
Frame.prototype.getView = function getView(ty) {
@@ -460,25 +488,26 @@
460488

461489
Frame.prototype.SP = function SP() {
462490
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);
465492
}
466493
return this.cachedSP;
467494
};
468495

469496
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);
472498
};
473499

474500
Frame.prototype.close = function close() {
501+
const wordSize = wordTy.size;
475502
var wordOffset = 0;
476503
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.
477506
for (var name in mangles) {
478507
var variable = mangles[name];
479508
if (mangles[name].isStackAllocated) {
480509
variable.wordOffset = wordOffset;
481-
wordOffset += wordAlignment(variable.type.align.size) / 4;
510+
wordOffset += alignTo(variable.type.size, wordSize * 2) / wordSize;
482511
}
483512
}
484513

@@ -1182,7 +1211,19 @@
11821211
quote(tystr(rty, 0)) + " to " + quote(tystr(lty, 0)));
11831212

11841213
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);
11861227
} else {
11871228
this.right = cast(this.right, lty);
11881229
return cast(this, lty);
@@ -1266,8 +1307,20 @@
12661307
return expr;
12671308
}
12681309

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;
12711324

12721325
if (lalign === ralign) {
12731326
return expr;
@@ -1283,20 +1336,13 @@
12831336
}
12841337

12851338
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+
}
12951340

12961341
function alignAddress(base, byteOffset, ty) {
1297-
var address = base;
1342+
var address = realign(base, ty.align.size);
12981343
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);
13001346
var offset = byteOffset / ty.align.size;
13011347
address = new BinaryExpression("+", address, new Literal(offset));
13021348
}
@@ -1306,7 +1352,10 @@
13061352
function dereference(address, byteOffset, ty, scope) {
13071353
assert(scope);
13081354
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;
13101359
}
13111360

13121361
function createPrologue(node, o) {
@@ -1429,6 +1478,12 @@
14291478
}
14301479
};
14311480

1481+
VariableDeclaration.prototype.lowerNode = function (o) {
1482+
if (this.declarations.length === 0) {
1483+
return null;
1484+
}
1485+
};
1486+
14321487
VariableDeclarator.prototype.lowerNode = function (o) {
14331488
if (!(this.id instanceof Identifier)) {
14341489
if (this.init) {

0 commit comments

Comments
 (0)
0