brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.3 KiB · be88f33 Raw
572 lines · cpp
1//===-- SPIRVPrepareFunctions.cpp - modify function signatures --*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This pass modifies function signatures containing aggregate arguments10// and/or return value before IRTranslator. Information about the original11// signatures is stored in metadata. It is used during call lowering to12// restore correct SPIR-V types of function arguments and return values.13// This pass also substitutes some llvm intrinsic calls with calls to newly14// generated functions (as the Khronos LLVM/SPIR-V Translator does).15//16// NOTE: this pass is a module-level one due to the necessity to modify17// GVs/functions.18//19//===----------------------------------------------------------------------===//20 21#include "SPIRV.h"22#include "SPIRVSubtarget.h"23#include "SPIRVTargetMachine.h"24#include "SPIRVUtils.h"25#include "llvm/ADT/StringExtras.h"26#include "llvm/Analysis/ValueTracking.h"27#include "llvm/CodeGen/IntrinsicLowering.h"28#include "llvm/IR/IRBuilder.h"29#include "llvm/IR/IntrinsicInst.h"30#include "llvm/IR/Intrinsics.h"31#include "llvm/IR/IntrinsicsSPIRV.h"32#include "llvm/Transforms/Utils/Cloning.h"33#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"34#include <regex>35 36using namespace llvm;37 38namespace {39 40class SPIRVPrepareFunctions : public ModulePass {41  const SPIRVTargetMachine &TM;42  bool substituteIntrinsicCalls(Function *F);43  Function *removeAggregateTypesFromSignature(Function *F);44 45public:46  static char ID;47  SPIRVPrepareFunctions(const SPIRVTargetMachine &TM)48      : ModulePass(ID), TM(TM) {}49 50  bool runOnModule(Module &M) override;51 52  StringRef getPassName() const override { return "SPIRV prepare functions"; }53 54  void getAnalysisUsage(AnalysisUsage &AU) const override {55    ModulePass::getAnalysisUsage(AU);56  }57};58 59static cl::list<std::string> SPVAllowUnknownIntrinsics(60    "spv-allow-unknown-intrinsics", cl::CommaSeparated,61    cl::desc("Emit unknown intrinsics as calls to external functions. A "62             "comma-separated input list of intrinsic prefixes must be "63             "provided, and only intrinsics carrying a listed prefix get "64             "emitted as described."),65    cl::value_desc("intrinsic_prefix_0,intrinsic_prefix_1"), cl::ValueOptional);66} // namespace67 68char SPIRVPrepareFunctions::ID = 0;69 70INITIALIZE_PASS(SPIRVPrepareFunctions, "prepare-functions",71                "SPIRV prepare functions", false, false)72 73static std::string lowerLLVMIntrinsicName(IntrinsicInst *II) {74  Function *IntrinsicFunc = II->getCalledFunction();75  assert(IntrinsicFunc && "Missing function");76  std::string FuncName = IntrinsicFunc->getName().str();77  llvm::replace(FuncName, '.', '_');78  FuncName = "spirv." + FuncName;79  return FuncName;80}81 82static Function *getOrCreateFunction(Module *M, Type *RetTy,83                                     ArrayRef<Type *> ArgTypes,84                                     StringRef Name) {85  FunctionType *FT = FunctionType::get(RetTy, ArgTypes, false);86  Function *F = M->getFunction(Name);87  if (F && F->getFunctionType() == FT)88    return F;89  Function *NewF = Function::Create(FT, GlobalValue::ExternalLinkage, Name, M);90  if (F)91    NewF->setDSOLocal(F->isDSOLocal());92  NewF->setCallingConv(CallingConv::SPIR_FUNC);93  return NewF;94}95 96static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic) {97  // For @llvm.memset.* intrinsic cases with constant value and length arguments98  // are emulated via "storing" a constant array to the destination. For other99  // cases we wrap the intrinsic in @spirv.llvm_memset_* function and expand the100  // intrinsic to a loop via expandMemSetAsLoop().101  if (auto *MSI = dyn_cast<MemSetInst>(Intrinsic))102    if (isa<Constant>(MSI->getValue()) && isa<ConstantInt>(MSI->getLength()))103      return false; // It is handled later using OpCopyMemorySized.104 105  Module *M = Intrinsic->getModule();106  std::string FuncName = lowerLLVMIntrinsicName(Intrinsic);107  if (Intrinsic->isVolatile())108    FuncName += ".volatile";109  // Redirect @llvm.intrinsic.* call to @spirv.llvm_intrinsic_*110  Function *F = M->getFunction(FuncName);111  if (F) {112    Intrinsic->setCalledFunction(F);113    return true;114  }115  // TODO copy arguments attributes: nocapture writeonly.116  FunctionCallee FC =117      M->getOrInsertFunction(FuncName, Intrinsic->getFunctionType());118  auto IntrinsicID = Intrinsic->getIntrinsicID();119  Intrinsic->setCalledFunction(FC);120 121  F = dyn_cast<Function>(FC.getCallee());122  assert(F && "Callee must be a function");123 124  switch (IntrinsicID) {125  case Intrinsic::memset: {126    auto *MSI = static_cast<MemSetInst *>(Intrinsic);127    Argument *Dest = F->getArg(0);128    Argument *Val = F->getArg(1);129    Argument *Len = F->getArg(2);130    Argument *IsVolatile = F->getArg(3);131    Dest->setName("dest");132    Val->setName("val");133    Len->setName("len");134    IsVolatile->setName("isvolatile");135    BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);136    IRBuilder<> IRB(EntryBB);137    auto *MemSet = IRB.CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),138                                    MSI->isVolatile());139    IRB.CreateRetVoid();140    expandMemSetAsLoop(cast<MemSetInst>(MemSet));141    MemSet->eraseFromParent();142    break;143  }144  case Intrinsic::bswap: {145    BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);146    IRBuilder<> IRB(EntryBB);147    auto *BSwap = IRB.CreateIntrinsic(Intrinsic::bswap, Intrinsic->getType(),148                                      F->getArg(0));149    IRB.CreateRet(BSwap);150    IntrinsicLowering IL(M->getDataLayout());151    IL.LowerIntrinsicCall(BSwap);152    break;153  }154  default:155    break;156  }157  return true;158}159 160static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal) {161  if (auto *Ref = dyn_cast_or_null<GetElementPtrInst>(AnnoVal))162    AnnoVal = Ref->getOperand(0);163  if (auto *Ref = dyn_cast_or_null<BitCastInst>(OptAnnoVal))164    OptAnnoVal = Ref->getOperand(0);165 166  std::string Anno;167  if (auto *C = dyn_cast_or_null<Constant>(AnnoVal)) {168    StringRef Str;169    if (getConstantStringInfo(C, Str))170      Anno = Str;171  }172  // handle optional annotation parameter in a way that Khronos Translator do173  // (collect integers wrapped in a struct)174  if (auto *C = dyn_cast_or_null<Constant>(OptAnnoVal);175      C && C->getNumOperands()) {176    Value *MaybeStruct = C->getOperand(0);177    if (auto *Struct = dyn_cast<ConstantStruct>(MaybeStruct)) {178      for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {179        if (auto *CInt = dyn_cast<ConstantInt>(Struct->getOperand(I)))180          Anno += (I == 0 ? ": " : ", ") +181                  std::to_string(CInt->getType()->getIntegerBitWidth() == 1182                                     ? CInt->getZExtValue()183                                     : CInt->getSExtValue());184      }185    } else if (auto *Struct = dyn_cast<ConstantAggregateZero>(MaybeStruct)) {186      // { i32 i32 ... } zeroinitializer187      for (unsigned I = 0, E = Struct->getType()->getStructNumElements();188           I != E; ++I)189        Anno += I == 0 ? ": 0" : ", 0";190    }191  }192  return Anno;193}194 195static SmallVector<Metadata *> parseAnnotation(Value *I,196                                               const std::string &Anno,197                                               LLVMContext &Ctx,198                                               Type *Int32Ty) {199  // Try to parse the annotation string according to the following rules:200  // annotation := ({kind} | {kind:value,value,...})+201  // kind := number202  // value := number | string203  static const std::regex R(204      "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");205  SmallVector<Metadata *> MDs;206  int Pos = 0;207  for (std::sregex_iterator208           It = std::sregex_iterator(Anno.begin(), Anno.end(), R),209           ItEnd = std::sregex_iterator();210       It != ItEnd; ++It) {211    if (It->position() != Pos)212      return SmallVector<Metadata *>{};213    Pos = It->position() + It->length();214    std::smatch Match = *It;215    SmallVector<Metadata *> MDsItem;216    for (std::size_t i = 1; i < Match.size(); ++i) {217      std::ssub_match SMatch = Match[i];218      std::string Item = SMatch.str();219      if (Item.length() == 0)220        break;221      if (Item[0] == '"') {222        Item = Item.substr(1, Item.length() - 2);223        // Acceptable format of the string snippet is:224        static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");225        if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {226          for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)227            if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())228              MDsItem.push_back(ConstantAsMetadata::get(229                  ConstantInt::get(Int32Ty, std::stoi(SubStr))));230        } else {231          MDsItem.push_back(MDString::get(Ctx, Item));232        }233      } else if (int32_t Num; llvm::to_integer(StringRef(Item), Num, 10)) {234        MDsItem.push_back(235            ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Num)));236      } else {237        MDsItem.push_back(MDString::get(Ctx, Item));238      }239    }240    if (MDsItem.size() == 0)241      return SmallVector<Metadata *>{};242    MDs.push_back(MDNode::get(Ctx, MDsItem));243  }244  return Pos == static_cast<int>(Anno.length()) ? std::move(MDs)245                                                : SmallVector<Metadata *>{};246}247 248static void lowerPtrAnnotation(IntrinsicInst *II) {249  LLVMContext &Ctx = II->getContext();250  Type *Int32Ty = Type::getInt32Ty(Ctx);251 252  // Retrieve an annotation string from arguments.253  Value *PtrArg = nullptr;254  if (auto *BI = dyn_cast<BitCastInst>(II->getArgOperand(0)))255    PtrArg = BI->getOperand(0);256  else257    PtrArg = II->getOperand(0);258  std::string Anno =259      getAnnotation(II->getArgOperand(1),260                    4 < II->arg_size() ? II->getArgOperand(4) : nullptr);261 262  // Parse the annotation.263  SmallVector<Metadata *> MDs = parseAnnotation(II, Anno, Ctx, Int32Ty);264 265  // If the annotation string is not parsed successfully we don't know the266  // format used and output it as a general UserSemantic decoration.267  // Otherwise MDs is a Metadata tuple (a decoration list) in the format268  // expected by `spirv.Decorations`.269  if (MDs.size() == 0) {270    auto UserSemantic = ConstantAsMetadata::get(ConstantInt::get(271        Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));272    MDs.push_back(MDNode::get(Ctx, {UserSemantic, MDString::get(Ctx, Anno)}));273  }274 275  // Build the internal intrinsic function.276  IRBuilder<> IRB(II->getParent());277  IRB.SetInsertPoint(II);278  IRB.CreateIntrinsic(279      Intrinsic::spv_assign_decoration, {PtrArg->getType()},280      {PtrArg, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});281  II->replaceAllUsesWith(II->getOperand(0));282}283 284static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic) {285  // Get a separate function - otherwise, we'd have to rework the CFG of the286  // current one. Then simply replace the intrinsic uses with a call to the new287  // function.288  // Generate LLVM IR for  i* @spirv.llvm_fsh?_i* (i* %a, i* %b, i* %c)289  Module *M = FSHIntrinsic->getModule();290  FunctionType *FSHFuncTy = FSHIntrinsic->getFunctionType();291  Type *FSHRetTy = FSHFuncTy->getReturnType();292  const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);293  Function *FSHFunc =294      getOrCreateFunction(M, FSHRetTy, FSHFuncTy->params(), FuncName);295 296  if (!FSHFunc->empty()) {297    FSHIntrinsic->setCalledFunction(FSHFunc);298    return;299  }300  BasicBlock *RotateBB = BasicBlock::Create(M->getContext(), "rotate", FSHFunc);301  IRBuilder<> IRB(RotateBB);302  Type *Ty = FSHFunc->getReturnType();303  // Build the actual funnel shift rotate logic.304  // In the comments, "int" is used interchangeably with "vector of int305  // elements".306  FixedVectorType *VectorTy = dyn_cast<FixedVectorType>(Ty);307  Type *IntTy = VectorTy ? VectorTy->getElementType() : Ty;308  unsigned BitWidth = IntTy->getIntegerBitWidth();309  ConstantInt *BitWidthConstant = IRB.getInt({BitWidth, BitWidth});310  Value *BitWidthForInsts =311      VectorTy312          ? IRB.CreateVectorSplat(VectorTy->getNumElements(), BitWidthConstant)313          : BitWidthConstant;314  Value *RotateModVal =315      IRB.CreateURem(/*Rotate*/ FSHFunc->getArg(2), BitWidthForInsts);316  Value *FirstShift = nullptr, *SecShift = nullptr;317  if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {318    // Shift the less significant number right, the "rotate" number of bits319    // will be 0-filled on the left as a result of this regular shift.320    FirstShift = IRB.CreateLShr(FSHFunc->getArg(1), RotateModVal);321  } else {322    // Shift the more significant number left, the "rotate" number of bits323    // will be 0-filled on the right as a result of this regular shift.324    FirstShift = IRB.CreateShl(FSHFunc->getArg(0), RotateModVal);325  }326  // We want the "rotate" number of the more significant int's LSBs (MSBs) to327  // occupy the leftmost (rightmost) "0 space" left by the previous operation.328  // Therefore, subtract the "rotate" number from the integer bitsize...329  Value *SubRotateVal = IRB.CreateSub(BitWidthForInsts, RotateModVal);330  if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {331    // ...and left-shift the more significant int by this number, zero-filling332    // the LSBs.333    SecShift = IRB.CreateShl(FSHFunc->getArg(0), SubRotateVal);334  } else {335    // ...and right-shift the less significant int by this number, zero-filling336    // the MSBs.337    SecShift = IRB.CreateLShr(FSHFunc->getArg(1), SubRotateVal);338  }339  // A simple binary addition of the shifted ints yields the final result.340  IRB.CreateRet(IRB.CreateOr(FirstShift, SecShift));341 342  FSHIntrinsic->setCalledFunction(FSHFunc);343}344 345static void lowerConstrainedFPCmpIntrinsic(346    ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic,347    SmallVector<Instruction *> &EraseFromParent) {348  if (!ConstrainedCmpIntrinsic)349    return;350  // Extract the floating-point values being compared351  Value *LHS = ConstrainedCmpIntrinsic->getArgOperand(0);352  Value *RHS = ConstrainedCmpIntrinsic->getArgOperand(1);353  FCmpInst::Predicate Pred = ConstrainedCmpIntrinsic->getPredicate();354  IRBuilder<> Builder(ConstrainedCmpIntrinsic);355  Value *FCmp = Builder.CreateFCmp(Pred, LHS, RHS);356  ConstrainedCmpIntrinsic->replaceAllUsesWith(FCmp);357  EraseFromParent.push_back(dyn_cast<Instruction>(ConstrainedCmpIntrinsic));358}359 360static void lowerExpectAssume(IntrinsicInst *II) {361  // If we cannot use the SPV_KHR_expect_assume extension, then we need to362  // ignore the intrinsic and move on. It should be removed later on by LLVM.363  // Otherwise we should lower the intrinsic to the corresponding SPIR-V364  // instruction.365  // For @llvm.assume we have OpAssumeTrueKHR.366  // For @llvm.expect we have OpExpectKHR.367  //368  // We need to lower this into a builtin and then the builtin into a SPIR-V369  // instruction.370  if (II->getIntrinsicID() == Intrinsic::assume) {371    Function *F = Intrinsic::getOrInsertDeclaration(372        II->getModule(), Intrinsic::SPVIntrinsics::spv_assume);373    II->setCalledFunction(F);374  } else if (II->getIntrinsicID() == Intrinsic::expect) {375    Function *F = Intrinsic::getOrInsertDeclaration(376        II->getModule(), Intrinsic::SPVIntrinsics::spv_expect,377        {II->getOperand(0)->getType()});378    II->setCalledFunction(F);379  } else {380    llvm_unreachable("Unknown intrinsic");381  }382}383 384static bool toSpvLifetimeIntrinsic(IntrinsicInst *II, Intrinsic::ID NewID) {385  IRBuilder<> Builder(II);386  auto *Alloca = cast<AllocaInst>(II->getArgOperand(0));387  std::optional<TypeSize> Size =388      Alloca->getAllocationSize(Alloca->getDataLayout());389  Value *SizeVal = Builder.getInt64(Size ? *Size : -1);390  Builder.CreateIntrinsic(NewID, Alloca->getType(),391                          {SizeVal, II->getArgOperand(0)});392  II->eraseFromParent();393  return true;394}395 396// Substitutes calls to LLVM intrinsics with either calls to SPIR-V intrinsics397// or calls to proper generated functions. Returns True if F was modified.398bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {399  bool Changed = false;400  const SPIRVSubtarget &STI = TM.getSubtarget<SPIRVSubtarget>(*F);401  SmallVector<Instruction *> EraseFromParent;402  for (BasicBlock &BB : *F) {403    for (Instruction &I : make_early_inc_range(BB)) {404      auto Call = dyn_cast<CallInst>(&I);405      if (!Call)406        continue;407      Function *CF = Call->getCalledFunction();408      if (!CF || !CF->isIntrinsic())409        continue;410      auto *II = cast<IntrinsicInst>(Call);411      switch (II->getIntrinsicID()) {412      case Intrinsic::memset:413      case Intrinsic::bswap:414        Changed |= lowerIntrinsicToFunction(II);415        break;416      case Intrinsic::fshl:417      case Intrinsic::fshr:418        lowerFunnelShifts(II);419        Changed = true;420        break;421      case Intrinsic::assume:422      case Intrinsic::expect:423        if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))424          lowerExpectAssume(II);425        Changed = true;426        break;427      case Intrinsic::lifetime_start:428        if (!STI.isShader()) {429          Changed |= toSpvLifetimeIntrinsic(430              II, Intrinsic::SPVIntrinsics::spv_lifetime_start);431        } else {432          II->eraseFromParent();433          Changed = true;434        }435        break;436      case Intrinsic::lifetime_end:437        if (!STI.isShader()) {438          Changed |= toSpvLifetimeIntrinsic(439              II, Intrinsic::SPVIntrinsics::spv_lifetime_end);440        } else {441          II->eraseFromParent();442          Changed = true;443        }444        break;445      case Intrinsic::ptr_annotation:446        lowerPtrAnnotation(II);447        Changed = true;448        break;449      case Intrinsic::experimental_constrained_fcmp:450      case Intrinsic::experimental_constrained_fcmps:451        lowerConstrainedFPCmpIntrinsic(dyn_cast<ConstrainedFPCmpIntrinsic>(II),452                                       EraseFromParent);453        Changed = true;454        break;455      default:456        if (TM.getTargetTriple().getVendor() == Triple::AMD ||457            any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) {458              if (Prefix.empty())459                return false;460              return II->getCalledFunction()->getName().starts_with(Prefix);461            }))462          Changed |= lowerIntrinsicToFunction(II);463        break;464      }465    }466  }467  for (auto *I : EraseFromParent)468    I->eraseFromParent();469  return Changed;470}471 472// Returns F if aggregate argument/return types are not present or cloned F473// function with the types replaced by i32 types. The change in types is474// noted in 'spv.cloned_funcs' metadata for later restoration.475Function *476SPIRVPrepareFunctions::removeAggregateTypesFromSignature(Function *F) {477  bool IsRetAggr = F->getReturnType()->isAggregateType();478  // Allow intrinsics with aggregate return type to reach GlobalISel479  if (F->isIntrinsic() && IsRetAggr)480    return F;481 482  IRBuilder<> B(F->getContext());483 484  bool HasAggrArg = llvm::any_of(F->args(), [](Argument &Arg) {485    return Arg.getType()->isAggregateType();486  });487  bool DoClone = IsRetAggr || HasAggrArg;488  if (!DoClone)489    return F;490  SmallVector<std::pair<int, Type *>, 4> ChangedTypes;491  Type *RetType = IsRetAggr ? B.getInt32Ty() : F->getReturnType();492  if (IsRetAggr)493    ChangedTypes.push_back(std::pair<int, Type *>(-1, F->getReturnType()));494  SmallVector<Type *, 4> ArgTypes;495  for (const auto &Arg : F->args()) {496    if (Arg.getType()->isAggregateType()) {497      ArgTypes.push_back(B.getInt32Ty());498      ChangedTypes.push_back(499          std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));500    } else501      ArgTypes.push_back(Arg.getType());502  }503  FunctionType *NewFTy =504      FunctionType::get(RetType, ArgTypes, F->getFunctionType()->isVarArg());505  Function *NewF =506      Function::Create(NewFTy, F->getLinkage(), F->getName(), *F->getParent());507 508  ValueToValueMapTy VMap;509  auto NewFArgIt = NewF->arg_begin();510  for (auto &Arg : F->args()) {511    StringRef ArgName = Arg.getName();512    NewFArgIt->setName(ArgName);513    VMap[&Arg] = &(*NewFArgIt++);514  }515  SmallVector<ReturnInst *, 8> Returns;516 517  CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,518                    Returns);519  NewF->takeName(F);520 521  NamedMDNode *FuncMD =522      F->getParent()->getOrInsertNamedMetadata("spv.cloned_funcs");523  SmallVector<Metadata *, 2> MDArgs;524  MDArgs.push_back(MDString::get(B.getContext(), NewF->getName()));525  for (auto &ChangedTyP : ChangedTypes)526    MDArgs.push_back(MDNode::get(527        B.getContext(),528        {ConstantAsMetadata::get(B.getInt32(ChangedTyP.first)),529         ValueAsMetadata::get(Constant::getNullValue(ChangedTyP.second))}));530  MDNode *ThisFuncMD = MDNode::get(B.getContext(), MDArgs);531  FuncMD->addOperand(ThisFuncMD);532 533  for (auto *U : make_early_inc_range(F->users())) {534    if (auto *CI = dyn_cast<CallInst>(U))535      CI->mutateFunctionType(NewF->getFunctionType());536    U->replaceUsesOfWith(F, NewF);537  }538 539  // register the mutation540  if (RetType != F->getReturnType())541    TM.getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(542        NewF, F->getReturnType());543  return NewF;544}545 546bool SPIRVPrepareFunctions::runOnModule(Module &M) {547  bool Changed = false;548  for (Function &F : M) {549    Changed |= substituteIntrinsicCalls(&F);550    Changed |= sortBlocks(F);551  }552 553  std::vector<Function *> FuncsWorklist;554  for (auto &F : M)555    FuncsWorklist.push_back(&F);556 557  for (auto *F : FuncsWorklist) {558    Function *NewF = removeAggregateTypesFromSignature(F);559 560    if (NewF != F) {561      F->eraseFromParent();562      Changed = true;563    }564  }565  return Changed;566}567 568ModulePass *569llvm::createSPIRVPrepareFunctionsPass(const SPIRVTargetMachine &TM) {570  return new SPIRVPrepareFunctions(TM);571}572