|  | //===- ConvergenceVerifier.cpp - Verify convergence control -----*- C++ -*-===// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/IR/ConvergenceVerifier.h" | 
|  | #include "llvm/IR/Dominators.h" | 
|  | #include "llvm/IR/GenericConvergenceVerifierImpl.h" | 
|  | #include "llvm/IR/Instructions.h" | 
|  | #include "llvm/IR/SSAContext.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | template <> | 
|  | auto GenericConvergenceVerifier<SSAContext>::getConvOp(const Instruction &I) | 
|  | -> ConvOpKind { | 
|  | const auto *CB = dyn_cast<CallBase>(&I); | 
|  | if (!CB) | 
|  | return CONV_NONE; | 
|  | switch (CB->getIntrinsicID()) { | 
|  | default: | 
|  | return CONV_NONE; | 
|  | case Intrinsic::experimental_convergence_anchor: | 
|  | return CONV_ANCHOR; | 
|  | case Intrinsic::experimental_convergence_entry: | 
|  | return CONV_ENTRY; | 
|  | case Intrinsic::experimental_convergence_loop: | 
|  | return CONV_LOOP; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <> | 
|  | void GenericConvergenceVerifier<SSAContext>::checkConvergenceTokenProduced( | 
|  | const Instruction &I) {} | 
|  |  | 
|  | template <> | 
|  | const Instruction * | 
|  | GenericConvergenceVerifier<SSAContext>::findAndCheckConvergenceTokenUsed( | 
|  | const Instruction &I) { | 
|  | auto *CB = dyn_cast<CallBase>(&I); | 
|  | if (!CB) | 
|  | return nullptr; | 
|  |  | 
|  | unsigned Count = | 
|  | CB->countOperandBundlesOfType(LLVMContext::OB_convergencectrl); | 
|  | CheckOrNull(Count <= 1, | 
|  | "The 'convergencectrl' bundle can occur at most once on a call", | 
|  | {Context.print(CB)}); | 
|  | if (!Count) | 
|  | return nullptr; | 
|  |  | 
|  | auto Bundle = CB->getOperandBundle(LLVMContext::OB_convergencectrl); | 
|  | CheckOrNull(Bundle->Inputs.size() == 1 && | 
|  | Bundle->Inputs[0]->getType()->isTokenTy(), | 
|  | "The 'convergencectrl' bundle requires exactly one token use.", | 
|  | {Context.print(CB)}); | 
|  | auto *Token = Bundle->Inputs[0].get(); | 
|  | auto *Def = dyn_cast<Instruction>(Token); | 
|  |  | 
|  | CheckOrNull(Def && getConvOp(*Def) != CONV_NONE, | 
|  | "Convergence control tokens can only be produced by calls to the " | 
|  | "convergence control intrinsics.", | 
|  | {Context.print(Token), Context.print(&I)}); | 
|  |  | 
|  | if (Def) | 
|  | Tokens[&I] = Def; | 
|  |  | 
|  | return Def; | 
|  | } | 
|  |  | 
|  | template <> | 
|  | bool GenericConvergenceVerifier<SSAContext>::isInsideConvergentFunction( | 
|  | const Instruction &I) { | 
|  | auto *F = I.getFunction(); | 
|  | return F->isConvergent(); | 
|  | } | 
|  |  | 
|  | template <> | 
|  | bool GenericConvergenceVerifier<SSAContext>::isConvergent( | 
|  | const Instruction &I) { | 
|  | if (auto *CB = dyn_cast<CallBase>(&I)) { | 
|  | return CB->isConvergent(); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | template class llvm::GenericConvergenceVerifier<SSAContext>; |