1*0b57cec5SDimitry Andric //===---- X86FixupSetCC.cpp - optimize usage of LEA instructions ----------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file defines a pass that fixes zero-extension of setcc patterns.
10*0b57cec5SDimitry Andric // X86 setcc instructions are modeled to have no input arguments, and a single
11*0b57cec5SDimitry Andric // GR8 output argument. This is consistent with other similar instructions
12*0b57cec5SDimitry Andric // (e.g. movb), but means it is impossible to directly generate a setcc into
13*0b57cec5SDimitry Andric // the lower GR8 of a specified GR32.
14*0b57cec5SDimitry Andric // This means that ISel must select (zext (setcc)) into something like
15*0b57cec5SDimitry Andric // seta %al; movzbl %al, %eax.
16*0b57cec5SDimitry Andric // Unfortunately, this can cause a stall due to the partial register write
17*0b57cec5SDimitry Andric // performed by the setcc. Instead, we can use:
18*0b57cec5SDimitry Andric // xor %eax, %eax; seta %al
19*0b57cec5SDimitry Andric // This both avoids the stall, and encodes shorter.
20*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
21*0b57cec5SDimitry Andric
22*0b57cec5SDimitry Andric #include "X86.h"
23*0b57cec5SDimitry Andric #include "X86InstrInfo.h"
24*0b57cec5SDimitry Andric #include "X86Subtarget.h"
25*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
28*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
29*0b57cec5SDimitry Andric
30*0b57cec5SDimitry Andric using namespace llvm;
31*0b57cec5SDimitry Andric
32*0b57cec5SDimitry Andric #define DEBUG_TYPE "x86-fixup-setcc"
33*0b57cec5SDimitry Andric
34*0b57cec5SDimitry Andric STATISTIC(NumSubstZexts, "Number of setcc + zext pairs substituted");
35*0b57cec5SDimitry Andric
36*0b57cec5SDimitry Andric namespace {
37*0b57cec5SDimitry Andric class X86FixupSetCCPass : public MachineFunctionPass {
38*0b57cec5SDimitry Andric public:
39*0b57cec5SDimitry Andric static char ID;
40*0b57cec5SDimitry Andric
X86FixupSetCCPass()41*0b57cec5SDimitry Andric X86FixupSetCCPass() : MachineFunctionPass(ID) {}
42*0b57cec5SDimitry Andric
getPassName() const43*0b57cec5SDimitry Andric StringRef getPassName() const override { return "X86 Fixup SetCC"; }
44*0b57cec5SDimitry Andric
45*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
46*0b57cec5SDimitry Andric
47*0b57cec5SDimitry Andric private:
48*0b57cec5SDimitry Andric MachineRegisterInfo *MRI = nullptr;
49*0b57cec5SDimitry Andric const X86InstrInfo *TII = nullptr;
50*0b57cec5SDimitry Andric
51*0b57cec5SDimitry Andric enum { SearchBound = 16 };
52*0b57cec5SDimitry Andric };
53*0b57cec5SDimitry Andric } // end anonymous namespace
54*0b57cec5SDimitry Andric
55*0b57cec5SDimitry Andric char X86FixupSetCCPass::ID = 0;
56*0b57cec5SDimitry Andric
INITIALIZE_PASS(X86FixupSetCCPass,DEBUG_TYPE,DEBUG_TYPE,false,false)57*0b57cec5SDimitry Andric INITIALIZE_PASS(X86FixupSetCCPass, DEBUG_TYPE, DEBUG_TYPE, false, false)
58*0b57cec5SDimitry Andric
59*0b57cec5SDimitry Andric FunctionPass *llvm::createX86FixupSetCC() { return new X86FixupSetCCPass(); }
60*0b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & MF)61*0b57cec5SDimitry Andric bool X86FixupSetCCPass::runOnMachineFunction(MachineFunction &MF) {
62*0b57cec5SDimitry Andric bool Changed = false;
63*0b57cec5SDimitry Andric MRI = &MF.getRegInfo();
64*0b57cec5SDimitry Andric TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();
65*0b57cec5SDimitry Andric
66*0b57cec5SDimitry Andric SmallVector<MachineInstr*, 4> ToErase;
67*0b57cec5SDimitry Andric
68*0b57cec5SDimitry Andric for (auto &MBB : MF) {
69*0b57cec5SDimitry Andric MachineInstr *FlagsDefMI = nullptr;
70*0b57cec5SDimitry Andric for (auto &MI : MBB) {
71*0b57cec5SDimitry Andric // Remember the most recent preceding eflags defining instruction.
72*0b57cec5SDimitry Andric if (MI.definesRegister(X86::EFLAGS))
73*0b57cec5SDimitry Andric FlagsDefMI = &MI;
74*0b57cec5SDimitry Andric
75*0b57cec5SDimitry Andric // Find a setcc that is used by a zext.
76*0b57cec5SDimitry Andric // This doesn't have to be the only use, the transformation is safe
77*0b57cec5SDimitry Andric // regardless.
78*0b57cec5SDimitry Andric if (MI.getOpcode() != X86::SETCCr)
79*0b57cec5SDimitry Andric continue;
80*0b57cec5SDimitry Andric
81*0b57cec5SDimitry Andric MachineInstr *ZExt = nullptr;
82*0b57cec5SDimitry Andric for (auto &Use : MRI->use_instructions(MI.getOperand(0).getReg()))
83*0b57cec5SDimitry Andric if (Use.getOpcode() == X86::MOVZX32rr8)
84*0b57cec5SDimitry Andric ZExt = &Use;
85*0b57cec5SDimitry Andric
86*0b57cec5SDimitry Andric if (!ZExt)
87*0b57cec5SDimitry Andric continue;
88*0b57cec5SDimitry Andric
89*0b57cec5SDimitry Andric if (!FlagsDefMI)
90*0b57cec5SDimitry Andric continue;
91*0b57cec5SDimitry Andric
92*0b57cec5SDimitry Andric // We'd like to put something that clobbers eflags directly before
93*0b57cec5SDimitry Andric // FlagsDefMI. This can't hurt anything after FlagsDefMI, because
94*0b57cec5SDimitry Andric // it, itself, by definition, clobbers eflags. But it may happen that
95*0b57cec5SDimitry Andric // FlagsDefMI also *uses* eflags, in which case the transformation is
96*0b57cec5SDimitry Andric // invalid.
97*0b57cec5SDimitry Andric if (FlagsDefMI->readsRegister(X86::EFLAGS))
98*0b57cec5SDimitry Andric continue;
99*0b57cec5SDimitry Andric
100*0b57cec5SDimitry Andric // On 32-bit, we need to be careful to force an ABCD register.
101*0b57cec5SDimitry Andric const TargetRegisterClass *RC = MF.getSubtarget<X86Subtarget>().is64Bit()
102*0b57cec5SDimitry Andric ? &X86::GR32RegClass
103*0b57cec5SDimitry Andric : &X86::GR32_ABCDRegClass;
104*0b57cec5SDimitry Andric if (!MRI->constrainRegClass(ZExt->getOperand(0).getReg(), RC)) {
105*0b57cec5SDimitry Andric // If we cannot constrain the register, we would need an additional copy
106*0b57cec5SDimitry Andric // and are better off keeping the MOVZX32rr8 we have now.
107*0b57cec5SDimitry Andric continue;
108*0b57cec5SDimitry Andric }
109*0b57cec5SDimitry Andric
110*0b57cec5SDimitry Andric ++NumSubstZexts;
111*0b57cec5SDimitry Andric Changed = true;
112*0b57cec5SDimitry Andric
113*0b57cec5SDimitry Andric // Initialize a register with 0. This must go before the eflags def
114*0b57cec5SDimitry Andric Register ZeroReg = MRI->createVirtualRegister(RC);
115*0b57cec5SDimitry Andric BuildMI(MBB, FlagsDefMI, MI.getDebugLoc(), TII->get(X86::MOV32r0),
116*0b57cec5SDimitry Andric ZeroReg);
117*0b57cec5SDimitry Andric
118*0b57cec5SDimitry Andric // X86 setcc only takes an output GR8, so fake a GR32 input by inserting
119*0b57cec5SDimitry Andric // the setcc result into the low byte of the zeroed register.
120*0b57cec5SDimitry Andric BuildMI(*ZExt->getParent(), ZExt, ZExt->getDebugLoc(),
121*0b57cec5SDimitry Andric TII->get(X86::INSERT_SUBREG), ZExt->getOperand(0).getReg())
122*0b57cec5SDimitry Andric .addReg(ZeroReg)
123*0b57cec5SDimitry Andric .addReg(MI.getOperand(0).getReg())
124*0b57cec5SDimitry Andric .addImm(X86::sub_8bit);
125*0b57cec5SDimitry Andric ToErase.push_back(ZExt);
126*0b57cec5SDimitry Andric }
127*0b57cec5SDimitry Andric }
128*0b57cec5SDimitry Andric
129*0b57cec5SDimitry Andric for (auto &I : ToErase)
130*0b57cec5SDimitry Andric I->eraseFromParent();
131*0b57cec5SDimitry Andric
132*0b57cec5SDimitry Andric return Changed;
133*0b57cec5SDimitry Andric }
134*0b57cec5SDimitry Andric