Changeset 196513 in webkit
- Timestamp:
- Feb 12, 2016, 2:32:44 PM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 18 edited
-
ChangeLog (modified) (1 diff)
-
assembler/MacroAssemblerARM64.h (modified) (1 diff)
-
assembler/MacroAssemblerX86Common.h (modified) (13 diffs)
-
assembler/MacroAssemblerX86_64.h (modified) (4 diffs)
-
assembler/X86Assembler.h (modified) (2 diffs)
-
b3/B3CheckSpecial.cpp (modified) (4 diffs)
-
b3/B3CheckSpecial.h (modified) (1 diff)
-
b3/B3LowerToAir.cpp (modified) (1 diff)
-
b3/air/AirCustom.h (modified) (1 diff)
-
b3/air/AirInst.h (modified) (1 diff)
-
b3/air/AirInstInlines.h (modified) (1 diff)
-
b3/air/AirIteratedRegisterCoalescing.cpp (modified) (16 diffs)
-
b3/air/AirOpcode.opcodes (modified) (17 diffs)
-
b3/air/AirSpecial.cpp (modified) (1 diff)
-
b3/air/AirSpecial.h (modified) (1 diff)
-
b3/testb3.cpp (modified) (5 diffs)
-
dfg/DFGOSRExitCompilerCommon.cpp (modified) (1 diff)
-
jit/AssemblyHelpers.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r196498 r196513 1 2016-02-12 Benjamin Poulain <benjamin@webkit.org> 2 3 [JSC] On x86, improve the selection of which value are selected for the UseDef part of commutative operations 4 https://bugs.webkit.org/show_bug.cgi?id=154151 5 6 Reviewed by Filip Pizlo. 7 8 Previously, when an instruction destroy an argument with 9 a UseDef use, we would try to pick a good target for the UseDef 10 while doing instruction selection. 11 12 For example: 13 @x = Add(@1, @2) 14 15 can be lowered to: 16 Move @1 Tmp3 17 Add @2 Tmp3 18 or 19 Move @2 Tmp3 20 Add @1 Tmp3 21 22 The choice of which value ends up copied is done by preferRightForResult() 23 at lowering time. 24 25 There are two common problems with the code we generate: 26 1) It is based on UseCount. If a value is at its last use, 27 it is a good target for coalescing even with a use-count > 1. 28 2) When both values are at their last use, the best choice 29 depends on the register pressure of each. We don't have that information 30 until we do register allocation. 31 32 This patch implements a simple idea to minimize how many of those Moves are needed. 33 Each commutative operation gets a 3 op variant. The register allocator then attempts 34 to alias *both* of them to the destination. 35 Since our aliasing is conservative, it removes as many copy as possible without causing 36 spilling. 37 38 There was an unexpected cool impovement too. If you have: 39 Move Tmp1, Tmp2 40 BranchAdd32 Tmp3, Tmp2 41 we would previously restore Tmp2 by substracting Tmp3 from the result. 42 We can now just use Tmp1. That removes quite a few Sub from the slow paths. 43 44 The problem is that simple idea uncoverred a bunch of issues that had to be fixed too. 45 I detail them inline below. 46 47 * assembler/MacroAssemblerARM64.h: 48 (JSC::MacroAssemblerARM64::and64): 49 * assembler/MacroAssemblerX86Common.h: 50 Most addition are adding an Address version of the 3 operands opcodes. 51 The reason for this is allow the complex addressing forms of instructions 52 when spilling. 53 54 (JSC::MacroAssemblerX86Common::and32): 55 (JSC::MacroAssemblerX86Common::mul32): 56 (JSC::MacroAssemblerX86Common::or32): 57 (JSC::MacroAssemblerX86Common::xor32): 58 (JSC::MacroAssemblerX86Common::moveDouble): 59 This was an unexpected discovery: removing tons of Move32 made floating-point heavy 60 code much slower. 61 62 It turns out the MoveDouble we were using has partial register dependencies. 63 64 The x86 optimization manual, Chapter 3, section 3.4.1.13 lists the move instructions executed 65 directly on the frontend. That's what we use now. 66 67 (JSC::MacroAssemblerX86Common::addDouble): 68 (JSC::MacroAssemblerX86Common::addFloat): 69 (JSC::MacroAssemblerX86Common::mulDouble): 70 (JSC::MacroAssemblerX86Common::mulFloat): 71 (JSC::MacroAssemblerX86Common::andDouble): 72 (JSC::MacroAssemblerX86Common::andFloat): 73 (JSC::MacroAssemblerX86Common::xorDouble): 74 (JSC::MacroAssemblerX86Common::xorFloat): 75 If the destination is not aliased, the version taking an address 76 use LoadFloat/LoadDouble instead of direct addressing. 77 78 That is because this: 79 Move Tmp1, Tmp2 80 Op [Tmp3], Tmp2 81 is slower than 82 Move [Tmp3] Tmp2 83 Op Tmp1, Tmp2 84 (sometimes significantly). 85 86 I am not exactly sure why. 87 88 (JSC::MacroAssemblerX86Common::branchAdd32): 89 * assembler/MacroAssemblerX86_64.h: 90 (JSC::MacroAssemblerX86_64::and64): 91 * assembler/MacroAssemblerARM64.h: 92 (JSC::MacroAssemblerARM64::and64): 93 * assembler/MacroAssemblerX86Common.h: 94 (JSC::MacroAssemblerX86Common::and32): 95 (JSC::MacroAssemblerX86Common::mul32): 96 (JSC::MacroAssemblerX86Common::or32): 97 (JSC::MacroAssemblerX86Common::xor32): 98 (JSC::MacroAssemblerX86Common::moveDouble): 99 (JSC::MacroAssemblerX86Common::addDouble): 100 (JSC::MacroAssemblerX86Common::addFloat): 101 (JSC::MacroAssemblerX86Common::mulDouble): 102 (JSC::MacroAssemblerX86Common::mulFloat): 103 (JSC::MacroAssemblerX86Common::andDouble): 104 (JSC::MacroAssemblerX86Common::andFloat): 105 (JSC::MacroAssemblerX86Common::xorDouble): 106 (JSC::MacroAssemblerX86Common::xorFloat): 107 (JSC::MacroAssemblerX86Common::branchAdd32): 108 * assembler/MacroAssemblerX86_64.h: 109 (JSC::MacroAssemblerX86_64::and64): 110 (JSC::MacroAssemblerX86_64::mul64): 111 (JSC::MacroAssemblerX86_64::xor64): 112 (JSC::MacroAssemblerX86_64::branchAdd64): 113 * assembler/X86Assembler.h: 114 (JSC::X86Assembler::movapd_rr): 115 (JSC::X86Assembler::movaps_rr): 116 * b3/B3CheckSpecial.cpp: 117 (JSC::B3::CheckSpecial::shouldTryAliasingDef): 118 (JSC::B3::CheckSpecial::generate): 119 * b3/B3CheckSpecial.h: 120 * b3/B3LowerToAir.cpp: 121 (JSC::B3::Air::LowerToAir::lower): 122 * b3/air/AirCustom.h: 123 (JSC::B3::Air::PatchCustom::shouldTryAliasingDef): 124 * b3/air/AirInst.h: 125 * b3/air/AirInstInlines.h: 126 (JSC::B3::Air::Inst::shouldTryAliasingDef): 127 * b3/air/AirIteratedRegisterCoalescing.cpp: 128 Aliasing the operands is done the same way as any coalescing. 129 130 There were problem with considering all those coalescing 131 as equivalent for the result. 132 133 Moves are mostly generated for Upsilon-Phis. Getting rid of 134 those tends to give better loops. 135 136 Sometimes, blocks have only Phis and a Jump. Coalescing 137 those moves gets rids of the block entirely. 138 139 Where it go interesting was that something like: 140 Move Tmp1, Tmp2 141 Op Tmp3, Tmp2 142 was significantly better than: 143 Op Tmp1, Tmp3 144 Move Tmp1, Tmp4 145 even in the same basic block. 146 147 To get back to the same performance when, I had to prioritize 148 regular Moves operations over argument coalescing. 149 150 Another argument for doing this is that the alias has a shorter 151 life in the hardware because the operation itself gets a new 152 virtual register from the bank. 153 154 * b3/air/AirOpcode.opcodes: 155 * b3/air/AirSpecial.cpp: 156 (JSC::B3::Air::Special::shouldTryAliasingDef): 157 * b3/air/AirSpecial.h: 158 * b3/testb3.cpp: 159 (JSC::B3::testCheckAddArgumentAliasing64): 160 (JSC::B3::testCheckAddArgumentAliasing32): 161 (JSC::B3::testCheckAddSelfOverflow64): 162 (JSC::B3::testCheckAddSelfOverflow32): 163 (JSC::B3::testCheckMulArgumentAliasing64): 164 (JSC::B3::testCheckMulArgumentAliasing32): 165 (JSC::B3::run): 166 167 * dfg/DFGOSRExitCompilerCommon.cpp: 168 (JSC::DFG::reifyInlinedCallFrames): 169 * jit/AssemblyHelpers.h: 170 (JSC::AssemblyHelpers::emitSaveOrCopyCalleeSavesFor): 171 This ruined my week. 172 173 When regenerating the frame of an inlined function that 174 was called through a tail call, we were ignoring r13 for some reason. 175 176 Since this patch makes it more likely to increase the degree 177 of each Tmp, the number of register used increased and r13 was more 178 commonly used. 179 180 When getting out of OSRExit, we would have that value trashed :( 181 182 The fix is simply to restore it like the other two Baseline callee saved 183 register. 184 1 185 2016-02-12 Yusuke Suzuki <utatane.tea@gmail.com> 2 186 -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
r196152 r196513 363 363 } 364 364 365 void and64(RegisterID src1, RegisterID src2, RegisterID dest) 366 { 367 m_assembler.and_<64>(dest, src1, src2); 368 } 369 365 370 void and64(RegisterID src, RegisterID dest) 366 371 { -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
r196433 r196513 268 268 } 269 269 270 void and32(Address op1, RegisterID op2, RegisterID dest) 271 { 272 move(op2, dest); 273 and32(op1, dest); 274 } 275 276 void and32(RegisterID op1, Address op2, RegisterID dest) 277 { 278 move(op1, dest); 279 and32(op2, dest); 280 } 281 270 282 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) 271 283 { … … 335 347 } 336 348 349 void mul32(RegisterID src1, RegisterID src2, RegisterID dest) 350 { 351 if (src2 == dest) { 352 m_assembler.imull_rr(src1, dest); 353 return; 354 } 355 move(src1, dest); 356 m_assembler.imull_rr(src2, dest); 357 } 358 337 359 void mul32(Address src, RegisterID dest) 338 360 { 339 361 m_assembler.imull_mr(src.offset, src.base, dest); 362 } 363 364 void mul32(Address src1, RegisterID src2, RegisterID dest) 365 { 366 move(src2, dest); 367 mul32(src1, dest); 368 } 369 370 void mul32(RegisterID src1, Address src2, RegisterID dest) 371 { 372 move(src1, dest); 373 mul32(src2, dest); 340 374 } 341 375 … … 414 448 or32(op1, dest); 415 449 } 450 } 451 452 void or32(Address op1, RegisterID op2, RegisterID dest) 453 { 454 move(op2, dest); 455 or32(op1, dest); 456 } 457 458 void or32(RegisterID op1, Address op2, RegisterID dest) 459 { 460 move(op1, dest); 461 or32(op2, dest); 416 462 } 417 463 … … 567 613 } 568 614 615 void xor32(Address op1, RegisterID op2, RegisterID dest) 616 { 617 move(op2, dest); 618 xor32(op1, dest); 619 } 620 621 void xor32(RegisterID op1, Address op2, RegisterID dest) 622 { 623 move(op1, dest); 624 xor32(op2, dest); 625 } 626 569 627 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) 570 628 { … … 906 964 ASSERT(isSSE2Present()); 907 965 if (src != dest) 908 m_assembler.mov sd_rr(src, dest);966 m_assembler.movaps_rr(src, dest); 909 967 } 910 968 … … 1015 1073 } 1016 1074 1075 void addDouble(Address op1, FPRegisterID op2, FPRegisterID dest) 1076 { 1077 ASSERT(isSSE2Present()); 1078 if (op2 == dest) { 1079 addDouble(op1, dest); 1080 return; 1081 } 1082 1083 loadDouble(op1, dest); 1084 addDouble(op2, dest); 1085 } 1086 1087 void addDouble(FPRegisterID op1, Address op2, FPRegisterID dest) 1088 { 1089 ASSERT(isSSE2Present()); 1090 if (op1 == dest) { 1091 addDouble(op2, dest); 1092 return; 1093 } 1094 1095 loadDouble(op2, dest); 1096 addDouble(op1, dest); 1097 } 1098 1017 1099 void addFloat(FPRegisterID src, FPRegisterID dest) 1018 1100 { … … 1025 1107 ASSERT(isSSE2Present()); 1026 1108 m_assembler.addss_mr(src.offset, src.base, dest); 1109 } 1110 1111 void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 1112 { 1113 ASSERT(isSSE2Present()); 1114 if (op1 == dest) 1115 addFloat(op2, dest); 1116 else { 1117 moveDouble(op2, dest); 1118 addFloat(op1, dest); 1119 } 1120 } 1121 1122 void addFloat(Address op1, FPRegisterID op2, FPRegisterID dest) 1123 { 1124 ASSERT(isSSE2Present()); 1125 if (op2 == dest) { 1126 addFloat(op1, dest); 1127 return; 1128 } 1129 1130 loadFloat(op1, dest); 1131 addFloat(op2, dest); 1132 } 1133 1134 void addFloat(FPRegisterID op1, Address op2, FPRegisterID dest) 1135 { 1136 ASSERT(isSSE2Present()); 1137 if (op1 == dest) { 1138 addFloat(op2, dest); 1139 return; 1140 } 1141 1142 loadFloat(op2, dest); 1143 addFloat(op1, dest); 1027 1144 } 1028 1145 … … 1116 1233 } 1117 1234 1235 void mulDouble(Address op1, FPRegisterID op2, FPRegisterID dest) 1236 { 1237 ASSERT(isSSE2Present()); 1238 if (op2 == dest) { 1239 mulDouble(op1, dest); 1240 return; 1241 } 1242 loadDouble(op1, dest); 1243 mulDouble(op2, dest); 1244 } 1245 1246 void mulDouble(FPRegisterID op1, Address op2, FPRegisterID dest) 1247 { 1248 ASSERT(isSSE2Present()); 1249 if (op1 == dest) { 1250 mulDouble(op2, dest); 1251 return; 1252 } 1253 loadDouble(op2, dest); 1254 mulDouble(op1, dest); 1255 } 1256 1118 1257 void mulFloat(FPRegisterID src, FPRegisterID dest) 1119 1258 { … … 1126 1265 ASSERT(isSSE2Present()); 1127 1266 m_assembler.mulss_mr(src.offset, src.base, dest); 1267 } 1268 1269 void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 1270 { 1271 ASSERT(isSSE2Present()); 1272 if (op1 == dest) 1273 mulFloat(op2, dest); 1274 else { 1275 moveDouble(op2, dest); 1276 mulFloat(op1, dest); 1277 } 1278 } 1279 1280 void mulFloat(Address op1, FPRegisterID op2, FPRegisterID dest) 1281 { 1282 ASSERT(isSSE2Present()); 1283 if (op2 == dest) { 1284 mulFloat(op1, dest); 1285 return; 1286 } 1287 loadFloat(op1, dest); 1288 mulFloat(op2, dest); 1289 } 1290 1291 void mulFloat(FPRegisterID op1, Address op2, FPRegisterID dest) 1292 { 1293 ASSERT(isSSE2Present()); 1294 if (op1 == dest) { 1295 mulFloat(op2, dest); 1296 return; 1297 } 1298 loadFloat(op2, dest); 1299 mulFloat(op1, dest); 1128 1300 } 1129 1301 … … 1134 1306 } 1135 1307 1308 void andDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst) 1309 { 1310 if (src1 == dst) 1311 andDouble(src2, dst); 1312 else { 1313 moveDouble(src2, dst); 1314 andDouble(src1, dst); 1315 } 1316 } 1317 1136 1318 void andFloat(FPRegisterID src, FPRegisterID dst) 1137 1319 { … … 1139 1321 } 1140 1322 1323 void andFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst) 1324 { 1325 if (src1 == dst) 1326 andFloat(src2, dst); 1327 else { 1328 moveDouble(src2, dst); 1329 andFloat(src1, dst); 1330 } 1331 } 1332 1141 1333 void xorDouble(FPRegisterID src, FPRegisterID dst) 1142 1334 { … … 1144 1336 } 1145 1337 1338 void xorDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst) 1339 { 1340 if (src1 == dst) 1341 xorDouble(src2, dst); 1342 else { 1343 moveDouble(src2, dst); 1344 xorDouble(src1, dst); 1345 } 1346 } 1347 1146 1348 void xorFloat(FPRegisterID src, FPRegisterID dst) 1147 1349 { 1148 1350 m_assembler.xorps_rr(src, dst); 1351 } 1352 1353 void xorFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst) 1354 { 1355 if (src1 == dst) 1356 xorFloat(src2, dst); 1357 else { 1358 moveDouble(src2, dst); 1359 xorFloat(src1, dst); 1360 } 1149 1361 } 1150 1362 … … 1709 1921 move(src2, dest); 1710 1922 return branchAdd32(cond, src1, dest); 1923 } 1924 1925 Jump branchAdd32(ResultCondition cond, Address src1, RegisterID src2, RegisterID dest) 1926 { 1927 move(src2, dest); 1928 return branchAdd32(cond, src1, dest); 1929 } 1930 1931 Jump branchAdd32(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest) 1932 { 1933 move(src1, dest); 1934 return branchAdd32(cond, src2, dest); 1711 1935 } 1712 1936 -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
r196433 r196513 350 350 } 351 351 352 void and64(RegisterID op1, RegisterID op2, RegisterID dest) 353 { 354 if (op1 == op2 && op1 != dest && op2 != dest) 355 move(op1, dest); 356 else if (op1 == dest) 357 and64(op2, dest); 358 else { 359 move(op2, dest); 360 and64(op1, dest); 361 } 362 } 363 352 364 void countLeadingZeros64(RegisterID src, RegisterID dst) 353 365 { … … 431 443 m_assembler.imulq_rr(src, dest); 432 444 } 445 446 void mul64(RegisterID src1, RegisterID src2, RegisterID dest) 447 { 448 if (src2 == dest) { 449 m_assembler.imulq_rr(src1, dest); 450 return; 451 } 452 move(src1, dest); 453 m_assembler.imulq_rr(src2, dest); 454 } 433 455 434 456 void x86ConvertToQuadWord64() … … 542 564 m_assembler.xorq_rr(src, dest); 543 565 } 566 567 void xor64(RegisterID op1, RegisterID op2, RegisterID dest) 568 { 569 if (op1 == op2) 570 move(TrustedImm32(0), dest); 571 else if (op1 == dest) 572 xor64(op2, dest); 573 else { 574 move(op2, dest); 575 xor64(op1, dest); 576 } 577 } 544 578 545 579 void xor64(RegisterID src, Address dest) … … 868 902 } 869 903 904 Jump branchAdd64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) 905 { 906 if (src1 == dest) 907 return branchAdd64(cond, src2, dest); 908 move(src2, dest); 909 return branchAdd64(cond, src1, dest); 910 } 911 912 Jump branchAdd64(ResultCondition cond, Address src1, RegisterID src2, RegisterID dest) 913 { 914 move(src2, dest); 915 return branchAdd64(cond, src1, dest); 916 } 917 918 Jump branchAdd64(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest) 919 { 920 move(src1, dest); 921 return branchAdd64(cond, src2, dest); 922 } 923 870 924 Jump branchAdd64(ResultCondition cond, RegisterID src, RegisterID dest) 925 { 926 add64(src, dest); 927 return Jump(m_assembler.jCC(x86Condition(cond))); 928 } 929 930 Jump branchAdd64(ResultCondition cond, Address src, RegisterID dest) 871 931 { 872 932 add64(src, dest); -
trunk/Source/JavaScriptCore/assembler/X86Assembler.h
r195549 r196513 264 264 OP2_MOVSS_VsdWsd = 0x10, 265 265 OP2_MOVSS_WsdVsd = 0x11, 266 OP2_MOVAPD_VpdWpd = 0x28, 267 OP2_MOVAPS_VpdWpd = 0x28, 266 268 OP2_CVTSI2SD_VsdEd = 0x2A, 267 269 OP2_CVTTSD2SI_GdWsd = 0x2C, … … 2210 2212 #endif 2211 2213 2214 void movapd_rr(XMMRegisterID src, XMMRegisterID dst) 2215 { 2216 m_formatter.prefix(PRE_SSE_66); 2217 m_formatter.twoByteOp(OP2_MOVAPD_VpdWpd, (RegisterID)dst, (RegisterID)src); 2218 } 2219 2220 void movaps_rr(XMMRegisterID src, XMMRegisterID dst) 2221 { 2222 m_formatter.twoByteOp(OP2_MOVAPS_VpdWpd, (RegisterID)dst, (RegisterID)src); 2223 } 2224 2212 2225 void movsd_rr(XMMRegisterID src, XMMRegisterID dst) 2213 2226 { -
trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp
r195298 r196513 131 131 } 132 132 133 bool CheckSpecial::shouldTryAliasingDef(Inst& inst, unsigned& defIndex) 134 { 135 if (hiddenBranch(inst).shouldTryAliasingDef(defIndex)) { 136 defIndex += 1; 137 return true; 138 } 139 return false; 140 } 141 133 142 CCallHelpers::Jump CheckSpecial::generate(Inst& inst, CCallHelpers& jit, GenerationContext& context) 134 143 { … … 155 164 switch (m_checkOpcode) { 156 165 case BranchAdd32: 157 if (args[1] == args[2]) { 166 if ((m_numCheckArgs == 4 && args[1] == args[2] && args[2] == args[3]) 167 || (m_numCheckArgs == 3 && args[1] == args[2])) { 158 168 // This is ugly, but that's fine - we won't have to do this very often. 159 169 ASSERT(args[1].isGPR()); … … 168 178 break; 169 179 } 170 Inst(Sub32, nullptr, args[1], args[2]).generate(jit, context); 180 if (m_numCheckArgs == 4) { 181 if (args[1] == args[3]) 182 Inst(Sub32, nullptr, args[2], args[3]).generate(jit, context); 183 else if (args[2] == args[3]) 184 Inst(Sub32, nullptr, args[1], args[3]).generate(jit, context); 185 } else if (m_numCheckArgs == 3) 186 Inst(Sub32, nullptr, args[1], args[2]).generate(jit, context); 171 187 break; 172 188 case BranchAdd64: 173 if (args[1] == args[2]) { 189 if ((m_numCheckArgs == 4 && args[1] == args[2] && args[2] == args[3]) 190 || (m_numCheckArgs == 3 && args[1] == args[2])) { 174 191 // This is ugly, but that's fine - we won't have to do this very often. 175 192 ASSERT(args[1].isGPR()); … … 184 201 break; 185 202 } 186 Inst(Sub64, nullptr, args[1], args[2]).generate(jit, context); 203 if (m_numCheckArgs == 4) { 204 if (args[1] == args[3]) 205 Inst(Sub64, nullptr, args[2], args[3]).generate(jit, context); 206 else if (args[2] == args[3]) 207 Inst(Sub64, nullptr, args[1], args[3]).generate(jit, context); 208 } else if (m_numCheckArgs == 3) 209 Inst(Sub64, nullptr, args[1], args[2]).generate(jit, context); 187 210 break; 188 211 case BranchSub32: -
trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h
r195298 r196513 127 127 bool isValid(Air::Inst&) override; 128 128 bool admitsStack(Air::Inst&, unsigned argIndex) override; 129 bool shouldTryAliasingDef(Air::Inst&, unsigned& defIndex) override; 129 130 130 131 // NOTE: the generate method will generate the hidden branch and then register a LatePath that -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r196045 r196513 2147 2147 sources.append(imm(right)); 2148 2148 append(Move, tmp(left), result); 2149 } else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp)) { 2149 } else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp, Arg::Tmp)) { 2150 sources.append(tmp(left)); 2151 sources.append(tmp(right)); 2152 } else if (isValidForm(opcode, Arg::ResCond, Arg::Tmp, Arg::Tmp)) { 2150 2153 if (commutativity == Commutative && preferRightForResult(left, right)) { 2151 2154 sources.append(tmp(left)); -
trunk/Source/JavaScriptCore/b3/air/AirCustom.h
r195298 r196513 81 81 } 82 82 83 static bool shouldTryAliasingDef(Inst& inst, unsigned& defIndex) 84 { 85 return inst.args[0].special()->shouldTryAliasingDef(inst, defIndex); 86 } 87 83 88 static bool hasNonArgNonControlEffects(Inst& inst) 84 89 { -
trunk/Source/JavaScriptCore/b3/air/AirInst.h
r195298 r196513 181 181 CCallHelpers::Jump generate(CCallHelpers&, GenerationContext&); 182 182 183 // Returns true if the register allocator should attempt to alias the arguments with the destination 184 // for this instruction. 185 // If the method returns true, defIndex is set to the index of the destination argument. The indices 186 // (defIndex - 1) and (defIndex - 2) are the one to alias to defIndex. 187 bool shouldTryAliasingDef(unsigned& defIndex); 188 183 189 void dump(PrintStream&) const; 184 190 -
trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h
r196032 r196513 165 165 } 166 166 167 inline bool Inst::shouldTryAliasingDef(unsigned& defIndex) 168 { 169 if (!isX86()) 170 return false; 171 172 switch (opcode) { 173 case Add32: 174 case Add64: 175 case And32: 176 case And64: 177 case Mul32: 178 case Mul64: 179 case Or32: 180 case Or64: 181 case Xor32: 182 case Xor64: 183 case AddDouble: 184 case AddFloat: 185 case AndFloat: 186 case AndDouble: 187 case MulDouble: 188 case MulFloat: 189 case XorDouble: 190 case XorFloat: 191 if (args.size() == 3) { 192 defIndex = 2; 193 return true; 194 } 195 break; 196 case BranchAdd32: 197 case BranchAdd64: 198 if (args.size() == 4) { 199 defIndex = 3; 200 return true; 201 } 202 break; 203 case Patch: 204 return PatchCustom::shouldTryAliasingDef(*this, defIndex); 205 default: 206 break; 207 } 208 return false; 209 } 210 167 211 inline bool isShiftValid(const Inst& inst) 168 212 { -
trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp
r196032 r196513 170 170 if (traceDebug) 171 171 dataLog(" Coalesced\n"); 172 } else if (isPrecolored(v) || m_interferenceEdges.contains(InterferenceEdge(u, v))) { 172 } else if (isPrecolored(v) 173 || m_interferenceEdges.contains(InterferenceEdge(u, v)) 174 || (u == m_framePointerIndex && m_interferesWithFramePointer.quickGet(v))) { 173 175 addWorkList(u); 174 176 addWorkList(v); … … 400 402 }); 401 403 404 if (m_framePointerIndex && m_interferesWithFramePointer.quickGet(v)) 405 m_interferesWithFramePointer.quickSet(u); 406 402 407 if (m_degrees[u] >= m_regsInPriorityOrder.size() && m_freezeWorklist.remove(u)) 403 408 addToSpill(u); … … 575 580 Vector<IndexType> m_selectStack; 576 581 582 IndexType m_framePointerIndex { 0 }; 583 BitVector m_interferesWithFramePointer; 584 577 585 struct OrderedMoveSet { 578 586 unsigned addMove() 579 587 { 580 unsigned nextIndex = m_moveList.size(); 588 ASSERT(m_lowPriorityMoveList.isEmpty()); 589 ASSERT(!m_firstLowPriorityMoveIndex); 590 591 unsigned nextIndex = m_positionInMoveList.size(); 592 unsigned position = m_moveList.size(); 581 593 m_moveList.append(nextIndex); 582 m_positionInMoveList.append( nextIndex);594 m_positionInMoveList.append(position); 583 595 return nextIndex; 584 596 } 585 597 598 void startAddingLowPriorityMoves() 599 { 600 ASSERT(m_lowPriorityMoveList.isEmpty()); 601 m_firstLowPriorityMoveIndex = m_moveList.size(); 602 } 603 604 unsigned addLowPriorityMove() 605 { 606 ASSERT(m_firstLowPriorityMoveIndex == m_moveList.size()); 607 608 unsigned nextIndex = m_positionInMoveList.size(); 609 unsigned position = m_lowPriorityMoveList.size(); 610 m_lowPriorityMoveList.append(nextIndex); 611 m_positionInMoveList.append(position); 612 613 ASSERT(nextIndex >= m_firstLowPriorityMoveIndex); 614 615 return nextIndex; 616 } 617 586 618 bool isEmpty() const 587 619 { 588 return m_moveList.isEmpty() ;620 return m_moveList.isEmpty() && m_lowPriorityMoveList.isEmpty(); 589 621 } 590 622 … … 600 632 return; 601 633 602 ASSERT(m_moveList[positionInMoveList] == moveIndex); 603 unsigned lastIndex = m_moveList.last(); 604 m_positionInMoveList[lastIndex] = positionInMoveList; 605 m_moveList[positionInMoveList] = lastIndex; 606 m_moveList.removeLast(); 634 if (moveIndex < m_firstLowPriorityMoveIndex) { 635 ASSERT(m_moveList[positionInMoveList] == moveIndex); 636 unsigned lastIndex = m_moveList.last(); 637 m_positionInMoveList[lastIndex] = positionInMoveList; 638 m_moveList[positionInMoveList] = lastIndex; 639 m_moveList.removeLast(); 640 } else { 641 ASSERT(m_lowPriorityMoveList[positionInMoveList] == moveIndex); 642 unsigned lastIndex = m_lowPriorityMoveList.last(); 643 m_positionInMoveList[lastIndex] = positionInMoveList; 644 m_lowPriorityMoveList[positionInMoveList] = lastIndex; 645 m_lowPriorityMoveList.removeLast(); 646 } 607 647 608 648 m_positionInMoveList[moveIndex] = std::numeric_limits<unsigned>::max(); … … 615 655 ASSERT(!isEmpty()); 616 656 617 unsigned lastIndex = m_moveList.takeLast(); 618 ASSERT(m_positionInMoveList[lastIndex] == m_moveList.size()); 657 unsigned lastIndex; 658 if (!m_moveList.isEmpty()) { 659 lastIndex = m_moveList.takeLast(); 660 ASSERT(m_positionInMoveList[lastIndex] == m_moveList.size()); 661 } else { 662 lastIndex = m_lowPriorityMoveList.takeLast(); 663 ASSERT(m_positionInMoveList[lastIndex] == m_lowPriorityMoveList.size()); 664 } 619 665 m_positionInMoveList[lastIndex] = std::numeric_limits<unsigned>::max(); 620 666 … … 630 676 ASSERT(!contains(index)); 631 677 632 unsigned position = m_moveList.size(); 633 m_moveList.append(index); 634 m_positionInMoveList[index] = position; 678 if (index < m_firstLowPriorityMoveIndex) { 679 unsigned position = m_moveList.size(); 680 m_moveList.append(index); 681 m_positionInMoveList[index] = position; 682 } else { 683 unsigned position = m_lowPriorityMoveList.size(); 684 m_lowPriorityMoveList.append(index); 685 m_positionInMoveList[index] = position; 686 } 635 687 636 688 ASSERT(contains(index)); … … 641 693 m_positionInMoveList.clear(); 642 694 m_moveList.clear(); 695 m_lowPriorityMoveList.clear(); 643 696 } 644 697 … … 646 699 Vector<unsigned, 0, UnsafeVectorOverflow> m_positionInMoveList; 647 700 Vector<unsigned, 0, UnsafeVectorOverflow> m_moveList; 701 Vector<unsigned, 0, UnsafeVectorOverflow> m_lowPriorityMoveList; 702 unsigned m_firstLowPriorityMoveIndex { 0 }; 648 703 }; 649 704 … … 679 734 , m_useCounts(useCounts) 680 735 { 736 if (type == Arg::GP) { 737 m_framePointerIndex = AbsoluteTmpMapper<type>::absoluteIndex(Tmp(MacroAssembler::framePointerRegister)); 738 m_interferesWithFramePointer.ensureSize(tmpArraySize(code)); 739 } 740 681 741 initializePrecoloredTmp(); 682 742 build(); … … 801 861 m_coloredTmp[i] = tmp.reg(); 802 862 } 863 } 864 865 bool mayBeCoalesced(Arg left, Arg right) 866 { 867 if (!left.isTmp() || !right.isTmp()) 868 return false; 869 870 Tmp leftTmp = left.tmp(); 871 Tmp rightTmp = right.tmp(); 872 873 if (leftTmp == rightTmp) 874 return false; 875 876 if (leftTmp.isGP() != (type == Arg::GP) || rightTmp.isGP() != (type == Arg::GP)) 877 return false; 878 879 unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp); 880 unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp); 881 882 return !m_interferenceEdges.contains(InterferenceEdge(leftIndex, rightIndex)); 883 } 884 885 void addToLowPriorityCoalescingCandidates(Arg left, Arg right) 886 { 887 ASSERT(mayBeCoalesced(left, right)); 888 Tmp leftTmp = left.tmp(); 889 Tmp rightTmp = right.tmp(); 890 891 unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp); 892 unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp); 893 894 unsigned nextMoveIndex = m_coalescingCandidates.size(); 895 m_coalescingCandidates.append({ leftIndex, rightIndex }); 896 897 unsigned newIndexInWorklist = m_worklistMoves.addLowPriorityMove(); 898 ASSERT_UNUSED(newIndexInWorklist, newIndexInWorklist == nextMoveIndex); 899 900 ASSERT(nextMoveIndex <= m_activeMoves.size()); 901 m_activeMoves.ensureSize(nextMoveIndex + 1); 902 903 m_moveList[leftIndex].add(nextMoveIndex); 904 m_moveList[rightIndex].add(nextMoveIndex); 803 905 } 804 906 … … 816 918 build(nullptr, &block->at(0), localCalc); 817 919 } 920 buildLowPriorityMoveList(); 818 921 } 819 922 … … 882 985 } 883 986 987 void buildLowPriorityMoveList() 988 { 989 if (!isX86()) 990 return; 991 992 m_worklistMoves.startAddingLowPriorityMoves(); 993 for (BasicBlock* block : m_code) { 994 for (Inst& inst : *block) { 995 unsigned defArgIndex = 0; 996 if (inst.shouldTryAliasingDef(defArgIndex)) { 997 Arg op1 = inst.args[defArgIndex - 2]; 998 Arg op2 = inst.args[defArgIndex - 1]; 999 Arg dest = inst.args[defArgIndex]; 1000 1001 if (op1 == dest || op2 == dest) 1002 continue; 1003 1004 if (mayBeCoalesced(op1, dest)) 1005 addToLowPriorityCoalescingCandidates(op1, dest); 1006 if (op1 != op2 && mayBeCoalesced(op2, dest)) 1007 addToLowPriorityCoalescingCandidates(op2, dest); 1008 } 1009 } 1010 } 1011 } 1012 884 1013 void addEdges(Inst* prevInst, Inst* nextInst, typename TmpLiveness<type>::LocalCalc::Iterable liveTmps) 885 1014 { … … 896 1025 } 897 1026 898 if (type == Arg::GP && !arg.isGPR()) { 899 m_interferenceEdges.add(InterferenceEdge( 900 AbsoluteTmpMapper<type>::absoluteIndex(Tmp(MacroAssembler::framePointerRegister)), 901 AbsoluteTmpMapper<type>::absoluteIndex(arg))); 902 } 1027 if (type == Arg::GP && !arg.isGPR()) 1028 m_interferesWithFramePointer.quickSet(AbsoluteTmpMapper<type>::absoluteIndex(arg)); 903 1029 }); 904 1030 } … … 1033 1159 dataLog("Interference: ", listDump(m_interferenceEdges), "\n"); 1034 1160 dumpInterferenceGraphInDot(WTF::dataFile()); 1161 dataLog("Coalescing candidates:\n"); 1162 for (MoveOperands& moveOp : m_coalescingCandidates) { 1163 dataLog(" ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.srcIndex), 1164 " -> ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.dstIndex), "\n"); 1165 } 1035 1166 dataLog("Initial work list\n"); 1036 1167 dumpWorkLists(WTF::dataFile()); … … 1132 1263 void iteratedRegisterCoalescingOnType() 1133 1264 { 1134 HashSet<unsigned> unspillableTmps ;1265 HashSet<unsigned> unspillableTmps = computeUnspillableTmps<type>(); 1135 1266 1136 1267 // FIXME: If a Tmp is used only from a Scratch role and that argument is !admitsStack, then … … 1173 1304 1174 1305 template<Arg::Type type> 1306 HashSet<unsigned> computeUnspillableTmps() 1307 { 1308 HashSet<unsigned> unspillableTmps; 1309 1310 struct Range { 1311 unsigned first { std::numeric_limits<unsigned>::max() }; 1312 unsigned last { 0 }; 1313 unsigned count { 0 }; 1314 unsigned admitStackCount { 0 }; 1315 }; 1316 1317 unsigned numTmps = m_code.numTmps(type); 1318 unsigned arraySize = AbsoluteTmpMapper<type>::absoluteIndex(numTmps); 1319 1320 Vector<Range, 0, UnsafeVectorOverflow> ranges; 1321 ranges.fill(Range(), arraySize); 1322 1323 unsigned globalIndex = 0; 1324 for (BasicBlock* block : m_code) { 1325 for (Inst& inst : *block) { 1326 inst.forEachArg([&] (Arg& arg, Arg::Role, Arg::Type argType, Arg::Width) { 1327 if (arg.isTmp() && inst.admitsStack(arg)) { 1328 if (argType != type) 1329 return; 1330 1331 Tmp tmp = arg.tmp(); 1332 Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)]; 1333 range.count++; 1334 range.admitStackCount++; 1335 if (globalIndex < range.first) { 1336 range.first = globalIndex; 1337 range.last = globalIndex; 1338 } else 1339 range.last = globalIndex; 1340 1341 return; 1342 } 1343 1344 arg.forEachTmpFast([&] (Tmp& tmp) { 1345 if (tmp.isGP() != (type == Arg::GP)) 1346 return; 1347 1348 Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)]; 1349 range.count++; 1350 if (globalIndex < range.first) { 1351 range.first = globalIndex; 1352 range.last = globalIndex; 1353 } else 1354 range.last = globalIndex; 1355 }); 1356 }); 1357 1358 ++globalIndex; 1359 } 1360 ++globalIndex; 1361 } 1362 for (unsigned i = AbsoluteTmpMapper<type>::lastMachineRegisterIndex() + 1; i < ranges.size(); ++i) { 1363 Range& range = ranges[i]; 1364 if (range.last - range.first <= 1 && range.count > range.admitStackCount) 1365 unspillableTmps.add(i); 1366 } 1367 1368 return unspillableTmps; 1369 } 1370 1371 template<Arg::Type type> 1175 1372 void assignRegistersToTmp(const ColoringAllocator<type>& allocator) 1176 1373 { -
trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
r196409 r196513 108 108 Nop 109 109 110 Add32 U:G:32, U:G:32, ZD:G:32 111 Imm, Tmp, Tmp 112 Tmp, Tmp, Tmp 113 110 114 Add32 U:G:32, UZD:G:32 111 115 Tmp, Tmp … … 129 133 Tmp, Index 130 134 131 Add32 U:G:32, U:G:32, ZD:G:32132 Imm, Tmp, Tmp133 Tmp, Tmp, Tmp134 135 135 64: Add64 U:G:64, UD:G:64 136 136 Tmp, Tmp … … 144 144 Tmp, Tmp, Tmp 145 145 146 arm64: AddDouble U:F:64, U:F:64, D:F:64 147 Tmp, Tmp, Tmp 146 AddDouble U:F:64, U:F:64, D:F:64 147 Tmp, Tmp, Tmp 148 x86: Addr, Tmp, Tmp 149 x86: Tmp, Addr, Tmp 148 150 149 151 x86: AddDouble U:F:64, UD:F:64 … … 151 153 Addr, Tmp 152 154 153 arm64: AddFloat U:F:32, U:F:32, D:F:32 154 Tmp, Tmp, Tmp 155 AddFloat U:F:32, U:F:32, D:F:32 156 Tmp, Tmp, Tmp 157 x86: Addr, Tmp, Tmp 158 x86: Tmp, Addr, Tmp 155 159 156 160 x86: AddFloat U:F:32, UD:F:32 … … 201 205 202 206 Mul32 U:G:32, U:G:32, ZD:G:32 203 arm64: Tmp, Tmp, Tmp 207 Tmp, Tmp, Tmp 208 x86: Addr, Tmp, Tmp 209 x86: Tmp, Addr, Tmp 204 210 x86: Imm, Tmp, Tmp 205 211 … … 207 213 Tmp, Tmp 208 214 209 arm64:Mul64 U:G:64, U:G:64, D:G:64215 Mul64 U:G:64, U:G:64, D:G:64 210 216 Tmp, Tmp, Tmp 211 217 … … 216 222 Tmp, Tmp, Tmp 217 223 218 arm64: MulDouble U:F:64, U:F:64, D:F:64 219 Tmp, Tmp, Tmp 224 MulDouble U:F:64, U:F:64, D:F:64 225 Tmp, Tmp, Tmp 226 x86: Addr, Tmp, Tmp 227 x86: Tmp, Addr, Tmp 220 228 221 229 x86: MulDouble U:F:64, UD:F:64 … … 223 231 Addr, Tmp 224 232 225 arm64: MulFloat U:F:32, U:F:32, D:F:32 226 Tmp, Tmp, Tmp 233 MulFloat U:F:32, U:F:32, D:F:32 234 Tmp, Tmp, Tmp 235 x86: Addr, Tmp, Tmp 236 x86: Tmp, Addr, Tmp 227 237 228 238 x86: MulFloat U:F:32, UD:F:32 … … 259 269 Addr, Tmp 260 270 271 And32 U:G:32, U:G:32, ZD:G:32 272 Tmp, Tmp, Tmp 273 x86: Tmp, Addr, Tmp 274 x86: Addr, Tmp, Tmp 275 261 276 And32 U:G:32, UZD:G:32 262 277 Tmp, Tmp … … 266 281 x86: Imm, Addr 267 282 268 64: And64 U:G:64, UD:G:64 283 64: And64 U:G:64, U:G:64, D:G:64 284 Tmp, Tmp, Tmp 285 286 x86_64: And64 U:G:64, UD:G:64 269 287 Tmp, Tmp 270 288 x86: Imm, Tmp 271 289 272 arm64:AndDouble U:F:64, U:F:64, D:F:64290 AndDouble U:F:64, U:F:64, D:F:64 273 291 Tmp, Tmp, Tmp 274 292 … … 276 294 Tmp, Tmp 277 295 278 arm64:AndFloat U:F:32, U:F:32, D:F:32296 AndFloat U:F:32, U:F:32, D:F:32 279 297 Tmp, Tmp, Tmp 280 298 … … 282 300 Tmp, Tmp 283 301 302 x86: XorDouble U:F:64, U:F:64, D:F:64 303 Tmp, Tmp, Tmp 304 284 305 x86: XorDouble U:F:64, UD:F:64 285 306 Tmp, Tmp 307 308 x86: XorFloat U:F:32, U:F:32, D:F:32 309 Tmp, Tmp, Tmp 286 310 287 311 x86: XorFloat U:F:32, UD:F:32 … … 336 360 Imm, Tmp 337 361 362 Or32 U:G:32, U:G:32, ZD:G:32 363 Tmp, Tmp, Tmp 364 x86: Tmp, Addr, Tmp 365 x86: Addr, Tmp, Tmp 366 338 367 Or32 U:G:32, UZD:G:32 339 368 Tmp, Tmp … … 343 372 x86: Imm, Addr 344 373 374 64: Or64 U:G:64, U:G:64, D:G:64 375 Tmp, Tmp, Tmp 376 345 377 64: Or64 U:G:64, UD:G:64 346 378 Tmp, Tmp 347 379 x86: Imm, Tmp 380 381 Xor32 U:G:32, U:G:32, ZD:G:32 382 Tmp, Tmp, Tmp 383 x86: Tmp, Addr, Tmp 384 x86: Addr, Tmp, Tmp 348 385 349 386 Xor32 U:G:32, UZD:G:32 … … 353 390 x86: Addr, Tmp 354 391 x86: Imm, Addr 392 393 64: Xor64 U:G:64, U:G:64, D:G:64 394 Tmp, Tmp, Tmp 355 395 356 396 64: Xor64 U:G:64, UD:G:64 … … 610 650 DoubleCond, Tmp, Tmp 611 651 652 BranchAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch 653 ResCond, Tmp, Tmp, Tmp 654 x86:ResCond, Tmp, Addr, Tmp 655 x86:ResCond, Addr, Tmp, Tmp 656 612 657 BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch 613 658 ResCond, Tmp, Tmp … … 617 662 x86: ResCond, Addr, Tmp 618 663 664 BranchAdd64 U:G:32, U:G:64, U:G:64, ZD:G:64 /branch 665 ResCond, Tmp, Tmp, Tmp 666 x86:ResCond, Tmp, Addr, Tmp 667 x86:ResCond, Addr, Tmp, Tmp 668 619 669 64: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch 620 670 ResCond, Imm, Tmp 621 671 ResCond, Tmp, Tmp 672 x86:ResCond, Addr, Tmp 622 673 623 674 x86: BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch -
trunk/Source/JavaScriptCore/b3/air/AirSpecial.cpp
r196032 r196513 51 51 } 52 52 53 bool Special::shouldTryAliasingDef(Inst&, unsigned&) 54 { 55 return false; 56 } 57 53 58 bool Special::hasNonArgNonControlEffects() 54 59 { -
trunk/Source/JavaScriptCore/b3/air/AirSpecial.h
r196032 r196513 57 57 virtual bool isValid(Inst&) = 0; 58 58 virtual bool admitsStack(Inst&, unsigned argIndex) = 0; 59 virtual bool shouldTryAliasingDef(Inst&, unsigned& defIndex); 59 60 60 61 // This gets called on for each Inst that uses this Special. Note that there is no way to -
trunk/Source/JavaScriptCore/b3/testb3.cpp
r196433 r196513 7493 7493 } 7494 7494 7495 void testCheckAddArgumentAliasing64() 7496 { 7497 Procedure proc; 7498 BasicBlock* root = proc.addBlock(); 7499 Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 7500 Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 7501 Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); 7502 7503 // Pretend to use all the args. 7504 PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7505 useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); 7506 useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 7507 useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); 7508 useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7509 7510 // Last use of first arg (here, arg1). 7511 CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); 7512 checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7513 7514 // Last use of second arg (here, arg2). 7515 CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg3, arg2); 7516 checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7517 7518 // Keep arg3 live. 7519 PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7520 keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 7521 keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7522 7523 // Only use of checkAdd1 and checkAdd2. 7524 CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2); 7525 checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7526 7527 root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3); 7528 7529 CHECK(compileAndRun<int64_t>(proc, 1, 2, 3) == 8); 7530 } 7531 7532 void testCheckAddArgumentAliasing32() 7533 { 7534 Procedure proc; 7535 BasicBlock* root = proc.addBlock(); 7536 Value* arg1 = root->appendNew<Value>( 7537 proc, Trunc, Origin(), 7538 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 7539 Value* arg2 = root->appendNew<Value>( 7540 proc, Trunc, Origin(), 7541 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 7542 Value* arg3 = root->appendNew<Value>( 7543 proc, Trunc, Origin(), 7544 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); 7545 7546 // Pretend to use all the args. 7547 PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7548 useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); 7549 useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 7550 useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); 7551 useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7552 7553 // Last use of first arg (here, arg1). 7554 CheckValue* checkAdd1 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg1, arg2); 7555 checkAdd1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7556 7557 // Last use of second arg (here, arg3). 7558 CheckValue* checkAdd2 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg2, arg3); 7559 checkAdd2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7560 7561 // Keep arg3 live. 7562 PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7563 keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 7564 keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7565 7566 // Only use of checkAdd1 and checkAdd2. 7567 CheckValue* checkAdd3 = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), checkAdd1, checkAdd2); 7568 checkAdd3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 7569 7570 root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd3); 7571 7572 CHECK(compileAndRun<int32_t>(proc, 1, 2, 3) == 8); 7573 } 7574 7575 void testCheckAddSelfOverflow64() 7576 { 7577 Procedure proc; 7578 BasicBlock* root = proc.addBlock(); 7579 Value* arg = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 7580 CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg); 7581 checkAdd->append(arg); 7582 checkAdd->setGenerator( 7583 [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { 7584 AllowMacroScratchRegisterUsage allowScratch(jit); 7585 jit.move(params[0].gpr(), GPRInfo::returnValueGPR); 7586 jit.emitFunctionEpilogue(); 7587 jit.ret(); 7588 }); 7589 7590 // Make sure the arg is not the destination of the operation. 7591 PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7592 opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister)); 7593 opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7594 7595 root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); 7596 7597 auto code = compile(proc); 7598 7599 CHECK(invoke<int64_t>(*code, 0ll) == 0); 7600 CHECK(invoke<int64_t>(*code, 1ll) == 2); 7601 CHECK(invoke<int64_t>(*code, std::numeric_limits<int64_t>::max()) == std::numeric_limits<int64_t>::max()); 7602 } 7603 7604 void testCheckAddSelfOverflow32() 7605 { 7606 Procedure proc; 7607 BasicBlock* root = proc.addBlock(); 7608 Value* arg = root->appendNew<Value>( 7609 proc, Trunc, Origin(), 7610 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 7611 CheckValue* checkAdd = root->appendNew<CheckValue>(proc, CheckAdd, Origin(), arg, arg); 7612 checkAdd->append(arg); 7613 checkAdd->setGenerator( 7614 [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { 7615 AllowMacroScratchRegisterUsage allowScratch(jit); 7616 jit.move(params[0].gpr(), GPRInfo::returnValueGPR); 7617 jit.emitFunctionEpilogue(); 7618 jit.ret(); 7619 }); 7620 7621 // Make sure the arg is not the destination of the operation. 7622 PatchpointValue* opaqueUse = root->appendNew<PatchpointValue>(proc, Void, Origin()); 7623 opaqueUse->append(ConstrainedValue(arg, ValueRep::SomeRegister)); 7624 opaqueUse->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 7625 7626 root->appendNew<ControlValue>(proc, Return, Origin(), checkAdd); 7627 7628 auto code = compile(proc); 7629 7630 CHECK(invoke<int32_t>(*code, 0ll) == 0); 7631 CHECK(invoke<int32_t>(*code, 1ll) == 2); 7632 CHECK(invoke<int32_t>(*code, std::numeric_limits<int32_t>::max()) == std::numeric_limits<int32_t>::max()); 7633 } 7634 7495 7635 void testCheckSubImm() 7496 7636 { … … 7942 8082 7943 8083 CHECK(invoke<int>(*code) == 42); 8084 } 8085 8086 void testCheckMulArgumentAliasing64() 8087 { 8088 Procedure proc; 8089 BasicBlock* root = proc.addBlock(); 8090 Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 8091 Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); 8092 Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2); 8093 8094 // Pretend to use all the args. 8095 PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); 8096 useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); 8097 useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 8098 useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); 8099 useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 8100 8101 // Last use of first arg (here, arg1). 8102 CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); 8103 checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8104 8105 // Last use of second arg (here, arg2). 8106 CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg3, arg2); 8107 checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8108 8109 // Keep arg3 live. 8110 PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); 8111 keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 8112 keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 8113 8114 // Only use of checkMul1 and checkMul2. 8115 CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2); 8116 checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8117 8118 root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3); 8119 8120 CHECK(compileAndRun<int64_t>(proc, 2, 3, 4) == 72); 8121 } 8122 8123 void testCheckMulArgumentAliasing32() 8124 { 8125 Procedure proc; 8126 BasicBlock* root = proc.addBlock(); 8127 Value* arg1 = root->appendNew<Value>( 8128 proc, Trunc, Origin(), 8129 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 8130 Value* arg2 = root->appendNew<Value>( 8131 proc, Trunc, Origin(), 8132 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 8133 Value* arg3 = root->appendNew<Value>( 8134 proc, Trunc, Origin(), 8135 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); 8136 8137 // Pretend to use all the args. 8138 PatchpointValue* useArgs = root->appendNew<PatchpointValue>(proc, Void, Origin()); 8139 useArgs->append(ConstrainedValue(arg1, ValueRep::SomeRegister)); 8140 useArgs->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 8141 useArgs->append(ConstrainedValue(arg3, ValueRep::SomeRegister)); 8142 useArgs->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 8143 8144 // Last use of first arg (here, arg1). 8145 CheckValue* checkMul1 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg1, arg2); 8146 checkMul1->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8147 8148 // Last use of second arg (here, arg3). 8149 CheckValue* checkMul2 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), arg2, arg3); 8150 checkMul2->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8151 8152 // Keep arg3 live. 8153 PatchpointValue* keepArg2Live = root->appendNew<PatchpointValue>(proc, Void, Origin()); 8154 keepArg2Live->append(ConstrainedValue(arg2, ValueRep::SomeRegister)); 8155 keepArg2Live->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { }); 8156 8157 // Only use of checkMul1 and checkMul2. 8158 CheckValue* checkMul3 = root->appendNew<CheckValue>(proc, CheckMul, Origin(), checkMul1, checkMul2); 8159 checkMul3->setGenerator([&] (CCallHelpers& jit, const StackmapGenerationParams&) { jit.oops(); }); 8160 8161 root->appendNew<ControlValue>(proc, Return, Origin(), checkMul3); 8162 8163 CHECK(compileAndRun<int32_t>(proc, 2, 3, 4) == 72); 7944 8164 } 7945 8165 … … 11062 11282 RUN(testCheckAddFold(100, 200)); 11063 11283 RUN(testCheckAddFoldFail(2147483647, 100)); 11284 RUN(testCheckAddArgumentAliasing64()); 11285 RUN(testCheckAddArgumentAliasing32()); 11286 RUN(testCheckAddSelfOverflow64()); 11287 RUN(testCheckAddSelfOverflow32()); 11064 11288 RUN(testCheckSubImm()); 11065 11289 RUN(testCheckSubBadImm()); … … 11076 11300 RUN(testCheckMulFold(100, 200)); 11077 11301 RUN(testCheckMulFoldFail(2147483647, 100)); 11302 RUN(testCheckMulArgumentAliasing64()); 11303 RUN(testCheckMulArgumentAliasing32()); 11078 11304 11079 11305 RUN(testCompare(Equal, 42, 42)); … … 11605 11831 11606 11832 RUN(testCheckMul64SShr()); 11833 11607 11834 RUN(testComputeDivisionMagic<int32_t>(2, -2147483647, 0)); 11608 11835 RUN(testTrivialInfiniteLoop()); -
trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp
r195831 r196513 214 214 baselineCodeBlock, 215 215 static_cast<VirtualRegister>(inlineCallFrame->stackOffset), 216 trueCaller ? AssemblyHelpers::UseExistingTagRegisterContents : AssemblyHelpers::Copy SavedTagRegistersFromBaseFrame,216 trueCaller ? AssemblyHelpers::UseExistingTagRegisterContents : AssemblyHelpers::CopyBaselineCalleeSavedRegistersFromBaseFrame, 217 217 GPRInfo::regT2); 218 218 -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r195134 r196513 214 214 } 215 215 216 enum RestoreTagRegisterMode { UseExistingTagRegisterContents, Copy SavedTagRegistersFromBaseFrame };216 enum RestoreTagRegisterMode { UseExistingTagRegisterContents, CopyBaselineCalleeSavedRegistersFromBaseFrame }; 217 217 218 218 void emitSaveOrCopyCalleeSavesFor(CodeBlock* codeBlock, VirtualRegister offsetVirtualRegister, RestoreTagRegisterMode tagRegisterMode, GPRReg temp) … … 223 223 RegisterSet dontSaveRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs()); 224 224 unsigned registerCount = calleeSaves->size(); 225 226 #if USE(JSVALUE64) 227 RegisterSet baselineCalleeSaves = RegisterSet::llintBaselineCalleeSaveRegisters(); 228 #endif 225 229 226 230 for (unsigned i = 0; i < registerCount; i++) { … … 235 239 UNUSED_PARAM(temp); 236 240 #else 237 if (tagRegisterMode == CopySavedTagRegistersFromBaseFrame 238 && (entry.reg() == GPRInfo::tagTypeNumberRegister || entry.reg() == GPRInfo::tagMaskRegister)) { 241 if (tagRegisterMode == CopyBaselineCalleeSavedRegistersFromBaseFrame && baselineCalleeSaves.get(entry.reg())) { 239 242 registerToWrite = temp; 240 243 loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, entry.offset()), registerToWrite);
Note:
See TracChangeset
for help on using the changeset viewer.