Unverified Commit fbf0a77e authored by Bill Wendling's avatar Bill Wendling Committed by GitHub
Browse files

[CodeGen] Avoid potential sideeffects from XOR (#67193)

XOR may change flag values (e.g. for X86 gprs). In the case where that's
not desirable, specify that buildClearRegister() should use MOV instead.
parent e6d0b126
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -2093,10 +2093,13 @@ public:
        "Target didn't implement TargetInstrInfo::insertOutlinedCall!");
  }

  /// Insert an architecture-specific instruction to clear a register.
  /// Insert an architecture-specific instruction to clear a register. If you
  /// need to avoid sideeffects (e.g. avoid XOR on x86, which sets EFLAGS), set
  /// \p AllowSideEffects to \p false.
  virtual void buildClearRegister(Register Reg, MachineBasicBlock &MBB,
                                  MachineBasicBlock::iterator Iter,
                                  DebugLoc &DL) const {
                                  DebugLoc &DL,
                                  bool AllowSideEffects = true) const {
    llvm_unreachable(
        "Target didn't implement TargetInstrInfo::buildClearRegister!");
  }
+4 −2
Original line number Diff line number Diff line
@@ -9134,13 +9134,15 @@ bool AArch64InstrInfo::shouldOutlineFromFunctionByDefault(

void AArch64InstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB,
                                          MachineBasicBlock::iterator Iter,
                                          DebugLoc &DL) const {
                                          DebugLoc &DL,
                                          bool AllowSideEffects) const {
  const MachineFunction &MF = *MBB.getParent();
  const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
  const AArch64RegisterInfo &TRI = *STI.getRegisterInfo();

  if (TRI.isGeneralPurposeRegister(MF, Reg)) {
    BuildMI(MBB, Iter, DL, get(AArch64::MOVi64imm), Reg)
    BuildMI(MBB, Iter, DL, get(AArch64::MOVZXi), Reg)
      .addImm(0)
      .addImm(0);
  } else if (STI.hasSVE()) {
    BuildMI(MBB, Iter, DL, get(AArch64::DUP_ZI_D), Reg)
+2 −2
Original line number Diff line number Diff line
@@ -333,8 +333,8 @@ public:
  bool shouldOutlineFromFunctionByDefault(MachineFunction &MF) const override;

  void buildClearRegister(Register Reg, MachineBasicBlock &MBB,
                          MachineBasicBlock::iterator Iter,
                          DebugLoc &DL) const override;
                          MachineBasicBlock::iterator Iter, DebugLoc &DL,
                          bool AllowSideEffects = true) const override;

  /// Returns the vector element size (B, H, S or D) of an SVE opcode.
  uint64_t getElementSizeForOpcode(unsigned Opc) const;
+23 −10
Original line number Diff line number Diff line
@@ -10130,19 +10130,27 @@ X86InstrInfo::insertOutlinedCall(Module &M, MachineBasicBlock &MBB,
  return It;
}

void X86InstrInfo::buildClearRegister(Register Reg,
                                      MachineBasicBlock &MBB,
void X86InstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator Iter,
                                      DebugLoc &DL) const {
                                      DebugLoc &DL,
                                      bool AllowSideEffects) const {
  const MachineFunction &MF = *MBB.getParent();
  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
  const TargetRegisterInfo &TRI = getRegisterInfo();

  if (ST.hasMMX() && X86::VR64RegClass.contains(Reg))
    // FIXME: Ignore MMX registers?
    // FIXME: Should we ignore MMX registers?
    return;

  if (TRI.isGeneralPurposeRegister(MF, Reg)) {
    // Convert register to the 32-bit version. Both 'movl' and 'xorl' clear the
    // upper bits of a 64-bit register automagically.
    Reg = getX86SubSuperRegister(Reg, 32);

    if (!AllowSideEffects)
      // XOR affects flags, so use a MOV instead.
      BuildMI(MBB, Iter, DL, get(X86::MOV32ri), Reg).addImm(0);
    else
      BuildMI(MBB, Iter, DL, get(X86::XOR32rr), Reg)
          .addReg(Reg, RegState::Undef)
          .addReg(Reg, RegState::Undef);
@@ -10151,6 +10159,7 @@ void X86InstrInfo::buildClearRegister(Register Reg,
    if (!ST.hasSSE1())
      return;

    // PXOR is safe to use because it doesn't affect flags.
    BuildMI(MBB, Iter, DL, get(X86::PXORrr), Reg)
      .addReg(Reg, RegState::Undef)
      .addReg(Reg, RegState::Undef);
@@ -10159,6 +10168,7 @@ void X86InstrInfo::buildClearRegister(Register Reg,
    if (!ST.hasAVX())
      return;

    // VPXOR is safe to use because it doesn't affect flags.
    BuildMI(MBB, Iter, DL, get(X86::VPXORrr), Reg)
      .addReg(Reg, RegState::Undef)
      .addReg(Reg, RegState::Undef);
@@ -10167,6 +10177,7 @@ void X86InstrInfo::buildClearRegister(Register Reg,
    if (!ST.hasAVX512())
      return;

    // VPXORY is safe to use because it doesn't affect flags.
    BuildMI(MBB, Iter, DL, get(X86::VPXORYrr), Reg)
      .addReg(Reg, RegState::Undef)
      .addReg(Reg, RegState::Undef);
@@ -10178,7 +10189,9 @@ void X86InstrInfo::buildClearRegister(Register Reg,
    if (!ST.hasVLX())
      return;

    BuildMI(MBB, Iter, DL, get(ST.hasBWI() ? X86::KXORQrr : X86::KXORWrr), Reg)
    // KXOR is safe to use because it doesn't affect flags.
    unsigned Op = ST.hasBWI() ? X86::KXORQrr : X86::KXORWrr;
    BuildMI(MBB, Iter, DL, get(Op), Reg)
        .addReg(Reg, RegState::Undef)
        .addReg(Reg, RegState::Undef);
  }
+2 −2
Original line number Diff line number Diff line
@@ -583,8 +583,8 @@ public:
                     outliner::Candidate &C) const override;

  void buildClearRegister(Register Reg, MachineBasicBlock &MBB,
                          MachineBasicBlock::iterator Iter,
                          DebugLoc &DL) const override;
                          MachineBasicBlock::iterator Iter, DebugLoc &DL,
                          bool AllowSideEffects = true) const override;

  bool verifyInstruction(const MachineInstr &MI,
                         StringRef &ErrInfo) const override;