168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//===-- SITypeRewriter.cpp - Remove unwanted types ------------------------===//
268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//
368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//                     The LLVM Compiler Infrastructure
468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//
568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard// This file is distributed under the University of Illinois Open Source
668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard// License. See LICENSE.TXT for details.
768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//
868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//===----------------------------------------------------------------------===//
968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//
1068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard/// \file
1168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard/// This pass removes performs the following type substitution on all
1268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard/// non-compute shaders:
1368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard///
1468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard/// v16i8 => i128
1568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard///   - v16i8 is used for constant memory resource descriptors.  This type is
1668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard///      legal for some compute APIs, and we don't want to declare it as legal
1768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard///      in the backend, because we want the legalizer to expand all v16i8
1868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard///      operations.
19e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard/// v1* => *
20e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard///   - Having v1* types complicates the legalizer and we can easily replace
21e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard///   - them with the element type.
2268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard//===----------------------------------------------------------------------===//
2368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
2468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard#include "AMDGPU.h"
2568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard#include "llvm/IR/IRBuilder.h"
2636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/IR/InstVisitor.h"
2768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
2868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardusing namespace llvm;
2968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
3068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardnamespace {
3168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
3268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardclass SITypeRewriter : public FunctionPass,
3368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard                       public InstVisitor<SITypeRewriter> {
3468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
3568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  static char ID;
3668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Module *Mod;
3768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Type *v16i8;
38dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  Type *v4i32;
3968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
4068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardpublic:
4168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  SITypeRewriter() : FunctionPass(ID) { }
42dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  bool doInitialization(Module &M) override;
43dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  bool runOnFunction(Function &F) override;
44dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const char *getPassName() const override {
4568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    return "SI Type Rewriter";
4668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
4768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  void visitLoadInst(LoadInst &I);
4868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  void visitCallInst(CallInst &I);
4968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  void visitBitCast(BitCastInst &I);
5068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard};
5168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
5268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard} // End anonymous namespace
5368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
5468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardchar SITypeRewriter::ID = 0;
5568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
5668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardbool SITypeRewriter::doInitialization(Module &M) {
5768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Mod = &M;
5868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  v16i8 = VectorType::get(Type::getInt8Ty(M.getContext()), 16);
59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  v4i32 = VectorType::get(Type::getInt32Ty(M.getContext()), 4);
6068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  return false;
6168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
6268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
6368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardbool SITypeRewriter::runOnFunction(Function &F) {
6468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  AttributeSet Set = F.getAttributes();
6568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Attribute A = Set.getAttribute(AttributeSet::FunctionIndex, "ShaderType");
6668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
6768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  unsigned ShaderType = ShaderType::COMPUTE;
6868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  if (A.isStringAttribute()) {
6968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    StringRef Str = A.getValueAsString();
7068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    Str.getAsInteger(0, ShaderType);
7168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
7236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  if (ShaderType == ShaderType::COMPUTE)
7336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return false;
7468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
7568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  visit(F);
7636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  visit(F);
7768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
7868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  return false;
7968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
8068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
8168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardvoid SITypeRewriter::visitLoadInst(LoadInst &I) {
8268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Value *Ptr = I.getPointerOperand();
8368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Type *PtrTy = Ptr->getType();
8468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Type *ElemTy = PtrTy->getPointerElementType();
8568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  IRBuilder<> Builder(&I);
8668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  if (ElemTy == v16i8)  {
87dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    Value *BitCast = Builder.CreateBitCast(Ptr,
88dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        PointerType::get(v4i32,PtrTy->getPointerAddressSpace()));
8968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    LoadInst *Load = Builder.CreateLoad(BitCast);
9068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    SmallVector <std::pair<unsigned, MDNode*>, 8> MD;
9168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    I.getAllMetadataOtherThanDebugLoc(MD);
9268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    for (unsigned i = 0, e = MD.size(); i != e; ++i) {
9368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      Load->setMetadata(MD[i].first, MD[i].second);
9468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    }
9568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    Value *BitCastLoad = Builder.CreateBitCast(Load, I.getType());
9668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    I.replaceAllUsesWith(BitCastLoad);
9768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    I.eraseFromParent();
9868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
9968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
10068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
10168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardvoid SITypeRewriter::visitCallInst(CallInst &I) {
10268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  IRBuilder<> Builder(&I);
103dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
10468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  SmallVector <Value*, 8> Args;
10568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  SmallVector <Type*, 8> Types;
10668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  bool NeedToReplace = false;
10768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Function *F = I.getCalledFunction();
10868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  std::string Name = F->getName().str();
10968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) {
11068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    Value *Arg = I.getArgOperand(i);
11168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    if (Arg->getType() == v16i8) {
112dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Args.push_back(Builder.CreateBitCast(Arg, v4i32));
113dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Types.push_back(v4i32);
11468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      NeedToReplace = true;
115dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Name = Name + ".v4i32";
116e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard    } else if (Arg->getType()->isVectorTy() &&
117e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard               Arg->getType()->getVectorNumElements() == 1 &&
118e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard               Arg->getType()->getVectorElementType() ==
119e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard                                              Type::getInt32Ty(I.getContext())){
120e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      Type *ElementTy = Arg->getType()->getVectorElementType();
121e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      std::string TypeName = "i32";
122cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines      InsertElementInst *Def = cast<InsertElementInst>(Arg);
123e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      Args.push_back(Def->getOperand(1));
124e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      Types.push_back(ElementTy);
125e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      std::string VecTypeName = "v1" + TypeName;
126e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      Name = Name.replace(Name.find(VecTypeName), VecTypeName.length(), TypeName);
127e8e33f448e8830590c498ac5101ef8b27446ca3bTom Stellard      NeedToReplace = true;
12868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    } else {
12968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      Args.push_back(Arg);
13068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      Types.push_back(Arg->getType());
13168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    }
13268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
13368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
13468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  if (!NeedToReplace) {
13568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    return;
13668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
13768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  Function *NewF = Mod->getFunction(Name);
13868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  if (!NewF) {
13968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    NewF = Function::Create(FunctionType::get(F->getReturnType(), Types, false), GlobalValue::ExternalLinkage, Name, Mod);
14068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    NewF->setAttributes(F->getAttributes());
14168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
14268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  I.replaceAllUsesWith(Builder.CreateCall(NewF, Args));
14368db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  I.eraseFromParent();
14468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
14568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
14668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellardvoid SITypeRewriter::visitBitCast(BitCastInst &I) {
14768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  IRBuilder<> Builder(&I);
148dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (I.getDestTy() != v4i32) {
14968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    return;
15068db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
15168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
15268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  if (BitCastInst *Op = dyn_cast<BitCastInst>(I.getOperand(0))) {
153dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (Op->getSrcTy() == v4i32) {
15468db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      I.replaceAllUsesWith(Op->getOperand(0));
15568db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard      I.eraseFromParent();
15668db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard    }
15768db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  }
15868db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
15968db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard
16068db37b952be497c94c7aa98cf26f3baadb5afd3Tom StellardFunctionPass *llvm::createSITypeRewriter() {
16168db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard  return new SITypeRewriter();
16268db37b952be497c94c7aa98cf26f3baadb5afd3Tom Stellard}
163