@@ -87,6 +87,9 @@ class SystemZElimCompare : public MachineFunctionPass {
87
87
SmallVectorImpl<MachineInstr *> &CCUsers);
88
88
bool convertToLogical (MachineInstr &MI, MachineInstr &Compare,
89
89
SmallVectorImpl<MachineInstr *> &CCUsers);
90
+ bool adjustCCMasksForInstr (MachineInstr &MI, MachineInstr &Compare,
91
+ SmallVectorImpl<MachineInstr *> &CCUsers,
92
+ unsigned ConvOpc = 0 );
90
93
bool optimizeCompareZero (MachineInstr &Compare,
91
94
SmallVectorImpl<MachineInstr *> &CCUsers);
92
95
bool fuseCompareOperations (MachineInstr &Compare,
@@ -253,7 +256,7 @@ bool SystemZElimCompare::convertToLoadAndTest(
253
256
254
257
// Try to adjust CC masks for the LOAD AND TEST opcode that could replace MI.
255
258
unsigned Opcode = TII->getLoadAndTest (MI.getOpcode ());
256
- if (!Opcode || !TII-> adjustCCMasksForInstr (MI, Compare, CCUsers, Opcode))
259
+ if (!Opcode || !adjustCCMasksForInstr (MI, Compare, CCUsers, Opcode))
257
260
return false ;
258
261
259
262
// Rebuild to get the CC operand in the right place.
@@ -279,8 +282,18 @@ bool SystemZElimCompare::convertToLogical(
279
282
MachineInstr &MI, MachineInstr &Compare,
280
283
SmallVectorImpl<MachineInstr *> &CCUsers) {
281
284
282
- unsigned ConvOpc = TII->getConvertToLogicalOpcode (MI.getOpcode ());
283
- if (!ConvOpc || !TII->adjustCCMasksForInstr (MI, Compare, CCUsers, ConvOpc))
285
+ unsigned ConvOpc = 0 ;
286
+ switch (MI.getOpcode ()) {
287
+ case SystemZ::AR: ConvOpc = SystemZ::ALR; break ;
288
+ case SystemZ::ARK: ConvOpc = SystemZ::ALRK; break ;
289
+ case SystemZ::AGR: ConvOpc = SystemZ::ALGR; break ;
290
+ case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK; break ;
291
+ case SystemZ::A: ConvOpc = SystemZ::AL; break ;
292
+ case SystemZ::AY: ConvOpc = SystemZ::ALY; break ;
293
+ case SystemZ::AG: ConvOpc = SystemZ::ALG; break ;
294
+ default : break ;
295
+ }
296
+ if (!ConvOpc || !adjustCCMasksForInstr (MI, Compare, CCUsers, ConvOpc))
284
297
return false ;
285
298
286
299
// Operands should be identical, so just change the opcode and remove the
@@ -290,6 +303,167 @@ bool SystemZElimCompare::convertToLogical(
290
303
return true ;
291
304
}
292
305
306
+ #ifndef NDEBUG
307
+ static bool isAddWithImmediate (unsigned Opcode) {
308
+ switch (Opcode) {
309
+ case SystemZ::AHI:
310
+ case SystemZ::AHIK:
311
+ case SystemZ::AGHI:
312
+ case SystemZ::AGHIK:
313
+ case SystemZ::AFI:
314
+ case SystemZ::AIH:
315
+ case SystemZ::AGFI:
316
+ return true ;
317
+ default : break ;
318
+ }
319
+ return false ;
320
+ }
321
+ #endif
322
+
323
+ // The CC users in CCUsers are testing the result of a comparison of some
324
+ // value X against zero and we know that any CC value produced by MI would
325
+ // also reflect the value of X. ConvOpc may be used to pass the transfomed
326
+ // opcode MI will have if this succeeds. Try to adjust CCUsers so that they
327
+ // test the result of MI directly, returning true on success. Leave
328
+ // everything unchanged on failure.
329
+ bool SystemZElimCompare::adjustCCMasksForInstr (
330
+ MachineInstr &MI, MachineInstr &Compare,
331
+ SmallVectorImpl<MachineInstr *> &CCUsers,
332
+ unsigned ConvOpc) {
333
+ unsigned CompareFlags = Compare.getDesc ().TSFlags ;
334
+ unsigned CompareCCValues = SystemZII::getCCValues (CompareFlags);
335
+ int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode ());
336
+ const MCInstrDesc &Desc = TII->get (Opcode);
337
+ unsigned MIFlags = Desc.TSFlags ;
338
+
339
+ // If Compare may raise an FP exception, we can only eliminate it
340
+ // if MI itself would have already raised the exception.
341
+ if (Compare.mayRaiseFPException ()) {
342
+ // If the caller will change MI to use ConvOpc, only test whether
343
+ // ConvOpc is suitable; it is on the caller to set the MI flag.
344
+ if (ConvOpc && !Desc.mayRaiseFPException ())
345
+ return false ;
346
+ // If the caller will not change MI, we test the MI flag here.
347
+ if (!ConvOpc && !MI.mayRaiseFPException ())
348
+ return false ;
349
+ }
350
+
351
+ // See which compare-style condition codes are available.
352
+ unsigned CCValues = SystemZII::getCCValues (MIFlags);
353
+ unsigned ReusableCCMask = CCValues;
354
+ // For unsigned comparisons with zero, only equality makes sense.
355
+ if (CompareFlags & SystemZII::IsLogical)
356
+ ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;
357
+ unsigned OFImplies = 0 ;
358
+ bool LogicalMI = false ;
359
+ bool MIEquivalentToCmp = false ;
360
+ if (MI.getFlag (MachineInstr::NoSWrap) &&
361
+ (MIFlags & SystemZII::CCIfNoSignedWrap)) {
362
+ // If MI has the NSW flag set in combination with the
363
+ // SystemZII::CCIfNoSignedWrap flag, all CCValues are valid.
364
+ }
365
+ else if ((MIFlags & SystemZII::CCIfNoSignedWrap) &&
366
+ MI.getOperand (2 ).isImm ()) {
367
+ // Signed addition of immediate. If adding a positive immediate
368
+ // overflows, the result must be less than zero. If adding a negative
369
+ // immediate overflows, the result must be larger than zero (except in
370
+ // the special case of adding the minimum value of the result range, in
371
+ // which case we cannot predict whether the result is larger than or
372
+ // equal to zero).
373
+ assert (isAddWithImmediate (Opcode) && " Expected an add with immediate." );
374
+ assert (!MI.mayLoadOrStore () && " Expected an immediate term." );
375
+ int64_t RHS = MI.getOperand (2 ).getImm ();
376
+ if (SystemZ::GRX32BitRegClass.contains (MI.getOperand (0 ).getReg ()) &&
377
+ RHS == INT32_MIN)
378
+ return false ;
379
+ OFImplies = (RHS > 0 ? SystemZ::CCMASK_CMP_LT : SystemZ::CCMASK_CMP_GT);
380
+ }
381
+ else if ((MIFlags & SystemZII::IsLogical) && CCValues) {
382
+ // Use CCMASK_CMP_EQ to match with CCUsers. On success CCMask:s will be
383
+ // converted to CCMASK_LOGICAL_ZERO or CCMASK_LOGICAL_NONZERO.
384
+ LogicalMI = true ;
385
+ ReusableCCMask = SystemZ::CCMASK_CMP_EQ;
386
+ }
387
+ else {
388
+ ReusableCCMask &= SystemZII::getCompareZeroCCMask (MIFlags);
389
+ assert ((ReusableCCMask & ~CCValues) == 0 && " Invalid CCValues" );
390
+ MIEquivalentToCmp =
391
+ ReusableCCMask == CCValues && CCValues == CompareCCValues;
392
+ }
393
+ if (ReusableCCMask == 0 )
394
+ return false ;
395
+
396
+ if (!MIEquivalentToCmp) {
397
+ // Now check whether these flags are enough for all users.
398
+ SmallVector<MachineOperand *, 4 > AlterMasks;
399
+ for (MachineInstr *CCUserMI : CCUsers) {
400
+ // Fail if this isn't a use of CC that we understand.
401
+ unsigned Flags = CCUserMI->getDesc ().TSFlags ;
402
+ unsigned FirstOpNum;
403
+ if (Flags & SystemZII::CCMaskFirst)
404
+ FirstOpNum = 0 ;
405
+ else if (Flags & SystemZII::CCMaskLast)
406
+ FirstOpNum = CCUserMI->getNumExplicitOperands () - 2 ;
407
+ else
408
+ return false ;
409
+
410
+ // Check whether the instruction predicate treats all CC values
411
+ // outside of ReusableCCMask in the same way. In that case it
412
+ // doesn't matter what those CC values mean.
413
+ unsigned CCValid = CCUserMI->getOperand (FirstOpNum).getImm ();
414
+ unsigned CCMask = CCUserMI->getOperand (FirstOpNum + 1 ).getImm ();
415
+ assert (CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
416
+ " Corrupt CC operands of CCUser." );
417
+ unsigned OutValid = ~ReusableCCMask & CCValid;
418
+ unsigned OutMask = ~ReusableCCMask & CCMask;
419
+ if (OutMask != 0 && OutMask != OutValid)
420
+ return false ;
421
+
422
+ AlterMasks.push_back (&CCUserMI->getOperand (FirstOpNum));
423
+ AlterMasks.push_back (&CCUserMI->getOperand (FirstOpNum + 1 ));
424
+ }
425
+
426
+ // All users are OK. Adjust the masks for MI.
427
+ for (unsigned I = 0 , E = AlterMasks.size (); I != E; I += 2 ) {
428
+ AlterMasks[I]->setImm (CCValues);
429
+ unsigned CCMask = AlterMasks[I + 1 ]->getImm ();
430
+ if (LogicalMI) {
431
+ // Translate the CCMask into its "logical" value.
432
+ CCMask = (CCMask == SystemZ::CCMASK_CMP_EQ ?
433
+ SystemZ::CCMASK_LOGICAL_ZERO : SystemZ::CCMASK_LOGICAL_NONZERO);
434
+ CCMask &= CCValues; // Logical subtracts never set CC=0.
435
+ } else {
436
+ if (CCMask & ~ReusableCCMask)
437
+ CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
438
+ CCMask |= (CCMask & OFImplies) ? SystemZ::CCMASK_ARITH_OVERFLOW : 0 ;
439
+ }
440
+ AlterMasks[I + 1 ]->setImm (CCMask);
441
+ }
442
+ }
443
+
444
+ // CC is now live after MI.
445
+ if (!ConvOpc)
446
+ MI.clearRegisterDeads (SystemZ::CC);
447
+
448
+ // Check if MI lies before Compare.
449
+ bool BeforeCmp = false ;
450
+ MachineBasicBlock::iterator MBBI = MI, MBBE = MI.getParent ()->end ();
451
+ for (++MBBI; MBBI != MBBE; ++MBBI)
452
+ if (MBBI == Compare) {
453
+ BeforeCmp = true ;
454
+ break ;
455
+ }
456
+
457
+ // Clear any intervening kills of CC.
458
+ if (BeforeCmp) {
459
+ MachineBasicBlock::iterator MBBI = MI, MBBE = Compare;
460
+ for (++MBBI; MBBI != MBBE; ++MBBI)
461
+ MBBI->clearRegisterKills (SystemZ::CC, TRI);
462
+ }
463
+
464
+ return true ;
465
+ }
466
+
293
467
// Try to optimize cases where comparison instruction Compare is testing
294
468
// a value against zero. Return true on success and if Compare should be
295
469
// deleted as dead. CCUsers is the list of instructions that use the CC
@@ -325,7 +499,7 @@ bool SystemZElimCompare::optimizeCompareZero(
325
499
// Try to eliminate Compare by reusing a CC result from MI.
326
500
if ((!CCRefs && convertToLoadAndTest (MI, Compare, CCUsers)) ||
327
501
(!CCRefs.Def &&
328
- (TII-> adjustCCMasksForInstr (MI, Compare, CCUsers) ||
502
+ (adjustCCMasksForInstr (MI, Compare, CCUsers) ||
329
503
convertToLogical (MI, Compare, CCUsers)))) {
330
504
EliminatedComparisons += 1 ;
331
505
return true ;
0 commit comments