Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit afa0e2d

Browse files
authoredAug 15, 2022
Move bswap to builtins. Remove bswap16 (#2417)
1 parent cf676d3 commit afa0e2d

19 files changed

+1538
-1822
lines changed
 

‎src/builtins.ts

+183
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ 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+
146148
export const add = "~lib/builtins/add";
147149
export const sub = "~lib/builtins/sub";
148150
export const mul = "~lib/builtins/mul";
@@ -1144,6 +1146,187 @@ function builtin_idof(ctx: BuiltinContext): ExpressionRef {
11441146
}
11451147
builtins.set(BuiltinNames.idof, builtin_idof);
11461148

1149+
// bswap<T?>(value: T) -> T
1150+
function builtin_bswap(ctx: BuiltinContext): ExpressionRef {
1151+
var compiler = ctx.compiler;
1152+
var module = compiler.module;
1153+
if (
1154+
checkTypeOptional(ctx, true) |
1155+
checkArgsRequired(ctx, 1)
1156+
) return module.unreachable();
1157+
1158+
var typeArguments = ctx.typeArguments;
1159+
var arg0 = typeArguments
1160+
? compiler.compileExpression(
1161+
ctx.operands[0],
1162+
typeArguments[0].toUnsigned(),
1163+
Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP
1164+
)
1165+
: compiler.compileExpression(
1166+
ctx.operands[0],
1167+
Type.u32,
1168+
Constraints.MUST_WRAP
1169+
);
1170+
1171+
var type = compiler.currentType;
1172+
if (type.isValue) {
1173+
switch (type.kind) {
1174+
case TypeKind.BOOL:
1175+
case TypeKind.I8:
1176+
case TypeKind.U8: return arg0;
1177+
case TypeKind.I16:
1178+
case TypeKind.U16: {
1179+
// <T>(x << 8 | x >> 8)
1180+
let flow = compiler.currentFlow;
1181+
let temp = flow.getTempLocal(type);
1182+
flow.setLocalFlag(temp.index, LocalFlags.WRAPPED);
1183+
1184+
let res = module.binary(
1185+
BinaryOp.OrI32,
1186+
module.binary(
1187+
BinaryOp.ShlI32,
1188+
module.local_tee(temp.index, arg0, false),
1189+
module.i32(8)
1190+
),
1191+
module.binary(
1192+
BinaryOp.ShrU32,
1193+
module.local_get(temp.index, TypeRef.I32),
1194+
module.i32(8)
1195+
)
1196+
);
1197+
// avoid wrapping for u16 due to it's already done for input arg
1198+
if (type.kind == TypeKind.I16) {
1199+
res = compiler.ensureSmallIntegerWrap(res, Type.i16);
1200+
}
1201+
flow.freeTempLocal(temp);
1202+
return res;
1203+
}
1204+
case TypeKind.I32:
1205+
case TypeKind.U32:
1206+
case TypeKind.ISIZE:
1207+
case TypeKind.USIZE: {
1208+
if (type.size == 32) {
1209+
// rotl(x & 0xFF00FF00, 8) | rotr(x & 0x00FF00FF, 8)
1210+
let flow = compiler.currentFlow;
1211+
let temp = flow.getTempLocal(type);
1212+
flow.setLocalFlag(temp.index, LocalFlags.WRAPPED);
1213+
1214+
let res = module.binary(
1215+
BinaryOp.OrI32,
1216+
module.binary(
1217+
BinaryOp.RotlI32,
1218+
module.binary(
1219+
BinaryOp.AndI32,
1220+
module.local_tee(temp.index, arg0, false),
1221+
module.i32(0xFF00FF00)
1222+
),
1223+
module.i32(8)
1224+
),
1225+
module.binary(
1226+
BinaryOp.RotrI32,
1227+
module.binary(
1228+
BinaryOp.AndI32,
1229+
module.local_get(temp.index, TypeRef.I32),
1230+
module.i32(0x00FF00FF)
1231+
),
1232+
module.i32(8)
1233+
),
1234+
);
1235+
flow.freeTempLocal(temp);
1236+
return res;
1237+
}
1238+
// fall-through
1239+
}
1240+
case TypeKind.I64:
1241+
case TypeKind.U64: {
1242+
// let t =
1243+
// ((x >>> 8) & 0x00FF00FF00FF00FF) |
1244+
// ((x & 0x00FF00FF00FF00FF) << 8)
1245+
//
1246+
// let res =
1247+
// ((t >>> 16) & 0x0000FFFF0000FFFF) |
1248+
// ((t & 0x0000FFFF0000FFFF) << 16)
1249+
//
1250+
// rotr(res, 32)
1251+
1252+
let flow = compiler.currentFlow;
1253+
let temp1 = flow.getTempLocal(type);
1254+
flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED);
1255+
let temp2 = flow.getTempLocal(type);
1256+
flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED);
1257+
1258+
// t = ((x >>> 8) & 0x00FF00FF00FF00FF) | ((x & 0x00FF00FF00FF00FF) << 8)
1259+
let expr = module.local_tee(
1260+
temp2.index,
1261+
module.binary(
1262+
BinaryOp.OrI64,
1263+
module.binary(
1264+
BinaryOp.AndI64,
1265+
module.binary(
1266+
BinaryOp.ShrU64,
1267+
module.local_tee(temp1.index, arg0, false),
1268+
module.i64(8)
1269+
),
1270+
module.i64(0x00FF00FF, 0x00FF00FF)
1271+
),
1272+
module.binary(
1273+
BinaryOp.ShlI64,
1274+
module.binary(
1275+
BinaryOp.AndI64,
1276+
module.local_get(temp1.index, TypeRef.I64),
1277+
module.i64(0x00FF00FF, 0x00FF00FF)
1278+
),
1279+
module.i64(8)
1280+
),
1281+
),
1282+
false
1283+
);
1284+
1285+
// ((t >>> 16) & 0x0000FFFF0000FFFF) | ((t & 0x0000FFFF0000FFFF) << 16)
1286+
let res = module.binary(
1287+
BinaryOp.OrI64,
1288+
module.binary(
1289+
BinaryOp.AndI64,
1290+
module.binary(
1291+
BinaryOp.ShrU64,
1292+
expr,
1293+
module.i64(16)
1294+
),
1295+
module.i64(0x0000FFFF, 0x0000FFFF)
1296+
),
1297+
module.binary(
1298+
BinaryOp.ShlI64,
1299+
module.binary(
1300+
BinaryOp.AndI64,
1301+
module.local_get(temp2.index, TypeRef.I64),
1302+
module.i64(0x0000FFFF, 0x0000FFFF)
1303+
),
1304+
module.i64(16)
1305+
),
1306+
);
1307+
1308+
// rotr(res, 32)
1309+
res = module.binary(
1310+
BinaryOp.RotrI64,
1311+
res,
1312+
module.i64(32)
1313+
);
1314+
1315+
flow.freeTempLocal(temp2);
1316+
flow.freeTempLocal(temp1);
1317+
1318+
return res;
1319+
}
1320+
}
1321+
}
1322+
compiler.error(
1323+
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
1324+
ctx.reportNode.typeArgumentsRange, "bswap", type.toString()
1325+
);
1326+
return module.unreachable();
1327+
}
1328+
builtins.set(BuiltinNames.bswap, builtin_bswap);
1329+
11471330
// === Math ===================================================================================
11481331

