LCOV - code coverage report
Current view: top level - src - llvm-gc-invariant-verifier.cpp (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 88 100 88.0 %
Date: 2022-07-16 23:42:53 Functions: 18 20 90.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 51 70 72.9 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : // This LLVM pass verifies invariants required for correct GC root placement.
       4                 :            : // See the devdocs for a description of these invariants.
       5                 :            : 
       6                 :            : #include "llvm-version.h"
       7                 :            : #include "passes.h"
       8                 :            : 
       9                 :            : #include <llvm-c/Core.h>
      10                 :            : #include <llvm-c/Types.h>
      11                 :            : 
      12                 :            : #include <llvm/ADT/BitVector.h>
      13                 :            : #include <llvm/ADT/PostOrderIterator.h>
      14                 :            : #include <llvm/Analysis/CFG.h>
      15                 :            : #include <llvm/IR/Value.h>
      16                 :            : #include <llvm/IR/Constants.h>
      17                 :            : #include <llvm/IR/LegacyPassManager.h>
      18                 :            : #include <llvm/IR/Dominators.h>
      19                 :            : #include <llvm/IR/Function.h>
      20                 :            : #include <llvm/IR/Instructions.h>
      21                 :            : #include <llvm/IR/IntrinsicInst.h>
      22                 :            : #include <llvm/IR/InstVisitor.h>
      23                 :            : #include <llvm/IR/Module.h>
      24                 :            : #include <llvm/IR/IRBuilder.h>
      25                 :            : #include <llvm/IR/Verifier.h>
      26                 :            : #include <llvm/Pass.h>
      27                 :            : #include <llvm/Support/Debug.h>
      28                 :            : 
      29                 :            : #include "codegen_shared.h"
      30                 :            : #include "julia.h"
      31                 :            : 
      32                 :            : #define DEBUG_TYPE "verify_gc_invariants"
      33                 :            : #undef DEBUG
      34                 :            : 
      35                 :            : using namespace llvm;
      36                 :            : 
      37                 :            : struct GCInvariantVerifier : public InstVisitor<GCInvariantVerifier> {
      38                 :            :     bool Broken = false;
      39                 :            :     bool Strong;
      40                 :    1381430 :     GCInvariantVerifier(bool Strong = false) : Strong(Strong) {}
      41                 :            : 
      42                 :            : private:
      43                 :   80252700 :     void Check(bool Cond, const char *message, Value *Val) {
      44         [ -  + ]:   80252700 :         if (!Cond) {
      45                 :          0 :             dbgs() << message << "\n\t" << *Val << "\n";
      46                 :          0 :             Broken = true;
      47                 :            :         }
      48                 :   80252700 :     }
      49                 :            : 
      50                 :            : public:
      51                 :            :     void visitAddrSpaceCastInst(AddrSpaceCastInst &I);
      52                 :            :     void visitLoadInst(LoadInst &LI);
      53                 :            :     void visitStoreInst(StoreInst &SI);
      54                 :            :     void visitAtomicCmpXchgInst(AtomicCmpXchgInst &SI);
      55                 :            :     void visitAtomicRMWInst(AtomicRMWInst &SI);
      56                 :            :     void visitReturnInst(ReturnInst &RI);
      57                 :            :     void visitGetElementPtrInst(GetElementPtrInst &GEP);
      58                 :            :     void visitIntToPtrInst(IntToPtrInst &IPI);
      59                 :            :     void visitPtrToIntInst(PtrToIntInst &PII);
      60                 :            :     void visitCallInst(CallInst &CI);
      61                 :            : 
      62                 :            :     void checkStoreInst(Type *VTy, unsigned AS, Value &SI);
      63                 :            : };
      64                 :            : 
      65                 :   10375400 : void GCInvariantVerifier::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
      66                 :   10375400 :     unsigned FromAS = cast<PointerType>(I.getSrcTy())->getAddressSpace();
      67                 :   10375400 :     unsigned ToAS = cast<PointerType>(I.getDestTy())->getAddressSpace();
      68         [ +  + ]:   10375400 :     if (FromAS == 0)
      69                 :    1583420 :         return;
      70   [ +  -  +  - ]:    8791970 :     Check(ToAS != AddressSpace::Loaded && FromAS != AddressSpace::Loaded,
      71                 :            :           "Illegal address space cast involving loaded ptr", &I);
      72         [ +  + ]:   17583900 :     Check(FromAS != AddressSpace::Tracked ||
      73   [ +  -  +  - ]:   17583900 :           ToAS   == AddressSpace::CalleeRooted ||
      74                 :            :           ToAS   == AddressSpace::Derived,
      75                 :            :           "Illegal address space cast from tracked ptr", &I);
      76   [ +  -  +  - ]:    8791970 :     Check(FromAS != AddressSpace::CalleeRooted &&
      77                 :            :           FromAS != AddressSpace::Derived,
      78                 :            :           "Illegal address space cast from decayed ptr", &I);
      79                 :            : }
      80                 :            : 
      81                 :    9645150 : void GCInvariantVerifier::checkStoreInst(Type *VTy, unsigned AS, Value &SI) {
      82         [ +  + ]:    9645150 :     if (VTy->isPointerTy()) {
      83                 :            :         /* We currently don't obey this for arguments. That's ok - they're
      84                 :            :            externally rooted. */
      85                 :    1985100 :         unsigned AS = cast<PointerType>(VTy)->getAddressSpace();
      86   [ +  -  +  - ]:    1985100 :         Check(AS != AddressSpace::CalleeRooted &&
      87                 :            :               AS != AddressSpace::Derived,
      88                 :            :               "Illegal store of decayed value", &SI);
      89                 :            :     }
      90                 :    9645150 :     Check(AS != AddressSpace::CalleeRooted,
      91                 :            :           "Illegal store to callee rooted value", &SI);
      92                 :    9645150 : }
      93                 :            : 
      94                 :    9626750 : void GCInvariantVerifier::visitStoreInst(StoreInst &SI) {
      95                 :    9626750 :     Type *VTy = SI.getValueOperand()->getType();
      96                 :    9626750 :     checkStoreInst(VTy, SI.getPointerAddressSpace(), SI);
      97                 :    9626750 : }
      98                 :            : 
      99                 :       6303 : void GCInvariantVerifier::visitAtomicRMWInst(AtomicRMWInst &SI) {
     100                 :       6303 :     Type *VTy = SI.getValOperand()->getType();
     101                 :       6303 :     checkStoreInst(VTy, SI.getPointerAddressSpace(), SI);
     102                 :       6303 : }
     103                 :            : 
     104                 :      12099 : void GCInvariantVerifier::visitAtomicCmpXchgInst(AtomicCmpXchgInst &SI) {
     105                 :      12099 :     Type *VTy = SI.getNewValOperand()->getType();
     106                 :      12099 :     checkStoreInst(VTy, SI.getPointerAddressSpace(), SI);
     107                 :      12099 : }
     108                 :            : 
     109                 :   19520000 : void GCInvariantVerifier::visitLoadInst(LoadInst &LI) {
     110                 :   19520000 :     Type *Ty = LI.getType();
     111         [ +  + ]:   19520000 :     if (Ty->isPointerTy()) {
     112                 :    9210560 :         unsigned AS = cast<PointerType>(Ty)->getAddressSpace();
     113   [ +  -  +  - ]:    9210560 :         Check(AS != AddressSpace::CalleeRooted &&
     114                 :            :               AS != AddressSpace::Derived,
     115                 :            :               "Illegal load of gc relevant value", &LI);
     116                 :            :     }
     117                 :   19520000 :     Ty = LI.getPointerOperand()->getType();
     118         [ +  - ]:   19520000 :     if (Ty->isPointerTy()) {
     119                 :   19520000 :         unsigned AS = cast<PointerType>(Ty)->getAddressSpace();
     120                 :   19520000 :         Check(AS != AddressSpace::CalleeRooted,
     121                 :            :               "Illegal load of callee rooted value", &LI);
     122                 :            :     }
     123                 :   19520000 : }
     124                 :            : 
     125                 :   21462100 : static bool isSpecialAS(unsigned AS) {
     126   [ +  +  +  - ]:   21462100 :     return AddressSpace::FirstSpecial <= AS && AS <= AddressSpace::LastSpecial;
     127                 :            : }
     128                 :            : 
     129                 :    1423120 : void GCInvariantVerifier::visitReturnInst(ReturnInst &RI) {
     130         [ +  + ]:    1423120 :     if (!RI.getReturnValue())
     131                 :     186178 :         return;
     132                 :    1236940 :     Type *RTy = RI.getReturnValue()->getType();
     133         [ +  + ]:    1236940 :     if (!RTy->isPointerTy())
     134                 :     226228 :         return;
     135                 :    1010710 :     unsigned AS = cast<PointerType>(RTy)->getAddressSpace();
     136   [ +  +  +  - ]:    1010710 :     Check(!isSpecialAS(AS) || AS == AddressSpace::Tracked,
     137                 :            :           "Only gc tracked values may be directly returned", &RI);
     138                 :            : }
     139                 :            : 
     140                 :   20131900 : void GCInvariantVerifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
     141                 :   20131900 :     Type *Ty = GEP.getType();
     142         [ +  + ]:   20131900 :     if (!Ty->isPointerTy())
     143                 :        121 :         return;
     144                 :   20131800 :     unsigned AS = cast<PointerType>(Ty)->getAddressSpace();
     145         [ +  + ]:   20131800 :     if (!isSpecialAS(AS))
     146                 :   10130300 :         return;
     147                 :            :     /* We're actually ok with GEPs here, as long as they don't feed into any
     148                 :            :        uses. Upstream is currently still debating whether CAST(GEP) == GEP(CAST).
     149                 :            :        In the frontend, we always perform CAST(GEP), so while we can enforce
     150                 :            :        this invariant when we run directly after the frontend (Strong == 1),
     151                 :            :        the optimizer will introduce the other form. Thus, we need to allow it
     152                 :            :        while upstream hasn't decided whether the optimizer is allowed to
     153                 :            :        introduce these.
     154                 :            :        */
     155         [ +  + ]:   10001400 :     if (Strong) {
     156                 :    7011200 :         Check(AS != AddressSpace::Tracked,
     157                 :            :              "GC tracked values may not appear in GEP expressions."
     158                 :            :              " You may have to decay the value first", &GEP);
     159                 :            :     }
     160                 :            : }
     161                 :            : 
     162                 :   17487900 : void GCInvariantVerifier::visitCallInst(CallInst &CI) {
     163                 :   17487900 :     Function *Callee = CI.getCalledFunction();
     164   [ +  +  +  +  :   33246500 :     if (Callee && (Callee->getName() == "julia.call" ||
                   +  + ]
     165         [ +  + ]:   33246500 :                    Callee->getName() == "julia.call2")) {
     166                 :    1149260 :         bool First = true;
     167         [ +  + ]:    6323680 :         for (Value *Arg : CI.args()) {
     168                 :    5174420 :             Type *Ty = Arg->getType();
     169   [ +  -  +  +  :    5174420 :             Check(Ty->isPointerTy() && cast<PointerType>(Ty)->getAddressSpace() == (First ? 0 : AddressSpace::Tracked),
                   +  - ]
     170                 :            :                 "Invalid derived pointer in jlcall", &CI);
     171                 :    5174420 :             First = false;
     172                 :            :         }
     173                 :            :     }
     174                 :   17487900 : }
     175                 :            : 
     176                 :            : /* These next two are caught by the regular verifier on LLVM 5.0+, but we
     177                 :            :    may want to run this on earlier LLVM versions. */
     178                 :      15018 : void GCInvariantVerifier::visitIntToPtrInst(IntToPtrInst &IPI) {
     179                 :      15018 :     Check(!isSpecialAS(IPI.getAddressSpace()),
     180                 :            :           "Illegal inttoptr", &IPI);
     181                 :      15018 : }
     182                 :            : 
     183                 :     304627 : void GCInvariantVerifier::visitPtrToIntInst(PtrToIntInst &PII) {
     184                 :     304627 :     Check(!isSpecialAS(PII.getPointerAddressSpace()),
     185                 :            :           "Illegal inttoptr", &PII);
     186                 :     304627 : }
     187                 :            : 
     188                 :          0 : PreservedAnalyses GCInvariantVerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
     189                 :          0 :     GCInvariantVerifier GIV(Strong);
     190                 :          0 :     GIV.visit(F);
     191         [ #  # ]:          0 :     if (GIV.Broken) {
     192                 :          0 :         abort();
     193                 :            :     }
     194                 :          0 :     return PreservedAnalyses::all();
     195                 :            : }
     196                 :            : 
     197                 :            : struct GCInvariantVerifierLegacy : public FunctionPass {
     198                 :            :     static char ID;
     199                 :            :     bool Strong;
     200                 :       2104 :     GCInvariantVerifierLegacy(bool Strong=false) : FunctionPass(ID), Strong(Strong) {}
     201                 :            : 
     202                 :            : public:
     203                 :       2104 :     void getAnalysisUsage(AnalysisUsage &AU) const override {
     204                 :       2104 :         FunctionPass::getAnalysisUsage(AU);
     205                 :       2104 :         AU.setPreservesAll();
     206                 :       2104 :     }
     207                 :            : 
     208                 :    1381430 :     bool runOnFunction(Function &F) override {
     209                 :    1381430 :         GCInvariantVerifier GIV(Strong);
     210                 :    1381430 :         GIV.visit(F);
     211         [ -  + ]:    1381430 :         if (GIV.Broken) {
     212                 :          0 :             abort();
     213                 :            :         }
     214                 :    1381430 :         return false;
     215                 :            :     }
     216                 :            : };
     217                 :            : 
     218                 :            : char GCInvariantVerifierLegacy::ID = 0;
     219                 :            : static RegisterPass<GCInvariantVerifierLegacy> X("GCInvariantVerifier", "GC Invariant Verification Pass", false, false);
     220                 :            : 
     221                 :       2104 : Pass *createGCInvariantVerifierPass(bool Strong) {
     222                 :       2104 :     return new GCInvariantVerifierLegacy(Strong);
     223                 :            : }
     224                 :            : 
     225                 :          0 : extern "C" JL_DLLEXPORT void LLVMExtraAddGCInvariantVerifierPass_impl(LLVMPassManagerRef PM, LLVMBool Strong)
     226                 :            : {
     227                 :          0 :     unwrap(PM)->add(createGCInvariantVerifierPass(Strong));
     228                 :          0 : }

Generated by: LCOV version 1.14