@@ -2281,42 +2281,181 @@ LowererMD::GenerateFastDivByPow2(IR::Instr *instr)
2281
2281
}
2282
2282
2283
2283
bool
2284
- LowererMD::GenerateFastBrString (IR::BranchInstr *branchInstr )
2284
+ LowererMD::GenerateFastBrOrCmString (IR::Instr* instr )
2285
2285
{
2286
- Assert (branchInstr->m_opcode == Js::OpCode::BrSrEq_A ||
2287
- branchInstr->m_opcode == Js::OpCode::BrSrNeq_A ||
2288
- branchInstr->m_opcode == Js::OpCode::BrEq_A ||
2289
- branchInstr->m_opcode == Js::OpCode::BrNeq_A ||
2290
- branchInstr->m_opcode == Js::OpCode::BrSrNotEq_A ||
2291
- branchInstr->m_opcode == Js::OpCode::BrSrNotNeq_A ||
2292
- branchInstr->m_opcode == Js::OpCode::BrNotEq_A ||
2293
- branchInstr->m_opcode == Js::OpCode::BrNotNeq_A
2294
- );
2286
+ IR::RegOpnd *srcReg1 = instr->GetSrc1 ()->IsRegOpnd () ? instr->GetSrc1 ()->AsRegOpnd () : nullptr ;
2287
+ IR::RegOpnd *srcReg2 = instr->GetSrc2 ()->IsRegOpnd () ? instr->GetSrc2 ()->AsRegOpnd () : nullptr ;
2295
2288
2296
- IR::Instr* instrInsert = branchInstr;
2297
- IR::RegOpnd *srcReg1 = branchInstr->GetSrc1 ()->IsRegOpnd () ? branchInstr->GetSrc1 ()->AsRegOpnd () : nullptr ;
2298
- IR::RegOpnd *srcReg2 = branchInstr->GetSrc2 ()->IsRegOpnd () ? branchInstr->GetSrc2 ()->AsRegOpnd () : nullptr ;
2289
+ if (!srcReg1 ||
2290
+ !srcReg2 ||
2291
+ srcReg1->IsTaggedInt () ||
2292
+ srcReg2->IsTaggedInt () ||
2293
+ !srcReg1->GetValueType ().IsLikelyString () ||
2294
+ !srcReg2->GetValueType ().IsLikelyString ())
2295
+ {
2296
+ return false ;
2297
+ }
2298
+
2299
+ IR::LabelInstr *labelHelper = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func , true );
2300
+ IR::LabelInstr *labelBranchFail = nullptr ;
2301
+ IR::LabelInstr *labelBranchSuccess = nullptr ;
2302
+ IR::Instr *instrMovSuccess = nullptr ;
2303
+ IR::Instr *instrMovFailure = nullptr ;
2304
+
2305
+ bool isEqual = false ;
2306
+ bool isStrict = false ;
2307
+ bool isBranch = true ;
2308
+ bool isCmNegOp = false ;
2299
2309
2300
- if (srcReg1 && srcReg2 )
2310
+ switch (instr-> m_opcode )
2301
2311
{
2302
- if (srcReg1->IsTaggedInt () || srcReg2->IsTaggedInt ())
2303
- {
2304
- return false ;
2305
- }
2312
+ case Js::OpCode::BrSrEq_A:
2313
+ case Js::OpCode::BrSrNotNeq_A:
2314
+ isStrict = true ;
2315
+ case Js::OpCode::BrEq_A:
2316
+ case Js::OpCode::BrNotNeq_A:
2317
+ labelBranchFail = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2318
+ labelBranchSuccess = instr->AsBranchInstr ()->GetTarget ();
2319
+ instr->InsertAfter (labelBranchFail);
2320
+ isEqual = true ;
2321
+ break ;
2306
2322
2307
- bool isSrc1String = srcReg1->GetValueType ().IsLikelyString ();
2308
- bool isSrc2String = srcReg2->GetValueType ().IsLikelyString ();
2309
- // Left and right hand are both LikelyString
2310
- if (!isSrc1String || !isSrc2String)
2311
- {
2312
- return false ;
2313
- }
2323
+ case Js::OpCode::BrSrNeq_A:
2324
+ case Js::OpCode::BrSrNotEq_A:
2325
+ isStrict = true ;
2326
+ case Js::OpCode::BrNeq_A:
2327
+ case Js::OpCode::BrNotEq_A:
2328
+ labelBranchSuccess = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2329
+ labelBranchFail = instr->AsBranchInstr ()->GetTarget ();
2330
+ instr->InsertAfter (labelBranchSuccess);
2331
+ isEqual = false ;
2332
+ break ;
2333
+
2334
+ case Js::OpCode::CmSrEq_A:
2335
+ isStrict = true ;
2336
+ case Js::OpCode::CmEq_A:
2337
+ isEqual = true ;
2338
+ isBranch = false ;
2339
+ break ;
2340
+
2341
+ case Js::OpCode::CmSrNeq_A:
2342
+ isStrict = true ;
2343
+ case Js::OpCode::CmNeq_A:
2344
+ isEqual = false ;
2345
+ isBranch = false ;
2346
+ isCmNegOp = true ;
2347
+ break ;
2348
+
2349
+ default :
2350
+ Assert (UNREACHED);
2351
+ __assume (0 );
2352
+ }
2353
+
2354
+ if (!isBranch)
2355
+ {
2356
+ labelBranchSuccess = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2357
+ labelBranchFail = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2358
+
2359
+ LibraryValue successValueType = !isCmNegOp ? LibraryValue::ValueTrue : LibraryValue::ValueFalse;
2360
+ LibraryValue failureValueType = !isCmNegOp ? LibraryValue::ValueFalse : LibraryValue::ValueTrue;
2361
+
2362
+ instrMovFailure = IR::Instr::New (Js::OpCode::MOV, instr->GetDst (), this ->m_lowerer ->LoadLibraryValueOpnd (instr, failureValueType), m_func);
2363
+ instrMovSuccess = IR::Instr::New (Js::OpCode::MOV, instr->GetDst (), this ->m_lowerer ->LoadLibraryValueOpnd (instr, successValueType), m_func);
2364
+ }
2365
+
2366
+ this ->GenerateFastStringCheck (instr, srcReg1, srcReg2, isEqual, isStrict, labelHelper, labelBranchSuccess, labelBranchFail);
2367
+
2368
+ IR::LabelInstr *labelFallthrough = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2369
+
2370
+ if (!isBranch)
2371
+ {
2372
+ instr->InsertBefore (labelBranchSuccess);
2373
+ instr->InsertBefore (instrMovSuccess);
2374
+ instr->InsertBefore (IR::BranchInstr::New (Js::OpCode::JMP, labelFallthrough, this ->m_func ));
2375
+
2376
+ instr->InsertBefore (labelBranchFail);
2377
+ instr->InsertBefore (instrMovFailure);
2378
+ instr->InsertBefore (IR::BranchInstr::New (Js::OpCode::JMP, labelFallthrough, this ->m_func ));
2379
+ }
2380
+
2381
+ instr->InsertBefore (labelHelper);
2382
+
2383
+ instr->InsertAfter (labelFallthrough);
2384
+
2385
+ #if DBG
2386
+ // The fast-path for strings assumes the case where 2 strings are equal is rare, and marks that path as 'helper'.
2387
+ // This breaks the helper label dbchecks as it can result in non-helper blocks be reachable only from helper blocks.
2388
+ // Use m_isHelperToNonHelperBranch and m_noHelperAssert to fix this.
2389
+ IR::Instr *blockEndInstr;
2390
+
2391
+ if (isEqual)
2392
+ {
2393
+ blockEndInstr = labelHelper->GetNextBranchOrLabel ();
2314
2394
}
2315
2395
else
2316
2396
{
2317
- return false ;
2397
+ blockEndInstr = instr-> GetNextBranchOrLabel () ;
2318
2398
}
2319
2399
2400
+ if (blockEndInstr->IsBranchInstr ())
2401
+ {
2402
+ blockEndInstr->AsBranchInstr ()->m_isHelperToNonHelperBranch = true ;
2403
+ }
2404
+
2405
+ labelFallthrough->m_noHelperAssert = true ;
2406
+ #endif
2407
+
2408
+ return true ;
2409
+ }
2410
+
2411
+ bool
2412
+ LowererMD::GenerateFastStringCheck (IR::Instr *instr, IR::RegOpnd *srcReg1, IR::RegOpnd *srcReg2, bool isEqual, bool isStrict, IR::LabelInstr *labelHelper, IR::LabelInstr *labelBranchSuccess, IR::LabelInstr *labelBranchFail)
2413
+ {
2414
+ Assert (instr->m_opcode == Js::OpCode::BrSrEq_A ||
2415
+ instr->m_opcode == Js::OpCode::BrSrNeq_A ||
2416
+ instr->m_opcode == Js::OpCode::BrEq_A ||
2417
+ instr->m_opcode == Js::OpCode::BrNeq_A ||
2418
+ instr->m_opcode == Js::OpCode::BrSrNotEq_A ||
2419
+ instr->m_opcode == Js::OpCode::BrSrNotNeq_A ||
2420
+ instr->m_opcode == Js::OpCode::BrNotEq_A ||
2421
+ instr->m_opcode == Js::OpCode::BrNotNeq_A ||
2422
+ instr->m_opcode == Js::OpCode::CmEq_A ||
2423
+ instr->m_opcode == Js::OpCode::CmNeq_A ||
2424
+ instr->m_opcode == Js::OpCode::CmSrEq_A ||
2425
+ instr->m_opcode == Js::OpCode::CmSrNeq_A );
2426
+
2427
+ // if src1 is not string
2428
+ // generate object test, if not equal jump to $helper
2429
+ // compare type check to string, if not jump to $helper
2430
+ //
2431
+ // if strict mode generate string test as above for src1 and jump to $failure if failed any time
2432
+ // else if not strict generate string test as above for src1 and jump to $helper if failed any time
2433
+ //
2434
+ // Compare length of src1 and src2 if not equal goto $failure
2435
+ //
2436
+ // if src1 is not flat string jump to $helper
2437
+ //
2438
+ // if src1 and src2 m_pszValue pointer match goto $success
2439
+ //
2440
+ // if src2 is not flat string jump to $helper
2441
+ //
2442
+ // if first character of src1 and src2 doesn't match goto $failure
2443
+ //
2444
+ // shift left by 1 length of src1 (length*2)
2445
+ //
2446
+ // memcmp src1 and src2 flat strings till length * 2
2447
+ //
2448
+ // test eax (result of memcmp)
2449
+ // if equal jump to $success else to $failure
2450
+ //
2451
+ // $success
2452
+ // jmp to $fallthrough
2453
+ // $failure
2454
+ // jmp to $fallthrough
2455
+ // $helper
2456
+ //
2457
+ // $fallthrough
2458
+
2320
2459
// Generates:
2321
2460
// GenerateObjectTest(src1);
2322
2461
// MOV s1, [srcReg1 + offset(Type)]
@@ -2346,42 +2485,7 @@ LowererMD::GenerateFastBrString(IR::BranchInstr *branchInstr)
2346
2485
// JEQ $success
2347
2486
// JMP $fail
2348
2487
2349
-
2350
- IR::LabelInstr *labelHelper = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func , true );
2351
- IR::LabelInstr *labelTarget = branchInstr->GetTarget ();
2352
- IR::LabelInstr *labelBranchFail = nullptr ;
2353
- IR::LabelInstr *labelBranchSuccess = nullptr ;
2354
- bool isEqual = false ;
2355
- bool isStrict = false ;
2356
-
2357
- switch (branchInstr->m_opcode )
2358
- {
2359
- case Js::OpCode::BrSrEq_A:
2360
- case Js::OpCode::BrSrNotNeq_A:
2361
- isStrict = true ;
2362
- case Js::OpCode::BrEq_A:
2363
- case Js::OpCode::BrNotNeq_A:
2364
- labelBranchFail = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2365
- labelBranchSuccess = labelTarget;
2366
- branchInstr->InsertAfter (labelBranchFail);
2367
- isEqual = true ;
2368
- break ;
2369
-
2370
- case Js::OpCode::BrSrNeq_A:
2371
- case Js::OpCode::BrSrNotEq_A:
2372
- isStrict = true ;
2373
- case Js::OpCode::BrNeq_A:
2374
- case Js::OpCode::BrNotEq_A:
2375
- labelBranchSuccess = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2376
- labelBranchFail = labelTarget;
2377
- branchInstr->InsertAfter (labelBranchSuccess);
2378
- isEqual = false ;
2379
- break ;
2380
-
2381
- default :
2382
- Assert (UNREACHED);
2383
- __assume (0 );
2384
- }
2488
+ IR::Instr* instrInsert = instr;
2385
2489
2386
2490
this ->m_lowerer ->GenerateStringTest (srcReg1, instrInsert, labelHelper);
2387
2491
@@ -2471,50 +2575,24 @@ LowererMD::GenerateFastBrString(IR::BranchInstr *branchInstr)
2471
2575
2472
2576
// eax = memcmp(src1String, src2String, length*2)
2473
2577
2474
- this ->LoadHelperArgument (branchInstr , src1LengthOpnd);
2475
- this ->LoadHelperArgument (branchInstr , src1FlatString);
2476
- this ->LoadHelperArgument (branchInstr , src2FlatString);
2578
+ this ->LoadHelperArgument (instr , src1LengthOpnd);
2579
+ this ->LoadHelperArgument (instr , src1FlatString);
2580
+ this ->LoadHelperArgument (instr , src2FlatString);
2477
2581
IR::RegOpnd *dstOpnd = IR::RegOpnd::New (TyInt32, this ->m_func );
2478
2582
IR::Instr *instrCall = IR::Instr::New (Js::OpCode::CALL, dstOpnd, IR::HelperCallOpnd::New (IR::HelperMemCmp, this ->m_func ), this ->m_func );
2479
- branchInstr ->InsertBefore (instrCall);
2583
+ instr ->InsertBefore (instrCall);
2480
2584
this ->LowerCall (instrCall, 3 );
2481
2585
2482
2586
// TEST eax, eax
2483
2587
IR::Instr *instrTest = IR::Instr::New (Js::OpCode::TEST, this ->m_func );
2484
2588
instrTest->SetSrc1 (instrCall->GetDst ());
2485
2589
instrTest->SetSrc2 (instrCall->GetDst ());
2486
2590
instrInsert->InsertBefore (instrTest);
2591
+
2487
2592
// JEQ success
2488
- instrInsert ->InsertBefore (IR::BranchInstr::New (Js::OpCode::JEQ, labelBranchSuccess, this ->m_func ));
2593
+ instr ->InsertBefore (IR::BranchInstr::New (Js::OpCode::JEQ, labelBranchSuccess, this ->m_func ));
2489
2594
// JMP fail
2490
- instrInsert->InsertBefore (IR::BranchInstr::New (Js::OpCode::JMP, labelBranchFail, this ->m_func ));
2491
-
2492
- branchInstr->InsertBefore (labelHelper);
2493
- IR::LabelInstr *labelFallthrough = IR::LabelInstr::New (Js::OpCode::Label, this ->m_func );
2494
- branchInstr->InsertAfter (labelFallthrough);
2495
-
2496
- #if DBG
2497
- // The fast-path for strings assumes the case where 2 strings are equal is rare, and marks that path as 'helper'.
2498
- // This breaks the helper label dbchecks as it can result in non-helper blocks be reachable only from helper blocks.
2499
- // Use m_isHelperToNonHelperBranch and m_noHelperAssert to fix this.
2500
- IR::Instr *blockEndInstr;
2501
-
2502
- if (isEqual)
2503
- {
2504
- blockEndInstr = labelHelper->GetNextBranchOrLabel ();
2505
- }
2506
- else
2507
- {
2508
- blockEndInstr = branchInstr->GetNextBranchOrLabel ();
2509
- }
2510
-
2511
- if (blockEndInstr->IsBranchInstr ())
2512
- {
2513
- blockEndInstr->AsBranchInstr ()->m_isHelperToNonHelperBranch = true ;
2514
- }
2515
-
2516
- labelFallthrough->m_noHelperAssert = true ;
2517
- #endif
2595
+ instr->InsertBefore (IR::BranchInstr::New (Js::OpCode::JMP, labelBranchFail, this ->m_func ));
2518
2596
2519
2597
return true ;
2520
2598
}
0 commit comments