Skip to content

Commit 9c24ebf

Browse files
author
Evgeny Astigeevich
committedApr 6, 2016
[AArch64][CodeGen] NFC refactor AArch64InstrInfo::optimizeCompareInstr to prepare it for fixing a bug in it
AArch64InstrInfo::optimizeCompareInstr has a bug which causes generation of incorrect code (PR#27158). The patch refactors the function to simplify reviewing the fix of the bug. 1. Function name ‘modifiesConditionCode’ is changed to ‘areCFlagsAccessedBetweenInstrs’ to reflect that the function can check modifying accesses, reading accesses or both. 2. Function ‘AArch64InstrInfo::optimizeCompareInstr’ - Documented the function - Cmp_NZCV is DeadNZCVIdx to reflect that it is an operand index of dead NZCV - The code for the case of substituting CmpInstr is put into separate functions the main of them is ‘substituteCmpInstr’. Differential Revision: http://reviews.llvm.org/D18609 llvm-svn: 265531
1 parent 0b0da29 commit 9c24ebf

File tree

2 files changed

+101
-57
lines changed

2 files changed

+101
-57
lines changed
 

‎llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

+99-57
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/MC/MCInst.h"
2323
#include "llvm/Support/ErrorHandling.h"
2424
#include "llvm/Support/TargetRegistry.h"
25+
#include <algorithm>
2526

2627
using namespace llvm;
2728

@@ -790,48 +791,68 @@ static unsigned convertFlagSettingOpcode(const MachineInstr *MI) {
790791
}
791792
}
792793

