Changeset 279362 in webkit
- Timestamp:
- Jun 28, 2021, 9:05:14 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 11 edited
-
ChangeLog (modified) (1 diff)
-
assembler/ARM64Assembler.h (modified) (1 diff)
-
assembler/MacroAssemblerARM64.h (modified) (3 diffs)
-
assembler/testmasm.cpp (modified) (17 diffs)
-
b3/B3LowerToAir.cpp (modified) (9 diffs)
-
b3/B3ReduceStrength.cpp (modified) (4 diffs)
-
b3/air/AirOpcode.opcodes (modified) (2 diffs)
-
b3/testb3.h (modified) (1 diff)
-
b3/testb3_2.cpp (modified) (6 diffs)
-
ftl/FTLLowerDFGToB3.cpp (modified) (1 diff)
-
jit/AssemblyHelpers.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r279343 r279362 1 2021-06-28 Yijia Huang <yijia_huang@apple.com> 2 3 Add a new pattern to instruction selector to use BIC supported by ARM64 4 https://bugs.webkit.org/show_bug.cgi?id=227202 5 6 Reviewed by Filip Pizlo. 7 8 This patch includes three modifications: 9 1. Add bit clear (BIC), or not (ORN), and extract and insert bitfield at lower end (FBXIL) 10 to Air opcode to serve intruciton selector. 11 2. Add bitfield clear (BFC) to MacroAssembler. 12 4. Do refactoring - rename Air opcodes added in the previous patches. 13 14 ------------------ 15 ### Part A BIC ### 16 ------------------ 17 Given the operation: 18 19 bic Rd, Rn, Rm 20 21 The BIC (Bit Clear) instruction performs an AND operation on the bits in Rn with the 22 complements of the corresponding bits in the value of Rm. The instruction selector can 23 utilize this to lowering certain patterns in B3 IR before further Air optimization. 24 The equivalent patterns of this instruction are: 25 26 Pattern 1: 27 d = n & (-m - 1) 28 29 Pattern 2: 30 d = n & (m ^ -1) 31 32 In order to get benefits for complement operation, current instruction selector uses 33 mvn instruction to lower the pattern value ^ -1. Then, a new strength reduction rule is 34 introduced: 35 Turn this: -value - 1 36 Into this: value ^ -1 37 38 So, d = n & (m ^ -1) is selected as the canonical form. 39 40 Given B3 IR: 41 Int @0 = ArgumentReg(%x0) 42 Int @1 = ArgumentReg(%x1) 43 Int @2 = -1 44 Int @3 = BitXor(@1, @2) 45 Int @4 = BitAnd(@0, @3) 46 Void@5 = Return(@4, Terminal) 47 48 Before Adding BIC: 49 // Old optimized AIR 50 Not %x1, %x1, @3 51 And %x0, %x1, %x0, @4 52 Ret %x0, @5 53 54 After Adding BIC: 55 // New optimized AIR 56 Bic %x0, %x1, %x0, @4 57 Ret %x0, @5 58 59 ------------------ 60 ### Part A ORN ### 61 ------------------ 62 Given the operation: 63 64 orn Rd, Rn, Rm 65 66 Bitwise OR NOT (shifted register) performs a bitwise (inclusive) OR of a register value 67 Rn and the complement of an optionally-shifted register value Rm, and writes the result 68 to the destination register Rd. 69 70 The equivalent patterns of this instruction are: 71 72 Pattern 1: 73 d = n | (-m - 1) 74 75 Pattern 2: 76 d = n | (m ^ -1) 77 78 Then, d = n | (m ^ -1) is selected as the canonical form. 79 80 Given B3 IR: 81 Int @0 = ArgumentReg(%x0) 82 Int @1 = ArgumentReg(%x1) 83 Int @2 = -1 84 Int @3 = BitXor(@1, @2) 85 Int @4 = BitOr(@0, @3) 86 Void@5 = Return(@4, Terminal) 87 88 Before Adding BIC: 89 // Old optimized AIR 90 Not %x1, %x1, @3 91 Or %x0, %x1, %x0, @4 92 Ret %x0, @5 93 94 After Adding BIC: 95 // New optimized AIR 96 Orn %x0, %x1, %x0, @4 97 Ret %x0, @5 98 99 -------------------- 100 ### Part A FBXIL ### 101 -------------------- 102 Given the operation: 103 104 bfxil Rd, Rn, lsb, width 105 106 Bitfield extract and insert at low end(FBXIL) copies any number of low-order bits 107 from a source register into the same number of adjacent bits at the low end in 108 the destination register, leaving other bits unchanged. 109 110 The equivalent patterns of this instruction are: 111 112 Pattern 1: 113 mask1 = (1 << width) - 1 114 mask2 = ~mask1 115 ((n >> lsb) & mask1) | (d & mask2) 116 117 Pattern 2: 118 mask1 = ((1 << width) - 1) << lsb 119 mask2 = ~(mask1 >> lsb) 120 ((n & mask1) >> lsb) | (d & mask2) 121 122 Then, introduce a strength reduction rule for easier recognization. 123 Turn this: (v & maskShift) >> shiftAmount 124 Into this: (v >> shiftAmount) & mask 125 126 with constraints: 127 1. maskShift = mask << lsb 128 2. mask = (1 << width) - 1 129 3. 0 <= shiftAmount < datasize 130 4. 0 < width < datasize 131 5. shiftAmount + width <= datasize 132 133 The canonical form to match FBXIL is d = ((n >> lsb) & mask1) | (d & mask2). 134 135 Given B3 IR: 136 Int @0 = ArgumentReg(%x0) 137 Int @1 = ArgumentReg(%x1) 138 Int @2 = lsb 139 Int @3 = mask1 140 Int @4 = mask2 141 Int @5 = BitAnd(@1, @3) 142 Int @6 = BitAnd(@0, @4)) 143 Int @7 = ZShr(@5, @2) 144 Int @8 = BitOr(@7, @6) 145 Void@9 = Return(@8, Terminal) 146 147 Before Adding BIC: 148 // Old optimized AIR 149 And mask2, %x0, %x0, @6 150 ExtractUnsignedBitfield %x1, lsb, width, %x1, @7 151 Or %x0, %x1, %x0, @8 152 Ret %x0, @9 153 154 After Adding BIC: 155 // New optimized AIR 156 ExtractInsertBitfieldAtLowEnd %x1, lsb, width, %x0, @8 157 Ret64 %x0, @9 158 159 -------------- 160 ### Part B ### 161 -------------- 162 The Bitfield Clear (BFC), leaving other bits unchanged, is similar to BFI which is an 163 alias of BFM. Given the operation: 164 165 bfc Rd, lsb, width 166 167 The equivalent pattern of this instruction is: 168 169 mask = ((1 << width) - 1) << lsb 170 d = d & ~mask 171 172 Since mask is a constant and B3 performs constant fold in the optimization phase, this 173 pattern will directly lower to the BitAnd binary operation. So, no need to match this pattern. 174 175 -------------- 176 ### Part C ### 177 -------------- 178 At MacroAssembler level, the emitters are exepected to be expressed in english 179 (e.g. something like clearBitField for BFC). Do refactoring to rename Air opcode for 180 UBFX, UBFIZ, BFI, and BIC. 181 182 * assembler/ARM64Assembler.h: 183 (JSC::ARM64Assembler::bfc): 184 * assembler/MacroAssemblerARM64.h: 185 (JSC::MacroAssemblerARM64::extractUnsignedBitfield32): 186 (JSC::MacroAssemblerARM64::extractUnsignedBitfield64): 187 (JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero32): 188 (JSC::MacroAssemblerARM64::insertUnsignedBitfieldInZero64): 189 (JSC::MacroAssemblerARM64::insertBitField32): 190 (JSC::MacroAssemblerARM64::insertBitField64): 191 (JSC::MacroAssemblerARM64::clearBitField32): 192 (JSC::MacroAssemblerARM64::clearBitField64): 193 (JSC::MacroAssemblerARM64::clearBitsWithMask32): 194 (JSC::MacroAssemblerARM64::clearBitsWithMask64): 195 (JSC::MacroAssemblerARM64::orNot32): 196 (JSC::MacroAssemblerARM64::orNot64): 197 (JSC::MacroAssemblerARM64::ubfx32): Deleted. 198 (JSC::MacroAssemblerARM64::ubfx64): Deleted. 199 (JSC::MacroAssemblerARM64::ubfiz32): Deleted. 200 (JSC::MacroAssemblerARM64::ubfiz64): Deleted. 201 (JSC::MacroAssemblerARM64::bitFieldInsert32): Deleted. 202 (JSC::MacroAssemblerARM64::bitFieldInsert64): Deleted. 203 * assembler/testmasm.cpp: 204 (JSC::testMultiplySignExtend32): 205 (JSC::testMultiplySubSignExtend32): 206 (JSC::testExtractUnsignedBitfield32): 207 (JSC::testExtractUnsignedBitfield64): 208 (JSC::testInsertUnsignedBitfieldInZero32): 209 (JSC::testInsertUnsignedBitfieldInZero64): 210 (JSC::testInsertBitField32): 211 (JSC::testInsertBitField64): 212 (JSC::testClearBitField32): 213 (JSC::testClearBitField64): 214 (JSC::testClearBitsWithMask32): 215 (JSC::testClearBitsWithMask64): 216 (JSC::testOrNot32): 217 (JSC::testOrNot64): 218 (JSC::testMul32SignExtend): Deleted. 219 (JSC::testMulSubSignExtend32): Deleted. 220 (JSC::testUbfx32): Deleted. 221 (JSC::testUbfx64): Deleted. 222 (JSC::testUbfiz32): Deleted. 223 (JSC::testUbfiz64): Deleted. 224 (JSC::testBitFieldInsert32): Deleted. 225 (JSC::testBitFieldInsert64): Deleted. 226 * b3/B3LowerToAir.cpp: 227 * b3/B3ReduceStrength.cpp: 228 * b3/air/AirOpcode.opcodes: 229 * b3/testb3.h: 230 * b3/testb3_2.cpp: 231 (testInsertBitField32): 232 (testInsertBitField64): 233 (testBIC32): 234 (testBIC64): 235 (testOrNot32): 236 (testOrNot64): 237 (addBitTests): 238 (testBitFieldInsert32): Deleted. 239 (testBitFieldInsert64): Deleted. 240 * ftl/FTLLowerDFGToB3.cpp: 241 (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq): 242 * jit/AssemblyHelpers.cpp: 243 (JSC::AssemblyHelpers::cageWithoutUntagging): 244 (JSC::AssemblyHelpers::cageConditionallyAndUntag): 245 1 246 2021-06-28 Mikhail R. Gadelha <mikhail@igalia.com> 2 247 -
trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h
r278856 r279362 834 834 835 835 template<int datasize> 836 ALWAYS_INLINE void bfc(RegisterID rd, int lsb, int width) 837 { 838 bfi<datasize>(rd, ARM64Registers::zr, lsb, width); 839 } 840 841 template<int datasize> 836 842 ALWAYS_INLINE void bfi(RegisterID rd, RegisterID rn, int lsb, int width) 837 843 { -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
r279256 r279362 391 391 } 392 392 393 void ubfx32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)394 {395 m_assembler.ubfx<32>(dest, src, lsb.m_value, width.m_value);396 }397 398 void ubfx64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)399 {400 m_assembler.ubfx<64>(dest, src, lsb.m_value, width.m_value);401 }402 403 void ubfiz32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)404 {405 m_assembler.ubfiz<32>(dest, src, lsb.m_value, width.m_value);406 }407 408 void ubfiz64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)409 {410 m_assembler.ubfiz<64>(dest, src, lsb.m_value, width.m_value);411 }412 413 393 void and64(RegisterID src1, RegisterID src2, RegisterID dest) 414 394 { … … 467 447 move(imm, getCachedDataTempRegisterIDAndInvalidate()); 468 448 m_assembler.and_<64>(dest, dest, dataTempRegister); 449 } 450 451 // Bit Operations: 452 void extractUnsignedBitfield32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 453 { 454 m_assembler.ubfx<32>(dest, src, lsb.m_value, width.m_value); 455 } 456 457 void extractUnsignedBitfield64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 458 { 459 m_assembler.ubfx<64>(dest, src, lsb.m_value, width.m_value); 460 } 461 462 void insertUnsignedBitfieldInZero32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 463 { 464 m_assembler.ubfiz<32>(dest, src, lsb.m_value, width.m_value); 465 } 466 467 void insertUnsignedBitfieldInZero64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 468 { 469 m_assembler.ubfiz<64>(dest, src, lsb.m_value, width.m_value); 470 } 471 472 void insertBitField32(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 473 { 474 m_assembler.bfi<32>(dest, source, lsb.m_value, width.m_value); 475 } 476 477 void insertBitField64(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 478 { 479 m_assembler.bfi<64>(dest, source, lsb.m_value, width.m_value); 480 } 481 482 void clearBitField32(TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 483 { 484 m_assembler.bfc<32>(dest, lsb.m_value, width.m_value); 485 } 486 487 void clearBitField64(TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 488 { 489 m_assembler.bfc<64>(dest, lsb.m_value, width.m_value); 490 } 491 492 void clearBitsWithMask32(RegisterID src, RegisterID mask, RegisterID dest) 493 { 494 m_assembler.bic<32>(dest, src, mask); 495 } 496 497 void clearBitsWithMask64(RegisterID src, RegisterID mask, RegisterID dest) 498 { 499 m_assembler.bic<64>(dest, src, mask); 500 } 501 502 void orNot32(RegisterID src, RegisterID mask, RegisterID dest) 503 { 504 m_assembler.orn<32>(dest, src, mask); 505 } 506 507 void orNot64(RegisterID src, RegisterID mask, RegisterID dest) 508 { 509 m_assembler.orn<64>(dest, src, mask); 510 } 511 512 void extractInsertBitfieldAtLowEnd32(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 513 { 514 m_assembler.bfxil<32>(dest, src, lsb.m_value, width.m_value); 515 } 516 517 void extractInsertBitfieldAtLowEnd64(RegisterID src, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest) 518 { 519 m_assembler.bfxil<64>(dest, src, lsb.m_value, width.m_value); 469 520 } 470 521 … … 2751 2802 m_assembler.tst<64>(left, right); 2752 2803 m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond)); 2753 }2754 2755 // Bit field operations:2756 void bitFieldInsert32(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)2757 {2758 m_assembler.bfi<32>(dest, source, lsb.m_value, width.m_value);2759 }2760 2761 // destBitOffset is the top bit of the destination where the bits should be copied to. Zero is the lowest order bit.2762 void bitFieldInsert64(RegisterID source, TrustedImm32 lsb, TrustedImm32 width, RegisterID dest)2763 {2764 m_assembler.bfi<64>(dest, source, lsb.m_value, width.m_value);2765 2804 } 2766 2805 -
trunk/Source/JavaScriptCore/assembler/testmasm.cpp
r279341 r279362 905 905 906 906 #if CPU(ARM64) 907 void testMul 32SignExtend()907 void testMultiplySignExtend32() 908 908 { 909 909 for (auto value : int32Operands()) { … … 1090 1090 } 1091 1091 1092 void testMul SubSignExtend32()1092 void testMultiplySubSignExtend32() 1093 1093 { 1094 1094 // d = a - SExt32(n) * SExt32(m) … … 1113 1113 } 1114 1114 1115 void test Ubfx32()1115 void testExtractUnsignedBitfield32() 1116 1116 { 1117 1117 uint32_t src = 0xf0f0f0f0; … … 1123 1123 emitFunctionPrologue(jit); 1124 1124 1125 jit. ubfx32(GPRInfo::argumentGPR0,1125 jit.extractUnsignedBitfield32(GPRInfo::argumentGPR0, 1126 1126 CCallHelpers::TrustedImm32(lsb), 1127 1127 CCallHelpers::TrustedImm32(width), … … 1137 1137 } 1138 1138 1139 void test Ubfx64()1139 void testExtractUnsignedBitfield64() 1140 1140 { 1141 1141 uint64_t src = 0xf0f0f0f0f0f0f0f0; … … 1147 1147 emitFunctionPrologue(jit); 1148 1148 1149 jit. ubfx64(GPRInfo::argumentGPR0,1149 jit.extractUnsignedBitfield64(GPRInfo::argumentGPR0, 1150 1150 CCallHelpers::TrustedImm32(lsb), 1151 1151 CCallHelpers::TrustedImm32(width), … … 1161 1161 } 1162 1162 1163 void test Ubfiz32()1163 void testInsertUnsignedBitfieldInZero32() 1164 1164 { 1165 1165 uint32_t src = 0xf0f0f0f0; … … 1171 1171 emitFunctionPrologue(jit); 1172 1172 1173 jit. ubfiz32(GPRInfo::argumentGPR0,1173 jit.insertUnsignedBitfieldInZero32(GPRInfo::argumentGPR0, 1174 1174 CCallHelpers::TrustedImm32(lsb), 1175 1175 CCallHelpers::TrustedImm32(width), … … 1186 1186 } 1187 1187 1188 void test Ubfiz64()1188 void testInsertUnsignedBitfieldInZero64() 1189 1189 { 1190 1190 uint64_t src = 0xf0f0f0f0f0f0f0f0; … … 1196 1196 emitFunctionPrologue(jit); 1197 1197 1198 jit. ubfiz64(GPRInfo::argumentGPR0,1198 jit.insertUnsignedBitfieldInZero64(GPRInfo::argumentGPR0, 1199 1199 CCallHelpers::TrustedImm32(lsb), 1200 1200 CCallHelpers::TrustedImm32(width), … … 1211 1211 } 1212 1212 1213 void test BitFieldInsert32()1213 void testInsertBitField32() 1214 1214 { 1215 1215 uint32_t src = 0x0f0f0f0f; … … 1222 1222 emitFunctionPrologue(jit); 1223 1223 1224 jit. bitFieldInsert64(GPRInfo::argumentGPR0,1224 jit.insertBitField32(GPRInfo::argumentGPR0, 1225 1225 CCallHelpers::TrustedImm32(lsb), 1226 1226 CCallHelpers::TrustedImm32(width), … … 1241 1241 } 1242 1242 1243 void test BitFieldInsert64()1243 void testInsertBitField64() 1244 1244 { 1245 1245 uint64_t src = 0x0f0f0f0f0f0f0f0f; … … 1252 1252 emitFunctionPrologue(jit); 1253 1253 1254 jit. bitFieldInsert64(GPRInfo::argumentGPR0,1254 jit.insertBitField64(GPRInfo::argumentGPR0, 1255 1255 CCallHelpers::TrustedImm32(lsb), 1256 1256 CCallHelpers::TrustedImm32(width), … … 1268 1268 } 1269 1269 } 1270 } 1271 } 1272 1273 void testExtractInsertBitfieldAtLowEnd32() 1274 { 1275 uint32_t src = 0xf0f0f0f0; 1276 uint32_t dst = 0x0f0f0f0f; 1277 Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 }; 1278 for (auto lsb : imms) { 1279 for (auto width : imms) { 1280 if (lsb >= 0 && width > 0 && lsb + width < 32) { 1281 auto bfxil32 = compile([=] (CCallHelpers& jit) { 1282 emitFunctionPrologue(jit); 1283 1284 jit.extractInsertBitfieldAtLowEnd32(GPRInfo::argumentGPR0, 1285 CCallHelpers::TrustedImm32(lsb), 1286 CCallHelpers::TrustedImm32(width), 1287 GPRInfo::argumentGPR1); 1288 jit.move(GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1289 1290 emitFunctionEpilogue(jit); 1291 jit.ret(); 1292 }); 1293 uint32_t mask1 = (1U << width) - 1U; 1294 uint32_t mask2 = ~mask1; 1295 uint32_t rhs = invoke<uint32_t>(bfxil32, src, dst); 1296 uint32_t lhs = ((src >> lsb) & mask1) | (dst & mask2); 1297 CHECK_EQ(rhs, lhs); 1298 } 1299 } 1300 } 1301 } 1302 1303 void testExtractInsertBitfieldAtLowEnd64() 1304 { 1305 uint64_t src = 0x0f0f0f0f0f0f0f0f; 1306 uint64_t dst = 0xf0f0f0f0f0f0f0f0; 1307 Vector<uint64_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 }; 1308 for (auto lsb : imms) { 1309 for (auto width : imms) { 1310 if (lsb >= 0 && width > 0 && lsb + width < 64) { 1311 auto bfxil64 = compile([=] (CCallHelpers& jit) { 1312 emitFunctionPrologue(jit); 1313 1314 jit.extractInsertBitfieldAtLowEnd64(GPRInfo::argumentGPR0, 1315 CCallHelpers::TrustedImm32(lsb), 1316 CCallHelpers::TrustedImm32(width), 1317 GPRInfo::argumentGPR1); 1318 jit.move(GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1319 1320 emitFunctionEpilogue(jit); 1321 jit.ret(); 1322 }); 1323 uint64_t mask1 = (1ULL << width) - 1ULL; 1324 uint64_t mask2 = ~mask1; 1325 uint64_t rhs = invoke<uint64_t>(bfxil64, src, dst); 1326 uint64_t lhs = ((src >> lsb) & mask1) | (dst & mask2); 1327 CHECK_EQ(rhs, lhs); 1328 } 1329 } 1330 } 1331 } 1332 1333 void testClearBitField32() 1334 { 1335 uint32_t src = std::numeric_limits<uint32_t>::max(); 1336 Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 }; 1337 for (auto lsb : imms) { 1338 for (auto width : imms) { 1339 if (lsb >= 0 && width > 0 && lsb + width < 32) { 1340 auto bfc32 = compile([=] (CCallHelpers& jit) { 1341 emitFunctionPrologue(jit); 1342 1343 jit.clearBitField32(CCallHelpers::TrustedImm32(lsb), CCallHelpers::TrustedImm32(width), GPRInfo::argumentGPR0); 1344 jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR); 1345 1346 emitFunctionEpilogue(jit); 1347 jit.ret(); 1348 }); 1349 uint32_t mask = ((1U << width) - 1U) << lsb; 1350 uint32_t rhs = invoke<uint32_t>(bfc32, src); 1351 uint32_t lhs = src & ~mask; 1352 CHECK_EQ(rhs, lhs); 1353 } 1354 } 1355 } 1356 } 1357 1358 void testClearBitField64() 1359 { 1360 uint64_t src = std::numeric_limits<uint64_t>::max(); 1361 Vector<uint32_t> imms = { 0, 1, 5, 7, 30, 31, 32, 42, 56, 62, 63, 64 }; 1362 for (auto lsb : imms) { 1363 for (auto width : imms) { 1364 if (lsb >= 0 && width > 0 && lsb + width < 32) { 1365 auto bfc64 = compile([=] (CCallHelpers& jit) { 1366 emitFunctionPrologue(jit); 1367 1368 jit.clearBitField64(CCallHelpers::TrustedImm32(lsb), CCallHelpers::TrustedImm32(width), GPRInfo::argumentGPR0); 1369 jit.move(GPRInfo::argumentGPR0, GPRInfo::returnValueGPR); 1370 1371 emitFunctionEpilogue(jit); 1372 jit.ret(); 1373 }); 1374 uint64_t mask = ((1ULL << width) - 1ULL) << lsb; 1375 uint64_t rhs = invoke<uint64_t>(bfc64, src); 1376 uint64_t lhs = src & ~mask; 1377 CHECK_EQ(rhs, lhs); 1378 } 1379 } 1380 } 1381 } 1382 1383 void testClearBitsWithMask32() 1384 { 1385 auto test = compile([] (CCallHelpers& jit) { 1386 emitFunctionPrologue(jit); 1387 1388 jit.clearBitsWithMask32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1389 1390 emitFunctionEpilogue(jit); 1391 jit.ret(); 1392 }); 1393 1394 for (auto mask : int32Operands()) { 1395 uint32_t src = std::numeric_limits<uint32_t>::max(); 1396 CHECK_EQ(invoke<uint32_t>(test, src, mask), (src & ~mask)); 1397 CHECK_EQ(invoke<uint32_t>(test, 0U, mask), 0U); 1398 } 1399 } 1400 1401 void testClearBitsWithMask64() 1402 { 1403 auto test = compile([] (CCallHelpers& jit) { 1404 emitFunctionPrologue(jit); 1405 1406 jit.clearBitsWithMask64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1407 1408 emitFunctionEpilogue(jit); 1409 jit.ret(); 1410 }); 1411 1412 for (auto mask : int64Operands()) { 1413 uint64_t src = std::numeric_limits<uint64_t>::max(); 1414 CHECK_EQ(invoke<uint64_t>(test, src, mask), (src & ~mask)); 1415 CHECK_EQ(invoke<uint64_t>(test, 0ULL, mask), 0ULL); 1416 } 1417 } 1418 1419 void testOrNot32() 1420 { 1421 auto test = compile([] (CCallHelpers& jit) { 1422 emitFunctionPrologue(jit); 1423 1424 jit.orNot32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1425 1426 emitFunctionEpilogue(jit); 1427 jit.ret(); 1428 }); 1429 1430 for (auto mask : int32Operands()) { 1431 int32_t src = std::numeric_limits<uint32_t>::max(); 1432 CHECK_EQ(invoke<int32_t>(test, src, mask), (src | ~mask)); 1433 CHECK_EQ(invoke<int32_t>(test, 0U, mask), ~mask); 1434 } 1435 } 1436 1437 void testOrNot64() 1438 { 1439 auto test = compile([] (CCallHelpers& jit) { 1440 emitFunctionPrologue(jit); 1441 1442 jit.orNot64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::returnValueGPR); 1443 1444 emitFunctionEpilogue(jit); 1445 jit.ret(); 1446 }); 1447 1448 for (auto mask : int64Operands()) { 1449 int64_t src = std::numeric_limits<uint64_t>::max(); 1450 CHECK_EQ(invoke<int64_t>(test, src, mask), (src | ~mask)); 1451 CHECK_EQ(invoke<int64_t>(test, 0ULL, mask), ~mask); 1270 1452 } 1271 1453 } … … 3426 3608 RUN(testLoadStorePair64Int64()); 3427 3609 RUN(testLoadStorePair64Double()); 3428 RUN(testMul32SignExtend()); 3429 RUN(testMultiplyAddSignExtend32Left()); 3430 RUN(testMultiplyAddSignExtend32Right()); 3610 RUN(testMultiplySignExtend32()); 3611 3431 3612 RUN(testSub32Args()); 3432 3613 RUN(testSub32Imm()); … … 3436 3617 RUN(testSub64Imm64()); 3437 3618 RUN(testSub64ArgImm64()); 3438 RUN(testMulSubSignExtend32()); 3439 RUN(testUbfx32()); 3440 RUN(testUbfx64()); 3441 RUN(testUbfiz32()); 3442 RUN(testUbfiz64()); 3443 RUN(testBitFieldInsert32()); 3444 RUN(testBitFieldInsert64()); 3619 3620 RUN(testMultiplyAddSignExtend32Left()); 3621 RUN(testMultiplyAddSignExtend32Right()); 3622 RUN(testMultiplySubSignExtend32()); 3623 3624 RUN(testExtractUnsignedBitfield32()); 3625 RUN(testExtractUnsignedBitfield64()); 3626 RUN(testInsertUnsignedBitfieldInZero32()); 3627 RUN(testInsertUnsignedBitfieldInZero64()); 3628 RUN(testInsertBitField32()); 3629 RUN(testInsertBitField64()); 3630 RUN(testExtractInsertBitfieldAtLowEnd32()); 3631 RUN(testExtractInsertBitfieldAtLowEnd64()); 3632 RUN(testClearBitField32()); 3633 RUN(testClearBitField64()); 3634 RUN(testClearBitsWithMask32()); 3635 RUN(testClearBitsWithMask64()); 3636 3637 RUN(testOrNot32()); 3638 RUN(testOrNot64()); 3445 3639 #endif 3446 3640 -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r279249 r279362 2765 2765 // Where: mask = (1 << width) - 1 2766 2766 auto tryAppendUBFX = [&] () -> bool { 2767 Air::Opcode opcode = opcodeForType( Ubfx32, Ubfx64, m_value->type());2767 Air::Opcode opcode = opcodeForType(ExtractUnsignedBitfield32, ExtractUnsignedBitfield64, m_value->type()); 2768 2768 if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp)) 2769 2769 return false; … … 2781 2781 return false; 2782 2782 uint64_t width = WTF::bitCount(mask); 2783 uint64_t datasize = opcode == Ubfx32 ? 32 : 64;2783 uint64_t datasize = opcode == ExtractUnsignedBitfield32 ? 32 : 64; 2784 2784 if (lsb + width > datasize) 2785 2785 return false; … … 2793 2793 return; 2794 2794 2795 // BIC Pattern: d = n & (m ^ -1) 2796 auto tryAppendBIC = [&] (Value* left, Value* right) -> bool { 2797 Air::Opcode opcode = opcodeForType(ClearBitsWithMask32, ClearBitsWithMask64, m_value->type()); 2798 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) 2799 return false; 2800 if (right->opcode() != BitXor || !canBeInternal(right)) 2801 return false; 2802 2803 Value* nValue = left; 2804 Value* mValue = right->child(0); 2805 Value* minusOne = right->child(1); 2806 if (m_locked.contains(nValue) || m_locked.contains(mValue) || !minusOne->hasInt() || !minusOne->isInt(-1)) 2807 return false; 2808 2809 append(opcode, tmp(nValue), tmp(mValue), tmp(m_value)); 2810 commitInternal(right); 2811 return true; 2812 }; 2813 2814 if (tryAppendBIC(left, right) || tryAppendBIC(right, left)) 2815 return; 2816 2795 2817 appendBinOp<And32, And64, AndDouble, AndFloat, Commutative>(left, right); 2796 2818 return; … … 2805 2827 // mask2 = ~(mask1 << lsb) 2806 2828 auto tryAppendBFI = [&] (Value* left, Value* right) -> bool { 2807 Air::Opcode opcode = opcodeForType( BitFieldInsert32, BitFieldInsert64, m_value->type());2829 Air::Opcode opcode = opcodeForType(InsertBitField32, InsertBitField64, m_value->type()); 2808 2830 if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp)) 2809 2831 return false; … … 2829 2851 if (!mask1 || mask1 & (mask1 + 1)) 2830 2852 return false; 2831 uint64_t datasize = opcode == BitFieldInsert32 ? 32 : 64;2853 uint64_t datasize = opcode == InsertBitField32 ? 32 : 64; 2832 2854 uint64_t width = WTF::bitCount(mask1); 2833 2855 if (lsb + width > datasize) … … 2858 2880 return; 2859 2881 2882 // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2) 2883 // Where: mask1 = ((1 << width) - 1) 2884 // mask2 = ~mask1 2885 auto tryAppendBFXIL = [&] (Value* left, Value* right) -> bool { 2886 Air::Opcode opcode = opcodeForType(ExtractInsertBitfieldAtLowEnd32, ExtractInsertBitfieldAtLowEnd64, m_value->type()); 2887 if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp)) 2888 return false; 2889 if (left->opcode() != BitAnd || !canBeInternal(left)) 2890 return false; 2891 if (left->child(0)->opcode() != ZShr || !canBeInternal(left->child(0))) 2892 return false; 2893 if (right->opcode() != BitAnd || !canBeInternal(right)) 2894 return false; 2895 2896 Value* nValue = left->child(0)->child(0); 2897 Value* maskValue1 = left->child(1); 2898 Value* lsbValue = left->child(0)->child(1); 2899 Value* dValue = right->child(0); 2900 Value* maskValue2 = right->child(1); 2901 if (m_locked.contains(nValue) || m_locked.contains(dValue)) 2902 return false; 2903 if (!maskValue1->hasInt() || !imm(lsbValue) || lsbValue->asInt() < 0 || !maskValue2->hasInt()) 2904 return false; 2905 2906 uint64_t lsb = lsbValue->asInt(); 2907 uint64_t mask1 = maskValue1->asInt(); 2908 if (!mask1 || mask1 & (mask1 + 1)) 2909 return false; 2910 uint64_t width = WTF::bitCount(mask1); 2911 uint64_t datasize = opcode == ExtractInsertBitfieldAtLowEnd32 ? 32 : 64; 2912 if (lsb + width > datasize) 2913 return false; 2914 uint64_t mask2 = maskValue2->asInt(); 2915 2916 auto isValidMask2 = [&] () -> bool { 2917 uint64_t mask = mask1 ^ mask2; 2918 uint64_t lowerSet = 0xffffffff; 2919 uint64_t fullSet = 0xffffffffffffffff; 2920 return datasize == 32 ? !((mask & lowerSet) ^ lowerSet) : !(mask ^ fullSet); 2921 }; 2922 2923 if (!isValidMask2()) 2924 return false; 2925 2926 Tmp result = tmp(m_value); 2927 append(relaxedMoveForType(m_value->type()), tmp(dValue), result); 2928 append(opcode, tmp(nValue), imm(lsbValue), imm(width), result); 2929 commitInternal(left->child(0)); 2930 commitInternal(left); 2931 commitInternal(right); 2932 return true; 2933 }; 2934 2935 if (tryAppendBFXIL(left, right) || tryAppendBFXIL(right, left)) 2936 return; 2937 2938 // ORN Pattern: d = n | (m ^ -1) 2939 auto tryAppendORN = [&] (Value* left, Value* right) -> bool { 2940 Air::Opcode opcode = opcodeForType(OrNot32, OrNot64, m_value->type()); 2941 if (!isValidForm(opcode, Arg::Tmp, Arg::Tmp, Arg::Tmp)) 2942 return false; 2943 if (right->opcode() != BitXor || !canBeInternal(right)) 2944 return false; 2945 2946 Value* nValue = left; 2947 Value* mValue = right->child(0); 2948 Value* minusOne = right->child(1); 2949 if (m_locked.contains(nValue) || m_locked.contains(mValue) || !minusOne->hasInt() || !minusOne->isInt(-1)) 2950 return false; 2951 2952 append(opcode, tmp(nValue), tmp(mValue), tmp(m_value)); 2953 commitInternal(right); 2954 return true; 2955 }; 2956 2957 if (tryAppendORN(left, right) || tryAppendORN(right, left)) 2958 return; 2959 2860 2960 appendBinOp<Or32, Or64, OrDouble, OrFloat, Commutative>(left, right); 2861 2961 return; … … 2900 3000 // Where: mask = (1 << width) - 1 2901 3001 auto tryAppendUBFZ = [&] () -> bool { 2902 Air::Opcode opcode = opcodeForType( Ubfiz32, Ubfiz64, m_value->type());3002 Air::Opcode opcode = opcodeForType(InsertUnsignedBitfieldInZero32, InsertUnsignedBitfieldInZero64, m_value->type()); 2903 3003 if (!isValidForm(opcode, Arg::Tmp, Arg::Imm, Arg::Imm, Arg::Tmp)) 2904 3004 return false; … … 2916 3016 return false; 2917 3017 uint64_t width = WTF::bitCount(mask); 2918 uint64_t datasize = opcode == Ubfiz32 ? 32 : 64;3018 uint64_t datasize = opcode == InsertUnsignedBitfieldInZero32 ? 32 : 64; 2919 3019 if (lsb + width > datasize) 2920 3020 return false; … … 2943 3043 2944 3044 case ZShr: { 2945 appendShift<Urshift32, Urshift64>(m_value->child(0), m_value->child(1)); 3045 Value* left = m_value->child(0); 3046 Value* right = m_value->child(1); 3047 3048 appendShift<Urshift32, Urshift64>(left, right); 2946 3049 return; 2947 3050 } -
trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp
r279193 r279362 628 628 629 629 if (m_value->isInteger()) { 630 // Turn this: Sub(Neg(value), 1) 631 // Into this: BitXor(value, -1) 632 if (m_value->child(0)->opcode() == Neg && m_value->child(1)->isInt(1)) { 633 Value* minusOne; 634 if (m_value->child(0)->child(0)->type() == Int32) 635 minusOne = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), -1); 636 else 637 minusOne = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), -1); 638 replaceWithNew<Value>(BitXor, m_value->origin(), m_value->child(0)->child(0), minusOne); 639 break; 640 } 641 630 642 // Turn this: Sub(value, constant) 631 643 // Into this: Add(value, -constant) … … 1061 1073 1062 1074 // Turn this: BitAnd(Shl(value, shiftAmount), maskShift) 1075 // Into this: Shl(BitAnd(value, mask), shiftAmount) 1063 1076 // Conditions: 1064 1077 // 1. maskShift = mask << shiftAmount … … 1067 1080 // 4. 0 < width < datasize 1068 1081 // 5. shiftAmount + width <= datasize 1069 // Into this: Shl(BitAnd(value, mask), shiftAmount)1070 1082 if (m_value->child(0)->opcode() == Shl 1071 1083 && m_value->child(0)->child(1)->hasInt() … … 1423 1435 replaceWithNewValue(constant); 1424 1436 break; 1437 } 1438 1439 // Turn this: ZShr(BitAnd(value, maskShift), shiftAmount) 1440 // Into this: BitAnd(ZShr(value, shiftAmount), mask) 1441 // Conditions: 1442 // 1. maskShift = mask << shiftAmount 1443 // 2. mask = (1 << width) - 1 1444 // 3. 0 <= shiftAmount < datasize 1445 // 4. 0 < width < datasize 1446 // 5. shiftAmount + width <= datasize 1447 if (m_value->child(0)->opcode() == BitAnd 1448 && m_value->child(0)->child(1)->hasInt() 1449 && m_value->child(1)->hasInt() 1450 && m_value->child(1)->asInt() >= 0) { 1451 uint64_t shiftAmount = m_value->child(1)->asInt(); 1452 uint64_t maskShift = m_value->child(0)->child(1)->asInt(); 1453 uint64_t maskShiftAmount = WTF::countTrailingZeros(maskShift); 1454 uint64_t mask = maskShift >> maskShiftAmount; 1455 uint64_t width = WTF::bitCount(mask); 1456 uint64_t datasize = m_value->child(0)->child(0)->type() == Int64 ? 64 : 32; 1457 bool isValidShiftAmount = maskShiftAmount == shiftAmount && shiftAmount < datasize; 1458 bool isValidMask = mask && !(mask & (mask + 1)) && width < datasize; 1459 if (isValidShiftAmount && isValidMask && shiftAmount + width <= datasize) { 1460 Value* maskValue; 1461 if (datasize == 32) 1462 maskValue = m_insertionSet.insert<Const32Value>(m_index, m_value->origin(), mask); 1463 else 1464 maskValue = m_insertionSet.insert<Const64Value>(m_index, m_value->origin(), mask); 1465 Value* shiftValue = m_insertionSet.insert<Value>(m_index, ZShr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)); 1466 replaceWithNew<Value>(BitAnd, m_value->origin(), shiftValue, maskValue); 1467 break; 1468 } 1425 1469 } 1426 1470 -
trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
r279249 r279362 364 364 x86: Imm, Index 365 365 366 arm64: Ubfx32 U:G:32, U:G:32, U:G:32, ZD:G:32367 Tmp, Imm, Imm, Tmp368 369 arm64: Ubfx64 U:G:64, U:G:32, U:G:32, D:G:64370 Tmp, Imm, Imm, Tmp371 372 arm64: Ubfiz32 U:G:32, U:G:32, U:G:32, ZD:G:32373 Tmp, Imm, Imm, Tmp374 375 arm64: Ubfiz64 U:G:64, U:G:32, U:G:32, D:G:64376 Tmp, Imm, Imm, Tmp377 378 arm64: BitFieldInsert32 U:G:32, U:G:32, U:G:32, ZD:G:32379 Tmp, Imm, Imm, Tmp380 381 arm64: BitFieldInsert64 U:G:64, U:G:32, U:G:32, D:G:64382 Tmp, Imm, Imm, Tmp383 384 366 64: And64 U:G:64, U:G:64, D:G:64 385 367 Tmp, Tmp, Tmp … … 831 813 Tmp, Index 832 814 815 arm64: ExtractUnsignedBitfield32 U:G:32, U:G:32, U:G:32, ZD:G:32 816 Tmp, Imm, Imm, Tmp 817 818 arm64: ExtractUnsignedBitfield64 U:G:64, U:G:32, U:G:32, D:G:64 819 Tmp, Imm, Imm, Tmp 820 821 arm64: InsertUnsignedBitfieldInZero32 U:G:32, U:G:32, U:G:32, ZD:G:32 822 Tmp, Imm, Imm, Tmp 823 824 arm64: InsertUnsignedBitfieldInZero64 U:G:64, U:G:32, U:G:32, D:G:64 825 Tmp, Imm, Imm, Tmp 826 827 arm64: InsertBitField32 U:G:32, U:G:32, U:G:32, ZD:G:32 828 Tmp, Imm, Imm, Tmp 829 830 arm64: InsertBitField64 U:G:64, U:G:32, U:G:32, D:G:64 831 Tmp, Imm, Imm, Tmp 832 833 arm64: ClearBitField32 U:G:32, U:G:32, ZD:G:32 834 Imm, Imm, Tmp 835 836 arm64: ClearBitField64 U:G:32, U:G:32, D:G:64 837 Imm, Imm, Tmp 838 839 arm64: ClearBitsWithMask32 U:G:32, U:G:32, ZD:G:32 840 Tmp, Tmp, Tmp 841 842 arm64: ClearBitsWithMask64 U:G:64, U:G:64, D:G:64 843 Tmp, Tmp, Tmp 844 845 arm64: OrNot32 U:G:32, U:G:32, ZD:G:32 846 Tmp, Tmp, Tmp 847 848 arm64: OrNot64 U:G:64, U:G:64, D:G:64 849 Tmp, Tmp, Tmp 850 851 arm64: ExtractInsertBitfieldAtLowEnd32 U:G:32, U:G:32, U:G:32, ZD:G:32 852 Tmp, Imm, Imm, Tmp 853 854 arm64: ExtractInsertBitfieldAtLowEnd64 U:G:64, U:G:32, U:G:32, D:G:64 855 Tmp, Imm, Imm, Tmp 856 833 857 # The first operand is rax. 834 858 # FIXME: This formulation means that the boolean result cannot be put in eax, even though all users -
trunk/Source/JavaScriptCore/b3/testb3.h
r279249 r279362 429 429 void testUbfiz64ShiftAnd(); 430 430 void testUbfiz64AndShift(); 431 void testBitFieldInsert32(); 432 void testBitFieldInsert64(); 431 void testInsertBitField32(); 432 void testInsertBitField64(); 433 void testExtractInsertBitfieldAtLowEnd32(); 434 void testExtractInsertBitfieldAtLowEnd64(); 435 void testBIC32(); 436 void testBIC64(); 437 void testOrNot32(); 438 void testOrNot64(); 433 439 void testBitAndZeroShiftRightArgImmMask32(); 434 440 void testBitAndZeroShiftRightArgImmMask64(); -
trunk/Source/JavaScriptCore/b3/testb3_2.cpp
r279249 r279362 3159 3159 } 3160 3160 3161 void test BitFieldInsert32()3161 void testInsertBitField32() 3162 3162 { 3163 3163 if (JSC::Options::defaultB3OptLevel() < 2) … … 3165 3165 uint32_t d = 0xf0f0f0f0; 3166 3166 uint32_t n = 0xffffffff; 3167 Vector<uint32_t> lsbs = { 1, 2, 14, 30, 30 };3167 Vector<uint32_t> lsbs = { 2, 2, 14, 30, 30 }; 3168 3168 Vector<uint32_t> widths = { 30, 3, 17, 1, 2 }; 3169 3169 … … 3237 3237 } 3238 3238 3239 void test BitFieldInsert64()3239 void testInsertBitField64() 3240 3240 { 3241 3241 if (JSC::Options::defaultB3OptLevel() < 2) … … 3243 3243 uint64_t d = 0xf0f0f0f0f0f0f0f0; 3244 3244 uint64_t n = 0xffffffffffffffff; 3245 Vector<uint64_t> lsbs = { 1, 30, 14, 62, 62 };3245 Vector<uint64_t> lsbs = { 2, 30, 14, 62, 62 }; 3246 3246 Vector<uint64_t> widths = { 62, 33, 17, 1, 2 }; 3247 3247 … … 3304 3304 CHECK(test1(lsb, mask1, mask2) == (((n & mask1) << lsb) | (d & mask2))); 3305 3305 CHECK(test2(lsb, mask1, mask2) == ((d & mask2) | ((n & mask1) << lsb))); 3306 } 3307 } 3308 3309 void testExtractInsertBitfieldAtLowEnd32() 3310 { 3311 if (JSC::Options::defaultB3OptLevel() < 2) 3312 return; 3313 uint32_t d = 0xf0f0f0f0; 3314 uint32_t n = 0xffffffff; 3315 Vector<uint32_t> lsbs = { 1, 10, 14, 30 }; 3316 Vector<uint32_t> widths = { 30, 11, 17, 1 }; 3317 3318 // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2) 3319 // Where: mask1 = ((1 << width) - 1) 3320 // mask2 = ~mask1 3321 auto test1 = [&] (uint32_t lsb, uint32_t mask1, uint32_t mask2) -> uint32_t { 3322 Procedure proc; 3323 BasicBlock* root = proc.addBlock(); 3324 3325 Value* dValue = root->appendNew<Value>( 3326 proc, Trunc, Origin(), 3327 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3328 Value* nValue = root->appendNew<Value>( 3329 proc, Trunc, Origin(), 3330 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3331 Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb); 3332 Value* maskValue1 = root->appendNew<Const32Value>(proc, Origin(), mask1); 3333 Value* maskValue2 = root->appendNew<Const32Value>(proc, Origin(), mask2); 3334 3335 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), nValue, lsbValue); 3336 Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), shiftValue, maskValue1); 3337 Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2); 3338 root->appendNewControlValue( 3339 proc, Return, Origin(), 3340 root->appendNew<Value>(proc, BitOr, Origin(), leftAndValue, rightAndValue)); 3341 3342 auto code = compileProc(proc); 3343 if (isARM64()) 3344 checkUsesInstruction(*code, "bfxil"); 3345 return invoke<uint32_t>(*code, d, n); 3346 }; 3347 3348 for (size_t i = 0; i < lsbs.size(); ++i) { 3349 uint32_t lsb = lsbs.at(i); 3350 uint32_t mask1 = (1U << widths.at(i)) - 1U; 3351 uint32_t mask2 = ~mask1; 3352 CHECK(test1(lsb, mask1, mask2) == (((n >> lsb) & mask1) | (d & mask2))); 3353 } 3354 3355 // BFXIL Pattern: d = ((n & mask1) >> lsb) | (d & mask2) 3356 // Where: mask1 = ((1 << width) - 1) << lsb 3357 // mask2 = ~(mask1 >> lsb) 3358 auto test2 = [&] (uint32_t lsb, uint32_t mask1, uint32_t mask2) -> uint32_t { 3359 Procedure proc; 3360 BasicBlock* root = proc.addBlock(); 3361 3362 Value* dValue = root->appendNew<Value>( 3363 proc, Trunc, Origin(), 3364 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3365 Value* nValue = root->appendNew<Value>( 3366 proc, Trunc, Origin(), 3367 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3368 Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb); 3369 Value* maskValue1 = root->appendNew<Const32Value>(proc, Origin(), mask1); 3370 Value* maskValue2 = root->appendNew<Const32Value>(proc, Origin(), mask2); 3371 3372 Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, maskValue1); 3373 Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2); 3374 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), leftAndValue, lsbValue); 3375 root->appendNewControlValue( 3376 proc, Return, Origin(), 3377 root->appendNew<Value>(proc, BitOr, Origin(), shiftValue, rightAndValue)); 3378 3379 auto code = compileProc(proc); 3380 if (isARM64()) 3381 checkUsesInstruction(*code, "bfxil"); 3382 return invoke<uint32_t>(*code, d, n); 3383 }; 3384 3385 for (size_t i = 0; i < lsbs.size(); ++i) { 3386 uint32_t lsb = lsbs.at(i); 3387 uint32_t mask1 = ((1U << widths.at(i)) - 1U) << lsb; 3388 uint32_t mask2 = ~(mask1 >> lsb); 3389 CHECK(test2(lsb, mask1, mask2) == (((n & mask1) >> lsb) | (d & mask2))); 3390 } 3391 } 3392 3393 void testExtractInsertBitfieldAtLowEnd64() 3394 { 3395 if (JSC::Options::defaultB3OptLevel() < 2) 3396 return; 3397 uint64_t d = 0xf0f0f0f0f0f0f0f0; 3398 uint64_t n = 0xffffffffffffffff; 3399 Vector<uint64_t> lsbs = { 1, 30, 14, 62 }; 3400 Vector<uint64_t> widths = { 62, 33, 17, 1 }; 3401 3402 // BFXIL Pattern: d = ((n >> lsb) & mask1) | (d & mask2) 3403 // Where: mask1 = ((1 << width) - 1) 3404 // mask2 = ~mask1 3405 auto test1 = [&] (uint64_t lsb, uint64_t mask1, uint64_t mask2) -> uint64_t { 3406 Procedure proc; 3407 BasicBlock* root = proc.addBlock(); 3408 3409 Value* dValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3410 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3411 Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb); 3412 Value* maskValue1 = root->appendNew<Const64Value>(proc, Origin(), mask1); 3413 Value* maskValue2 = root->appendNew<Const64Value>(proc, Origin(), mask2); 3414 3415 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), nValue, lsbValue); 3416 Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), shiftValue, maskValue1); 3417 Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2); 3418 root->appendNewControlValue( 3419 proc, Return, Origin(), 3420 root->appendNew<Value>(proc, BitOr, Origin(), leftAndValue, rightAndValue)); 3421 3422 auto code = compileProc(proc); 3423 if (isARM64()) 3424 checkUsesInstruction(*code, "bfxil"); 3425 return invoke<uint64_t>(*code, d, n); 3426 }; 3427 3428 for (size_t i = 0; i < lsbs.size(); ++i) { 3429 uint64_t lsb = lsbs.at(i); 3430 uint64_t mask1 = (1ULL << widths.at(i)) - 1ULL; 3431 uint64_t mask2 = ~mask1; 3432 CHECK(test1(lsb, mask1, mask2) == (((n >> lsb) & mask1) | (d & mask2))); 3433 } 3434 3435 // BFXIL Pattern: d = ((n & mask1) >> lsb) | (d & mask2) 3436 // Where: mask1 = ((1 << width) - 1) << lsb 3437 // mask2 = ~(mask1 >> lsb) 3438 auto test2 = [&] (uint64_t lsb, uint64_t mask1, uint64_t mask2) -> uint64_t { 3439 Procedure proc; 3440 BasicBlock* root = proc.addBlock(); 3441 3442 Value* dValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3443 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3444 Value* lsbValue = root->appendNew<Const32Value>(proc, Origin(), lsb); 3445 Value* maskValue1 = root->appendNew<Const64Value>(proc, Origin(), mask1); 3446 Value* maskValue2 = root->appendNew<Const64Value>(proc, Origin(), mask2); 3447 3448 Value* leftAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), nValue, maskValue1); 3449 Value* rightAndValue = root->appendNew<Value>(proc, BitAnd, Origin(), dValue, maskValue2); 3450 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), leftAndValue, lsbValue); 3451 root->appendNewControlValue( 3452 proc, Return, Origin(), 3453 root->appendNew<Value>(proc, BitOr, Origin(), shiftValue, rightAndValue)); 3454 3455 auto code = compileProc(proc); 3456 if (isARM64()) 3457 checkUsesInstruction(*code, "bfxil"); 3458 return invoke<uint64_t>(*code, d, n); 3459 }; 3460 3461 for (size_t i = 0; i < lsbs.size(); ++i) { 3462 uint64_t lsb = lsbs.at(i); 3463 uint64_t mask1 = ((1ULL << widths.at(i)) - 1ULL) << lsb; 3464 uint64_t mask2 = ~(mask1 >> lsb); 3465 CHECK(test2(lsb, mask1, mask2) == (((n & mask1) >> lsb) | (d & mask2))); 3466 } 3467 } 3468 3469 void testBIC32() 3470 { 3471 if (JSC::Options::defaultB3OptLevel() < 2) 3472 return; 3473 3474 // Test Pattern: d = n & (-m - 1) 3475 auto test1 = [&] (int32_t n, int32_t m) -> int32_t { 3476 Procedure proc; 3477 BasicBlock* root = proc.addBlock(); 3478 3479 Value* nValue = root->appendNew<Value>( 3480 proc, Trunc, Origin(), 3481 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3482 Value* mValue = root->appendNew<Value>( 3483 proc, Trunc, Origin(), 3484 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3485 Value* const1 = root->appendNew<Const32Value>(proc, Origin(), 1); 3486 3487 Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue); 3488 Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1); 3489 root->appendNewControlValue( 3490 proc, Return, Origin(), 3491 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, subValue)); 3492 3493 auto code = compileProc(proc); 3494 if (isARM64()) 3495 checkUsesInstruction(*code, "bic"); 3496 return invoke<int32_t>(*code, n, m); 3497 }; 3498 3499 // Test Pattern: d = n & (m ^ -1) 3500 auto test2 = [&] (int32_t n, int32_t m) -> int32_t { 3501 Procedure proc; 3502 BasicBlock* root = proc.addBlock(); 3503 3504 Value* nValue = root->appendNew<Value>( 3505 proc, Trunc, Origin(), 3506 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3507 Value* mValue = root->appendNew<Value>( 3508 proc, Trunc, Origin(), 3509 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3510 Value* minusOneValue = root->appendNew<Const32Value>(proc, Origin(), -1); 3511 3512 Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue); 3513 root->appendNewControlValue( 3514 proc, Return, Origin(), 3515 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, xorValue)); 3516 3517 auto code = compileProc(proc); 3518 if (isARM64()) 3519 checkUsesInstruction(*code, "bic"); 3520 return invoke<int32_t>(*code, n, m); 3521 }; 3522 3523 for (auto n : int32Operands()) { 3524 for (auto m : int32Operands()) { 3525 CHECK(test1(n.value, m.value) == (n.value & (-m.value - 1))); 3526 CHECK(test2(n.value, m.value) == (n.value & (m.value ^ -1))); 3527 } 3528 } 3529 } 3530 3531 void testBIC64() 3532 { 3533 if (JSC::Options::defaultB3OptLevel() < 2) 3534 return; 3535 3536 // Test Pattern: d = n & (-m - 1) 3537 auto test1 = [&] (int64_t n, int64_t m) -> int64_t { 3538 Procedure proc; 3539 BasicBlock* root = proc.addBlock(); 3540 3541 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3542 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3543 Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 1); 3544 3545 Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue); 3546 Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1); 3547 root->appendNewControlValue( 3548 proc, Return, Origin(), 3549 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, subValue)); 3550 3551 auto code = compileProc(proc); 3552 if (isARM64()) 3553 checkUsesInstruction(*code, "bic"); 3554 return invoke<int64_t>(*code, n, m); 3555 }; 3556 3557 // Test Pattern: d = n & (m ^ -1) 3558 auto test2 = [&] (int64_t n, int64_t m) -> int64_t { 3559 Procedure proc; 3560 BasicBlock* root = proc.addBlock(); 3561 3562 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3563 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3564 Value* minusOneValue = root->appendNew<Const64Value>(proc, Origin(), -1); 3565 3566 Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue); 3567 root->appendNewControlValue( 3568 proc, Return, Origin(), 3569 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, xorValue)); 3570 3571 auto code = compileProc(proc); 3572 if (isARM64()) 3573 checkUsesInstruction(*code, "bic"); 3574 return invoke<int64_t>(*code, n, m); 3575 }; 3576 3577 for (auto n : int64Operands()) { 3578 for (auto m : int64Operands()) { 3579 CHECK(test1(n.value, m.value) == (n.value & (-m.value - 1LL))); 3580 CHECK(test2(n.value, m.value) == (n.value & (m.value ^ -1LL))); 3581 } 3582 } 3583 } 3584 3585 void testOrNot32() 3586 { 3587 if (JSC::Options::defaultB3OptLevel() < 2) 3588 return; 3589 3590 // Test Pattern: d = n | (-m - 1) 3591 auto test1 = [&] (int32_t n, int32_t m) -> int32_t { 3592 Procedure proc; 3593 BasicBlock* root = proc.addBlock(); 3594 3595 Value* nValue = root->appendNew<Value>( 3596 proc, Trunc, Origin(), 3597 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3598 Value* mValue = root->appendNew<Value>( 3599 proc, Trunc, Origin(), 3600 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3601 Value* const1 = root->appendNew<Const32Value>(proc, Origin(), 1); 3602 3603 Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue); 3604 Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1); 3605 root->appendNewControlValue( 3606 proc, Return, Origin(), 3607 root->appendNew<Value>(proc, BitOr, Origin(), nValue, subValue)); 3608 3609 auto code = compileProc(proc); 3610 3611 if (isARM64()) 3612 checkUsesInstruction(*code, "orn"); 3613 return invoke<int32_t>(*code, n, m); 3614 }; 3615 3616 // Test Pattern: d = n | (m ^ -1) 3617 auto test2 = [&] (int32_t n, int32_t m) -> int32_t { 3618 Procedure proc; 3619 BasicBlock* root = proc.addBlock(); 3620 3621 Value* nValue = root->appendNew<Value>( 3622 proc, Trunc, Origin(), 3623 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3624 Value* mValue = root->appendNew<Value>( 3625 proc, Trunc, Origin(), 3626 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3627 Value* minusOneValue = root->appendNew<Const32Value>(proc, Origin(), -1); 3628 3629 Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue); 3630 root->appendNewControlValue( 3631 proc, Return, Origin(), 3632 root->appendNew<Value>(proc, BitOr, Origin(), nValue, xorValue)); 3633 3634 auto code = compileProc(proc); 3635 if (isARM64()) 3636 checkUsesInstruction(*code, "orn"); 3637 return invoke<int32_t>(*code, n, m); 3638 }; 3639 3640 for (auto n : int32Operands()) { 3641 for (auto m : int32Operands()) { 3642 CHECK(test1(n.value, m.value) == (n.value | (-m.value - 1))); 3643 CHECK(test2(n.value, m.value) == (n.value | (m.value ^ -1))); 3644 } 3645 } 3646 } 3647 3648 void testOrNot64() 3649 { 3650 if (JSC::Options::defaultB3OptLevel() < 2) 3651 return; 3652 3653 // Test Pattern: d = n | (-m - 1) 3654 auto test1 = [&] (int64_t n, int64_t m) -> int64_t { 3655 Procedure proc; 3656 BasicBlock* root = proc.addBlock(); 3657 3658 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3659 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3660 Value* const1 = root->appendNew<Const64Value>(proc, Origin(), 1); 3661 3662 Value* negValue = root->appendNew<Value>(proc, Neg, Origin(), mValue); 3663 Value* subValue = root->appendNew<Value>(proc, Sub, Origin(), negValue, const1); 3664 root->appendNewControlValue( 3665 proc, Return, Origin(), 3666 root->appendNew<Value>(proc, BitOr, Origin(), nValue, subValue)); 3667 3668 auto code = compileProc(proc); 3669 if (isARM64()) 3670 checkUsesInstruction(*code, "orn"); 3671 return invoke<int64_t>(*code, n, m); 3672 }; 3673 3674 // Test Pattern: d = n | (m ^ -1) 3675 auto test2 = [&] (int64_t n, int64_t m) -> int64_t { 3676 Procedure proc; 3677 BasicBlock* root = proc.addBlock(); 3678 3679 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 3680 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 3681 Value* minusOneValue = root->appendNew<Const64Value>(proc, Origin(), -1); 3682 3683 Value* xorValue = root->appendNew<Value>(proc, BitXor, Origin(), mValue, minusOneValue); 3684 root->appendNewControlValue( 3685 proc, Return, Origin(), 3686 root->appendNew<Value>(proc, BitOr, Origin(), nValue, xorValue)); 3687 3688 auto code = compileProc(proc); 3689 if (isARM64()) 3690 checkUsesInstruction(*code, "orn"); 3691 return invoke<int64_t>(*code, n, m); 3692 }; 3693 3694 for (auto n : int64Operands()) { 3695 for (auto m : int64Operands()) { 3696 CHECK(test1(n.value, m.value) == (n.value | (-m.value - 1LL))); 3697 CHECK(test2(n.value, m.value) == (n.value | (m.value ^ -1LL))); 3698 } 3306 3699 } 3307 3700 } … … 4199 4592 RUN(testUbfiz64ShiftAnd()); 4200 4593 RUN(testUbfiz64AndShift()); 4201 RUN(testBitFieldInsert32()); 4202 RUN(testBitFieldInsert64()); 4594 RUN(testInsertBitField32()); 4595 RUN(testInsertBitField64()); 4596 RUN(testExtractInsertBitfieldAtLowEnd32()); 4597 RUN(testExtractInsertBitfieldAtLowEnd64()); 4598 RUN(testBIC32()); 4599 RUN(testBIC64()); 4600 RUN(testOrNot32()); 4601 RUN(testOrNot64()); 4203 4602 RUN(testBitAndZeroShiftRightArgImmMask32()); 4204 4603 RUN(testBitAndZeroShiftRightArgImmMask64()); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r279253 r279362 16755 16755 merge->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) { 16756 16756 jit.move(params[2].gpr(), params[0].gpr()); 16757 jit. bitFieldInsert64(params[1].gpr(), CCallHelpers::TrustedImm32(0), CCallHelpers::TrustedImm32(64 - MacroAssembler::maxNumberOfAllowedPACBits), params[0].gpr());16757 jit.insertBitField64(params[1].gpr(), CCallHelpers::TrustedImm32(0), CCallHelpers::TrustedImm32(64 - MacroAssembler::maxNumberOfAllowedPACBits), params[0].gpr()); 16758 16758 }); 16759 16759 -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
r279256 r279362 1112 1112 #if CPU(ARM64E) 1113 1113 if (kind == Gigacage::Primitive) 1114 bitFieldInsert64(storage, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), tempReg);1114 insertBitField64(storage, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), tempReg); 1115 1115 if (skip.isSet()) 1116 1116 skip.link(this); … … 1149 1149 andPtr(TrustedImmPtr(Gigacage::mask(kind)), tempReg); 1150 1150 addPtr(scratch, tempReg); 1151 bitFieldInsert64(tempReg, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), storage);1151 insertBitField64(tempReg, TrustedImm32(0), TrustedImm32(64 - maxNumberOfAllowedPACBits), storage); 1152 1152 #else 1153 1153 andPtr(TrustedImmPtr(Gigacage::mask(kind)), storage);
Note:
See TracChangeset
for help on using the changeset viewer.