@@ -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}
11451147builtins . 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
0 commit comments