11491332
// clz<T?>(value: T) -> T

‎src/types.ts

+12
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,18 @@ export class Type {
367367
return nullableType;
368368
}
369369

370+
/** Use unsigned type for according size if possible. */
371+
toUnsigned(): Type {
372+
switch (this.kind) {
373+
case TypeKind.I8: return Type.u8;
374+
case TypeKind.I16: return Type.u16;
375+
case TypeKind.I32: return Type.u32;
376+
case TypeKind.I64: return Type.u64;
377+
case TypeKind.ISIZE: return this.size == 64 ? Type.usize64 : Type.usize32;
378+
}
379+
return this;
380+
}
381+
370382
/** Tests if this type equals the specified. */
371383
equals(other: Type): bool {
372384
if (this.kind != other.kind) return false;

‎std/assembly/builtins.ts

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

67+
// @ts-ignore
68+
@builtin
69+
export declare function bswap<T>(value: T): T;
70+
6771
// @ts-ignore: decorator
6872
@builtin
6973
export declare function clz<T>(value: T): T;

‎std/assembly/index.d.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ declare const ASC_VERSION_PATCH: i32;
107107

108108
// Builtins
109109

110+
/** Performs the sign-agnostic reverse bytes **/
111+
declare function bswap<T extends i8 | u8 | i16 | u16 | i32 | u32 | i64 | u64 | isize | usize>(value: T): T;
110112
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */
111113
declare function clz<T extends i32 | i64>(value: T): T;
112114
/** Performs the sign-agnostic count tailing zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered trailing if the value is zero. */
@@ -1470,13 +1472,6 @@ declare function WARNING(message?: any): void;
14701472
/** Emits a user-defined diagnostic info when encountered. */
14711473
declare function INFO(message?: any): void;
14721474

1473-
// Polyfills
1474-
1475-
/** Performs the sign-agnostic reverse bytes **/
1476-
declare function bswap<T extends i8 | u8 | i16 | u16 | i32 | u32 | i64 | u64 | isize | usize>(value: T): T;
1477-
/** Performs the sign-agnostic reverse bytes only for last 16-bit **/
1478-
declare function bswap16<T extends i8 | u8 | i16 | u16 | i32 | u32>(value: T): T;
1479-
14801475
// Standard library
14811476

14821477
/** Memory operations. */

‎std/assembly/polyfills.ts

-46
This file was deleted.

‎std/portable/index.d.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ declare const ASC_FEATURE_SIGN_EXTENSION: bool;
5252

5353
// Builtins
5454

55+
/** Performs the sign-agnostic reverse bytes **/
56+
declare function bswap<T = i32 | u32 | isize | usize>(value: T): T;
5557
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit integer. All zero bits are considered leading if the value is zero. */
5658
declare function clz<T = i32>(value: T): T;
5759
/** Performs the sign-agnostic count tailing zero bits operation on a 32-bit integer. All zero bits are considered trailing if the value is zero. */
@@ -295,13 +297,6 @@ declare namespace f64 {
295297
export function parseInt(string: string, radix?: i32): f64;
296298
}
297299

298-
// Polyfills
299-
300-
/** [Polyfill] Performs the sign-agnostic reverse bytes **/
301-
declare function bswap<T = i32 | u32 | isize | usize>(value: T): T;
302-
/** [Polyfill] Performs the sign-agnostic reverse bytes only for last 16-bit **/
303-
declare function bswap16<T = i16 | u16 | i32 | u32>(value: T): T;
304-
305300
// Standard library
306301

307302
declare const Mathf: typeof Math;

‎std/portable/index.js

-4
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,6 @@ if (typeof globalScope.ASC_TARGET === "undefined") {
165165
return a | b;
166166
};
167167

168-
globalScope["bswap16"] = function bswap16(value) {
169-
return ((value << 8) & 0xFF00) | ((value >> 8) & 0x00FF) | (value & 0xFFFF0000);
170-
};
171-
172168
function UnreachableError() {
173169
if (Error.captureStackTrace) {
174170
Error.captureStackTrace(this, UnreachableError);
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.