Skip to content

Commit cb7c9de

Browse files
authored
fix: Move bswap back to stdlib (#2701)
1 parent 9480469 commit cb7c9de

13 files changed

+1162
-1090
lines changed

src/builtins.ts

-177
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,6 @@ export namespace BuiltinNames {
143143
export const isManaged = "~lib/builtins/isManaged";
144144
export const isVoid = "~lib/builtins/isVoid";
145145

146-
export const bswap = "~lib/builtins/bswap";
147-
148146
export const add = "~lib/builtins/add";
149147
export const sub = "~lib/builtins/sub";
150148
export const mul = "~lib/builtins/mul";
@@ -1193,181 +1191,6 @@ function builtin_idof(ctx: BuiltinFunctionContext): ExpressionRef {
11931191
}
11941192
builtinFunctions.set(BuiltinNames.idof, builtin_idof);
11951193

1196-
// bswap<T?>(value: T) -> T
1197-
function builtin_bswap(ctx: BuiltinFunctionContext): ExpressionRef {
1198-
let compiler = ctx.compiler;
1199-
let module = compiler.module;
1200-
if (
1201-
checkTypeOptional(ctx, true) |
1202-
checkArgsRequired(ctx, 1)
1203-
) return module.unreachable();
1204-
1205-
let typeArguments = ctx.typeArguments;
1206-
let arg0 = typeArguments
1207-
? compiler.compileExpression(
1208-
ctx.operands[0],
1209-
typeArguments[0].toUnsigned(),
1210-
Constraints.ConvImplicit | Constraints.MustWrap
1211-
)
1212-
: compiler.compileExpression(
1213-
ctx.operands[0],
1214-
Type.u32,
1215-
Constraints.MustWrap
1216-
);
1217-
1218-
let type = compiler.currentType;
1219-
if (type.isValue) {
1220-
switch (type.kind) {
1221-
case TypeKind.Bool:
1222-
case TypeKind.I8:
1223-
case TypeKind.U8: return arg0;
1224-
case TypeKind.I16:
1225-
case TypeKind.U16: {
1226-
// <T>(x << 8 | x >> 8)
1227-
let flow = compiler.currentFlow;
1228-
let temp = flow.getTempLocal(type);
1229-
flow.setLocalFlag(temp.index, LocalFlags.Wrapped);
1230-
1231-
let res = module.binary(
1232-
BinaryOp.OrI32,
1233-
module.binary(
1234-
BinaryOp.ShlI32,
1235-
module.local_tee(temp.index, arg0, false),
1236-
module.i32(8)
1237-
),
1238-
module.binary(
1239-
BinaryOp.ShrU32,
1240-
module.local_get(temp.index, TypeRef.I32),
1241-
module.i32(8)
1242-
)
1243-
);
1244-
// avoid wrapping for u16 due to it's already done for input arg
1245-
if (type.kind == TypeKind.I16) {
1246-
res = compiler.ensureSmallIntegerWrap(res, Type.i16);
1247-
}
1248-
return res;
1249-
}
1250-
case TypeKind.I32:
1251-
case TypeKind.U32:
1252-
case TypeKind.Isize:
1253-
case TypeKind.Usize: {
1254-
if (type.size == 32) {
1255-
// rotl(x & 0xFF00FF00, 8) | rotr(x & 0x00FF00FF, 8)
1256-
let flow = compiler.currentFlow;
1257-
let temp = flow.getTempLocal(type);
1258-
flow.setLocalFlag(temp.index, LocalFlags.Wrapped);
1259-
1260-
let res = module.binary(
1261-
BinaryOp.OrI32,
1262-
module.binary(
1263-
BinaryOp.RotlI32,
1264-
module.binary(
1265-
BinaryOp.AndI32,
1266-
module.local_tee(temp.index, arg0, false),
1267-
module.i32(0xFF00FF00)
1268-
),
1269-
module.i32(8)
1270-
),
1271-
module.binary(
1272-
BinaryOp.RotrI32,
1273-
module.binary(
1274-
BinaryOp.AndI32,
1275-
module.local_get(temp.index, TypeRef.I32),
1276-
module.i32(0x00FF00FF)
1277-
),
1278-
module.i32(8)
1279-
),
1280-
);
1281-
return res;
1282-
}
1283-
// fall-through
1284-
}
1285-
case TypeKind.I64:
1286-
case TypeKind.U64: {
1287-
// let t =
1288-
// ((x >>> 8) & 0x00FF00FF00FF00FF) |
1289-
// ((x & 0x00FF00FF00FF00FF) << 8)
1290-
//
1291-
// let res =
1292-
// ((t >>> 16) & 0x0000FFFF0000FFFF) |
1293-
// ((t & 0x0000FFFF0000FFFF) << 16)
1294-
//
1295-
// rotr(res, 32)
1296-
1297-
let flow = compiler.currentFlow;
1298-
let temp1 = flow.getTempLocal(type);
1299-
flow.setLocalFlag(temp1.index, LocalFlags.Wrapped);
1300-
let temp2 = flow.getTempLocal(type);
1301-
flow.setLocalFlag(temp2.index, LocalFlags.Wrapped);
1302-
1303-
// t = ((x >>> 8) & 0x00FF00FF00FF00FF) | ((x & 0x00FF00FF00FF00FF) << 8)
1304-
let expr = module.local_tee(
1305-
temp2.index,
1306-
module.binary(
1307-
BinaryOp.OrI64,
1308-
module.binary(
1309-
BinaryOp.AndI64,
1310-
module.binary(
1311-
BinaryOp.ShrU64,
1312-
module.local_tee(temp1.index, arg0, false),
1313-
module.i64(8)
1314-
),
1315-
module.i64(0x00FF00FF, 0x00FF00FF)
1316-
),
1317-
module.binary(
1318-
BinaryOp.ShlI64,
1319-
module.binary(
1320-
BinaryOp.AndI64,
1321-
module.local_get(temp1.index, TypeRef.I64),
1322-
module.i64(0x00FF00FF, 0x00FF00FF)
1323-
),
1324-
module.i64(8)
1325-
),
1326-
),
1327-
false
1328-
);
1329-
1330-
// ((t >>> 16) & 0x0000FFFF0000FFFF) | ((t & 0x0000FFFF0000FFFF) << 16)
1331-
let res = module.binary(
1332-
BinaryOp.OrI64,
1333-
module.binary(
1334-
BinaryOp.AndI64,
1335-
module.binary(
1336-
BinaryOp.ShrU64,
1337-
expr,
1338-
module.i64(16)
1339-
),
1340-
module.i64(0x0000FFFF, 0x0000FFFF)
1341-
),
1342-
module.binary(
1343-
BinaryOp.ShlI64,
1344-
module.binary(
1345-
BinaryOp.AndI64,
1346-
module.local_get(temp2.index, TypeRef.I64),
1347-
module.i64(0x0000FFFF, 0x0000FFFF)
1348-
),
1349-
module.i64(16)
1350-
),
1351-
);
1352-
1353-
// rotr(res, 32)
1354-
res = module.binary(
1355-
BinaryOp.RotrI64,
1356-
res,
1357-
module.i64(32)
1358-
);
1359-
return res;
1360-
}
1361-
}
1362-
}
1363-
compiler.error(
1364-
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
1365-
ctx.reportNode.typeArgumentsRange, "bswap", type.toString()
1366-
);
1367-
return module.unreachable();
1368-
}
1369-
builtinFunctions.set(BuiltinNames.bswap, builtin_bswap);
1370-
13711194
// === Math ===================================================================================
13721195

13731196
// NaN

std/assembly/builtins.ts

-4
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ export declare function isVoid<T>(): bool;
6666
@builtin
6767
export declare function lengthof<T>(func?: T): i32;
6868

69-
// @ts-ignore
70-
@builtin
71-
export declare function bswap<T>(value: T): T;
72-
7369
// @ts-ignore: decorator
7470
@builtin
7571
export declare function clz<T>(value: T): T;

std/assembly/polyfills.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export function bswap<T extends number>(value: T): T {
2+
if (isInteger<T>()) {
3+
if (sizeof<T>() == 1) {
4+
return value;
5+
}
6+
if (sizeof<T>() == 2) {
7+
return <T>(<u16>value << 8 | (<u16>value >> 8));
8+
}
9+
if (sizeof<T>() == 4) {
10+
return <T>(
11+
rotl(<u32>value & 0xFF00FF00, 8) |
12+
rotr(<u32>value & 0x00FF00FF, 8)
13+
);
14+
}
15+
if (sizeof<T>() == 8) {
16+
let a = (<u64>value >> 8) & 0x00FF00FF00FF00FF;
17+
let b = (<u64>value & 0x00FF00FF00FF00FF) << 8;
18+
let v = a | b;
19+
20+
a = (v >>> 16) & 0x0000FFFF0000FFFF;
21+
b = (v & 0x0000FFFF0000FFFF) << 16;
22+
23+
return <T>rotr(a | b, 32);
24+
}
25+
}
26+
ERROR("Unsupported generic type");
27+
}

0 commit comments

Comments
 (0)