[llvm] r179802 - Implement optimizeCompareInstr for PPC
Hal Finkel
hfinkel at anl.gov
Tue May 7 11:03:18 PDT 2013
----- Original Message -----
> From: "Hal Finkel" <hfinkel at anl.gov>
> To: "Bill Schmidt" <wschmidt at linux.vnet.ibm.com>
> Cc: llvm-commits at cs.uiuc.edu
> Sent: Monday, May 6, 2013 6:25:25 PM
> Subject: Re: [llvm] r179802 - Implement optimizeCompareInstr for PPC
>
> ----- Original Message -----
> > From: "Bill Schmidt" <wschmidt at linux.vnet.ibm.com>
> > To: "Hal Finkel" <hfinkel at anl.gov>
> > Cc: llvm-commits at cs.uiuc.edu
> > Sent: Monday, April 22, 2013 11:43:27 AM
> > Subject: Re: [llvm] r179802 - Implement optimizeCompareInstr for
> > PPC
> >
> > Hi Hal,
> >
> > This generally looks good -- I have a couple of small
> > questions/suggestions below. As always, ignore anything that
> > doesn't
> > make sense. ;)
> >
> > On Thu, 2013-04-18 at 22:15 +0000, Hal Finkel wrote:
> > > Author: hfinkel
> > > Date: Thu Apr 18 17:15:08 2013
> > > New Revision: 179802
> > >
> > > URL: http://llvm.org/viewvc/llvm-project?rev=179802&view=rev
> > > Log:
> > > Implement optimizeCompareInstr for PPC
> > >
> > > Many PPC instructions have a so-called 'record form' which stores
> > > to a specific
> > > condition register the result of comparing the result of the
> > > instruction with
> > > zero (always as a signed comparison). For integer operations on
> > > PPC64, this is
> > > always a 64-bit comparison.
> > >
> > > This implementation is derived from the implementation in the ARM
> > > backend;
> > > there are some differences because PPC condition registers are
> > > allocatable
> > > virtual registers (although the record forms always use a
> > > specific
> > > one), and we
> > > look for a matching subtraction instruction after the compare
> > > (but
> > > before the
> > > first use) in addition to before it.
> > >
> > > Added:
> > > llvm/trunk/test/CodeGen/PowerPC/optcmp.ll
> > > Modified:
> > > llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.cpp
> > > llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.h
> > >
> > > Modified: llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.cpp
> > > URL:
> > > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.cpp?rev=179802&r1=179801&r2=179802&view=diff
> > > ==============================================================================
> > > --- llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.cpp (original)
> > > +++ llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.cpp Thu Apr 18
> > > 17:15:08 2013
> > > @@ -32,6 +32,7 @@
> > > #include "llvm/Support/TargetRegistry.h"
> > > #include "llvm/Support/raw_ostream.h"
> > >
> > > +#define GET_INSTRMAP_INFO
> > > #define GET_INSTRINFO_CTOR
> > > #include "PPCGenInstrInfo.inc"
> > >
> > > @@ -1055,6 +1056,305 @@ bool PPCInstrInfo::isPredicable(MachineI
> > > }
> > > }
> > >
> > > +bool PPCInstrInfo::analyzeCompare(const MachineInstr *MI,
> > > + unsigned &SrcReg, unsigned
> > > &SrcReg2,
> > > + int &Mask, int &Value) const {
> > > + unsigned Opc = MI->getOpcode();
> > > +
> > > + switch (Opc) {
> > > + default: return false;
> > > + case PPC::CMPWI:
> > > + case PPC::CMPLWI:
> > > + case PPC::CMPDI:
> > > + case PPC::CMPLDI:
> > > + SrcReg = MI->getOperand(1).getReg();
> > > + SrcReg2 = 0;
> > > + Value = MI->getOperand(2).getImm();
> > > + Mask = 0xFFFF;
> > > + return true;
> > > + case PPC::CMPW:
> > > + case PPC::CMPLW:
> > > + case PPC::CMPD:
> > > + case PPC::CMPLD:
> > > + case PPC::FCMPUS:
> > > + case PPC::FCMPUD:
> > > + SrcReg = MI->getOperand(1).getReg();
> > > + SrcReg2 = MI->getOperand(2).getReg();
> > > + return true;
> > > + }
> > > +}
> > > +
> > > +bool PPCInstrInfo::optimizeCompareInstr(MachineInstr *CmpInstr,
> > > + unsigned SrcReg,
> > > unsigned
> > > SrcReg2,
> > > + int Mask, int Value,
> > > + const
> > > MachineRegisterInfo
> > > *MRI) const {
> > > + int OpC = CmpInstr->getOpcode();
> > > + unsigned CRReg = CmpInstr->getOperand(0).getReg();
> > > + bool isFP = OpC == PPC::FCMPUS || OpC == PPC::FCMPUD;
> > > + unsigned CRRecReg = isFP ? PPC::CR1 : PPC::CR0;
> > > +
> > > + // The record forms set the condition register based on a
> > > signed
> > > comparison
> > > + // with zero (so says the ISA manual). This is not as
> > > straightforward as it
> > > + // seems, however, because this is always a 64-bit comparison
> > > on
> > > PPC64, even
> > > + // for instructions that are 32-bit in nature (like slw for
> > > example).
> > > + // So, on PPC32, for unsigned comparisons, we can use the
> > > record
> > > forms only
> > > + // for equality checks (as those don't depend on the sign). On
> > > PPC64,
> > > + // we are restricted to equality for unsigned 64-bit
> > > comparisons
> > > and for
> > > + // signed 32-bit comparisons the applicability is more
> > > restricted.
> > > + bool isPPC64 = TM.getSubtargetImpl()->isPPC64();
> > > + bool is32BitSignedCompare = OpC == PPC::CMPWI || OpC ==
> > > PPC::CMPW;
> > > + bool is32BitUnsignedCompare = OpC == PPC::CMPLWI || OpC ==
> > > PPC::CMPLW;
> > > + bool is64BitUnsignedCompare = OpC == PPC::CMPLDI || OpC ==
> > > PPC::CMPLD;
> > > +
> > > + // Get the unique definition of SrcReg.
> > > + MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
> > > + if (!MI) return false;
> > > + int MIOpC = MI->getOpcode();
> > > +
> > > + bool equalityOnly = false;
> > > + bool noSub = false;
> > > + if (isPPC64) {
> > > + if (is32BitSignedCompare) {
> > > + // We can perform this optimization only if MI is
> > > sign-extending.
> > > + if (MIOpC == PPC::SRAW || MIOpC == PPC::SRAWo ||
> > > + MIOpC == PPC::SRAWI || MIOpC == PPC::SRAWIo ||
> > > + MIOpC == PPC::EXTSB || MIOpC == PPC::EXTSBo ||
> > > + MIOpC == PPC::EXTSH || MIOpC == PPC::EXTSHo ||
> > > + MIOpC == PPC::EXTSW || MIOpC == PPC::EXTSWo) {
> > > + noSub = true;
> > > + } else
> > > + return false;
> > > + } else if (is32BitUnsignedCompare) {
> > > + // We can perform this optimization, equality only, if MI
> > > is
> > > + // zero-extending.
> > > + if (MIOpC == PPC::CNTLZW || MIOpC == PPC::CNTLZWo ||
> > > + MIOpC == PPC::SLW || MIOpC == PPC::SLWo ||
> > > + MIOpC == PPC::SRW || MIOpC == PPC::SRWo) {
> > > + noSub = true;
> > > + equalityOnly = true;
> > > + } else
> > > + return false;
> > > + } else if (!isFP)
> > > + equalityOnly = is64BitUnsignedCompare;
> > > + } else if (!isFP)
> > > + equalityOnly = is32BitUnsignedCompare;
> > > +
> > > + if (equalityOnly) {
> > > + // We need to check the uses of the condition register in
> > > order to reject
> > > + // non-equality comparisons.
> > > + for (MachineRegisterInfo::use_iterator I =
> > > MRI->use_begin(CRReg),
> > > + IE = MRI->use_end(); I != IE; ++I) {
> > > + MachineInstr *UseMI = &*I;
> > > + if (UseMI->getOpcode() == PPC::BCC) {
> > > + unsigned Pred = UseMI->getOperand(0).getImm();
> > > + if (Pred == PPC::PRED_EQ || Pred == PPC::PRED_NE)
> > > + continue;
> > > +
> > > + return false;
> >
> > Minor style point -- could just negate the test and return false to
> > avoid the unnecessary continue.
>
> Good point.
>
> >
> > > + } else if (UseMI->getOpcode() == PPC::ISEL ||
> > > + UseMI->getOpcode() == PPC::ISEL8) {
> > > + unsigned SubIdx = UseMI->getOperand(3).getSubReg();
> > > + if (SubIdx == PPC::sub_eq)
> > > + continue;
> > > +
> > > + return false;
> >
> > Same here.
> >
> > > + } else
> > > + return false;
> > > + }
> > > + }
> > > +
> > > + // Get ready to iterate backward from CmpInstr.
> > > + MachineBasicBlock::iterator I = CmpInstr, E = MI,
> > > + B =
> > > CmpInstr->getParent()->begin();
> >
> > I found this confusing, given that you don't iterate backward until
> > later. Right here, you're about to iterate forward. I'd suggest
> > moving
> > the comment, and the initializations of E and B, to a point closer
> > to
> > where they're used.
>
> Yep, this comment was appropriate in the ARM implementation, but as
> I've inserted an extra step, I should move the comment.
>
> >
> > > +
> > > + // Scan forward to find the first use of the compare.
> > > + for (MachineBasicBlock::iterator EL =
> > > CmpInstr->getParent()->end();
> > > + I != EL; ++I) {
> > > + bool FoundUse = false;
> > > + for (MachineRegisterInfo::use_iterator J =
> > > MRI->use_begin(CRReg),
> > > + JE = MRI->use_end(); J != JE; ++J)
> > > + if (&*J == &*I) {
> > > + FoundUse = true;
> > > + break;
> > > + }
> > > +
> > > + if (FoundUse)
> > > + break;
> > > + }
> > > +
> > > + // Early exit if we're at the beginning of the BB.
> > > + if (I == B) return false;
> >
> > Um...since you iterated forward, this can't happen, right?
>
> Right. In addition, this seems like it might be broken if we each
> end(), because we might later call --I. I'll fix this.
Ignore this comment about decrementing I, --C.end() is okay for sequential containers. Other cleanups committed in r181338.
Thanks again,
Hal
>
> >
> > > +
> > > + // There are two possible candidates which can be changed to
> > > set
> > > CR[01].
> > > + // One is MI, the other is a SUB instruction.
> > > + // For CMPrr(r1,r2), we are looking for SUB(r1,r2) or
> > > SUB(r2,r1).
> > > + MachineInstr *Sub = NULL;
> > > + if (SrcReg2 != 0)
> > > + // MI is not a candidate for CMPrr.
> > > + MI = NULL;
> >
> > It seems you lost some opportunities here by doing this. What if
> > MI
> > points to a SRAWI or SRADI? This seems to preclude turning any
> > immediate-form instruction into a recording form. Granted, there
> > aren't
> > very many of those, but there are at least those two (along with
> > andi.,
> > etc., that don't have non-record forms).
> >
> > Could you just set noSub = true instead of nulling MI?
>
> This says if the compare is a register-register comparison, and
> specifically not a register-to-zero comparison, then we can't use MI
> (which will work only for replacing register-to-zero comparisons).
> MI is not the sub, it is the defining instruction (which might be
> something else). noSub is used to exclude matching subtracts on
> ppc64 (which always use all of the bits) to some 32-bit comparisons.
>
> >
> >
> > > + // FIXME: Conservatively refuse to convert an instruction
> > > which
> > > isn't in the
> > > + // same BB as the comparison. This is to allow the check below
> > > to avoid calls
> > > + // (and other explicit clobbers); instead we should really
> > > check
> > > for these
> > > + // more explicitly (in at least a few predecessors).
> > > + else if (MI->getParent() != CmpInstr->getParent() || Value !=
> > > 0)
> > > {
> > > + // PPC does not have a record-form SUBri.
> > > + return false;
> > > + }
> >
> > This looks like an appropriate place to initialize E and B.
> >
>
> Sounds good. I'll move them.
>
> > The only other comment I have is on the test cases. You have some
> > logic
> > that handles multiple uses of the CR. It might be good to have
> > variants
> > where one use is legitimate and the other is not, and make sure the
> > recording form isn't generated in that case.
>
> Agreed.
>
> Thanks again,
> Hal
>
> > Just a thought, do with
> > it
> > what you will.
> >
> > Thanks!
> > Bill
> >
> > > +
> > > + // Search for Sub.
> > > + const TargetRegisterInfo *TRI = &getRegisterInfo();
> > > + --I;
> > > + for (; I != E && !noSub; --I) {
> > > + const MachineInstr &Instr = *I;
> > > + unsigned IOpC = Instr.getOpcode();
> > > +
> > > + if (&*I != CmpInstr && (
> > > + Instr.modifiesRegister(CRRecReg, TRI) ||
> > > + Instr.readsRegister(CRRecReg, TRI)))
> > > + // This instruction modifies or uses the record condition
> > > register after
> > > + // the one we want to change. While we could do this
> > > transformation, it
> > > + // would likely not be profitable. This transformation
> > > removes one
> > > + // instruction, and so even forcing RA to generate one
> > > move
> > > probably
> > > + // makes it unprofitable.
> > > + return false;
> > > +
> > > + // Check whether CmpInstr can be made redundant by the
> > > current
> > > instruction.
> > > + if ((OpC == PPC::CMPW || OpC == PPC::CMPLW ||
> > > + OpC == PPC::CMPD || OpC == PPC::CMPLD) &&
> > > + (IOpC == PPC::SUBF || IOpC == PPC::SUBF8) &&
> > > + ((Instr.getOperand(1).getReg() == SrcReg &&
> > > + Instr.getOperand(2).getReg() == SrcReg2) ||
> > > + (Instr.getOperand(1).getReg() == SrcReg2 &&
> > > + Instr.getOperand(2).getReg() == SrcReg))) {
> > > + Sub = &*I;
> > > + break;
> > > + }
> > > +
> > > + if (isFP && (IOpC == PPC::FSUB || IOpC == PPC::FSUBS) &&
> > > + ((Instr.getOperand(1).getReg() == SrcReg &&
> > > + Instr.getOperand(2).getReg() == SrcReg2) ||
> > > + (Instr.getOperand(1).getReg() == SrcReg2 &&
> > > + Instr.getOperand(2).getReg() == SrcReg))) {
> > > + Sub = &*I;
> > > + break;
> > > + }
> > > +
> > > + if (I == B)
> > > + // The 'and' is below the comparison instruction.
> > > + return false;
> > > + }
> > > +
> > > + // Return false if no candidates exist.
> > > + if (!MI && !Sub)
> > > + return false;
> > > +
> > > + // The single candidate is called MI.
> > > + if (!MI) MI = Sub;
> > > +
> > > + int NewOpC = -1;
> > > + MIOpC = MI->getOpcode();
> > > + if (MIOpC == PPC::ANDIo || MIOpC == PPC::ANDIo8)
> > > + NewOpC = MIOpC;
> > > + else {
> > > + NewOpC = PPC::getRecordFormOpcode(MIOpC);
> > > + if (NewOpC == -1 && PPC::getNonRecordFormOpcode(MIOpC) !=
> > > -1)
> > > + NewOpC = MIOpC;
> > > + }
> > > +
> > > + // FIXME: On the non-embedded POWER architectures, only some
> > > of
> > > the record
> > > + // forms are fast, and we should use only the fast ones.
> > > +
> > > + // The defining instruction has a record form (or is already a
> > > record
> > > + // form). It is possible, however, that we'll need to reverse
> > > the condition
> > > + // code of the users.
> > > + if (NewOpC == -1)
> > > + return false;
> > > +
> > > + SmallVector<std::pair<MachineOperand*, PPC::Predicate>, 4>
> > > + OperandsToUpdate;
> > > + SmallVector<std::pair<MachineOperand*, MachineOperand*>, 4>
> > > + OperandsToSwap;
> > > +
> > > + // If we have SUB(r1, r2) and CMP(r2, r1), the condition code
> > > based on CMP
> > > + // needs to be updated to be based on SUB. Push the condition
> > > code
> > > + // operands to OperandsToUpdate. If it is safe to remove
> > > CmpInstr, the
> > > + // condition code of these operands will be modified.
> > > + bool ShouldSwap = false;
> > > + if (Sub) {
> > > + ShouldSwap = SrcReg2 != 0 && Sub->getOperand(1).getReg() ==
> > > SrcReg2 &&
> > > + Sub->getOperand(2).getReg() == SrcReg;
> > > +
> > > + // The operands to subf are the opposite of sub, so only in
> > > the fixed-point
> > > + // case, invert the order.
> > > + if (!isFP)
> > > + ShouldSwap = !ShouldSwap;
> > > + }
> > > +
> > > + if (ShouldSwap)
> > > + for (MachineRegisterInfo::use_iterator I =
> > > MRI->use_begin(CRReg),
> > > + IE = MRI->use_end(); I != IE; ++I) {
> > > + MachineInstr *UseMI = &*I;
> > > + if (UseMI->getOpcode() == PPC::BCC) {
> > > + PPC::Predicate Pred = (PPC::Predicate)
> > > UseMI->getOperand(0).getImm();
> > > + if (ShouldSwap)
> > > +
> > > OperandsToUpdate.push_back(std::make_pair(&((*I).getOperand(0)),
> > > +
> > > PPC::InvertPredicate(Pred)));
> > > + } else if (UseMI->getOpcode() == PPC::ISEL ||
> > > + UseMI->getOpcode() == PPC::ISEL8) {
> > > + if (ShouldSwap)
> > > +
> > > OperandsToSwap.push_back(std::make_pair(&((*I).getOperand(1)),
> > > +
> > > &((*I).getOperand(2))));
> > > + } else // We need to abort on a user we don't understand.
> > > + return false;
> > > + }
> > > +
> > > + // Create a new virtual register to hold the value of the CR
> > > set
> > > by the
> > > + // record-form instruction. If the instruction was not
> > > previously in
> > > + // record form, then set the kill flag on the CR.
> > > + CmpInstr->eraseFromParent();
> > > +
> > > + MachineBasicBlock::iterator MII = MI;
> > > + BuildMI(*MI->getParent(), llvm::next(MII), MI->getDebugLoc(),
> > > + get(TargetOpcode::COPY), CRReg)
> > > + .addReg(CRRecReg, MIOpC != NewOpC ? RegState::Kill : 0);
> > > +
> > > + if (MIOpC != NewOpC) {
> > > + // We need to be careful here: we're replacing one
> > > instruction
> > > with
> > > + // another, and we need to make sure that we get all of the
> > > right
> > > + // implicit uses and defs. On the other hand, the caller may
> > > be holding
> > > + // an iterator to this instruction, and so we can't delete
> > > it
> > > (this is
> > > + // specifically the case if this is the instruction directly
> > > after the
> > > + // compare).
> > > +
> > > + const MCInstrDesc &NewDesc = get(NewOpC);
> > > + MI->setDesc(NewDesc);
> > > +
> > > + if (NewDesc.ImplicitDefs)
> > > + for (const uint16_t *ImpDefs = NewDesc.getImplicitDefs();
> > > + *ImpDefs; ++ImpDefs)
> > > + if (!MI->definesRegister(*ImpDefs))
> > > + MI->addOperand(*MI->getParent()->getParent(),
> > > + MachineOperand::CreateReg(*ImpDefs,
> > > true,
> > > true));
> > > + if (NewDesc.ImplicitUses)
> > > + for (const uint16_t *ImpUses = NewDesc.getImplicitUses();
> > > + *ImpUses; ++ImpUses)
> > > + if (!MI->readsRegister(*ImpUses))
> > > + MI->addOperand(*MI->getParent()->getParent(),
> > > + MachineOperand::CreateReg(*ImpUses,
> > > false, true));
> > > + }
> > > +
> > > + // Modify the condition code of operands in OperandsToUpdate.
> > > + // Since we have SUB(r1, r2) and CMP(r2, r1), the condition
> > > code
> > > needs to
> > > + // be changed from r2 > r1 to r1 < r2, from r2 < r1 to r1 >
> > > r2,
> > > etc.
> > > + for (unsigned i = 0, e = OperandsToUpdate.size(); i < e; i++)
> > > +
> > > OperandsToUpdate[i].first->setImm(OperandsToUpdate[i].second);
> > > +
> > > + for (unsigned i = 0, e = OperandsToSwap.size(); i < e; i++)
> > > + std::swap(*OperandsToSwap[i].first,
> > > *OperandsToSwap[i].second);
> > > +
> > > + return true;
> > > +}
> > > +
> > > /// GetInstSize - Return the number of bytes of code the
> > > specified
> > > /// instruction may be. This returns the maximum number of
> > > bytes.
> > > ///
> > >
> > > Modified: llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.h
> > > URL:
> > > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.h?rev=179802&r1=179801&r2=179802&view=diff
> > > ==============================================================================
> > > --- llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.h (original)
> > > +++ llvm/trunk/lib/Target/PowerPC/PPCInstrInfo.h Thu Apr 18
> > > 17:15:08 2013
> > > @@ -205,6 +205,18 @@ public:
> > >
> > > virtual bool isPredicable(MachineInstr *MI) const;
> > >
> > > + // Comparison optimization.
> > > +
> > > +
> > > + virtual bool analyzeCompare(const MachineInstr *MI,
> > > + unsigned &SrcReg, unsigned
> > > &SrcReg2,
> > > + int &Mask, int &Value) const;
> > > +
> > > + virtual bool optimizeCompareInstr(MachineInstr *CmpInstr,
> > > + unsigned SrcReg, unsigned
> > > SrcReg2,
> > > + int Mask, int Value,
> > > + const MachineRegisterInfo
> > > *MRI) const;
> > > +
> > > /// GetInstSize - Return the number of bytes of code the
> > > specified
> > > /// instruction may be. This returns the maximum number of
> > > bytes.
> > > ///
> > >
> > > Added: llvm/trunk/test/CodeGen/PowerPC/optcmp.ll
> > > URL:
> > > http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/optcmp.ll?rev=179802&view=auto
> > > ==============================================================================
> > > --- llvm/trunk/test/CodeGen/PowerPC/optcmp.ll (added)
> > > +++ llvm/trunk/test/CodeGen/PowerPC/optcmp.ll Thu Apr 18 17:15:08
> > > 2013
> > > @@ -0,0 +1,101 @@
> > > +; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=a2 |
> > > FileCheck %s
> > > +target datalayout =
> > > "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64"
> > > +target triple = "powerpc64-unknown-linux-gnu"
> > > +
> > > +define signext i32 @foo(i32 signext %a, i32 signext %b, i32*
> > > nocapture %c) #0 {
> > > +entry:
> > > + %sub = sub nsw i32 %a, %b
> > > + store i32 %sub, i32* %c, align 4, !tbaa !0
> > > + %cmp = icmp sgt i32 %a, %b
> > > + %cond = select i1 %cmp, i32 %a, i32 %b
> > > + ret i32 %cond
> > > +
> > > +; CHECK: @foo
> > > +; CHECK-NOT: subf.
> > > +}
> > > +
> > > +define signext i32 @foo2(i32 signext %a, i32 signext %b, i32*
> > > nocapture %c) #0 {
> > > +entry:
> > > + %shl = shl i32 %a, %b
> > > + store i32 %shl, i32* %c, align 4, !tbaa !0
> > > + %cmp = icmp sgt i32 %shl, 0
> > > + %conv = zext i1 %cmp to i32
> > > + ret i32 %conv
> > > +
> > > +; CHECK: @foo2
> > > +; CHECK-NOT: slw.
> > > +}
> > > +
> > > +define i64 @fool(i64 %a, i64 %b, i64* nocapture %c) #0 {
> > > +entry:
> > > + %sub = sub nsw i64 %a, %b
> > > + store i64 %sub, i64* %c, align 8, !tbaa !3
> > > + %cmp = icmp sgt i64 %a, %b
> > > + %cond = select i1 %cmp, i64 %a, i64 %b
> > > + ret i64 %cond
> > > +
> > > +; CHECK: @fool
> > > +; CHECK: subf. [[REG:[0-9]+]], 4, 3
> > > +; CHECK: isel 3, 3, 4, 1
> > > +; CHECK: std [[REG]], 0(5)
> > > +}
> > > +
> > > +define i64 @foolb(i64 %a, i64 %b, i64* nocapture %c) #0 {
> > > +entry:
> > > + %sub = sub nsw i64 %a, %b
> > > + store i64 %sub, i64* %c, align 8, !tbaa !3
> > > + %cmp = icmp sle i64 %a, %b
> > > + %cond = select i1 %cmp, i64 %a, i64 %b
> > > + ret i64 %cond
> > > +
> > > +; CHECK: @foolb
> > > +; CHECK: subf. [[REG:[0-9]+]], 4, 3
> > > +; CHECK: isel 3, 4, 3, 1
> > > +; CHECK: std [[REG]], 0(5)
> > > +}
> > > +
> > > +define i64 @foo2l(i64 %a, i64 %b, i64* nocapture %c) #0 {
> > > +entry:
> > > + %shl = shl i64 %a, %b
> > > + store i64 %shl, i64* %c, align 8, !tbaa !3
> > > + %cmp = icmp sgt i64 %shl, 0
> > > + %conv1 = zext i1 %cmp to i64
> > > + ret i64 %conv1
> > > +
> > > +; CHECK: @foo2l
> > > +; CHECK: sld. 4, 3, 4
> > > +; CHECK: std 4, 0(5)
> > > +}
> > > +
> > > +define double @food(double %a, double %b, double* nocapture %c)
> > > #0
> > > {
> > > +entry:
> > > + %sub = fsub double %a, %b
> > > + store double %sub, double* %c, align 8, !tbaa !3
> > > + %cmp = fcmp ogt double %a, %b
> > > + %cond = select i1 %cmp, double %a, double %b
> > > + ret double %cond
> > > +
> > > +; CHECK: @food
> > > +; CHECK: fsub. 0, 1, 2
> > > +; CHECK: stfd 0, 0(5)
> > > +}
> > > +
> > > +define float @foof(float %a, float %b, float* nocapture %c) #0 {
> > > +entry:
> > > + %sub = fsub float %a, %b
> > > + store float %sub, float* %c, align 4, !tbaa !3
> > > + %cmp = fcmp ogt float %a, %b
> > > + %cond = select i1 %cmp, float %a, float %b
> > > + ret float %cond
> > > +
> > > +; CHECK: @foof
> > > +; CHECK: fsubs. 0, 1, 2
> > > +; CHECK: stfs 0, 0(5)
> > > +}
> > > +
> > > +!0 = metadata !{metadata !"int", metadata !1}
> > > +!1 = metadata !{metadata !"omnipotent char", metadata !2}
> > > +!2 = metadata !{metadata !"Simple C/C++ TBAA"}
> > > +!3 = metadata !{metadata !"long", metadata !1}
> > > +!4 = metadata !{metadata !"any pointer", metadata !1}
> > > +
> > >
> > >
> > > _______________________________________________
> > > llvm-commits mailing list
> > > llvm-commits at cs.uiuc.edu
> > > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> > >
> >
> >
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
More information about the llvm-commits
mailing list