R600 optimizations

Tom Stellard tom at stellard.net
Mon Jun 3 13:40:29 PDT 2013


On Fri, May 31, 2013 at 02:59:59PM -0700, Vincent Lejeune wrote:
> Hi,
> 
> these patches improve code generation for R600 backend.
> The first one allows dot4 instruction (which is a pseudo instruction representing 4 dot4_eg/r600 instructions) to be folded with neg/abs/const instructions.
> Lot of shaders use dot4 on const provided value (for clipping for instance) and should benefit from such optimization by reducing number of COPY.
> The second and third ones uses abilities of texture/export instructions to swizzle their instruction to avoid COPY by removing duplication.
> I'm working on adding lit test case, the ones I'm using to test my implementation is generated by Lightmark and I doubt I can provide it.
> 
> 
> Vincent

> From 90832890b21525ac366653c6bb17ea9cdf3d1aba Mon Sep 17 00:00:00 2001
> From: Vincent Lejeune <vljn at ovi.com>
> Date: Wed, 22 May 2013 02:19:53 +0200
> Subject: [PATCH 1/3] R600: Const/Neg/Abs can be folded to dot4
> 
> ---
>  lib/Target/R600/AMDILISelDAGToDAG.cpp       | 186 +++++++++++++++++++++-------
>  lib/Target/R600/R600EmitClauseMarkers.cpp   |   6 +-
>  lib/Target/R600/R600ExpandSpecialInstrs.cpp |   4 +-
>  lib/Target/R600/R600InstrInfo.cpp           |  35 ++++++
>  lib/Target/R600/R600InstrInfo.h             |   2 +
>  5 files changed, 186 insertions(+), 47 deletions(-)
>

Can you add a simple test case for this, it shouldn't be too hard.

