| //===- 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>; |