LCOV - code coverage report
Current view: top level - src - llvm-alloc-helpers.cpp (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 172 211 81.5 %
Date: 2022-07-16 23:42:53 Functions: 6 7 85.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 143 186 76.9 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #include "llvm-version.h"
       4                 :            : #include "llvm-alloc-helpers.h"
       5                 :            : #include "codegen_shared.h"
       6                 :            : #include "julia_assert.h"
       7                 :            : 
       8                 :            : #include <llvm/IR/IntrinsicInst.h>
       9                 :            : 
      10                 :            : using namespace llvm;
      11                 :            : using namespace jl_alloc;
      12                 :            : 
      13                 :    1362400 : static bool hasObjref(Type *ty)
      14                 :            : {
      15         [ +  + ]:    1362400 :     if (auto ptrty = dyn_cast<PointerType>(ty))
      16                 :     644588 :         return ptrty->getAddressSpace() == AddressSpace::Tracked;
      17   [ +  +  +  +  :     717816 :     if (isa<ArrayType>(ty) || isa<VectorType>(ty))
                   +  + ]
      18                 :      60362 :         return hasObjref(GetElementPtrInst::getTypeAtIndex(ty, (uint64_t)0));
      19         [ +  + ]:     657454 :     if (auto structty = dyn_cast<StructType>(ty)) {
      20         [ +  + ]:      15212 :         for (auto elty: structty->elements()) {
      21         [ +  + ]:      14283 :             if (hasObjref(elty)) {
      22                 :       9405 :                 return true;
      23                 :            :             }
      24                 :            :         }
      25                 :            :     }
      26                 :     648049 :     return false;
      27                 :            : }
      28                 :            : 
      29                 :            : std::pair<const uint32_t,Field>&
      30                 :    1287760 : AllocUseInfo::getField(uint32_t offset, uint32_t size, Type *elty)
      31                 :            : {
      32                 :    1287760 :     auto it = findLowerField(offset);
      33                 :    1287760 :     auto end = memops.end();
      34                 :    1287760 :     auto lb = end; // first overlap
      35                 :    1287760 :     auto ub = end; // last overlap
      36         [ +  + ]:    1287760 :     if (it != end) {
      37                 :            :         // The slot found contains the current location
      38         [ +  + ]:     368475 :         if (it->first + it->second.size >= offset + size) {
      39         [ +  + ]:     156733 :             if (it->second.elty != elty)
      40                 :      54095 :                 it->second.elty = nullptr;
      41                 :            :             assert(it->second.elty == nullptr || (it->first == offset && it->second.size == size));
      42                 :     156733 :             return *it;
      43                 :            :         }
      44         [ +  + ]:     211742 :         if (it->first + it->second.size > offset) {
      45                 :          2 :             lb = it;
      46                 :          2 :             ub = it;
      47                 :            :         }
      48                 :            :     }
      49                 :            :     else {
      50                 :     919284 :         it = memops.begin();
      51                 :            :     }
      52                 :            :     // Now find the last slot that overlaps with the current memory location.
      53                 :            :     // Also set `lb` if we didn't find any above.
      54   [ +  +  +  +  :    1342770 :     for (; it != end && it->first < offset + size; ++it) {
                   +  + ]
      55         [ +  + ]:     211746 :         if (lb == end)
      56                 :     211740 :             lb = it;
      57                 :     211746 :         ub = it;
      58                 :            :     }
      59                 :            :     // no overlap found just create a new one.
      60         [ +  + ]:    1131030 :     if (lb == end)
      61                 :     919284 :         return *memops.emplace(offset, Field(size, elty)).first;
      62                 :            :     // We find overlapping but not containing slot we need to merge slot/create new one
      63                 :     211742 :     uint32_t new_offset = std::min(offset, lb->first);
      64                 :     211742 :     uint32_t new_addrub = std::max(offset + uint32_t(size), ub->first + ub->second.size);
      65                 :     211742 :     uint32_t new_size = new_addrub - new_offset;
      66                 :     211742 :     Field field(new_size, nullptr);
      67                 :     211742 :     field.multiloc = true;
      68                 :     211742 :     ++ub;
      69         [ +  + ]:     423488 :     for (it = lb; it != ub; ++it) {
      70                 :     211746 :         field.hasobjref |= it->second.hasobjref;
      71                 :     211746 :         field.hasload |= it->second.hasload;
      72                 :     211746 :         field.hasaggr |= it->second.hasaggr;
      73                 :     211746 :         field.accesses.append(it->second.accesses.begin(), it->second.accesses.end());
      74                 :            :     }
      75                 :     211742 :     memops.erase(lb, ub);
      76                 :     211742 :     return *memops.emplace(new_offset, std::move(field)).first;
      77                 :            : }
      78                 :            : 
      79                 :    1287760 : bool AllocUseInfo::addMemOp(Instruction *inst, unsigned opno, uint32_t offset,
      80                 :            :                                        Type *elty, bool isstore, const DataLayout &DL)
      81                 :            : {
      82                 :    1287760 :     MemOp memop(inst, opno);
      83                 :    1287760 :     memop.offset = offset;
      84                 :    1287760 :     uint64_t size = DL.getTypeStoreSize(elty);
      85                 :    1287760 :     memop.size = size;
      86   [ +  +  +  +  :    1287760 :     memop.isaggr = isa<StructType>(elty) || isa<ArrayType>(elty) || isa<VectorType>(elty);
                   +  + ]
      87                 :    1287760 :     memop.isobjref = hasObjref(elty);
      88                 :    1287760 :     auto &field = getField(offset, size, elty);
      89         [ +  + ]:    1287760 :     if (field.second.hasobjref != memop.isobjref)
      90                 :     555409 :         field.second.multiloc = true; // can't split this field, since it contains a mix of references and bits
      91         [ +  + ]:    1287760 :     if (!isstore)
      92                 :      49484 :         field.second.hasload = true;
      93         [ +  + ]:    1287760 :     if (memop.isobjref) {
      94         [ +  + ]:     644583 :         if (isstore) {
      95                 :     625056 :             refstore = true;
      96                 :            :         }
      97                 :            :         else {
      98                 :      19527 :             refload = true;
      99                 :            :         }
     100         [ +  + ]:     644583 :         if (memop.isaggr)
     101                 :      66817 :             field.second.hasaggr = true;
     102                 :     644583 :         field.second.hasobjref = true;
     103                 :            :     }
     104         [ +  + ]:     643176 :     else if (memop.isaggr) {
     105                 :       2152 :         field.second.hasaggr = true;
     106                 :            :     }
     107                 :    1287760 :     field.second.accesses.push_back(memop);
     108         [ -  + ]:    1287760 :     if (size >= UINT32_MAX - offset)
     109                 :          0 :         return false;
     110                 :    1287760 :     return true;
     111                 :            : }
     112                 :            : 
     113                 :          0 : JL_USED_FUNC void AllocUseInfo::dump()
     114                 :            : {
     115                 :          0 :     jl_safe_printf("escaped: %d\n", escaped);
     116                 :          0 :     jl_safe_printf("addrescaped: %d\n", addrescaped);
     117                 :          0 :     jl_safe_printf("returned: %d\n", returned);
     118                 :          0 :     jl_safe_printf("haserror: %d\n", haserror);
     119                 :          0 :     jl_safe_printf("hasload: %d\n", hasload);
     120                 :          0 :     jl_safe_printf("haspreserve: %d\n", haspreserve);
     121                 :          0 :     jl_safe_printf("hasunknownmem: %d\n", hasunknownmem);
     122                 :          0 :     jl_safe_printf("hastypeof: %d\n", hastypeof);
     123                 :          0 :     jl_safe_printf("refload: %d\n", refload);
     124                 :          0 :     jl_safe_printf("refstore: %d\n", refstore);
     125                 :          0 :     jl_safe_printf("Uses: %d\n", (unsigned)uses.size());
     126         [ #  # ]:          0 :     for (auto inst: uses)
     127                 :          0 :         llvm_dump(inst);
     128         [ #  # ]:          0 :     if (!preserves.empty()) {
     129                 :          0 :         jl_safe_printf("Preserves: %d\n", (unsigned)preserves.size());
     130         [ #  # ]:          0 :         for (auto inst: preserves) {
     131                 :          0 :             llvm_dump(inst);
     132                 :            :         }
     133                 :            :     }
     134         [ #  # ]:          0 :     if (!memops.empty()) {
     135                 :          0 :         jl_safe_printf("Memops: %d\n", (unsigned)memops.size());
     136         [ #  # ]:          0 :         for (auto &field: memops) {
     137                 :          0 :             jl_safe_printf("  Field %d @ %d\n", field.second.size, field.first);
     138                 :          0 :             jl_safe_printf("    Accesses:\n");
     139         [ #  # ]:          0 :             for (auto memop: field.second.accesses) {
     140                 :          0 :                 jl_safe_printf("    ");
     141                 :          0 :                 llvm_dump(memop.inst);
     142                 :            :             }
     143                 :            :         }
     144                 :            :     }
     145                 :          0 : }
     146                 :            : 
     147                 :    1641070 : void jl_alloc::runEscapeAnalysis(llvm::Instruction *I, EscapeAnalysisRequiredArgs required, EscapeAnalysisOptionalArgs options) {
     148                 :    1641070 :     required.use_info.reset();
     149         [ +  + ]:    1641070 :     if (I->use_empty())
     150                 :         89 :         return;
     151                 :    1640980 :     CheckInst::Frame cur{I, 0, I->use_begin(), I->use_end()};
     152                 :    1640980 :     required.check_stack.clear();
     153                 :            : 
     154                 :            :     // Recursion
     155                 :    2556310 :     auto push_inst = [&] (Instruction *inst) {
     156         [ +  + ]:    2556310 :         if (cur.use_it != cur.use_end)
     157                 :    1137570 :             required.check_stack.push_back(cur);
     158                 :    2556310 :         cur.parent = inst;
     159                 :    2556310 :         cur.use_it = inst->use_begin();
     160                 :    2556310 :         cur.use_end = inst->use_end();
     161                 :    4197290 :     };
     162                 :            : 
     163                 :    5887120 :     auto check_inst = [&] (Instruction *inst, Use *use) {
     164         [ +  + ]:    5887120 :         if (isa<LoadInst>(inst)) {
     165                 :    7735600 :             required.use_info.hasload = true;
     166   [ +  -  -  +  :      49484 :             if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, 0, cur.offset,
                   -  + ]
     167                 :            :                                                                inst->getType(),
     168                 :            :                                                                false, required.DL))
     169                 :          0 :                 required.use_info.hasunknownmem = true;
     170                 :      49484 :             return true;
     171                 :            :         }
     172         [ +  + ]:    5837630 :         if (auto call = dyn_cast<CallInst>(inst)) {
     173                 :            :             // TODO handle `memcmp`
     174                 :            :             // None of the intrinsics should care if the memory is stack or heap allocated.
     175                 :    1329060 :             auto callee = call->getCalledOperand();
     176         [ +  + ]:    1329060 :             if (auto II = dyn_cast<IntrinsicInst>(call)) {
     177         [ +  + ]:     315650 :                 if (auto id = II->getIntrinsicID()) {
     178         [ +  + ]:     315122 :                     if (id == Intrinsic::memset) {
     179                 :            :                         assert(call->arg_size() == 4);
     180                 :       3906 :                         if (cur.offset == UINT32_MAX ||
     181         [ +  - ]:       1302 :                             !isa<ConstantInt>(call->getArgOperand(2)) ||
     182   [ +  -  +  -  :       3906 :                             !isa<ConstantInt>(call->getArgOperand(1)) ||
                   -  + ]
     183                 :       1302 :                             (cast<ConstantInt>(call->getArgOperand(2))->getLimitedValue() >=
     184         [ -  + ]:       1302 :                              UINT32_MAX - cur.offset))
     185                 :          0 :                             required.use_info.hasunknownmem = true;
     186                 :     315650 :                         return true;
     187                 :            :                     }
     188   [ +  -  +  -  :     627640 :                     if (id == Intrinsic::lifetime_start || id == Intrinsic::lifetime_end ||
             -  +  -  + ]
     189                 :     313820 :                         isa<DbgInfoIntrinsic>(II))
     190                 :          0 :                         return true;
     191                 :     313820 :                     required.use_info.addrescaped = true;
     192                 :     313820 :                     return true;
     193                 :            :                 }
     194         [ +  - ]:        528 :                 if (required.pass.gc_preserve_begin_func == callee) {
     195         [ +  + ]:        714 :                     for (auto user: call->users())
     196                 :        186 :                         required.use_info.uses.insert(cast<Instruction>(user));
     197                 :        528 :                     required.use_info.preserves.insert(call);
     198                 :        528 :                     required.use_info.haspreserve = true;
     199                 :        528 :                     return true;
     200                 :            :                 }
     201                 :            :             }
     202         [ +  + ]:    1013410 :             if (required.pass.pointer_from_objref_func == callee) {
     203                 :      18946 :                 required.use_info.addrescaped = true;
     204                 :      18946 :                 return true;
     205                 :            :             }
     206         [ +  + ]:     994463 :             if (required.pass.typeof_func == callee) {
     207                 :        307 :                 required.use_info.hastypeof = true;
     208                 :            :                 assert(use->get() == I);
     209                 :        307 :                 return true;
     210                 :            :             }
     211         [ +  + ]:     994156 :             if (required.pass.write_barrier_func == callee ||
     212         [ +  + ]:     928734 :                 required.pass.write_barrier_binding_func == callee)
     213                 :      65790 :                 return true;
     214                 :     928366 :             auto opno = use->getOperandNo();
     215                 :            :             // Uses in `jl_roots` operand bundle are not counted as escaping, everything else is.
     216   [ +  +  -  + ]:     947056 :             if (!call->isBundleOperand(opno) ||
     217         [ +  + ]:     947056 :                 call->getOperandBundleForOperand(opno).getTagName() != "jl_roots") {
     218         [ +  + ]:     909676 :                 if (isa<UnreachableInst>(call->getParent()->getTerminator())) {
     219                 :     455857 :                     required.use_info.haserror = true;
     220                 :     455857 :                     return true;
     221                 :            :                 }
     222                 :     453819 :                 required.use_info.escaped = true;
     223                 :     453819 :                 return false;
     224                 :            :             }
     225                 :      18690 :             required.use_info.haspreserve = true;
     226                 :      18690 :             return true;
     227                 :            :         }
     228         [ +  + ]:    4508570 :         if (auto store = dyn_cast<StoreInst>(inst)) {
     229                 :            :             // Only store value count
     230         [ +  + ]:    1390520 :             if (use->getOperandNo() != StoreInst::getPointerOperandIndex()) {
     231                 :     158027 :                 required.use_info.escaped = true;
     232                 :     158027 :                 return false;
     233                 :            :             }
     234                 :    1232490 :             auto storev = store->getValueOperand();
     235   [ +  -  -  +  :    1232490 :             if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, use->getOperandNo(),
                   -  + ]
     236                 :            :                                                                cur.offset, storev->getType(),
     237                 :            :                                                                true, required.DL))
     238                 :          0 :                 required.use_info.hasunknownmem = true;
     239                 :    1232490 :             return true;
     240                 :            :         }
     241   [ +  +  -  +  :    3118060 :         if (isa<AtomicCmpXchgInst>(inst) || isa<AtomicRMWInst>(inst)) {
                   +  + ]
     242                 :            :             // Only store value count
     243   [ +  -  -  + ]:       5786 :             if (use->getOperandNo() != isa<AtomicCmpXchgInst>(inst) ? AtomicCmpXchgInst::getPointerOperandIndex() : AtomicRMWInst::getPointerOperandIndex()) {
     244                 :          0 :                 required.use_info.escaped = true;
     245                 :          0 :                 return false;
     246                 :            :             }
     247                 :       5786 :             required.use_info.hasload = true;
     248         [ +  - ]:       5786 :             auto storev = isa<AtomicCmpXchgInst>(inst) ? cast<AtomicCmpXchgInst>(inst)->getNewValOperand() : cast<AtomicRMWInst>(inst)->getValOperand();
     249   [ +  -  -  +  :       5786 :             if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, use->getOperandNo(),
                   -  + ]
     250                 :            :                                                                cur.offset, storev->getType(),
     251                 :            :                                                                true, required.DL))
     252                 :          0 :                 required.use_info.hasunknownmem = true;
     253                 :       5786 :             required.use_info.refload = true;
     254                 :       5786 :             return true;
     255                 :            :         }
     256   [ +  +  +  +  :    3112270 :         if (isa<AddrSpaceCastInst>(inst) || isa<BitCastInst>(inst)) {
                   +  + ]
     257                 :    2077480 :             push_inst(inst);
     258                 :    2077480 :             return true;
     259                 :            :         }
     260         [ +  + ]:    1034790 :         if (auto gep = dyn_cast<GetElementPtrInst>(inst)) {
     261                 :     478831 :             uint64_t next_offset = cur.offset;
     262         [ +  - ]:     478831 :             if (cur.offset != UINT32_MAX) {
     263                 :     957662 :                 APInt apoffset(sizeof(void*) * 8, cur.offset, true);
     264   [ +  -  -  +  :     478831 :                 if (!gep->accumulateConstantOffset(required.DL, apoffset) || apoffset.isNegative()) {
                   -  + ]
     265                 :          0 :                     next_offset = UINT32_MAX;
     266                 :            :                 }
     267                 :            :                 else {
     268                 :     478831 :                     next_offset = apoffset.getLimitedValue();
     269         [ -  + ]:     478831 :                     if (next_offset > UINT32_MAX) {
     270                 :          0 :                         next_offset = UINT32_MAX;
     271                 :            :                     }
     272                 :            :                 }
     273                 :            :             }
     274                 :     478831 :             push_inst(inst);
     275                 :     478831 :             cur.offset = (uint32_t)next_offset;
     276                 :     478831 :             return true;
     277                 :            :         }
     278         [ +  + ]:     555960 :         if (isa<ReturnInst>(inst)) {
     279                 :     291879 :             required.use_info.returned = true;
     280                 :     291879 :             return true;
     281                 :            :         }
     282                 :     264081 :         required.use_info.escaped = true;
     283                 :     264081 :         return false;
     284                 :    1640980 :     };
     285                 :            : 
     286                 :            :     while (true) {
     287                 :            :         assert(cur.use_it != cur.use_end);
     288                 :    5887980 :         auto use = &*cur.use_it;
     289                 :    5887980 :         auto inst = dyn_cast<Instruction>(use->getUser());
     290                 :    5887980 :         ++cur.use_it;
     291         [ -  + ]:    5887980 :         if (!inst) {
     292                 :          0 :             required.use_info.escaped = true;
     293                 :          0 :             return;
     294                 :            :         }
     295   [ +  +  +  +  :    5887980 :         if (!options.valid_set || options.valid_set->contains(inst->getParent())) {
                   +  + ]
     296         [ +  + ]:    5887120 :             if (!check_inst(inst, use))
     297                 :     875927 :                 return;
     298                 :    5011190 :             required.use_info.uses.insert(inst);
     299                 :            :         }
     300         [ +  + ]:    5012050 :         if (cur.use_it == cur.use_end) {
     301         [ +  + ]:    1900810 :             if (required.check_stack.empty())
     302                 :     765053 :                 return;
     303                 :    1135760 :             cur = required.check_stack.back();
     304                 :    1135760 :             required.check_stack.pop_back();
     305                 :            :         }
     306                 :    4247000 :     }
     307                 :            : }

Generated by: LCOV version 1.14