@@ -143,6 +143,8 @@ export namespace BuiltinNames {
143
143
export const isManaged = "~lib/builtins/isManaged" ;
144
144
export const isVoid = "~lib/builtins/isVoid" ;
145
145
146
+ export const bswap = "~lib/builtins/bswap" ;
147
+
146
148
export const add = "~lib/builtins/add" ;
147
149
export const sub = "~lib/builtins/sub" ;
148
150
export const mul = "~lib/builtins/mul" ;
@@ -1144,6 +1146,187 @@ function builtin_idof(ctx: BuiltinContext): ExpressionRef {
1144
1146
}
1145
1147
builtins . set ( BuiltinNames . idof , builtin_idof ) ;
1146
1148
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
+
1147
1330
// === Math ===================================================================================
1148
1331
1149
1332
// clz<T?>(value: T) -> T
0 commit comments