145 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- AMDGPUUnifyMetadata.cpp - Unify OpenCL metadata --------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// \file
 | 
						|
// This pass that unifies multiple OpenCL metadata due to linking.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "AMDGPU.h"
 | 
						|
#include "llvm/IR/Constants.h"
 | 
						|
#include "llvm/IR/Module.h"
 | 
						|
#include "llvm/IR/PassManager.h"
 | 
						|
#include "llvm/Pass.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
  namespace kOCLMD {
 | 
						|
 | 
						|
    const char SpirVer[]            = "opencl.spir.version";
 | 
						|
    const char OCLVer[]             = "opencl.ocl.version";
 | 
						|
    const char UsedExt[]            = "opencl.used.extensions";
 | 
						|
    const char UsedOptCoreFeat[]    = "opencl.used.optional.core.features";
 | 
						|
    const char CompilerOptions[]    = "opencl.compiler.options";
 | 
						|
    const char LLVMIdent[]          = "llvm.ident";
 | 
						|
 | 
						|
  } // end namespace kOCLMD
 | 
						|
 | 
						|
  /// Unify multiple OpenCL metadata due to linking.
 | 
						|
  class AMDGPUUnifyMetadata : public ModulePass {
 | 
						|
  public:
 | 
						|
    static char ID;
 | 
						|
 | 
						|
    explicit AMDGPUUnifyMetadata() : ModulePass(ID) {}
 | 
						|
 | 
						|
  private:
 | 
						|
    bool runOnModule(Module &M) override;
 | 
						|
  };
 | 
						|
 | 
						|
    /// Unify version metadata.
 | 
						|
    /// \return true if changes are made.
 | 
						|
    /// Assume the named metadata has operands each of which is a pair of
 | 
						|
    /// integer constant, e.g.
 | 
						|
    /// !Name = {!n1, !n2}
 | 
						|
    /// !n1 = {i32 1, i32 2}
 | 
						|
    /// !n2 = {i32 2, i32 0}
 | 
						|
    /// Keep the largest version as the sole operand if PickFirst is false.
 | 
						|
    /// Otherwise pick it from the first value, representing kernel module.
 | 
						|
    bool unifyVersionMD(Module &M, StringRef Name, bool PickFirst) {
 | 
						|
      auto NamedMD = M.getNamedMetadata(Name);
 | 
						|
      if (!NamedMD || NamedMD->getNumOperands() <= 1)
 | 
						|
        return false;
 | 
						|
      MDNode *MaxMD = nullptr;
 | 
						|
      auto MaxVer = 0U;
 | 
						|
      for (auto VersionMD : NamedMD->operands()) {
 | 
						|
        assert(VersionMD->getNumOperands() == 2);
 | 
						|
        auto CMajor = mdconst::extract<ConstantInt>(VersionMD->getOperand(0));
 | 
						|
        auto VersionMajor = CMajor->getZExtValue();
 | 
						|
        auto CMinor = mdconst::extract<ConstantInt>(VersionMD->getOperand(1));
 | 
						|
        auto VersionMinor = CMinor->getZExtValue();
 | 
						|
        auto Ver = (VersionMajor * 100) + (VersionMinor * 10);
 | 
						|
        if (Ver > MaxVer) {
 | 
						|
          MaxVer = Ver;
 | 
						|
          MaxMD = VersionMD;
 | 
						|
        }
 | 
						|
        if (PickFirst)
 | 
						|
          break;
 | 
						|
      }
 | 
						|
      NamedMD->eraseFromParent();
 | 
						|
      NamedMD = M.getOrInsertNamedMetadata(Name);
 | 
						|
      NamedMD->addOperand(MaxMD);
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
  /// Unify version metadata.
 | 
						|
  /// \return true if changes are made.
 | 
						|
  /// Assume the named metadata has operands each of which is a list e.g.
 | 
						|
  /// !Name = {!n1, !n2}
 | 
						|
  /// !n1 = !{!"cl_khr_fp16", {!"cl_khr_fp64"}}
 | 
						|
  /// !n2 = !{!"cl_khr_image"}
 | 
						|
  /// Combine it into a single list with unique operands.
 | 
						|
  bool unifyExtensionMD(Module &M, StringRef Name) {
 | 
						|
    auto NamedMD = M.getNamedMetadata(Name);
 | 
						|
    if (!NamedMD || NamedMD->getNumOperands() == 1)
 | 
						|
      return false;
 | 
						|
 | 
						|
    SmallVector<Metadata *, 4> All;
 | 
						|
    for (auto MD : NamedMD->operands())
 | 
						|
      for (const auto &Op : MD->operands())
 | 
						|
        if (!llvm::is_contained(All, Op.get()))
 | 
						|
          All.push_back(Op.get());
 | 
						|
 | 
						|
    NamedMD->eraseFromParent();
 | 
						|
    NamedMD = M.getOrInsertNamedMetadata(Name);
 | 
						|
    for (const auto &MD : All)
 | 
						|
      NamedMD->addOperand(MDNode::get(M.getContext(), MD));
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  bool unifyMetadataImpl(Module &M) {
 | 
						|
    const char *Vers[] = {kOCLMD::SpirVer, kOCLMD::OCLVer};
 | 
						|
    const char *Exts[] = {kOCLMD::UsedExt, kOCLMD::UsedOptCoreFeat,
 | 
						|
                          kOCLMD::CompilerOptions, kOCLMD::LLVMIdent};
 | 
						|
 | 
						|
    bool Changed = false;
 | 
						|
 | 
						|
    for (auto &I : Vers)
 | 
						|
      Changed |= unifyVersionMD(M, I, true);
 | 
						|
 | 
						|
    for (auto &I : Exts)
 | 
						|
      Changed |= unifyExtensionMD(M, I);
 | 
						|
 | 
						|
    return Changed;
 | 
						|
  }
 | 
						|
 | 
						|
  } // end anonymous namespace
 | 
						|
 | 
						|
  char AMDGPUUnifyMetadata::ID = 0;
 | 
						|
 | 
						|
  char &llvm::AMDGPUUnifyMetadataID = AMDGPUUnifyMetadata::ID;
 | 
						|
 | 
						|
  INITIALIZE_PASS(AMDGPUUnifyMetadata, "amdgpu-unify-metadata",
 | 
						|
                  "Unify multiple OpenCL metadata due to linking", false, false)
 | 
						|
 | 
						|
  ModulePass *llvm::createAMDGPUUnifyMetadataPass() {
 | 
						|
    return new AMDGPUUnifyMetadata();
 | 
						|
  }
 | 
						|
 | 
						|
  bool AMDGPUUnifyMetadata::runOnModule(Module &M) {
 | 
						|
    return unifyMetadataImpl(M);
 | 
						|
  }
 | 
						|
 | 
						|
  PreservedAnalyses AMDGPUUnifyMetadataPass::run(Module &M,
 | 
						|
                                                 ModuleAnalysisManager &AM) {
 | 
						|
    return unifyMetadataImpl(M) ? PreservedAnalyses::none()
 | 
						|
                                : PreservedAnalyses::all();
 | 
						|
  }
 |