> diff --git a/lib/Target/R600/AMDILISelDAGToDAG.cpp b/lib/Target/R600/AMDILISelDAGToDAG.cpp
> index 00d7c8f..6083609 100644
> --- a/lib/Target/R600/AMDILISelDAGToDAG.cpp
> +++ b/lib/Target/R600/AMDILISelDAGToDAG.cpp
> @@ -48,7 +48,10 @@ public:
>  
>  private:
>    inline SDValue getSmallIPtrImm(unsigned Imm);
> +  bool FoldOperand(SDValue &Src, SDValue &Sel, SDValue &Neg, SDValue &Abs,
> +                   const R600InstrInfo *TII, std::vector<unsigned> Cst);
>    bool FoldOperands(unsigned, const R600InstrInfo *, std::vector<SDValue> &);
> +  bool FoldDotOperands(unsigned, const R600InstrInfo *, std::vector<SDValue> &);
>  
>    // Complex pattern selectors
>    bool SelectADDRParam(SDValue Addr, SDValue& R1, SDValue& R2);
> @@ -317,6 +320,20 @@ SDNode *AMDGPUDAGToDAGISel::Select(SDNode *N) {
>    if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD6XXX) {
>      const R600InstrInfo *TII =
>          static_cast<const R600InstrInfo*>(TM.getInstrInfo());
> +    if (Result && Result->isMachineOpcode() && Result->getMachineOpcode() == AMDGPU::DOT_4) {
> +      bool IsModified = false;
> +      do {
> +        std::vector<SDValue> Ops;
> +        for(SDNode::op_iterator I = Result->op_begin(), E = Result->op_end();
> +            I != E; ++I)
> +          Ops.push_back(*I);
> +        IsModified = FoldDotOperands(Result->getMachineOpcode(), TII, Ops);
> +        if (IsModified) {
> +          Result = CurDAG->UpdateNodeOperands(Result, Ops.data(), Ops.size());
> +        }
> +      } while (IsModified);
> +      
> +    }
>      if (Result && Result->isMachineOpcode() &&
>          !(TII->get(Result->getMachineOpcode()).TSFlags & R600_InstFlag::VECTOR)
>          && TII->isALUInstr(Result->getMachineOpcode())) {
> @@ -359,6 +376,43 @@ SDNode *AMDGPUDAGToDAGISel::Select(SDNode *N) {
>    return Result;
>  }
>  
> +bool AMDGPUDAGToDAGISel::FoldOperand(SDValue &Src, SDValue &Sel, SDValue &Neg,
> +                                     SDValue &Abs, const R600InstrInfo *TII,
> +                                     std::vector<unsigned> Consts) {
> +  switch (Src.getOpcode()) {
> +  case AMDGPUISD::CONST_ADDRESS: {
> +    SDValue CstOffset;
> +    if (Src.getValueType().isVector() ||
> +        !SelectGlobalValueConstantOffset(Src.getOperand(0), CstOffset))
> +      return false;
> +
> +    ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(CstOffset);
> +    Consts.push_back(Cst->getZExtValue());
> +    if (!TII->fitsConstReadLimitations(Consts))
> +      return false;
> +
> +    Src = CurDAG->getRegister(AMDGPU::ALU_CONST, MVT::f32);
> +    Sel = CstOffset;
> +    return true;
> +    }
> +  case ISD::FNEG:
> +    Src = Src.getOperand(0);
> +    Neg = CurDAG->getTargetConstant(1, MVT::i32);
> +    return true;
> +  case ISD::FABS:
> +    if (!Abs.getNode())
> +      return false;
> +    Src = Src.getOperand(0);
> +    Abs = CurDAG->getTargetConstant(1, MVT::i32);
> +    return true;
> +  case ISD::BITCAST:
> +    Src = Src.getOperand(0);
> +    return true;
> +  default:
> +    return false;
> +  }
> +}
> +
>  bool AMDGPUDAGToDAGISel::FoldOperands(unsigned Opcode,
>      const R600InstrInfo *TII, std::vector<SDValue> &Ops) {
>    int OperandIdx[] = {
> @@ -382,59 +436,101 @@ bool AMDGPUDAGToDAGISel::FoldOperands(unsigned Opcode,
>      -1
>    };
>  
> +  // Gather constants values
> +  std::vector<unsigned> Consts;
> +  for (unsigned j = 0; j < 3; j++) {
> +    int SrcIdx = OperandIdx[j];
> +    if (SrcIdx < 0)
> +      break;
> +    if (RegisterSDNode *Reg = dyn_cast<RegisterSDNode>(Ops[SrcIdx - 1])) {
> +      if (Reg->getReg() == AMDGPU::ALU_CONST) {
> +        ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Ops[SelIdx[j] - 1]);
> +        Consts.push_back(Cst->getZExtValue());
> +      }
> +    }
> +  }
> +
>    for (unsigned i = 0; i < 3; i++) {
>      if (OperandIdx[i] < 0)
>        return false;
> -    SDValue Operand = Ops[OperandIdx[i] - 1];
> -    switch (Operand.getOpcode()) {
> -    case AMDGPUISD::CONST_ADDRESS: {
> -      SDValue CstOffset;
> -      if (Operand.getValueType().isVector() ||
> -          !SelectGlobalValueConstantOffset(Operand.getOperand(0), CstOffset))
> -        break;
> -
> -      // Gather others constants values
> -      std::vector<unsigned> Consts;
> -      for (unsigned j = 0; j < 3; j++) {
> -        int SrcIdx = OperandIdx[j];
> -        if (SrcIdx < 0)
> -          break;
> -        if (RegisterSDNode *Reg = dyn_cast<RegisterSDNode>(Ops[SrcIdx - 1])) {
> -          if (Reg->getReg() == AMDGPU::ALU_CONST) {
> -            ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Ops[SelIdx[j] - 1]);
> -            Consts.push_back(Cst->getZExtValue());
> -          }
> -        }
> -      }
> +    SDValue &Src = Ops[OperandIdx[i] - 1];
> +    SDValue &Sel = Ops[SelIdx[i] - 1];
> +    SDValue &Neg = Ops[NegIdx[i] - 1];
> +    SDValue FakeAbs;
> +    SDValue &Abs = (AbsIdx[i] > -1) ? Ops[AbsIdx[i] - 1] : FakeAbs;
> +    if (FoldOperand(Src, Sel, Neg, Abs, TII, Consts))
> +      return true;
> +  }
> +  return false;
> +}
>  
> -      ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(CstOffset);
> -      Consts.push_back(Cst->getZExtValue());
> -      if (!TII->fitsConstReadLimitations(Consts))
> -        break;
> +bool AMDGPUDAGToDAGISel::FoldDotOperands(unsigned Opcode,
> +    const R600InstrInfo *TII, std::vector<SDValue> &Ops) {
> +  int OperandIdx[] = {
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_W),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_W)
> +  };
> +  int SelIdx[] = {
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_SEL_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_SEL_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_SEL_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_SEL_W),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_SEL_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_SEL_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_SEL_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_SEL_W)
> +  };
> +  int NegIdx[] = {
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_NEG_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_NEG_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_NEG_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_NEG_W),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_NEG_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_NEG_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_NEG_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_NEG_W)
> +  };
> +  int AbsIdx[] = {
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_ABS_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_ABS_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_ABS_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC0_ABS_W),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_ABS_X),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_ABS_Y),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_ABS_Z),
> +    TII->getOperandIdx(Opcode, R600Operands::SRC1_ABS_W)
> +  };
>  
> -      Ops[OperandIdx[i] - 1] = CurDAG->getRegister(AMDGPU::ALU_CONST, MVT::f32);
> -      Ops[SelIdx[i] - 1] = CstOffset;
> -      return true;
> -      }
> -    case ISD::FNEG:
> -      if (NegIdx[i] < 0)
> -        break;
> -      Ops[OperandIdx[i] - 1] = Operand.getOperand(0);
> -      Ops[NegIdx[i] - 1] = CurDAG->getTargetConstant(1, MVT::i32);
> -      return true;
> -    case ISD::FABS:
> -      if (AbsIdx[i] < 0)
> -        break;
> -      Ops[OperandIdx[i] - 1] = Operand.getOperand(0);
> -      Ops[AbsIdx[i] - 1] = CurDAG->getTargetConstant(1, MVT::i32);
> -      return true;
> -    case ISD::BITCAST:
> -      Ops[OperandIdx[i] - 1] = Operand.getOperand(0);
> -      return true;
> -    default:
> +  // Gather constants values
> +  std::vector<unsigned> Consts;
> +  for (unsigned j = 0; j < 8; j++) {
> +    int SrcIdx = OperandIdx[j];
> +    if (SrcIdx < 0)
>        break;
> +    if (RegisterSDNode *Reg = dyn_cast<RegisterSDNode>(Ops[SrcIdx - 1])) {
> +      if (Reg->getReg() == AMDGPU::ALU_CONST) {
> +        ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Ops[SelIdx[j] - 1]);
> +        Consts.push_back(Cst->getZExtValue());
> +      }
>      }
>    }
> +
> +  for (unsigned i = 0; i < 8; i++) {
> +    if (OperandIdx[i] < 0)
> +      return false;
> +    SDValue &Src = Ops[OperandIdx[i] - 1];
> +    SDValue &Sel = Ops[SelIdx[i] - 1];
> +    SDValue &Neg = Ops[NegIdx[i] - 1];
> +    SDValue &Abs = Ops[AbsIdx[i] - 1];
> +    if (FoldOperand(Src, Sel, Neg, Abs, TII, Consts))
> +      return true;
> +  }
>    return false;
>  }
>  
> diff --git a/lib/Target/R600/R600EmitClauseMarkers.cpp b/lib/Target/R600/R600EmitClauseMarkers.cpp
> index ecfcfeb..c9d8ed1 100644
> --- a/lib/Target/R600/R600EmitClauseMarkers.cpp
> +++ b/lib/Target/R600/R600EmitClauseMarkers.cpp
> @@ -108,7 +108,8 @@ private:
>      std::vector<std::pair<unsigned, unsigned> > UsedKCache;
>      const SmallVector<std::pair<MachineOperand *, int64_t>, 3> &Consts =
>          TII->getSrcs(MI);
> -    assert(TII->isALUInstr(MI->getOpcode()) && "Can't assign Const");
> +    assert((TII->isALUInstr(MI->getOpcode()) ||
> +        MI->getOpcode() == AMDGPU::DOT_4) && "Can't assign Const");
>      for (unsigned i = 0, n = Consts.size(); i < n; ++i) {
>        if (Consts[i].first->getReg() != AMDGPU::ALU_CONST)
>          continue;
> @@ -183,6 +184,9 @@ private:
>        if (TII->isALUInstr(I->getOpcode()) &&
>            !SubstituteKCacheBank(I, KCacheBanks))
>          break;
> +      if (I->getOpcode() == AMDGPU::DOT_4 &&
> +          !SubstituteKCacheBank(I, KCacheBanks))
> +        break;
>        AluInstCount += OccupiedDwords(I);
>      }
>      unsigned Opcode = PushBeforeModifier ?
> diff --git a/lib/Target/R600/R600ExpandSpecialInstrs.cpp b/lib/Target/R600/R600ExpandSpecialInstrs.cpp
> index b9d5303..072ae3a 100644
> --- a/lib/Target/R600/R600ExpandSpecialInstrs.cpp
> +++ b/lib/Target/R600/R600ExpandSpecialInstrs.cpp
> @@ -214,7 +214,9 @@ bool R600ExpandSpecialInstrsPass::runOnMachineFunction(MachineFunction &MF) {
>                .getReg();
>            (void) Src0;
>            (void) Src1;
> -          assert(TRI.getHWRegChan(Src0) == TRI.getHWRegChan(Src1));
> +          if ((TRI.getEncodingValue(Src0) & 0xff) < 127 &&
> +              (TRI.getEncodingValue(Src1) & 0xff) < 127)
> +            assert(TRI.getHWRegChan(Src0) == TRI.getHWRegChan(Src1));
>          }
>          MI.eraseFromParent();
>          continue;
> diff --git a/lib/Target/R600/R600InstrInfo.cpp b/lib/Target/R600/R600InstrInfo.cpp
> index 5f8486d..2a4a245 100644
> --- a/lib/Target/R600/R600InstrInfo.cpp
> +++ b/lib/Target/R600/R600InstrInfo.cpp
> @@ -169,6 +169,31 @@ SmallVector<std::pair<MachineOperand *, int64_t>, 3>
>  R600InstrInfo::getSrcs(MachineInstr *MI) const {
>    SmallVector<std::pair<MachineOperand *, int64_t>, 3> Result;
>  
> +  if (MI->getOpcode() == AMDGPU::DOT_4) {
> +    static const R600Operands::VecOps OpTable[8][2] = {
> +      {R600Operands::SRC0_X, R600Operands::SRC0_SEL_X},
> +      {R600Operands::SRC0_Y, R600Operands::SRC0_SEL_Y},
> +      {R600Operands::SRC0_Z, R600Operands::SRC0_SEL_Z},
> +      {R600Operands::SRC0_W, R600Operands::SRC0_SEL_W},
> +      {R600Operands::SRC1_X, R600Operands::SRC1_SEL_X},
> +      {R600Operands::SRC1_Y, R600Operands::SRC1_SEL_Y},
> +      {R600Operands::SRC1_Z, R600Operands::SRC1_SEL_Z},
> +      {R600Operands::SRC1_W, R600Operands::SRC1_SEL_W},
> +    };
> +
> +    for (unsigned j = 0; j < 8; j++) {
> +      MachineOperand &MO = MI->getOperand(OpTable[j][0] + 1);
> +      unsigned Reg = MO.getReg();
> +      if (Reg == AMDGPU::ALU_CONST) {
> +        unsigned Sel = MI->getOperand(OpTable[j][1] + 1).getImm();
> +        Result.push_back(std::pair<MachineOperand *, int64_t>(&MO, Sel));
> +        continue;
> +      }
> +      
> +    }
> +    return Result;
> +  }
> +
>    static const R600Operands::Ops OpTable[3][2] = {
>      {R600Operands::SRC0, R600Operands::SRC0_SEL},
>      {R600Operands::SRC1, R600Operands::SRC1_SEL},
> @@ -967,6 +992,11 @@ int R600InstrInfo::getOperandIdx(const MachineInstr &MI,
>    return getOperandIdx(MI.getOpcode(), Op);
>  }
>  
> +int R600InstrInfo::getOperandIdx(const MachineInstr &MI,
> +                                 R600Operands::VecOps Op) const {
> +  return getOperandIdx(MI.getOpcode(), Op);
> +}
> +
>  int R600InstrInfo::getOperandIdx(unsigned Opcode,
>                                   R600Operands::Ops Op) const {
>    unsigned TargetFlags = get(Opcode).TSFlags;
> @@ -997,6 +1027,11 @@ int R600InstrInfo::getOperandIdx(unsigned Opcode,
>    return R600Operands::ALUOpTable[OpTableIdx][Op];
>  }
>  
> +int R600InstrInfo::getOperandIdx(unsigned Opcode,
> +                                 R600Operands::VecOps Op) const {
> +  return Op + 1;
> +}
> +
>  void R600InstrInfo::setImmOperand(MachineInstr *MI, R600Operands::Ops Op,
>                                    int64_t Imm) const {
>    int Idx = getOperandIdx(*MI, Op);
> diff --git a/lib/Target/R600/R600InstrInfo.h b/lib/Target/R600/R600InstrInfo.h
> index f9ccf4f..afc24e2 100644
> --- a/lib/Target/R600/R600InstrInfo.h
> +++ b/lib/Target/R600/R600InstrInfo.h
> @@ -212,11 +212,13 @@ namespace llvm {
>    ///
>    /// \returns -1 if the Instruction does not contain the specified \p Op.
>    int getOperandIdx(const MachineInstr &MI, R600Operands::Ops Op) const;
> +  int getOperandIdx(const MachineInstr &MI, R600Operands::VecOps Op) const;
>  
>    /// \brief Get the index of \p Op for the given Opcode.
>    ///
>    /// \returns -1 if the Instruction does not contain the specified \p Op.
>    int getOperandIdx(unsigned Opcode, R600Operands::Ops Op) const;
> +  int getOperandIdx(unsigned Opcode, R600Operands::VecOps Op) const;
>  
>    /// \brief Helper function for setting instruction flag values.
>    void setImmOperand(MachineInstr *MI, R600Operands::Ops Op, int64_t Imm) const;
> -- 
> 1.8.2.1
> 

> From f832ad1a86472206640cbf1f79c06804cbcf3177 Mon Sep 17 00:00:00 2001
> From: Vincent Lejeune <vljn at ovi.com>
> Date: Sun, 26 May 2013 18:51:20 +0200
> Subject: [PATCH 3/3] R600: Add a pass that merge Vector Register
> 

Could you write a small test case for this as well?

> ---
>  lib/Target/R600/AMDGPU.h                        |   1 +
>  lib/Target/R600/AMDGPUTargetMachine.cpp         |   5 +
>  lib/Target/R600/CMakeLists.txt                  |   1 +
>  lib/Target/R600/R600OptimizeVectorRegisters.cpp | 336 ++++++++++++++++++++++++
>  4 files changed, 343 insertions(+)
>  create mode 100644 lib/Target/R600/R600OptimizeVectorRegisters.cpp
> 
> diff --git a/lib/Target/R600/AMDGPU.h b/lib/Target/R600/AMDGPU.h
> index f9d70c9..d3ef426 100644
> --- a/lib/Target/R600/AMDGPU.h
> +++ b/lib/Target/R600/AMDGPU.h
> @@ -23,6 +23,7 @@ class AMDGPUTargetMachine;
>  // R600 Passes
>  FunctionPass* createR600TextureIntrinsicsReplacer();
>  FunctionPass* createR600KernelParametersPass(const DataLayout *TD);
> +FunctionPass *createR600VectorRegMerger(TargetMachine &tm);
>  FunctionPass *createR600ExpandSpecialInstrsPass(TargetMachine &tm);
>  FunctionPass *createR600EmitClauseMarkers(TargetMachine &tm);
>  FunctionPass *createR600Packetizer(TargetMachine &tm);
> diff --git a/lib/Target/R600/AMDGPUTargetMachine.cpp b/lib/Target/R600/AMDGPUTargetMachine.cpp
> index 88dc583..c52af56 100644
> --- a/lib/Target/R600/AMDGPUTargetMachine.cpp
> +++ b/lib/Target/R600/AMDGPUTargetMachine.cpp
> @@ -130,6 +130,11 @@ bool AMDGPUPassConfig::addInstSelector() {
>  
>  bool AMDGPUPassConfig::addPreRegAlloc() {
>    addPass(createAMDGPUConvertToISAPass(*TM));
> +  const AMDGPUSubtarget &ST = TM->getSubtarget<AMDGPUSubtarget>();
> +  
> +  if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD6XXX) {
> +    addPass(createR600VectorRegMerger(*TM));
> +  }
>    return false;
>  }
>  
> diff --git a/lib/Target/R600/CMakeLists.txt b/lib/Target/R600/CMakeLists.txt
> index c5ce9dc..558d001 100644
> --- a/lib/Target/R600/CMakeLists.txt
> +++ b/lib/Target/R600/CMakeLists.txt
> @@ -41,6 +41,7 @@ add_llvm_target(R600CodeGen
>    R600ISelLowering.cpp
>    R600MachineFunctionInfo.cpp
>    R600MachineScheduler.cpp
> +  R600OptimizeVectorRegisters.cpp
>    R600Packetizer.cpp
>    R600RegisterInfo.cpp
>    R600TextureIntrinsicsReplacer.cpp
> diff --git a/lib/Target/R600/R600OptimizeVectorRegisters.cpp b/lib/Target/R600/R600OptimizeVectorRegisters.cpp
> new file mode 100644
> index 0000000..387799f
> --- /dev/null
> +++ b/lib/Target/R600/R600OptimizeVectorRegisters.cpp
> @@ -0,0 +1,336 @@
> +//===--------------------- R600MergeVectorRegisters.cpp -------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +/// \file
> +/// This pass merges inputs of swizzeable instructions into vector sharing
> +/// common data and/or have enough undef subreg using swizzle abilities.
> +///
> +/// For instance let's consider the following pseudo code :
> +/// vreg5<def> = REG_SEQ vreg1, sub0, vreg2, sub1, vreg3, sub2, undef, sub3
> +/// ...
> +/// vreg7<def> = REG_SEQ vreg1, sub0, vreg3, sub1, undef, sub2, vreg4, sub3
> +/// (swizzable Inst) vreg7, SwizzleMask : sub0, sub1, sub2, sub3
> +///
> +/// is turned into :
> +/// vreg5<def> = REG_SEQ vreg1, sub0, vreg2, sub1, vreg3, sub2, undef, sub3
> +/// ...
> +/// vreg7<def> = INSERT_SUBREG vreg4, sub3
> +/// (swizzable Inst) vreg7, SwizzleMask : sub0, sub2, sub1, sub3
> +///
> +/// This allow regalloc to reduce register pressure for vector registers and
> +/// to reduce MOV count.
> +//===----------------------------------------------------------------------===//
> +
> +#define DEBUG_TYPE "vec-merger"
> +#include "llvm/Support/Debug.h"
> +#include "AMDGPU.h"
> +#include "R600InstrInfo.h"
> +#include "llvm/CodeGen/DFAPacketizer.h"
> +#include "llvm/CodeGen/MachineDominators.h"
> +#include "llvm/CodeGen/MachineFunctionPass.h"
> +#include "llvm/CodeGen/MachineLoopInfo.h"
> +#include "llvm/CodeGen/Passes.h"
> +#include "llvm/CodeGen/MachineInstrBuilder.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/CodeGen/MachineRegisterInfo.h"
> +
> +using namespace llvm;
> +
> +namespace {
> +
> +static bool
> +isImplicitlyDef(MachineRegisterInfo &MRI, unsigned Reg) {
> +  for (MachineRegisterInfo::def_iterator It = MRI.def_begin(Reg),
> +      E = MRI.def_end(); It != E; ++It) {
> +    return (*It).isImplicitDef();
> +  }
> +  llvm_unreachable("Reg without a def");
> +  return false;
> +}
> +
> +class RegSeqInfo {
> +public:
> +  MachineInstr *Instr;
> +  DenseMap<unsigned, unsigned> RegToChan;
> +  std::vector<unsigned> UndefReg;
> +  RegSeqInfo(MachineRegisterInfo &MRI, MachineInstr *MI) : Instr(MI) {
> +    assert (MI->getOpcode() == AMDGPU::REG_SEQUENCE);
> +    for (unsigned i = 1, e = Instr->getNumOperands(); i < e; i+=2) {
> +      MachineOperand &MO = Instr->getOperand(i);
> +      unsigned Chan = Instr->getOperand(i + 1).getImm();
> +      if (isImplicitlyDef(MRI, MO.getReg()))
> +        UndefReg.push_back(Chan);
> +      else
> +        RegToChan[MO.getReg()] = Chan;
> +    }
> +  }
> +  RegSeqInfo() {}
> +
> +  bool operator==(const RegSeqInfo &RSI) const {
> +    return RSI.Instr == Instr;
> +  }
> +};
> +
> +class R600VectorRegMerger : public MachineFunctionPass {
> +private:
> +  const R600InstrInfo *TII;
> +  bool canSwizzle(const MachineInstr &) const;
> +  void SwizzleInput(MachineInstr &,
> +      const std::vector<std::pair<unsigned, unsigned> > &) const;
> +  bool tryMergeVector(const RegSeqInfo *, RegSeqInfo *,
> +      std::vector<std::pair<unsigned, unsigned> > &Remap) const;
> +  MachineInstr *RebuildVector(MachineRegisterInfo &MRI, RegSeqInfo *MI,
> +      const RegSeqInfo *BaseVec,
> +      const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const;
> +  void RemoveMI(MachineInstr *);
> +
> +  typedef DenseMap<unsigned, std::vector<MachineInstr *> > InstructionSetMap;
> +  DenseMap<MachineInstr *, RegSeqInfo> PreviousRegSeq;
> +  InstructionSetMap PreviousRegSeqByReg;
> +  InstructionSetMap PreviousRegSeqByUndefCount;
> +public:
> +  static char ID;
> +  R600VectorRegMerger(TargetMachine &tm) : MachineFunctionPass(ID),
> +  TII (static_cast<const R600InstrInfo *>(tm.getInstrInfo())) { }
> +
> +  void getAnalysisUsage(AnalysisUsage &AU) const {
> +    AU.setPreservesCFG();
> +    AU.addRequired<MachineDominatorTree>();
> +    AU.addPreserved<MachineDominatorTree>();
> +    AU.addRequired<MachineLoopInfo>();
> +    AU.addPreserved<MachineLoopInfo>();
> +    MachineFunctionPass::getAnalysisUsage(AU);
> +  }
> +
> +  const char *getPassName() const {
> +    return "R600 Vector Registers Merge Pass";
> +  }
> +
> +  bool runOnMachineFunction(MachineFunction &Fn);
> +};
> +
> +char R600VectorRegMerger::ID = 0;
> +
> +bool R600VectorRegMerger::canSwizzle(const MachineInstr &MI)
> +    const {
> +  if (TII->get(MI.getOpcode()).TSFlags & R600_InstFlag::TEX_INST)
> +    return true;
> +  switch (MI.getOpcode()) {
> +  case AMDGPU::R600_ExportSwz:
> +  case AMDGPU::EG_ExportSwz:
> +    return true;
> +  default:
> +    return false;
> +  }
> +}
> +
> +bool R600VectorRegMerger::tryMergeVector(const RegSeqInfo *Untouched,
> +    RegSeqInfo *ToMerge, std::vector< std::pair<unsigned, unsigned> > &Remap)
> +    const {
> +  unsigned CurrentUndexIdx = 0;
> +  for (DenseMap<unsigned, unsigned>::iterator It = ToMerge->RegToChan.begin(),
> +      E = ToMerge->RegToChan.end(); It != E; ++It) {
> +    DenseMap<unsigned, unsigned>::const_iterator PosInUntouched =
> +        Untouched->RegToChan.find((*It).first);
> +    if (PosInUntouched != Untouched->RegToChan.end()) {
> +      Remap.push_back(std::pair<unsigned, unsigned>
> +          ((*It).second, (*PosInUntouched).second));
> +      continue;
> +    }
> +    if (CurrentUndexIdx >= Untouched->UndefReg.size())
> +      return false;
> +    Remap.push_back(std::pair<unsigned, unsigned>
> +        ((*It).second, Untouched->UndefReg[CurrentUndexIdx++]));
> +  }
> +
> +  return true;
> +}
> +
> +MachineInstr *R600VectorRegMerger::RebuildVector(MachineRegisterInfo &MRI,
> +RegSeqInfo *RSI, const RegSeqInfo *BaseRSI,
> +const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const {

Indentation looks strange here

> +  MachineBasicBlock::iterator Pos = RSI->Instr;
> +  MachineBasicBlock &MBB = *Pos->getParent();
> +  DebugLoc DL = Pos->getDebugLoc();
> +
> +  unsigned SrcVec = BaseRSI->Instr->getOperand(0).getReg();
> +  DenseMap<unsigned, unsigned> UpdatedRegToChan = BaseRSI->RegToChan;
> +  std::vector<unsigned> UpdatedUndef = BaseRSI->UndefReg;
> +  DEBUG(
> +    dbgs() << "Turning ";
> +    RSI->Instr->dump();
> +    dbgs() << " into ";
> +  );
> +  for (DenseMap<unsigned, unsigned>::iterator It = RSI->RegToChan.begin(),
> +      E = RSI->RegToChan.end(); It != E; ++It) {
> +    if (BaseRSI->RegToChan.find((*It).first) != BaseRSI->RegToChan.end()) {
> +      UpdatedRegToChan[(*It).first] = (*It).second;
> +      continue;
> +    }
> +    unsigned DstReg = MRI.createVirtualRegister(&AMDGPU::R600_Reg128RegClass);
> +    unsigned SubReg = (*It).first;
> +    unsigned Swizzle = (*It).second;
> +    unsigned Chan;
> +    for (unsigned j = 0, je = RemapChan.size(); j < je; j++) {
> +      if (RemapChan[j].first == Swizzle) {
> +        Chan = RemapChan[j].second;
> +        break;
> +      }
> +    }
> +    MachineInstr *Tmp = BuildMI(MBB, Pos, DL, TII->get(AMDGPU::INSERT_SUBREG),
> +        DstReg)
> +        .addReg(SrcVec)
> +        .addReg(SubReg)
> +        .addImm(Chan);
> +    UpdatedRegToChan[SubReg] = Chan;
> +    UpdatedUndef.erase(
> +        std::find(UpdatedUndef.begin(), UpdatedUndef.end(), Chan));
> +    DEBUG(
> +      Tmp->dump();
> +    );
> +    SrcVec = DstReg;
> +  }
> +  Pos = BuildMI(MBB, Pos, DL, TII->get(AMDGPU::COPY),
> +      RSI->Instr->getOperand(0).getReg())
> +      .addReg(SrcVec);
> +  DEBUG(
> +    Pos->dump();
> +    dbgs() << "-----------\n";
> +  );
> +  RSI->Instr = Pos;
> +  RSI->RegToChan = UpdatedRegToChan;
> +  RSI->UndefReg = UpdatedUndef;
> +
> +  return Pos;
> +}
> +
> +void R600VectorRegMerger::RemoveMI(MachineInstr *MI) {
> +  for (InstructionSetMap::iterator It = PreviousRegSeqByReg.begin(),
> +      E = PreviousRegSeqByReg.end(); It != E; ++It) {
> +    std::vector<MachineInstr *> &MIs = (*It).second;
> +    MIs.erase(std::find(MIs.begin(), MIs.end(), MI), MIs.end());
> +  }
> +  for (InstructionSetMap::iterator It = PreviousRegSeqByUndefCount.begin(),
> +      E = PreviousRegSeqByUndefCount.end(); It != E; ++It) {
> +    std::vector<MachineInstr *> &MIs = (*It).second;
> +    MIs.erase(std::find(MIs.begin(), MIs.end(), MI), MIs.end());
> +  }
> +}
> +
> +void R600VectorRegMerger::SwizzleInput(MachineInstr &MI,
> +    const std::vector<std::pair<unsigned, unsigned> > &RemapChan) const {
> +  unsigned Offset;
> +  if (TII->get(MI.getOpcode()).TSFlags & R600_InstFlag::TEX_INST)
> +    Offset = 2;
> +  else
> +    Offset = 3;
> +  for (unsigned i = 0; i < 4; i++) {
> +    unsigned Swizzle = MI.getOperand(i + Offset).getImm() + 1;
> +    for (unsigned j = 0, e = RemapChan.size(); j < e; j++) {
> +      if (RemapChan[j].first == Swizzle) {
> +        MI.getOperand(i + Offset).setImm(RemapChan[j].second - 1);
> +        break;
> +      }
> +    }
> +  }
> +}
> +
> +bool R600VectorRegMerger::runOnMachineFunction(MachineFunction &Fn) {
> +  MachineRegisterInfo &MRI = Fn.getRegInfo();
> +  for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end();
> +       MBB != MBBe; ++MBB) {
> +    MachineBasicBlock *MB = MBB;
> +    PreviousRegSeq.clear();
> +    PreviousRegSeqByReg.clear();
> +    PreviousRegSeqByUndefCount.clear();
> +
> +    for (MachineBasicBlock::iterator MII = MB->begin(), MIIE = MB->end();
> +         MII != MIIE; ++MII) {
> +      MachineInstr *MI = MII;
> +      if (MI->getOpcode() != AMDGPU::REG_SEQUENCE)
> +        continue;
> +
> +      RegSeqInfo &RSI = PreviousRegSeq[MI] = RegSeqInfo(MRI, MI);
> +
> +      // All uses of MI are swizzeable ?
> +      unsigned Reg = MI->getOperand(0).getReg();
> +      bool AllUseAreSwizzeable = true;
> +      for (MachineRegisterInfo::use_iterator It = MRI.use_begin(Reg),
> +          E = MRI.use_end(); It != E; ++It) {
> +        if (!canSwizzle(*It)) {
> +          AllUseAreSwizzeable = false;
> +          break;
> +        }
> +      }
> +      if (!AllUseAreSwizzeable)
> +        continue;
> +
> +      bool Merged = false;
> +      for (MachineInstr::mop_iterator MOp = MI->operands_begin(),
> +          MOE = MI->operands_end(); MOp != MOE; ++MOp) {
> +        if (!MOp->isReg())
> +          continue;
> +        if (PreviousRegSeqByReg[MOp->getReg()].empty())
> +          continue;
> +        std::vector<MachineInstr *> MIs = PreviousRegSeqByReg[MOp->getReg()];
> +        for (unsigned i = 0, e = MIs.size(); i < e; i++) {
> +          RegSeqInfo &CandidateRSI = PreviousRegSeq[MIs[i]];
> +          if (RSI == CandidateRSI)
> +            continue;
> +          std::vector<std::pair<unsigned, unsigned> > RemapChan;
> +          if (!tryMergeVector(&CandidateRSI, &RSI, RemapChan))
> +            continue;
> +          MII = RebuildVector(MRI, &RSI, &CandidateRSI, RemapChan);
> +          RemoveMI(CandidateRSI.Instr);
> +          MI->eraseFromParent();
> +          for (MachineRegisterInfo::use_iterator It = MRI.use_begin(Reg),
> +              E = MRI.use_end(); It != E; ++It) {
> +            SwizzleInput(*It, RemapChan);
> +          }
> +          Merged = true;
> +          break;
> +        }
> +        if (Merged)
> +          break;
> +      }
> +      if (Merged)
> +        continue;
> +      unsigned NeededUndefs = 4 - RSI.UndefReg.size();
> +      if (!PreviousRegSeqByUndefCount[NeededUndefs].empty()) {
> +        std::vector<MachineInstr *> &MIs =
> +            PreviousRegSeqByUndefCount[NeededUndefs];
> +        RegSeqInfo &PriorRSI = PreviousRegSeq[MIs.back()];
> +        std::vector<std::pair<unsigned, unsigned> > RemapChan;
> +        tryMergeVector(&PriorRSI, &RSI, RemapChan);
> +        MII = RebuildVector(MRI, &RSI, &PriorRSI, RemapChan);
> +        RemoveMI(PriorRSI.Instr);
> +        MI->eraseFromParent();
> +        for (MachineRegisterInfo::use_iterator It = MRI.use_begin(Reg),
> +            E = MRI.use_end(); It != E; ++It) {
> +          SwizzleInput(*It, RemapChan);
> +        }
> +        continue;
> +      }
> +      //Failed to merge
> +      for (DenseMap<unsigned, unsigned>::const_iterator
> +      It = RSI.RegToChan.begin(), E = RSI.RegToChan.end(); It != E; ++It) {
> +        PreviousRegSeqByReg[(*It).first].push_back(RSI.Instr);
> +      }
> +      PreviousRegSeqByUndefCount[RSI.UndefReg.size()].push_back(RSI.Instr);
> +    }
> +  }
> +  return false;
> +}
> +
> +}
> +
> +llvm::FunctionPass *llvm::createR600VectorRegMerger(TargetMachine &tm) {
> +  return new R600VectorRegMerger(tm);
> +}
> +
> -- 
> 1.8.2.1
> 

> From 8ab5368eb96cacdd86d02692ef2637157aff85b3 Mon Sep 17 00:00:00 2001
> From: Vincent Lejeune <vljn at ovi.com>
> Date: Thu, 23 May 2013 00:44:09 +0200
> Subject: [PATCH 2/3] R600: Swizzle texture/export instructions
>

Reviewed-by: Tom Stellard <tom at stellard.net>

> ---
>  lib/Target/R600/R600ISelLowering.cpp | 145 ++++++++++++++++++++++++++++++-----
>  lib/Target/R600/R600ISelLowering.h   |   1 +
>  test/CodeGen/R600/llvm.AMDGPU.tex.ll |  10 +--
>  3 files changed, 131 insertions(+), 25 deletions(-)
> 
> diff --git a/lib/Target/R600/R600ISelLowering.cpp b/lib/Target/R600/R600ISelLowering.cpp
> index 00adca3..267f367 100644
> --- a/lib/Target/R600/R600ISelLowering.cpp
> +++ b/lib/Target/R600/R600ISelLowering.cpp
> @@ -1210,6 +1210,99 @@ EVT R600TargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const {
>     return VT.changeVectorElementTypeToInteger();
>  }
>  
> +SDValue CompactSwizzlableVector(SelectionDAG &DAG, SDValue VectorEntry,
> +                                DenseMap<unsigned, unsigned> &RemapSwizzle) {
> +  assert(VectorEntry.getOpcode() == ISD::BUILD_VECTOR);
> +  assert(RemapSwizzle.empty());
> +  SDValue NewBldVec[4] = {
> +      VectorEntry.getOperand(0),
> +      VectorEntry.getOperand(1),
> +      VectorEntry.getOperand(2),
> +      VectorEntry.getOperand(3)
> +  };
> +
> +  for (unsigned i = 0; i < 4; i++) {
> +    if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(NewBldVec[i])) {
> +      if (C->isZero()) {
> +        RemapSwizzle[i] = 4; // SEL_0
> +        NewBldVec[i] = DAG.getUNDEF(MVT::f32);
> +      } else if (C->isExactlyValue(1.0)) {
> +        RemapSwizzle[i] = 5; // SEL_1
> +        NewBldVec[i] = DAG.getUNDEF(MVT::f32);
> +      }
> +    }
> +
> +    if (NewBldVec[i].getOpcode() == ISD::UNDEF)
> +      continue;
> +    for (unsigned j = 0; j < i; j++) {
> +      if (NewBldVec[i] == NewBldVec[j]) {
> +        NewBldVec[i] = DAG.getUNDEF(NewBldVec[i].getValueType());
> +        RemapSwizzle[i] = j;
> +        break;
> +      }
> +    }
> +  }
> +
> +  return DAG.getNode(ISD::BUILD_VECTOR, SDLoc(VectorEntry),
> +      VectorEntry.getValueType(), NewBldVec, 4);
> +}
> +
> +SDValue ReorganizeVector(SelectionDAG &DAG, SDValue VectorEntry,
> +                         DenseMap<unsigned, unsigned> &RemapSwizzle) {
> +  assert(VectorEntry.getOpcode() == ISD::BUILD_VECTOR);
> +  assert(RemapSwizzle.empty());
> +  SDValue NewBldVec[4] = {
> +      VectorEntry.getOperand(0),
> +      VectorEntry.getOperand(1),
> +      VectorEntry.getOperand(2),
> +      VectorEntry.getOperand(3)
> +  };
> +  bool isUnmovable[4] = { false, false, false, false };
> +
> +  for (unsigned i = 0; i < 4; i++) {
> +    if (NewBldVec[i].getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
> +      unsigned Idx = dyn_cast<ConstantSDNode>(NewBldVec[i].getOperand(1))
> +          ->getZExtValue();
> +      if (!isUnmovable[Idx]) {
> +        // Swap i and Idx
> +        std::swap(NewBldVec[Idx], NewBldVec[i]);
> +        RemapSwizzle[Idx] = i;
> +        RemapSwizzle[i] = Idx;
> +      }
> +      isUnmovable[Idx] = true;
> +    }
> +  }
> +
> +  return DAG.getNode(ISD::BUILD_VECTOR, SDLoc(VectorEntry),
> +      VectorEntry.getValueType(), NewBldVec, 4);
> +}
> +
> +
> +SDValue R600TargetLowering::OptimizeSwizzle(SDValue BuildVector,
> +SDValue Swz[4], SelectionDAG &DAG) const {
> +  assert(BuildVector.getOpcode() == ISD::BUILD_VECTOR);
> +  // Old -> New swizzle values
> +  DenseMap<unsigned, unsigned> SwizzleRemap;
> +
> +  BuildVector = CompactSwizzlableVector(DAG, BuildVector, SwizzleRemap);
> +  for (unsigned i = 0; i < 4; i++) {
> +    unsigned Idx = dyn_cast<ConstantSDNode>(Swz[i])->getZExtValue();
> +    if (SwizzleRemap.find(Idx) != SwizzleRemap.end())
> +      Swz[i] = DAG.getConstant(SwizzleRemap[Idx], MVT::i32);
> +  }
> +
> +  SwizzleRemap.clear();
> +  BuildVector = ReorganizeVector(DAG, BuildVector, SwizzleRemap);
> +  for (unsigned i = 0; i < 4; i++) {
> +    unsigned Idx = dyn_cast<ConstantSDNode>(Swz[i])->getZExtValue();
> +    if (SwizzleRemap.find(Idx) != SwizzleRemap.end())
> +      Swz[i] = DAG.getConstant(SwizzleRemap[Idx], MVT::i32);
> +  }
> +
> +  return BuildVector;
> +}
> +
> +
>  //===----------------------------------------------------------------------===//
>  // Custom DAG Optimizations
>  //===----------------------------------------------------------------------===//
> @@ -1319,12 +1412,7 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
>      SDValue Arg = N->getOperand(1);
>      if (Arg.getOpcode() != ISD::BUILD_VECTOR)
>        break;
> -    SDValue NewBldVec[4] = {
> -        DAG.getUNDEF(MVT::f32),
> -        DAG.getUNDEF(MVT::f32),
> -        DAG.getUNDEF(MVT::f32),
> -        DAG.getUNDEF(MVT::f32)
> -      };
> +
>      SDValue NewArgs[8] = {
>        N->getOperand(0), // Chain
>        SDValue(),
> @@ -1335,23 +1423,40 @@ SDValue R600TargetLowering::PerformDAGCombine(SDNode *N,
>        N->getOperand(6), // SWZ_Z
>        N->getOperand(7) // SWZ_W
>      };
> -    for (unsigned i = 0; i < Arg.getNumOperands(); i++) {
> -      if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Arg.getOperand(i))) {
> -        if (C->isZero()) {
> -          NewArgs[4 + i] = DAG.getConstant(4, MVT::i32); // SEL_0
> -        } else if (C->isExactlyValue(1.0)) {
> -          NewArgs[4 + i] = DAG.getConstant(5, MVT::i32); // SEL_0
> -        } else {
> -          NewBldVec[i] = Arg.getOperand(i);
> -        }
> -      } else {
> -        NewBldVec[i] = Arg.getOperand(i);
> -      }
> -    }
>      SDLoc DL(N);
> -    NewArgs[1] = DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4f32, NewBldVec, 4);
> +    NewArgs[1] = OptimizeSwizzle(N->getOperand(1), &NewArgs[4], DAG);
>      return DAG.getNode(AMDGPUISD::EXPORT, DL, N->getVTList(), NewArgs, 8);
>    }
> +  case AMDGPUISD::TEXTURE_FETCH: {
> +    SDValue Arg = N->getOperand(1);
> +    if (Arg.getOpcode() != ISD::BUILD_VECTOR)
> +      break;
> +
> +    SDValue NewArgs[19] = {
> +      N->getOperand(0),
> +      N->getOperand(1),
> +      N->getOperand(2),
> +      N->getOperand(3),
> +      N->getOperand(4),
> +      N->getOperand(5),
> +      N->getOperand(6),
> +      N->getOperand(7),
> +      N->getOperand(8),
> +      N->getOperand(9),
> +      N->getOperand(10),
> +      N->getOperand(11),
> +      N->getOperand(12),
> +      N->getOperand(13),
> +      N->getOperand(14),
> +      N->getOperand(15),
> +      N->getOperand(16),
> +      N->getOperand(17),
> +      N->getOperand(18),
> +    };
> +    NewArgs[1] = OptimizeSwizzle(N->getOperand(1), &NewArgs[2], DAG);
> +    return DAG.getNode(AMDGPUISD::TEXTURE_FETCH, SDLoc(N), N->getVTList(),
> +        NewArgs, 19);
> +  }
>    }
>    return SDValue();
>  }
> diff --git a/lib/Target/R600/R600ISelLowering.h b/lib/Target/R600/R600ISelLowering.h
> index 663aab4..2904396 100644
> --- a/lib/Target/R600/R600ISelLowering.h
> +++ b/lib/Target/R600/R600ISelLowering.h
> @@ -51,6 +51,7 @@ private:
>  
>    void lowerImplicitParameter(MachineInstr *MI, MachineBasicBlock &BB,
>        MachineRegisterInfo & MRI, unsigned dword_offset) const;
> +  SDValue OptimizeSwizzle(SDValue BuildVector, SDValue Swz[], SelectionDAG &DAG) const;
>  
>    /// \brief Lower ROTL opcode to BITALIGN
>    SDValue LowerROTL(SDValue Op, SelectionDAG &DAG) const;
> diff --git a/test/CodeGen/R600/llvm.AMDGPU.tex.ll b/test/CodeGen/R600/llvm.AMDGPU.tex.ll
> index 4ea82bb..aac014b 100644
> --- a/test/CodeGen/R600/llvm.AMDGPU.tex.ll
> +++ b/test/CodeGen/R600/llvm.AMDGPU.tex.ll
> @@ -5,12 +5,12 @@
>  ;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
>  ;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
>  ;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:UUNN
> -;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
> -;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
> -;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:UUNN
> +;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZZ}} RID:0 SID:0 CT:NNNN
> +;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZZ}} RID:0 SID:0 CT:NNNN
> +;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZZ}} RID:0 SID:0 CT:UUNN
> +;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYYW}} RID:0 SID:0 CT:NNUN
>  ;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNUN
> -;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNUN
> -;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNUN
> +;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYYZ}} RID:0 SID:0 CT:NNUN
>  ;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNUN
>  ;CHECK: TEX_SAMPLE_C T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
>  ;CHECK: TEX_SAMPLE T{{[0-9]+\.XYZW, T[0-9]+\.XYZW}} RID:0 SID:0 CT:NNNN
> -- 
> 1.8.2.1
> 

> _______________________________________________
> 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