793-
/// True when condition code could be modified on the instruction
794-
/// trace starting at from and ending at to.
795-
static bool modifiesConditionCode(MachineInstr *From, MachineInstr *To,
796-
const bool CheckOnlyCCWrites,
797-
const TargetRegisterInfo *TRI) {
794+
enum AccessKind {
795+
AK_Write = 0x01,
796+
AK_Read = 0x10,
797+
AK_All = 0x11
798+
};
799+
800+
/// True when condition flags are accessed (either by writing or reading)
801+
/// on the instruction trace starting at From and ending at To.
802+
///
803+
/// Note: If From and To are from different blocks it's assumed CC are accessed
804+
/// on the path.
805+
static bool areCFlagsAccessedBetweenInstrs(MachineInstr *From, MachineInstr *To,
806+
const TargetRegisterInfo *TRI,
807+
const AccessKind AccessToCheck = AK_All) {
798808
// We iterate backward starting \p To until we hit \p From
799809
MachineBasicBlock::iterator I = To, E = From, B = To->getParent()->begin();
800810

801811
// Early exit if To is at the beginning of the BB.
802812
if (I == B)
803813
return true;
804814

805-
// Check whether the definition of SrcReg is in the same basic block as
806-
// Compare. If not, assume the condition code gets modified on some path.
815+
// Check whether the instructions are in the same basic block
816+
// If not, assume the condition flags might get modified somewhere.
807817
if (To->getParent() != From->getParent())
808818
return true;
809819

810-
// Check that NZCV isn't set on the trace.
820+
// From must be above To.
821+
assert(std::find_if(MachineBasicBlock::reverse_iterator(To),
822+
To->getParent()->rend(),
823+
[From](MachineInstr &MI) {
824+
return &MI == From;
825+
}) != To->getParent()->rend());
826+
811827
for (--I; I != E; --I) {
812828
const MachineInstr &Instr = *I;
813829

814-
if (Instr.modifiesRegister(AArch64::NZCV, TRI) ||
815-
(!CheckOnlyCCWrites && Instr.readsRegister(AArch64::NZCV, TRI)))
816-
// This instruction modifies or uses NZCV after the one we want to
817-
// change.
818-
return true;
819-
if (I == B)
820-
// We currently don't allow the instruction trace to cross basic
821-
// block boundaries
830+
if ( ((AccessToCheck & AK_Write) && Instr.modifiesRegister(AArch64::NZCV, TRI)) ||
831+
((AccessToCheck & AK_Read) && Instr.readsRegister(AArch64::NZCV, TRI)))
822832
return true;
823833
}
824834
return false;
825835
}
826-
/// optimizeCompareInstr - Convert the instruction supplying the argument to the
827-
/// comparison into one that sets the zero bit in the flags register.
836+
837+
/// Try to optimize a compare instruction. A compare instruction is an
838+
/// instruction which produces AArch64::NZCV. It can be truly compare instruction
839+
/// when there are no uses of its destination register.
840+
///
841+
/// The following steps are tried in order:
842+
/// 1. Convert CmpInstr into an unconditional version.
843+
/// 2. Remove CmpInstr if above there is an instruction producing a needed
844+
/// condition code or an instruction which can be converted into such an instruction.
845+
/// Only comparison with zero is supported.
828846
bool AArch64InstrInfo::optimizeCompareInstr(
829847
MachineInstr *CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask,
830848
int CmpValue, const MachineRegisterInfo *MRI) const {
849+
assert(CmpInstr);
850+
assert(CmpInstr->getParent());
851+
assert(MRI);
831852

832853
// Replace SUBSWrr with SUBWrr if NZCV is not used.
833-
int Cmp_NZCV = CmpInstr->findRegisterDefOperandIdx(AArch64::NZCV, true);
834-
if (Cmp_NZCV != -1) {
854+
int DeadNZCVIdx = CmpInstr->findRegisterDefOperandIdx(AArch64::NZCV, true);
855+
if (DeadNZCVIdx != -1) {
835856
if (CmpInstr->definesRegister(AArch64::WZR) ||
836857
CmpInstr->definesRegister(AArch64::XZR)) {
837858
CmpInstr->eraseFromParent();
@@ -843,7 +864,7 @@ bool AArch64InstrInfo::optimizeCompareInstr(
843864
return false;
844865
const MCInstrDesc &MCID = get(NewOpc);
845866
CmpInstr->setDesc(MCID);
846-
CmpInstr->RemoveOperand(Cmp_NZCV);
867+
CmpInstr->RemoveOperand(DeadNZCVIdx);
847868
bool succeeded = UpdateOperandRegClass(CmpInstr);
848869
(void)succeeded;
849870
assert(succeeded && "Some operands reg class are incompatible!");
@@ -861,20 +882,18 @@ bool AArch64InstrInfo::optimizeCompareInstr(
861882
if (!MRI->use_nodbg_empty(CmpInstr->getOperand(0).getReg()))
862883
return false;
863884

864-
// Get the unique definition of SrcReg.
865-
MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
866-
if (!MI)
867-
return false;
868-
869-
bool CheckOnlyCCWrites = false;
870-
const TargetRegisterInfo *TRI = &getRegisterInfo();
871-
if (modifiesConditionCode(MI, CmpInstr, CheckOnlyCCWrites, TRI))
872-
return false;
885+
return substituteCmpInstr(CmpInstr, SrcReg, MRI);
886+
}
873887

874-
unsigned NewOpc = MI->getOpcode();
875-
switch (MI->getOpcode()) {
888+
/// Get opcode of S version of Instr.
889+
/// If Instr is S version its opcode is returned.
890+
/// AArch64::INSTRUCTION_LIST_END is returned if Instr does not have S version
891+
/// or we are not interested in it.
892+
static unsigned sForm(MachineInstr &Instr) {
893+
switch (Instr.getOpcode()) {
876894
default:
877-
return false;
895+
return AArch64::INSTRUCTION_LIST_END;
896+
878897
case AArch64::ADDSWrr:
879898
case AArch64::ADDSWri:
880899
case AArch64::ADDSXrr:
@@ -883,22 +902,50 @@ bool AArch64InstrInfo::optimizeCompareInstr(
883902
case AArch64::SUBSWri:
884903
case AArch64::SUBSXrr:
885904
case AArch64::SUBSXri:
886-
break;
887-
case AArch64::ADDWrr: NewOpc = AArch64::ADDSWrr; break;
888-
case AArch64::ADDWri: NewOpc = AArch64::ADDSWri; break;
889-
case AArch64::ADDXrr: NewOpc = AArch64::ADDSXrr; break;
890-
case AArch64::ADDXri: NewOpc = AArch64::ADDSXri; break;
891-
case AArch64::ADCWr: NewOpc = AArch64::ADCSWr; break;
892-
case AArch64::ADCXr: NewOpc = AArch64::ADCSXr; break;
893-
case AArch64::SUBWrr: NewOpc = AArch64::SUBSWrr; break;
894-
case AArch64::SUBWri: NewOpc = AArch64::SUBSWri; break;
895-
case AArch64::SUBXrr: NewOpc = AArch64::SUBSXrr; break;
896-
case AArch64::SUBXri: NewOpc = AArch64::SUBSXri; break;
897-
case AArch64::SBCWr: NewOpc = AArch64::SBCSWr; break;
898-
case AArch64::SBCXr: NewOpc = AArch64::SBCSXr; break;
899-
case AArch64::ANDWri: NewOpc = AArch64::ANDSWri; break;
900-
case AArch64::ANDXri: NewOpc = AArch64::ANDSXri; break;
901-
}
905+
return Instr.getOpcode();;
906+
907+
case AArch64::ADDWrr: return AArch64::ADDSWrr;
908+
case AArch64::ADDWri: return AArch64::ADDSWri;
909+
case AArch64::ADDXrr: return AArch64::ADDSXrr;
910+
case AArch64::ADDXri: return AArch64::ADDSXri;
911+
case AArch64::ADCWr: return AArch64::ADCSWr;
912+
case AArch64::ADCXr: return AArch64::ADCSXr;
913+
case AArch64::SUBWrr: return AArch64::SUBSWrr;
914+
case AArch64::SUBWri: return AArch64::SUBSWri;
915+
case AArch64::SUBXrr: return AArch64::SUBSXrr;
916+
case AArch64::SUBXri: return AArch64::SUBSXri;
917+
case AArch64::SBCWr: return AArch64::SBCSWr;
918+
case AArch64::SBCXr: return AArch64::SBCSXr;
919+
case AArch64::ANDWri: return AArch64::ANDSWri;
920+
case AArch64::ANDXri: return AArch64::ANDSXri;
921+
}
922+
}
923+
924+
/// Check if AArch64::NZCV should be alive in successors of MBB.
925+
static bool areCFlagsAliveInSuccessors(MachineBasicBlock *MBB) {
926+
for (auto *BB : MBB->successors())
927+
if (BB->isLiveIn(AArch64::NZCV))
928+
return true;
929+
return false;
930+
}
931+
932+
/// Substitute CmpInstr with another instruction which produces a needed
933+
/// condition code.
934+
/// Return true on success.
935+
bool AArch64InstrInfo::substituteCmpInstr(MachineInstr *CmpInstr,
936+
unsigned SrcReg, const MachineRegisterInfo *MRI) const {
937+
// Get the unique definition of SrcReg.
938+
MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
939+
if (!MI)
940+
return false;
941+
942+
const TargetRegisterInfo *TRI = &getRegisterInfo();
943+
if (areCFlagsAccessedBetweenInstrs(MI, CmpInstr, TRI))
944+
return false;
945+
946+
unsigned NewOpc = sForm(*MI);
947+
if (NewOpc == AArch64::INSTRUCTION_LIST_END)
948+
return false;
902949

903950
// Scan forward for the use of NZCV.
904951
// When checking against MI: if it's a conditional code requires
@@ -966,12 +1013,8 @@ bool AArch64InstrInfo::optimizeCompareInstr(
9661013

9671014
// If NZCV is not killed nor re-defined, we should check whether it is
9681015
// live-out. If it is live-out, do not optimize.
969-
if (!IsSafe) {
970-
MachineBasicBlock *ParentBlock = CmpInstr->getParent();
971-
for (auto *MBB : ParentBlock->successors())
972-
if (MBB->isLiveIn(AArch64::NZCV))
973-
return false;
974-
}
1016+
if (!IsSafe && areCFlagsAliveInSuccessors(CmpInstr->getParent()))
1017+
return false;
9751018

9761019
// Update the instruction to set NZCV.
9771020
MI->setDesc(get(NewOpc));
@@ -3201,11 +3244,10 @@ bool AArch64InstrInfo::optimizeCondBranch(MachineInstr *MI) const {
32013244
return false;
32023245

32033246
AArch64CC::CondCode CC = (AArch64CC::CondCode)DefMI->getOperand(3).getImm();
3204-
bool CheckOnlyCCWrites = true;
32053247
// Convert only when the condition code is not modified between
32063248
// the CSINC and the branch. The CC may be used by other
32073249
// instructions in between.
3208-
if (modifiesConditionCode(DefMI, MI, CheckOnlyCCWrites, &getRegisterInfo()))
3250+
if (areCFlagsAccessedBetweenInstrs(DefMI, MI, &getRegisterInfo(), AK_Write))
32093251
return false;
32103252
MachineBasicBlock &RefToMBB = *MBB;
32113253
MachineBasicBlock *TBB = MI->getOperand(TargetBBInMI).getMBB();

‎llvm/lib/Target/AArch64/AArch64InstrInfo.h

+2
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ class AArch64InstrInfo : public AArch64GenInstrInfo {
204204
void instantiateCondBranch(MachineBasicBlock &MBB, DebugLoc DL,
205205
MachineBasicBlock *TBB,
206206
ArrayRef<MachineOperand> Cond) const;
207+
bool substituteCmpInstr(MachineInstr *CmpInstr,
208+
unsigned SrcReg, const MachineRegisterInfo *MRI) const;
207209
};
208210

209211
/// emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg

0 commit comments

Comments
 (0)
Please sign in to comment.