LCOV - code coverage report
Current view: top level - src - llvm-cpufeatures.cpp (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 41 52 78.8 %
Date: 2022-07-17 01:01:28 Functions: 7 9 77.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 22 30 73.3 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : // Lower intrinsics that expose subtarget information to the language. This makes it
       4                 :            : // possible to write code that changes behavior based on, e.g., the availability of
       5                 :            : // specific CPU features.
       6                 :            : //
       7                 :            : // The following intrinsics are supported:
       8                 :            : // - julia.cpu.have_fma.$typ: returns 1 if the platform supports hardware-accelerated FMA.
       9                 :            : //
      10                 :            : // Some of these intrinsics are overloaded, i.e., they are suffixed with a type name.
      11                 :            : // To extend support, make sure codegen (in intrinsics.cpp) knows how to emit them.
      12                 :            : //
      13                 :            : // XXX: can / do we want to make this a codegen pass to enable querying TargetPassConfig
      14                 :            : //      instead of using the global target machine?
      15                 :            : 
      16                 :            : #include "llvm-version.h"
      17                 :            : #include "passes.h"
      18                 :            : 
      19                 :            : #include <llvm/ADT/Statistic.h>
      20                 :            : #include <llvm/IR/Module.h>
      21                 :            : #include <llvm/IR/Constants.h>
      22                 :            : #include <llvm/IR/Instructions.h>
      23                 :            : #include <llvm/IR/PassManager.h>
      24                 :            : #include <llvm/IR/LegacyPassManager.h>
      25                 :            : #include <llvm/IR/Verifier.h>
      26                 :            : #include <llvm/Target/TargetMachine.h>
      27                 :            : #include <llvm/Support/Debug.h>
      28                 :            : 
      29                 :            : #include "julia.h"
      30                 :            : #include "jitlayers.h"
      31                 :            : 
      32                 :            : #define DEBUG_TYPE "cpufeatures"
      33                 :            : 
      34                 :            : using namespace llvm;
      35                 :            : 
      36                 :            : STATISTIC(LoweredWithFMA, "Number of have_fma's that were lowered to true");
      37                 :            : STATISTIC(LoweredWithoutFMA, "Number of have_fma's that were lowered to false");
      38                 :            : 
      39                 :            : extern JuliaOJIT *jl_ExecutionEngine;
      40                 :            : 
      41                 :            : // whether this platform unconditionally (i.e. without needing multiversioning) supports FMA
      42                 :        292 : Optional<bool> always_have_fma(Function &intr) {
      43                 :        292 :     auto intr_name = intr.getName();
      44                 :        292 :     auto typ = intr_name.substr(strlen("julia.cpu.have_fma."));
      45                 :            : 
      46                 :            : #if defined(_CPU_AARCH64_)
      47                 :            :     return typ == "f32" || typ == "f64";
      48                 :            : #else
      49                 :            :     (void)typ;
      50                 :        292 :     return {};
      51                 :            : #endif
      52                 :            : }
      53                 :            : 
      54                 :        248 : bool have_fma(Function &intr, Function &caller) {
      55                 :        248 :     auto unconditional = always_have_fma(intr);
      56         [ -  + ]:        248 :     if (unconditional.hasValue())
      57                 :          0 :         return unconditional.getValue();
      58                 :            : 
      59                 :        248 :     auto intr_name = intr.getName();
      60                 :        248 :     auto typ = intr_name.substr(strlen("julia.cpu.have_fma."));
      61                 :            : 
      62                 :        248 :     Attribute FSAttr = caller.getFnAttribute("target-features");
      63                 :            :     StringRef FS =
      64         [ +  + ]:        248 :         FSAttr.isValid() ? FSAttr.getValueAsString() : jl_ExecutionEngine->getTargetFeatureString();
      65                 :            : 
      66                 :        496 :     SmallVector<StringRef, 6> Features;
      67                 :        248 :     FS.split(Features, ',');
      68         [ +  - ]:       5208 :     for (StringRef Feature : Features)
      69                 :            : #if defined _CPU_ARM_
      70                 :            :       if (Feature == "+vfp4")
      71                 :            :         return typ == "f32" || typ == "f64";
      72                 :            :       else if (Feature == "+vfp4sp")
      73                 :            :         return typ == "f32";
      74                 :            : #else
      75   [ +  +  -  +  :       5208 :       if (Feature == "+fma" || Feature == "+fma4")
                   +  + ]
      76   [ +  -  +  - ]:        248 :         return typ == "f32" || typ == "f64";
      77                 :            : #endif
      78                 :            : 
      79                 :          0 :     return false;
      80                 :            : }
      81                 :            : 
      82                 :        248 : void lowerHaveFMA(Function &intr, Function &caller, CallInst *I) {
      83         [ +  - ]:        248 :     if (have_fma(intr, caller)) {
      84                 :        248 :         ++LoweredWithFMA;
      85                 :        248 :         I->replaceAllUsesWith(ConstantInt::get(I->getType(), 1));
      86                 :            :     } else {
      87                 :          0 :         ++LoweredWithoutFMA;
      88                 :          0 :         I->replaceAllUsesWith(ConstantInt::get(I->getType(), 0));
      89                 :            :     }
      90                 :        248 :     return;
      91                 :            : }
      92                 :            : 
      93                 :      40403 : bool lowerCPUFeatures(Module &M)
      94                 :            : {
      95                 :      80806 :     SmallVector<Instruction*,6> Materialized;
      96                 :            : 
      97         [ +  + ]:     686391 :     for (auto &F: M.functions()) {
      98                 :     645988 :         auto FN = F.getName();
      99                 :            : 
     100         [ +  + ]:     645988 :         if (FN.startswith("julia.cpu.have_fma.")) {
     101         [ +  + ]:        300 :             for (Use &U: F.uses()) {
     102                 :        248 :                 User *RU = U.getUser();
     103                 :        248 :                 CallInst *I = cast<CallInst>(RU);
     104                 :        248 :                 lowerHaveFMA(F, *I->getParent()->getParent(), I);
     105                 :        248 :                 Materialized.push_back(I);
     106                 :            :             }
     107                 :            :         }
     108                 :            :     }
     109                 :            : 
     110         [ +  + ]:      40403 :     if (!Materialized.empty()) {
     111         [ +  + ]:        300 :         for (auto I: Materialized) {
     112                 :        248 :             I->eraseFromParent();
     113                 :            :         }
     114                 :            :         assert(!verifyModule(M));
     115                 :         52 :         return true;
     116                 :            :     } else {
     117                 :      40351 :         return false;
     118                 :            :     }
     119                 :            : }
     120                 :            : 
     121                 :          0 : PreservedAnalyses CPUFeatures::run(Module &M, ModuleAnalysisManager &AM)
     122                 :            : {
     123         [ #  # ]:          0 :     if (lowerCPUFeatures(M)) {
     124                 :          0 :         return PreservedAnalyses::allInSet<CFGAnalyses>();
     125                 :            :     }
     126                 :          0 :     return PreservedAnalyses::all();
     127                 :            : }
     128                 :            : 
     129                 :            : namespace {
     130                 :            : struct CPUFeaturesLegacy : public ModulePass {
     131                 :            :     static char ID;
     132                 :         17 :     CPUFeaturesLegacy() : ModulePass(ID) {};
     133                 :            : 
     134                 :      40403 :     bool runOnModule(Module &M)
     135                 :            :     {
     136                 :      40403 :         return lowerCPUFeatures(M);
     137                 :            :     }
     138                 :            : };
     139                 :            : 
     140                 :            : char CPUFeaturesLegacy::ID = 0;
     141                 :            : static RegisterPass<CPUFeaturesLegacy>
     142                 :            :         Y("CPUFeatures",
     143                 :            :           "Lower calls to CPU feature testing intrinsics.",
     144                 :            :           false,
     145                 :            :           false);
     146                 :            : }
     147                 :            : 
     148                 :         17 : Pass *createCPUFeaturesPass()
     149                 :            : {
     150                 :         17 :     return new CPUFeaturesLegacy();
     151                 :            : }
     152                 :            : 
     153                 :          0 : extern "C" JL_DLLEXPORT void LLVMExtraAddCPUFeaturesPass_impl(LLVMPassManagerRef PM)
     154                 :            : {
     155                 :          0 :     unwrap(PM)->add(createCPUFeaturesPass());
     156                 :          0 : }

Generated by: LCOV version 1.14