1*0fca6ea1SDimitry Andric //===-- NumericalStabilitySanitizer.cpp -----------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file contains the instrumentation pass for the numerical sanitizer. 10*0fca6ea1SDimitry Andric // Conceptually the pass injects shadow computations using higher precision 11*0fca6ea1SDimitry Andric // types and inserts consistency checks. For details see the paper 12*0fca6ea1SDimitry Andric // https://arxiv.org/abs/2102.12782. 13*0fca6ea1SDimitry Andric // 14*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h" 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseMap.h" 19*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallString.h" 20*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 21*0fca6ea1SDimitry Andric #include "llvm/ADT/Statistic.h" 22*0fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h" 23*0fca6ea1SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 24*0fca6ea1SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 25*0fca6ea1SDimitry Andric #include "llvm/IR/DataLayout.h" 26*0fca6ea1SDimitry Andric #include "llvm/IR/Function.h" 27*0fca6ea1SDimitry Andric #include "llvm/IR/IRBuilder.h" 28*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 29*0fca6ea1SDimitry Andric #include "llvm/IR/Intrinsics.h" 30*0fca6ea1SDimitry Andric #include "llvm/IR/LLVMContext.h" 31*0fca6ea1SDimitry Andric #include "llvm/IR/MDBuilder.h" 32*0fca6ea1SDimitry Andric #include "llvm/IR/Metadata.h" 33*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 34*0fca6ea1SDimitry Andric #include "llvm/IR/Type.h" 35*0fca6ea1SDimitry Andric #include "llvm/InitializePasses.h" 36*0fca6ea1SDimitry Andric #include "llvm/Support/CommandLine.h" 37*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h" 38*0fca6ea1SDimitry Andric #include "llvm/Support/MathExtras.h" 39*0fca6ea1SDimitry Andric #include "llvm/Support/Regex.h" 40*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h" 41*0fca6ea1SDimitry Andric #include "llvm/Transforms/Instrumentation.h" 42*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 43*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/EscapeEnumerator.h" 44*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 45*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric #include <cstdint> 48*0fca6ea1SDimitry Andric 49*0fca6ea1SDimitry Andric using namespace llvm; 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric #define DEBUG_TYPE "nsan" 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFTLoads, 54*0fca6ea1SDimitry Andric "Number of instrumented floating-point loads"); 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFTCalls, 57*0fca6ea1SDimitry Andric "Number of instrumented floating-point calls"); 58*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFTRets, 59*0fca6ea1SDimitry Andric "Number of instrumented floating-point returns"); 60*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFTStores, 61*0fca6ea1SDimitry Andric "Number of instrumented floating-point stores"); 62*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedNonFTStores, 63*0fca6ea1SDimitry Andric "Number of instrumented non floating-point stores"); 64*0fca6ea1SDimitry Andric STATISTIC( 65*0fca6ea1SDimitry Andric NumInstrumentedNonFTMemcpyStores, 66*0fca6ea1SDimitry Andric "Number of instrumented non floating-point stores with memcpy semantics"); 67*0fca6ea1SDimitry Andric STATISTIC(NumInstrumentedFCmp, "Number of instrumented fcmps"); 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric // Using smaller shadow types types can help improve speed. For example, `dlq` 70*0fca6ea1SDimitry Andric // is 3x slower to 5x faster in opt mode and 2-6x faster in dbg mode compared to 71*0fca6ea1SDimitry Andric // `dqq`. 72*0fca6ea1SDimitry Andric static cl::opt<std::string> ClShadowMapping( 73*0fca6ea1SDimitry Andric "nsan-shadow-type-mapping", cl::init("dqq"), 74*0fca6ea1SDimitry Andric cl::desc("One shadow type id for each of `float`, `double`, `long double`. " 75*0fca6ea1SDimitry Andric "`d`,`l`,`q`,`e` mean double, x86_fp80, fp128 (quad) and " 76*0fca6ea1SDimitry Andric "ppc_fp128 (extended double) respectively. The default is to " 77*0fca6ea1SDimitry Andric "shadow `float` as `double`, and `double` and `x86_fp80` as " 78*0fca6ea1SDimitry Andric "`fp128`"), 79*0fca6ea1SDimitry Andric cl::Hidden); 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric static cl::opt<bool> 82*0fca6ea1SDimitry Andric ClInstrumentFCmp("nsan-instrument-fcmp", cl::init(true), 83*0fca6ea1SDimitry Andric cl::desc("Instrument floating-point comparisons"), 84*0fca6ea1SDimitry Andric cl::Hidden); 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric static cl::opt<std::string> ClCheckFunctionsFilter( 87*0fca6ea1SDimitry Andric "check-functions-filter", 88*0fca6ea1SDimitry Andric cl::desc("Only emit checks for arguments of functions " 89*0fca6ea1SDimitry Andric "whose names match the given regular expression"), 90*0fca6ea1SDimitry Andric cl::value_desc("regex")); 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric static cl::opt<bool> ClTruncateFCmpEq( 93*0fca6ea1SDimitry Andric "nsan-truncate-fcmp-eq", cl::init(true), 94*0fca6ea1SDimitry Andric cl::desc( 95*0fca6ea1SDimitry Andric "This flag controls the behaviour of fcmp equality comparisons." 96*0fca6ea1SDimitry Andric "For equality comparisons such as `x == 0.0f`, we can perform the " 97*0fca6ea1SDimitry Andric "shadow check in the shadow (`x_shadow == 0.0) == (x == 0.0f)`) or app " 98*0fca6ea1SDimitry Andric " domain (`(trunc(x_shadow) == 0.0f) == (x == 0.0f)`). This helps " 99*0fca6ea1SDimitry Andric "catch the case when `x_shadow` is accurate enough (and therefore " 100*0fca6ea1SDimitry Andric "close enough to zero) so that `trunc(x_shadow)` is zero even though " 101*0fca6ea1SDimitry Andric "both `x` and `x_shadow` are not"), 102*0fca6ea1SDimitry Andric cl::Hidden); 103*0fca6ea1SDimitry Andric 104*0fca6ea1SDimitry Andric // When there is external, uninstrumented code writing to memory, the shadow 105*0fca6ea1SDimitry Andric // memory can get out of sync with the application memory. Enabling this flag 106*0fca6ea1SDimitry Andric // emits consistency checks for loads to catch this situation. 107*0fca6ea1SDimitry Andric // When everything is instrumented, this is not strictly necessary because any 108*0fca6ea1SDimitry Andric // load should have a corresponding store, but can help debug cases when the 109*0fca6ea1SDimitry Andric // framework did a bad job at tracking shadow memory modifications by failing on 110*0fca6ea1SDimitry Andric // load rather than store. 111*0fca6ea1SDimitry Andric // TODO: provide a way to resume computations from the FT value when the load 112*0fca6ea1SDimitry Andric // is inconsistent. This ensures that further computations are not polluted. 113*0fca6ea1SDimitry Andric static cl::opt<bool> ClCheckLoads("nsan-check-loads", 114*0fca6ea1SDimitry Andric cl::desc("Check floating-point load"), 115*0fca6ea1SDimitry Andric cl::Hidden); 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric static cl::opt<bool> ClCheckStores("nsan-check-stores", cl::init(true), 118*0fca6ea1SDimitry Andric cl::desc("Check floating-point stores"), 119*0fca6ea1SDimitry Andric cl::Hidden); 120*0fca6ea1SDimitry Andric 121*0fca6ea1SDimitry Andric static cl::opt<bool> ClCheckRet("nsan-check-ret", cl::init(true), 122*0fca6ea1SDimitry Andric cl::desc("Check floating-point return values"), 123*0fca6ea1SDimitry Andric cl::Hidden); 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric // LLVM may store constant floats as bitcasted ints. 126*0fca6ea1SDimitry Andric // It's not really necessary to shadow such stores, 127*0fca6ea1SDimitry Andric // if the shadow value is unknown the framework will re-extend it on load 128*0fca6ea1SDimitry Andric // anyway. Moreover, because of size collisions (e.g. bf16 vs f16) it is 129*0fca6ea1SDimitry Andric // impossible to determine the floating-point type based on the size. 130*0fca6ea1SDimitry Andric // However, for debugging purposes it can be useful to model such stores. 131*0fca6ea1SDimitry Andric static cl::opt<bool> ClPropagateNonFTConstStoresAsFT( 132*0fca6ea1SDimitry Andric "nsan-propagate-non-ft-const-stores-as-ft", 133*0fca6ea1SDimitry Andric cl::desc( 134*0fca6ea1SDimitry Andric "Propagate non floating-point const stores as floating point values." 135*0fca6ea1SDimitry Andric "For debugging purposes only"), 136*0fca6ea1SDimitry Andric cl::Hidden); 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric constexpr StringLiteral kNsanModuleCtorName("nsan.module_ctor"); 139*0fca6ea1SDimitry Andric constexpr StringLiteral kNsanInitName("__nsan_init"); 140*0fca6ea1SDimitry Andric 141*0fca6ea1SDimitry Andric // The following values must be kept in sync with the runtime. 142*0fca6ea1SDimitry Andric constexpr int kShadowScale = 2; 143*0fca6ea1SDimitry Andric constexpr int kMaxVectorWidth = 8; 144*0fca6ea1SDimitry Andric constexpr int kMaxNumArgs = 128; 145*0fca6ea1SDimitry Andric constexpr int kMaxShadowTypeSizeBytes = 16; // fp128 146*0fca6ea1SDimitry Andric 147*0fca6ea1SDimitry Andric namespace { 148*0fca6ea1SDimitry Andric 149*0fca6ea1SDimitry Andric // Defines the characteristics (type id, type, and floating-point semantics) 150*0fca6ea1SDimitry Andric // attached for all possible shadow types. 151*0fca6ea1SDimitry Andric class ShadowTypeConfig { 152*0fca6ea1SDimitry Andric public: 153*0fca6ea1SDimitry Andric static std::unique_ptr<ShadowTypeConfig> fromNsanTypeId(char TypeId); 154*0fca6ea1SDimitry Andric 155*0fca6ea1SDimitry Andric // The LLVM Type corresponding to the shadow type. 156*0fca6ea1SDimitry Andric virtual Type *getType(LLVMContext &Context) const = 0; 157*0fca6ea1SDimitry Andric 158*0fca6ea1SDimitry Andric // The nsan type id of the shadow type (`d`, `l`, `q`, ...). 159*0fca6ea1SDimitry Andric virtual char getNsanTypeId() const = 0; 160*0fca6ea1SDimitry Andric 161*0fca6ea1SDimitry Andric virtual ~ShadowTypeConfig() = default; 162*0fca6ea1SDimitry Andric }; 163*0fca6ea1SDimitry Andric 164*0fca6ea1SDimitry Andric template <char NsanTypeId> 165*0fca6ea1SDimitry Andric class ShadowTypeConfigImpl : public ShadowTypeConfig { 166*0fca6ea1SDimitry Andric public: 167*0fca6ea1SDimitry Andric char getNsanTypeId() const override { return NsanTypeId; } 168*0fca6ea1SDimitry Andric static constexpr const char kNsanTypeId = NsanTypeId; 169*0fca6ea1SDimitry Andric }; 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric // `double` (`d`) shadow type. 172*0fca6ea1SDimitry Andric class F64ShadowConfig : public ShadowTypeConfigImpl<'d'> { 173*0fca6ea1SDimitry Andric Type *getType(LLVMContext &Context) const override { 174*0fca6ea1SDimitry Andric return Type::getDoubleTy(Context); 175*0fca6ea1SDimitry Andric } 176*0fca6ea1SDimitry Andric }; 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric // `x86_fp80` (`l`) shadow type: X86 long double. 179*0fca6ea1SDimitry Andric class F80ShadowConfig : public ShadowTypeConfigImpl<'l'> { 180*0fca6ea1SDimitry Andric Type *getType(LLVMContext &Context) const override { 181*0fca6ea1SDimitry Andric return Type::getX86_FP80Ty(Context); 182*0fca6ea1SDimitry Andric } 183*0fca6ea1SDimitry Andric }; 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric // `fp128` (`q`) shadow type. 186*0fca6ea1SDimitry Andric class F128ShadowConfig : public ShadowTypeConfigImpl<'q'> { 187*0fca6ea1SDimitry Andric Type *getType(LLVMContext &Context) const override { 188*0fca6ea1SDimitry Andric return Type::getFP128Ty(Context); 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric }; 191*0fca6ea1SDimitry Andric 192*0fca6ea1SDimitry Andric // `ppc_fp128` (`e`) shadow type: IBM extended double with 106 bits of mantissa. 193*0fca6ea1SDimitry Andric class PPC128ShadowConfig : public ShadowTypeConfigImpl<'e'> { 194*0fca6ea1SDimitry Andric Type *getType(LLVMContext &Context) const override { 195*0fca6ea1SDimitry Andric return Type::getPPC_FP128Ty(Context); 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric }; 198*0fca6ea1SDimitry Andric 199*0fca6ea1SDimitry Andric // Creates a ShadowTypeConfig given its type id. 200*0fca6ea1SDimitry Andric std::unique_ptr<ShadowTypeConfig> 201*0fca6ea1SDimitry Andric ShadowTypeConfig::fromNsanTypeId(const char TypeId) { 202*0fca6ea1SDimitry Andric switch (TypeId) { 203*0fca6ea1SDimitry Andric case F64ShadowConfig::kNsanTypeId: 204*0fca6ea1SDimitry Andric return std::make_unique<F64ShadowConfig>(); 205*0fca6ea1SDimitry Andric case F80ShadowConfig::kNsanTypeId: 206*0fca6ea1SDimitry Andric return std::make_unique<F80ShadowConfig>(); 207*0fca6ea1SDimitry Andric case F128ShadowConfig::kNsanTypeId: 208*0fca6ea1SDimitry Andric return std::make_unique<F128ShadowConfig>(); 209*0fca6ea1SDimitry Andric case PPC128ShadowConfig::kNsanTypeId: 210*0fca6ea1SDimitry Andric return std::make_unique<PPC128ShadowConfig>(); 211*0fca6ea1SDimitry Andric } 212*0fca6ea1SDimitry Andric report_fatal_error("nsan: invalid shadow type id '" + Twine(TypeId) + "'"); 213*0fca6ea1SDimitry Andric } 214*0fca6ea1SDimitry Andric 215*0fca6ea1SDimitry Andric // An enum corresponding to shadow value types. Used as indices in arrays, so 216*0fca6ea1SDimitry Andric // not an `enum class`. 217*0fca6ea1SDimitry Andric enum FTValueType { kFloat, kDouble, kLongDouble, kNumValueTypes }; 218*0fca6ea1SDimitry Andric 219*0fca6ea1SDimitry Andric // If `FT` corresponds to a primitive FTValueType, return it. 220*0fca6ea1SDimitry Andric static std::optional<FTValueType> ftValueTypeFromType(Type *FT) { 221*0fca6ea1SDimitry Andric if (FT->isFloatTy()) 222*0fca6ea1SDimitry Andric return kFloat; 223*0fca6ea1SDimitry Andric if (FT->isDoubleTy()) 224*0fca6ea1SDimitry Andric return kDouble; 225*0fca6ea1SDimitry Andric if (FT->isX86_FP80Ty()) 226*0fca6ea1SDimitry Andric return kLongDouble; 227*0fca6ea1SDimitry Andric return {}; 228*0fca6ea1SDimitry Andric } 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric // Returns the LLVM type for an FTValueType. 231*0fca6ea1SDimitry Andric static Type *typeFromFTValueType(FTValueType VT, LLVMContext &Context) { 232*0fca6ea1SDimitry Andric switch (VT) { 233*0fca6ea1SDimitry Andric case kFloat: 234*0fca6ea1SDimitry Andric return Type::getFloatTy(Context); 235*0fca6ea1SDimitry Andric case kDouble: 236*0fca6ea1SDimitry Andric return Type::getDoubleTy(Context); 237*0fca6ea1SDimitry Andric case kLongDouble: 238*0fca6ea1SDimitry Andric return Type::getX86_FP80Ty(Context); 239*0fca6ea1SDimitry Andric case kNumValueTypes: 240*0fca6ea1SDimitry Andric return nullptr; 241*0fca6ea1SDimitry Andric } 242*0fca6ea1SDimitry Andric llvm_unreachable("Unhandled FTValueType enum"); 243*0fca6ea1SDimitry Andric } 244*0fca6ea1SDimitry Andric 245*0fca6ea1SDimitry Andric // Returns the type name for an FTValueType. 246*0fca6ea1SDimitry Andric static const char *typeNameFromFTValueType(FTValueType VT) { 247*0fca6ea1SDimitry Andric switch (VT) { 248*0fca6ea1SDimitry Andric case kFloat: 249*0fca6ea1SDimitry Andric return "float"; 250*0fca6ea1SDimitry Andric case kDouble: 251*0fca6ea1SDimitry Andric return "double"; 252*0fca6ea1SDimitry Andric case kLongDouble: 253*0fca6ea1SDimitry Andric return "longdouble"; 254*0fca6ea1SDimitry Andric case kNumValueTypes: 255*0fca6ea1SDimitry Andric return nullptr; 256*0fca6ea1SDimitry Andric } 257*0fca6ea1SDimitry Andric llvm_unreachable("Unhandled FTValueType enum"); 258*0fca6ea1SDimitry Andric } 259*0fca6ea1SDimitry Andric 260*0fca6ea1SDimitry Andric // A specific mapping configuration of application type to shadow type for nsan 261*0fca6ea1SDimitry Andric // (see -nsan-shadow-mapping flag). 262*0fca6ea1SDimitry Andric class MappingConfig { 263*0fca6ea1SDimitry Andric public: 264*0fca6ea1SDimitry Andric explicit MappingConfig(LLVMContext &C) : Context(C) { 265*0fca6ea1SDimitry Andric if (ClShadowMapping.size() != 3) 266*0fca6ea1SDimitry Andric report_fatal_error("Invalid nsan mapping: " + Twine(ClShadowMapping)); 267*0fca6ea1SDimitry Andric unsigned ShadowTypeSizeBits[kNumValueTypes]; 268*0fca6ea1SDimitry Andric for (int VT = 0; VT < kNumValueTypes; ++VT) { 269*0fca6ea1SDimitry Andric auto Config = ShadowTypeConfig::fromNsanTypeId(ClShadowMapping[VT]); 270*0fca6ea1SDimitry Andric if (!Config) 271*0fca6ea1SDimitry Andric report_fatal_error("Failed to get ShadowTypeConfig for " + 272*0fca6ea1SDimitry Andric Twine(ClShadowMapping[VT])); 273*0fca6ea1SDimitry Andric const unsigned AppTypeSize = 274*0fca6ea1SDimitry Andric typeFromFTValueType(static_cast<FTValueType>(VT), Context) 275*0fca6ea1SDimitry Andric ->getScalarSizeInBits(); 276*0fca6ea1SDimitry Andric const unsigned ShadowTypeSize = 277*0fca6ea1SDimitry Andric Config->getType(Context)->getScalarSizeInBits(); 278*0fca6ea1SDimitry Andric // Check that the shadow type size is at most kShadowScale times the 279*0fca6ea1SDimitry Andric // application type size, so that shadow memory compoutations are valid. 280*0fca6ea1SDimitry Andric if (ShadowTypeSize > kShadowScale * AppTypeSize) 281*0fca6ea1SDimitry Andric report_fatal_error("Invalid nsan mapping f" + Twine(AppTypeSize) + 282*0fca6ea1SDimitry Andric "->f" + Twine(ShadowTypeSize) + 283*0fca6ea1SDimitry Andric ": The shadow type size should be at most " + 284*0fca6ea1SDimitry Andric Twine(kShadowScale) + 285*0fca6ea1SDimitry Andric " times the application type size"); 286*0fca6ea1SDimitry Andric ShadowTypeSizeBits[VT] = ShadowTypeSize; 287*0fca6ea1SDimitry Andric Configs[VT] = std::move(Config); 288*0fca6ea1SDimitry Andric } 289*0fca6ea1SDimitry Andric 290*0fca6ea1SDimitry Andric // Check that the mapping is monotonous. This is required because if one 291*0fca6ea1SDimitry Andric // does an fpextend of `float->long double` in application code, nsan is 292*0fca6ea1SDimitry Andric // going to do an fpextend of `shadow(float) -> shadow(long double)` in 293*0fca6ea1SDimitry Andric // shadow code. This will fail in `qql` mode, since nsan would be 294*0fca6ea1SDimitry Andric // fpextending `f128->long`, which is invalid. 295*0fca6ea1SDimitry Andric // TODO: Relax this. 296*0fca6ea1SDimitry Andric if (ShadowTypeSizeBits[kFloat] > ShadowTypeSizeBits[kDouble] || 297*0fca6ea1SDimitry Andric ShadowTypeSizeBits[kDouble] > ShadowTypeSizeBits[kLongDouble]) 298*0fca6ea1SDimitry Andric report_fatal_error("Invalid nsan mapping: { float->f" + 299*0fca6ea1SDimitry Andric Twine(ShadowTypeSizeBits[kFloat]) + "; double->f" + 300*0fca6ea1SDimitry Andric Twine(ShadowTypeSizeBits[kDouble]) + 301*0fca6ea1SDimitry Andric "; long double->f" + 302*0fca6ea1SDimitry Andric Twine(ShadowTypeSizeBits[kLongDouble]) + " }"); 303*0fca6ea1SDimitry Andric } 304*0fca6ea1SDimitry Andric 305*0fca6ea1SDimitry Andric const ShadowTypeConfig &byValueType(FTValueType VT) const { 306*0fca6ea1SDimitry Andric assert(VT < FTValueType::kNumValueTypes && "invalid value type"); 307*0fca6ea1SDimitry Andric return *Configs[VT]; 308*0fca6ea1SDimitry Andric } 309*0fca6ea1SDimitry Andric 310*0fca6ea1SDimitry Andric // Returns the extended shadow type for a given application type. 311*0fca6ea1SDimitry Andric Type *getExtendedFPType(Type *FT) const { 312*0fca6ea1SDimitry Andric if (const auto VT = ftValueTypeFromType(FT)) 313*0fca6ea1SDimitry Andric return Configs[*VT]->getType(Context); 314*0fca6ea1SDimitry Andric if (FT->isVectorTy()) { 315*0fca6ea1SDimitry Andric auto *VecTy = cast<VectorType>(FT); 316*0fca6ea1SDimitry Andric // TODO: add support for scalable vector types. 317*0fca6ea1SDimitry Andric if (VecTy->isScalableTy()) 318*0fca6ea1SDimitry Andric return nullptr; 319*0fca6ea1SDimitry Andric Type *ExtendedScalar = getExtendedFPType(VecTy->getElementType()); 320*0fca6ea1SDimitry Andric return ExtendedScalar 321*0fca6ea1SDimitry Andric ? VectorType::get(ExtendedScalar, VecTy->getElementCount()) 322*0fca6ea1SDimitry Andric : nullptr; 323*0fca6ea1SDimitry Andric } 324*0fca6ea1SDimitry Andric return nullptr; 325*0fca6ea1SDimitry Andric } 326*0fca6ea1SDimitry Andric 327*0fca6ea1SDimitry Andric private: 328*0fca6ea1SDimitry Andric LLVMContext &Context; 329*0fca6ea1SDimitry Andric std::unique_ptr<ShadowTypeConfig> Configs[FTValueType::kNumValueTypes]; 330*0fca6ea1SDimitry Andric }; 331*0fca6ea1SDimitry Andric 332*0fca6ea1SDimitry Andric // The memory extents of a type specifies how many elements of a given 333*0fca6ea1SDimitry Andric // FTValueType needs to be stored when storing this type. 334*0fca6ea1SDimitry Andric struct MemoryExtents { 335*0fca6ea1SDimitry Andric FTValueType ValueType; 336*0fca6ea1SDimitry Andric uint64_t NumElts; 337*0fca6ea1SDimitry Andric }; 338*0fca6ea1SDimitry Andric 339*0fca6ea1SDimitry Andric static MemoryExtents getMemoryExtentsOrDie(Type *FT) { 340*0fca6ea1SDimitry Andric if (const auto VT = ftValueTypeFromType(FT)) 341*0fca6ea1SDimitry Andric return {*VT, 1}; 342*0fca6ea1SDimitry Andric if (auto *VecTy = dyn_cast<VectorType>(FT)) { 343*0fca6ea1SDimitry Andric const auto ScalarExtents = getMemoryExtentsOrDie(VecTy->getElementType()); 344*0fca6ea1SDimitry Andric return {ScalarExtents.ValueType, 345*0fca6ea1SDimitry Andric ScalarExtents.NumElts * VecTy->getElementCount().getFixedValue()}; 346*0fca6ea1SDimitry Andric } 347*0fca6ea1SDimitry Andric llvm_unreachable("invalid value type"); 348*0fca6ea1SDimitry Andric } 349*0fca6ea1SDimitry Andric 350*0fca6ea1SDimitry Andric // The location of a check. Passed as parameters to runtime checking functions. 351*0fca6ea1SDimitry Andric class CheckLoc { 352*0fca6ea1SDimitry Andric public: 353*0fca6ea1SDimitry Andric // Creates a location that references an application memory location. 354*0fca6ea1SDimitry Andric static CheckLoc makeStore(Value *Address) { 355*0fca6ea1SDimitry Andric CheckLoc Result(kStore); 356*0fca6ea1SDimitry Andric Result.Address = Address; 357*0fca6ea1SDimitry Andric return Result; 358*0fca6ea1SDimitry Andric } 359*0fca6ea1SDimitry Andric static CheckLoc makeLoad(Value *Address) { 360*0fca6ea1SDimitry Andric CheckLoc Result(kLoad); 361*0fca6ea1SDimitry Andric Result.Address = Address; 362*0fca6ea1SDimitry Andric return Result; 363*0fca6ea1SDimitry Andric } 364*0fca6ea1SDimitry Andric 365*0fca6ea1SDimitry Andric // Creates a location that references an argument, given by id. 366*0fca6ea1SDimitry Andric static CheckLoc makeArg(int ArgId) { 367*0fca6ea1SDimitry Andric CheckLoc Result(kArg); 368*0fca6ea1SDimitry Andric Result.ArgId = ArgId; 369*0fca6ea1SDimitry Andric return Result; 370*0fca6ea1SDimitry Andric } 371*0fca6ea1SDimitry Andric 372*0fca6ea1SDimitry Andric // Creates a location that references the return value of a function. 373*0fca6ea1SDimitry Andric static CheckLoc makeRet() { return CheckLoc(kRet); } 374*0fca6ea1SDimitry Andric 375*0fca6ea1SDimitry Andric // Creates a location that references a vector insert. 376*0fca6ea1SDimitry Andric static CheckLoc makeInsert() { return CheckLoc(kInsert); } 377*0fca6ea1SDimitry Andric 378*0fca6ea1SDimitry Andric // Returns the CheckType of location this refers to, as an integer-typed LLVM 379*0fca6ea1SDimitry Andric // IR value. 380*0fca6ea1SDimitry Andric Value *getType(LLVMContext &C) const { 381*0fca6ea1SDimitry Andric return ConstantInt::get(Type::getInt32Ty(C), static_cast<int>(CheckTy)); 382*0fca6ea1SDimitry Andric } 383*0fca6ea1SDimitry Andric 384*0fca6ea1SDimitry Andric // Returns a CheckType-specific value representing details of the location 385*0fca6ea1SDimitry Andric // (e.g. application address for loads or stores), as an `IntptrTy`-typed LLVM 386*0fca6ea1SDimitry Andric // IR value. 387*0fca6ea1SDimitry Andric Value *getValue(Type *IntptrTy, IRBuilder<> &Builder) const { 388*0fca6ea1SDimitry Andric switch (CheckTy) { 389*0fca6ea1SDimitry Andric case kUnknown: 390*0fca6ea1SDimitry Andric llvm_unreachable("unknown type"); 391*0fca6ea1SDimitry Andric case kRet: 392*0fca6ea1SDimitry Andric case kInsert: 393*0fca6ea1SDimitry Andric return ConstantInt::get(IntptrTy, 0); 394*0fca6ea1SDimitry Andric case kArg: 395*0fca6ea1SDimitry Andric return ConstantInt::get(IntptrTy, ArgId); 396*0fca6ea1SDimitry Andric case kLoad: 397*0fca6ea1SDimitry Andric case kStore: 398*0fca6ea1SDimitry Andric return Builder.CreatePtrToInt(Address, IntptrTy); 399*0fca6ea1SDimitry Andric } 400*0fca6ea1SDimitry Andric llvm_unreachable("Unhandled CheckType enum"); 401*0fca6ea1SDimitry Andric } 402*0fca6ea1SDimitry Andric 403*0fca6ea1SDimitry Andric private: 404*0fca6ea1SDimitry Andric // Must be kept in sync with the runtime, 405*0fca6ea1SDimitry Andric // see compiler-rt/lib/nsan/nsan_stats.h 406*0fca6ea1SDimitry Andric enum CheckType { 407*0fca6ea1SDimitry Andric kUnknown = 0, 408*0fca6ea1SDimitry Andric kRet, 409*0fca6ea1SDimitry Andric kArg, 410*0fca6ea1SDimitry Andric kLoad, 411*0fca6ea1SDimitry Andric kStore, 412*0fca6ea1SDimitry Andric kInsert, 413*0fca6ea1SDimitry Andric }; 414*0fca6ea1SDimitry Andric explicit CheckLoc(CheckType CheckTy) : CheckTy(CheckTy) {} 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric Value *Address = nullptr; 417*0fca6ea1SDimitry Andric const CheckType CheckTy; 418*0fca6ea1SDimitry Andric int ArgId = -1; 419*0fca6ea1SDimitry Andric }; 420*0fca6ea1SDimitry Andric 421*0fca6ea1SDimitry Andric // A map of LLVM IR values to shadow LLVM IR values. 422*0fca6ea1SDimitry Andric class ValueToShadowMap { 423*0fca6ea1SDimitry Andric public: 424*0fca6ea1SDimitry Andric explicit ValueToShadowMap(const MappingConfig &Config) : Config(Config) {} 425*0fca6ea1SDimitry Andric 426*0fca6ea1SDimitry Andric ValueToShadowMap(const ValueToShadowMap &) = delete; 427*0fca6ea1SDimitry Andric ValueToShadowMap &operator=(const ValueToShadowMap &) = delete; 428*0fca6ea1SDimitry Andric 429*0fca6ea1SDimitry Andric // Sets the shadow value for a value. Asserts that the value does not already 430*0fca6ea1SDimitry Andric // have a value. 431*0fca6ea1SDimitry Andric void setShadow(Value &V, Value &Shadow) { 432*0fca6ea1SDimitry Andric [[maybe_unused]] const bool Inserted = Map.try_emplace(&V, &Shadow).second; 433*0fca6ea1SDimitry Andric LLVM_DEBUG({ 434*0fca6ea1SDimitry Andric if (!Inserted) { 435*0fca6ea1SDimitry Andric if (auto *I = dyn_cast<Instruction>(&V)) 436*0fca6ea1SDimitry Andric errs() << I->getFunction()->getName() << ": "; 437*0fca6ea1SDimitry Andric errs() << "duplicate shadow (" << &V << "): "; 438*0fca6ea1SDimitry Andric V.dump(); 439*0fca6ea1SDimitry Andric } 440*0fca6ea1SDimitry Andric }); 441*0fca6ea1SDimitry Andric assert(Inserted && "duplicate shadow"); 442*0fca6ea1SDimitry Andric } 443*0fca6ea1SDimitry Andric 444*0fca6ea1SDimitry Andric // Returns true if the value already has a shadow (including if the value is a 445*0fca6ea1SDimitry Andric // constant). If true, calling getShadow() is valid. 446*0fca6ea1SDimitry Andric bool hasShadow(Value *V) const { 447*0fca6ea1SDimitry Andric return isa<Constant>(V) || (Map.find(V) != Map.end()); 448*0fca6ea1SDimitry Andric } 449*0fca6ea1SDimitry Andric 450*0fca6ea1SDimitry Andric // Returns the shadow value for a given value. Asserts that the value has 451*0fca6ea1SDimitry Andric // a shadow value. Lazily creates shadows for constant values. 452*0fca6ea1SDimitry Andric Value *getShadow(Value *V) const { 453*0fca6ea1SDimitry Andric if (Constant *C = dyn_cast<Constant>(V)) 454*0fca6ea1SDimitry Andric return getShadowConstant(C); 455*0fca6ea1SDimitry Andric return Map.find(V)->second; 456*0fca6ea1SDimitry Andric } 457*0fca6ea1SDimitry Andric 458*0fca6ea1SDimitry Andric bool empty() const { return Map.empty(); } 459*0fca6ea1SDimitry Andric 460*0fca6ea1SDimitry Andric private: 461*0fca6ea1SDimitry Andric // Extends a constant application value to its shadow counterpart. 462*0fca6ea1SDimitry Andric APFloat extendConstantFP(APFloat CV, const fltSemantics &To) const { 463*0fca6ea1SDimitry Andric bool LosesInfo = false; 464*0fca6ea1SDimitry Andric CV.convert(To, APFloatBase::rmTowardZero, &LosesInfo); 465*0fca6ea1SDimitry Andric return CV; 466*0fca6ea1SDimitry Andric } 467*0fca6ea1SDimitry Andric 468*0fca6ea1SDimitry Andric // Returns the shadow constant for the given application constant. 469*0fca6ea1SDimitry Andric Constant *getShadowConstant(Constant *C) const { 470*0fca6ea1SDimitry Andric if (UndefValue *U = dyn_cast<UndefValue>(C)) { 471*0fca6ea1SDimitry Andric return UndefValue::get(Config.getExtendedFPType(U->getType())); 472*0fca6ea1SDimitry Andric } 473*0fca6ea1SDimitry Andric if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) { 474*0fca6ea1SDimitry Andric // Floating-point constants. 475*0fca6ea1SDimitry Andric Type *Ty = Config.getExtendedFPType(CFP->getType()); 476*0fca6ea1SDimitry Andric return ConstantFP::get( 477*0fca6ea1SDimitry Andric Ty, extendConstantFP(CFP->getValueAPF(), Ty->getFltSemantics())); 478*0fca6ea1SDimitry Andric } 479*0fca6ea1SDimitry Andric // Vector, array, or aggregate constants. 480*0fca6ea1SDimitry Andric if (C->getType()->isVectorTy()) { 481*0fca6ea1SDimitry Andric SmallVector<Constant *, 8> Elements; 482*0fca6ea1SDimitry Andric for (int I = 0, E = cast<VectorType>(C->getType()) 483*0fca6ea1SDimitry Andric ->getElementCount() 484*0fca6ea1SDimitry Andric .getFixedValue(); 485*0fca6ea1SDimitry Andric I < E; ++I) 486*0fca6ea1SDimitry Andric Elements.push_back(getShadowConstant(C->getAggregateElement(I))); 487*0fca6ea1SDimitry Andric return ConstantVector::get(Elements); 488*0fca6ea1SDimitry Andric } 489*0fca6ea1SDimitry Andric llvm_unreachable("unimplemented"); 490*0fca6ea1SDimitry Andric } 491*0fca6ea1SDimitry Andric 492*0fca6ea1SDimitry Andric const MappingConfig &Config; 493*0fca6ea1SDimitry Andric DenseMap<Value *, Value *> Map; 494*0fca6ea1SDimitry Andric }; 495*0fca6ea1SDimitry Andric 496*0fca6ea1SDimitry Andric /// Instantiating NumericalStabilitySanitizer inserts the nsan runtime library 497*0fca6ea1SDimitry Andric /// API function declarations into the module if they don't exist already. 498*0fca6ea1SDimitry Andric /// Instantiating ensures the __nsan_init function is in the list of global 499*0fca6ea1SDimitry Andric /// constructors for the module. 500*0fca6ea1SDimitry Andric class NumericalStabilitySanitizer { 501*0fca6ea1SDimitry Andric public: 502*0fca6ea1SDimitry Andric NumericalStabilitySanitizer(Module &M); 503*0fca6ea1SDimitry Andric bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI); 504*0fca6ea1SDimitry Andric 505*0fca6ea1SDimitry Andric private: 506*0fca6ea1SDimitry Andric bool instrumentMemIntrinsic(MemIntrinsic *MI); 507*0fca6ea1SDimitry Andric void maybeAddSuffixForNsanInterface(CallBase *CI); 508*0fca6ea1SDimitry Andric bool addrPointsToConstantData(Value *Addr); 509*0fca6ea1SDimitry Andric void maybeCreateShadowValue(Instruction &Root, const TargetLibraryInfo &TLI, 510*0fca6ea1SDimitry Andric ValueToShadowMap &Map); 511*0fca6ea1SDimitry Andric Value *createShadowValueWithOperandsAvailable(Instruction &Inst, 512*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI, 513*0fca6ea1SDimitry Andric const ValueToShadowMap &Map); 514*0fca6ea1SDimitry Andric PHINode *maybeCreateShadowPhi(PHINode &Phi, const TargetLibraryInfo &TLI); 515*0fca6ea1SDimitry Andric void createShadowArguments(Function &F, const TargetLibraryInfo &TLI, 516*0fca6ea1SDimitry Andric ValueToShadowMap &Map); 517*0fca6ea1SDimitry Andric 518*0fca6ea1SDimitry Andric void populateShadowStack(CallBase &CI, const TargetLibraryInfo &TLI, 519*0fca6ea1SDimitry Andric const ValueToShadowMap &Map); 520*0fca6ea1SDimitry Andric 521*0fca6ea1SDimitry Andric void propagateShadowValues(Instruction &Inst, const TargetLibraryInfo &TLI, 522*0fca6ea1SDimitry Andric const ValueToShadowMap &Map); 523*0fca6ea1SDimitry Andric Value *emitCheck(Value *V, Value *ShadowV, IRBuilder<> &Builder, 524*0fca6ea1SDimitry Andric CheckLoc Loc); 525*0fca6ea1SDimitry Andric Value *emitCheckInternal(Value *V, Value *ShadowV, IRBuilder<> &Builder, 526*0fca6ea1SDimitry Andric CheckLoc Loc); 527*0fca6ea1SDimitry Andric void emitFCmpCheck(FCmpInst &FCmp, const ValueToShadowMap &Map); 528*0fca6ea1SDimitry Andric 529*0fca6ea1SDimitry Andric // Value creation handlers. 530*0fca6ea1SDimitry Andric Value *handleLoad(LoadInst &Load, Type *VT, Type *ExtendedVT); 531*0fca6ea1SDimitry Andric Value *handleCallBase(CallBase &Call, Type *VT, Type *ExtendedVT, 532*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI, 533*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, IRBuilder<> &Builder); 534*0fca6ea1SDimitry Andric Value *maybeHandleKnownCallBase(CallBase &Call, Type *VT, Type *ExtendedVT, 535*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI, 536*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, 537*0fca6ea1SDimitry Andric IRBuilder<> &Builder); 538*0fca6ea1SDimitry Andric Value *handleTrunc(const FPTruncInst &Trunc, Type *VT, Type *ExtendedVT, 539*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, IRBuilder<> &Builder); 540*0fca6ea1SDimitry Andric Value *handleExt(const FPExtInst &Ext, Type *VT, Type *ExtendedVT, 541*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, IRBuilder<> &Builder); 542*0fca6ea1SDimitry Andric 543*0fca6ea1SDimitry Andric // Value propagation handlers. 544*0fca6ea1SDimitry Andric void propagateFTStore(StoreInst &Store, Type *VT, Type *ExtendedVT, 545*0fca6ea1SDimitry Andric const ValueToShadowMap &Map); 546*0fca6ea1SDimitry Andric void propagateNonFTStore(StoreInst &Store, Type *VT, 547*0fca6ea1SDimitry Andric const ValueToShadowMap &Map); 548*0fca6ea1SDimitry Andric 549*0fca6ea1SDimitry Andric const DataLayout &DL; 550*0fca6ea1SDimitry Andric LLVMContext &Context; 551*0fca6ea1SDimitry Andric MappingConfig Config; 552*0fca6ea1SDimitry Andric IntegerType *IntptrTy = nullptr; 553*0fca6ea1SDimitry Andric FunctionCallee NsanGetShadowPtrForStore[FTValueType::kNumValueTypes] = {}; 554*0fca6ea1SDimitry Andric FunctionCallee NsanGetShadowPtrForLoad[FTValueType::kNumValueTypes] = {}; 555*0fca6ea1SDimitry Andric FunctionCallee NsanCheckValue[FTValueType::kNumValueTypes] = {}; 556*0fca6ea1SDimitry Andric FunctionCallee NsanFCmpFail[FTValueType::kNumValueTypes] = {}; 557*0fca6ea1SDimitry Andric FunctionCallee NsanCopyValues; 558*0fca6ea1SDimitry Andric FunctionCallee NsanSetValueUnknown; 559*0fca6ea1SDimitry Andric FunctionCallee NsanGetRawShadowTypePtr; 560*0fca6ea1SDimitry Andric FunctionCallee NsanGetRawShadowPtr; 561*0fca6ea1SDimitry Andric GlobalValue *NsanShadowRetTag = nullptr; 562*0fca6ea1SDimitry Andric 563*0fca6ea1SDimitry Andric Type *NsanShadowRetType = nullptr; 564*0fca6ea1SDimitry Andric GlobalValue *NsanShadowRetPtr = nullptr; 565*0fca6ea1SDimitry Andric 566*0fca6ea1SDimitry Andric GlobalValue *NsanShadowArgsTag = nullptr; 567*0fca6ea1SDimitry Andric 568*0fca6ea1SDimitry Andric Type *NsanShadowArgsType = nullptr; 569*0fca6ea1SDimitry Andric GlobalValue *NsanShadowArgsPtr = nullptr; 570*0fca6ea1SDimitry Andric 571*0fca6ea1SDimitry Andric std::optional<Regex> CheckFunctionsFilter; 572*0fca6ea1SDimitry Andric }; 573*0fca6ea1SDimitry Andric } // end anonymous namespace 574*0fca6ea1SDimitry Andric 575*0fca6ea1SDimitry Andric PreservedAnalyses 576*0fca6ea1SDimitry Andric NumericalStabilitySanitizerPass::run(Module &M, ModuleAnalysisManager &MAM) { 577*0fca6ea1SDimitry Andric getOrCreateSanitizerCtorAndInitFunctions( 578*0fca6ea1SDimitry Andric M, kNsanModuleCtorName, kNsanInitName, /*InitArgTypes=*/{}, 579*0fca6ea1SDimitry Andric /*InitArgs=*/{}, 580*0fca6ea1SDimitry Andric // This callback is invoked when the functions are created the first 581*0fca6ea1SDimitry Andric // time. Hook them into the global ctors list in that case: 582*0fca6ea1SDimitry Andric [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); }); 583*0fca6ea1SDimitry Andric 584*0fca6ea1SDimitry Andric NumericalStabilitySanitizer Nsan(M); 585*0fca6ea1SDimitry Andric auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 586*0fca6ea1SDimitry Andric for (Function &F : M) 587*0fca6ea1SDimitry Andric Nsan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F)); 588*0fca6ea1SDimitry Andric 589*0fca6ea1SDimitry Andric return PreservedAnalyses::none(); 590*0fca6ea1SDimitry Andric } 591*0fca6ea1SDimitry Andric 592*0fca6ea1SDimitry Andric static GlobalValue *createThreadLocalGV(const char *Name, Module &M, Type *Ty) { 593*0fca6ea1SDimitry Andric return dyn_cast<GlobalValue>(M.getOrInsertGlobal(Name, Ty, [&M, Ty, Name] { 594*0fca6ea1SDimitry Andric return new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, 595*0fca6ea1SDimitry Andric nullptr, Name, nullptr, 596*0fca6ea1SDimitry Andric GlobalVariable::InitialExecTLSModel); 597*0fca6ea1SDimitry Andric })); 598*0fca6ea1SDimitry Andric } 599*0fca6ea1SDimitry Andric 600*0fca6ea1SDimitry Andric NumericalStabilitySanitizer::NumericalStabilitySanitizer(Module &M) 601*0fca6ea1SDimitry Andric : DL(M.getDataLayout()), Context(M.getContext()), Config(Context) { 602*0fca6ea1SDimitry Andric IntptrTy = DL.getIntPtrType(Context); 603*0fca6ea1SDimitry Andric Type *PtrTy = PointerType::getUnqual(Context); 604*0fca6ea1SDimitry Andric Type *Int32Ty = Type::getInt32Ty(Context); 605*0fca6ea1SDimitry Andric Type *Int1Ty = Type::getInt1Ty(Context); 606*0fca6ea1SDimitry Andric Type *VoidTy = Type::getVoidTy(Context); 607*0fca6ea1SDimitry Andric 608*0fca6ea1SDimitry Andric AttributeList Attr; 609*0fca6ea1SDimitry Andric Attr = Attr.addFnAttribute(Context, Attribute::NoUnwind); 610*0fca6ea1SDimitry Andric // Initialize the runtime values (functions and global variables). 611*0fca6ea1SDimitry Andric for (int I = 0; I < kNumValueTypes; ++I) { 612*0fca6ea1SDimitry Andric const FTValueType VT = static_cast<FTValueType>(I); 613*0fca6ea1SDimitry Andric const char *VTName = typeNameFromFTValueType(VT); 614*0fca6ea1SDimitry Andric Type *VTTy = typeFromFTValueType(VT, Context); 615*0fca6ea1SDimitry Andric 616*0fca6ea1SDimitry Andric // Load/store. 617*0fca6ea1SDimitry Andric const std::string GetterPrefix = 618*0fca6ea1SDimitry Andric std::string("__nsan_get_shadow_ptr_for_") + VTName; 619*0fca6ea1SDimitry Andric NsanGetShadowPtrForStore[VT] = M.getOrInsertFunction( 620*0fca6ea1SDimitry Andric GetterPrefix + "_store", Attr, PtrTy, PtrTy, IntptrTy); 621*0fca6ea1SDimitry Andric NsanGetShadowPtrForLoad[VT] = M.getOrInsertFunction( 622*0fca6ea1SDimitry Andric GetterPrefix + "_load", Attr, PtrTy, PtrTy, IntptrTy); 623*0fca6ea1SDimitry Andric 624*0fca6ea1SDimitry Andric // Check. 625*0fca6ea1SDimitry Andric const auto &ShadowConfig = Config.byValueType(VT); 626*0fca6ea1SDimitry Andric Type *ShadowTy = ShadowConfig.getType(Context); 627*0fca6ea1SDimitry Andric NsanCheckValue[VT] = 628*0fca6ea1SDimitry Andric M.getOrInsertFunction(std::string("__nsan_internal_check_") + VTName + 629*0fca6ea1SDimitry Andric "_" + ShadowConfig.getNsanTypeId(), 630*0fca6ea1SDimitry Andric Attr, Int32Ty, VTTy, ShadowTy, Int32Ty, IntptrTy); 631*0fca6ea1SDimitry Andric NsanFCmpFail[VT] = M.getOrInsertFunction( 632*0fca6ea1SDimitry Andric std::string("__nsan_fcmp_fail_") + VTName + "_" + 633*0fca6ea1SDimitry Andric ShadowConfig.getNsanTypeId(), 634*0fca6ea1SDimitry Andric Attr, VoidTy, VTTy, VTTy, ShadowTy, ShadowTy, Int32Ty, Int1Ty, Int1Ty); 635*0fca6ea1SDimitry Andric } 636*0fca6ea1SDimitry Andric 637*0fca6ea1SDimitry Andric NsanCopyValues = M.getOrInsertFunction("__nsan_copy_values", Attr, VoidTy, 638*0fca6ea1SDimitry Andric PtrTy, PtrTy, IntptrTy); 639*0fca6ea1SDimitry Andric NsanSetValueUnknown = M.getOrInsertFunction("__nsan_set_value_unknown", Attr, 640*0fca6ea1SDimitry Andric VoidTy, PtrTy, IntptrTy); 641*0fca6ea1SDimitry Andric 642*0fca6ea1SDimitry Andric // TODO: Add attributes nofree, nosync, readnone, readonly, 643*0fca6ea1SDimitry Andric NsanGetRawShadowTypePtr = M.getOrInsertFunction( 644*0fca6ea1SDimitry Andric "__nsan_internal_get_raw_shadow_type_ptr", Attr, PtrTy, PtrTy); 645*0fca6ea1SDimitry Andric NsanGetRawShadowPtr = M.getOrInsertFunction( 646*0fca6ea1SDimitry Andric "__nsan_internal_get_raw_shadow_ptr", Attr, PtrTy, PtrTy); 647*0fca6ea1SDimitry Andric 648*0fca6ea1SDimitry Andric NsanShadowRetTag = createThreadLocalGV("__nsan_shadow_ret_tag", M, IntptrTy); 649*0fca6ea1SDimitry Andric 650*0fca6ea1SDimitry Andric NsanShadowRetType = ArrayType::get(Type::getInt8Ty(Context), 651*0fca6ea1SDimitry Andric kMaxVectorWidth * kMaxShadowTypeSizeBytes); 652*0fca6ea1SDimitry Andric NsanShadowRetPtr = 653*0fca6ea1SDimitry Andric createThreadLocalGV("__nsan_shadow_ret_ptr", M, NsanShadowRetType); 654*0fca6ea1SDimitry Andric 655*0fca6ea1SDimitry Andric NsanShadowArgsTag = 656*0fca6ea1SDimitry Andric createThreadLocalGV("__nsan_shadow_args_tag", M, IntptrTy); 657*0fca6ea1SDimitry Andric 658*0fca6ea1SDimitry Andric NsanShadowArgsType = 659*0fca6ea1SDimitry Andric ArrayType::get(Type::getInt8Ty(Context), 660*0fca6ea1SDimitry Andric kMaxVectorWidth * kMaxNumArgs * kMaxShadowTypeSizeBytes); 661*0fca6ea1SDimitry Andric 662*0fca6ea1SDimitry Andric NsanShadowArgsPtr = 663*0fca6ea1SDimitry Andric createThreadLocalGV("__nsan_shadow_args_ptr", M, NsanShadowArgsType); 664*0fca6ea1SDimitry Andric 665*0fca6ea1SDimitry Andric if (!ClCheckFunctionsFilter.empty()) { 666*0fca6ea1SDimitry Andric Regex R = Regex(ClCheckFunctionsFilter); 667*0fca6ea1SDimitry Andric std::string RegexError; 668*0fca6ea1SDimitry Andric assert(R.isValid(RegexError)); 669*0fca6ea1SDimitry Andric CheckFunctionsFilter = std::move(R); 670*0fca6ea1SDimitry Andric } 671*0fca6ea1SDimitry Andric } 672*0fca6ea1SDimitry Andric 673*0fca6ea1SDimitry Andric // Returns true if the given LLVM Value points to constant data (typically, a 674*0fca6ea1SDimitry Andric // global variable reference). 675*0fca6ea1SDimitry Andric bool NumericalStabilitySanitizer::addrPointsToConstantData(Value *Addr) { 676*0fca6ea1SDimitry Andric // If this is a GEP, just analyze its pointer operand. 677*0fca6ea1SDimitry Andric if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Addr)) 678*0fca6ea1SDimitry Andric Addr = GEP->getPointerOperand(); 679*0fca6ea1SDimitry Andric 680*0fca6ea1SDimitry Andric if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) 681*0fca6ea1SDimitry Andric return GV->isConstant(); 682*0fca6ea1SDimitry Andric return false; 683*0fca6ea1SDimitry Andric } 684*0fca6ea1SDimitry Andric 685*0fca6ea1SDimitry Andric // This instruments the function entry to create shadow arguments. 686*0fca6ea1SDimitry Andric // Pseudocode: 687*0fca6ea1SDimitry Andric // if (this_fn_ptr == __nsan_shadow_args_tag) { 688*0fca6ea1SDimitry Andric // s(arg0) = LOAD<sizeof(arg0)>(__nsan_shadow_args); 689*0fca6ea1SDimitry Andric // s(arg1) = LOAD<sizeof(arg1)>(__nsan_shadow_args + sizeof(arg0)); 690*0fca6ea1SDimitry Andric // ... 691*0fca6ea1SDimitry Andric // __nsan_shadow_args_tag = 0; 692*0fca6ea1SDimitry Andric // } else { 693*0fca6ea1SDimitry Andric // s(arg0) = fext(arg0); 694*0fca6ea1SDimitry Andric // s(arg1) = fext(arg1); 695*0fca6ea1SDimitry Andric // ... 696*0fca6ea1SDimitry Andric // } 697*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::createShadowArguments( 698*0fca6ea1SDimitry Andric Function &F, const TargetLibraryInfo &TLI, ValueToShadowMap &Map) { 699*0fca6ea1SDimitry Andric assert(!F.getIntrinsicID() && "found a definition of an intrinsic"); 700*0fca6ea1SDimitry Andric 701*0fca6ea1SDimitry Andric // Do not bother if there are no FP args. 702*0fca6ea1SDimitry Andric if (all_of(F.args(), [this](const Argument &Arg) { 703*0fca6ea1SDimitry Andric return Config.getExtendedFPType(Arg.getType()) == nullptr; 704*0fca6ea1SDimitry Andric })) 705*0fca6ea1SDimitry Andric return; 706*0fca6ea1SDimitry Andric 707*0fca6ea1SDimitry Andric IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHI()); 708*0fca6ea1SDimitry Andric // The function has shadow args if the shadow args tag matches the function 709*0fca6ea1SDimitry Andric // address. 710*0fca6ea1SDimitry Andric Value *HasShadowArgs = Builder.CreateICmpEQ( 711*0fca6ea1SDimitry Andric Builder.CreateLoad(IntptrTy, NsanShadowArgsTag, /*isVolatile=*/false), 712*0fca6ea1SDimitry Andric Builder.CreatePtrToInt(&F, IntptrTy)); 713*0fca6ea1SDimitry Andric 714*0fca6ea1SDimitry Andric unsigned ShadowArgsOffsetBytes = 0; 715*0fca6ea1SDimitry Andric for (Argument &Arg : F.args()) { 716*0fca6ea1SDimitry Andric Type *VT = Arg.getType(); 717*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 718*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 719*0fca6ea1SDimitry Andric continue; // Not an FT value. 720*0fca6ea1SDimitry Andric Value *L = Builder.CreateAlignedLoad( 721*0fca6ea1SDimitry Andric ExtendedVT, 722*0fca6ea1SDimitry Andric Builder.CreateConstGEP2_64(NsanShadowArgsType, NsanShadowArgsPtr, 0, 723*0fca6ea1SDimitry Andric ShadowArgsOffsetBytes), 724*0fca6ea1SDimitry Andric Align(1), /*isVolatile=*/false); 725*0fca6ea1SDimitry Andric Value *Shadow = Builder.CreateSelect(HasShadowArgs, L, 726*0fca6ea1SDimitry Andric Builder.CreateFPExt(&Arg, ExtendedVT)); 727*0fca6ea1SDimitry Andric Map.setShadow(Arg, *Shadow); 728*0fca6ea1SDimitry Andric TypeSize SlotSize = DL.getTypeStoreSize(ExtendedVT); 729*0fca6ea1SDimitry Andric assert(!SlotSize.isScalable() && "unsupported"); 730*0fca6ea1SDimitry Andric ShadowArgsOffsetBytes += SlotSize; 731*0fca6ea1SDimitry Andric } 732*0fca6ea1SDimitry Andric Builder.CreateStore(ConstantInt::get(IntptrTy, 0), NsanShadowArgsTag); 733*0fca6ea1SDimitry Andric } 734*0fca6ea1SDimitry Andric 735*0fca6ea1SDimitry Andric // Returns true if the instrumentation should emit code to check arguments 736*0fca6ea1SDimitry Andric // before a function call. 737*0fca6ea1SDimitry Andric static bool shouldCheckArgs(CallBase &CI, const TargetLibraryInfo &TLI, 738*0fca6ea1SDimitry Andric const std::optional<Regex> &CheckFunctionsFilter) { 739*0fca6ea1SDimitry Andric 740*0fca6ea1SDimitry Andric Function *Fn = CI.getCalledFunction(); 741*0fca6ea1SDimitry Andric 742*0fca6ea1SDimitry Andric if (CheckFunctionsFilter) { 743*0fca6ea1SDimitry Andric // Skip checking args of indirect calls. 744*0fca6ea1SDimitry Andric if (Fn == nullptr) 745*0fca6ea1SDimitry Andric return false; 746*0fca6ea1SDimitry Andric if (CheckFunctionsFilter->match(Fn->getName())) 747*0fca6ea1SDimitry Andric return true; 748*0fca6ea1SDimitry Andric return false; 749*0fca6ea1SDimitry Andric } 750*0fca6ea1SDimitry Andric 751*0fca6ea1SDimitry Andric if (Fn == nullptr) 752*0fca6ea1SDimitry Andric return true; // Always check args of indirect calls. 753*0fca6ea1SDimitry Andric 754*0fca6ea1SDimitry Andric // Never check nsan functions, the user called them for a reason. 755*0fca6ea1SDimitry Andric if (Fn->getName().starts_with("__nsan_")) 756*0fca6ea1SDimitry Andric return false; 757*0fca6ea1SDimitry Andric 758*0fca6ea1SDimitry Andric const auto ID = Fn->getIntrinsicID(); 759*0fca6ea1SDimitry Andric LibFunc LFunc = LibFunc::NumLibFuncs; 760*0fca6ea1SDimitry Andric // Always check args of unknown functions. 761*0fca6ea1SDimitry Andric if (ID == Intrinsic::ID() && !TLI.getLibFunc(*Fn, LFunc)) 762*0fca6ea1SDimitry Andric return true; 763*0fca6ea1SDimitry Andric 764*0fca6ea1SDimitry Andric // Do not check args of an `fabs` call that is used for a comparison. 765*0fca6ea1SDimitry Andric // This is typically used for `fabs(a-b) < tolerance`, where what matters is 766*0fca6ea1SDimitry Andric // the result of the comparison, which is already caught be the fcmp checks. 767*0fca6ea1SDimitry Andric if (ID == Intrinsic::fabs || LFunc == LibFunc_fabsf || 768*0fca6ea1SDimitry Andric LFunc == LibFunc_fabs || LFunc == LibFunc_fabsl) 769*0fca6ea1SDimitry Andric for (const auto &U : CI.users()) 770*0fca6ea1SDimitry Andric if (isa<CmpInst>(U)) 771*0fca6ea1SDimitry Andric return false; 772*0fca6ea1SDimitry Andric 773*0fca6ea1SDimitry Andric return true; // Default is check. 774*0fca6ea1SDimitry Andric } 775*0fca6ea1SDimitry Andric 776*0fca6ea1SDimitry Andric // Populates the shadow call stack (which contains shadow values for every 777*0fca6ea1SDimitry Andric // floating-point parameter to the function). 778*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::populateShadowStack( 779*0fca6ea1SDimitry Andric CallBase &CI, const TargetLibraryInfo &TLI, const ValueToShadowMap &Map) { 780*0fca6ea1SDimitry Andric // Do not create a shadow stack for inline asm. 781*0fca6ea1SDimitry Andric if (CI.isInlineAsm()) 782*0fca6ea1SDimitry Andric return; 783*0fca6ea1SDimitry Andric 784*0fca6ea1SDimitry Andric // Do not bother if there are no FP args. 785*0fca6ea1SDimitry Andric if (all_of(CI.operands(), [this](const Value *Arg) { 786*0fca6ea1SDimitry Andric return Config.getExtendedFPType(Arg->getType()) == nullptr; 787*0fca6ea1SDimitry Andric })) 788*0fca6ea1SDimitry Andric return; 789*0fca6ea1SDimitry Andric 790*0fca6ea1SDimitry Andric IRBuilder<> Builder(&CI); 791*0fca6ea1SDimitry Andric SmallVector<Value *, 8> ArgShadows; 792*0fca6ea1SDimitry Andric const bool ShouldCheckArgs = shouldCheckArgs(CI, TLI, CheckFunctionsFilter); 793*0fca6ea1SDimitry Andric for (auto [ArgIdx, Arg] : enumerate(CI.operands())) { 794*0fca6ea1SDimitry Andric if (Config.getExtendedFPType(Arg->getType()) == nullptr) 795*0fca6ea1SDimitry Andric continue; // Not an FT value. 796*0fca6ea1SDimitry Andric Value *ArgShadow = Map.getShadow(Arg); 797*0fca6ea1SDimitry Andric ArgShadows.push_back(ShouldCheckArgs ? emitCheck(Arg, ArgShadow, Builder, 798*0fca6ea1SDimitry Andric CheckLoc::makeArg(ArgIdx)) 799*0fca6ea1SDimitry Andric : ArgShadow); 800*0fca6ea1SDimitry Andric } 801*0fca6ea1SDimitry Andric 802*0fca6ea1SDimitry Andric // Do not create shadow stacks for intrinsics/known lib funcs. 803*0fca6ea1SDimitry Andric if (Function *Fn = CI.getCalledFunction()) { 804*0fca6ea1SDimitry Andric LibFunc LFunc; 805*0fca6ea1SDimitry Andric if (Fn->isIntrinsic() || TLI.getLibFunc(*Fn, LFunc)) 806*0fca6ea1SDimitry Andric return; 807*0fca6ea1SDimitry Andric } 808*0fca6ea1SDimitry Andric 809*0fca6ea1SDimitry Andric // Set the shadow stack tag. 810*0fca6ea1SDimitry Andric Builder.CreateStore(CI.getCalledOperand(), NsanShadowArgsTag); 811*0fca6ea1SDimitry Andric TypeSize ShadowArgsOffsetBytes = TypeSize::getFixed(0); 812*0fca6ea1SDimitry Andric 813*0fca6ea1SDimitry Andric unsigned ShadowArgId = 0; 814*0fca6ea1SDimitry Andric for (const Value *Arg : CI.operands()) { 815*0fca6ea1SDimitry Andric Type *VT = Arg->getType(); 816*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 817*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 818*0fca6ea1SDimitry Andric continue; // Not an FT value. 819*0fca6ea1SDimitry Andric Builder.CreateAlignedStore( 820*0fca6ea1SDimitry Andric ArgShadows[ShadowArgId++], 821*0fca6ea1SDimitry Andric Builder.CreateConstGEP2_64(NsanShadowArgsType, NsanShadowArgsPtr, 0, 822*0fca6ea1SDimitry Andric ShadowArgsOffsetBytes), 823*0fca6ea1SDimitry Andric Align(1), /*isVolatile=*/false); 824*0fca6ea1SDimitry Andric TypeSize SlotSize = DL.getTypeStoreSize(ExtendedVT); 825*0fca6ea1SDimitry Andric assert(!SlotSize.isScalable() && "unsupported"); 826*0fca6ea1SDimitry Andric ShadowArgsOffsetBytes += SlotSize; 827*0fca6ea1SDimitry Andric } 828*0fca6ea1SDimitry Andric } 829*0fca6ea1SDimitry Andric 830*0fca6ea1SDimitry Andric // Internal part of emitCheck(). Returns a value that indicates whether 831*0fca6ea1SDimitry Andric // computation should continue with the shadow or resume by re-fextending the 832*0fca6ea1SDimitry Andric // value. 833*0fca6ea1SDimitry Andric enum class ContinuationType { // Keep in sync with runtime. 834*0fca6ea1SDimitry Andric ContinueWithShadow = 0, 835*0fca6ea1SDimitry Andric ResumeFromValue = 1, 836*0fca6ea1SDimitry Andric }; 837*0fca6ea1SDimitry Andric 838*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::emitCheckInternal(Value *V, Value *ShadowV, 839*0fca6ea1SDimitry Andric IRBuilder<> &Builder, 840*0fca6ea1SDimitry Andric CheckLoc Loc) { 841*0fca6ea1SDimitry Andric // Do not emit checks for constant values, this is redundant. 842*0fca6ea1SDimitry Andric if (isa<Constant>(V)) 843*0fca6ea1SDimitry Andric return ConstantInt::get( 844*0fca6ea1SDimitry Andric Builder.getInt32Ty(), 845*0fca6ea1SDimitry Andric static_cast<int>(ContinuationType::ContinueWithShadow)); 846*0fca6ea1SDimitry Andric 847*0fca6ea1SDimitry Andric Type *Ty = V->getType(); 848*0fca6ea1SDimitry Andric if (const auto VT = ftValueTypeFromType(Ty)) 849*0fca6ea1SDimitry Andric return Builder.CreateCall( 850*0fca6ea1SDimitry Andric NsanCheckValue[*VT], 851*0fca6ea1SDimitry Andric {V, ShadowV, Loc.getType(Context), Loc.getValue(IntptrTy, Builder)}); 852*0fca6ea1SDimitry Andric 853*0fca6ea1SDimitry Andric if (Ty->isVectorTy()) { 854*0fca6ea1SDimitry Andric auto *VecTy = cast<VectorType>(Ty); 855*0fca6ea1SDimitry Andric // We currently skip scalable vector types in MappingConfig, 856*0fca6ea1SDimitry Andric // thus we should not encounter any such types here. 857*0fca6ea1SDimitry Andric assert(!VecTy->isScalableTy() && 858*0fca6ea1SDimitry Andric "Scalable vector types are not supported yet"); 859*0fca6ea1SDimitry Andric Value *CheckResult = nullptr; 860*0fca6ea1SDimitry Andric for (int I = 0, E = VecTy->getElementCount().getFixedValue(); I < E; ++I) { 861*0fca6ea1SDimitry Andric // We resume if any element resumes. Another option would be to create a 862*0fca6ea1SDimitry Andric // vector shuffle with the array of ContinueWithShadow, but that is too 863*0fca6ea1SDimitry Andric // complex. 864*0fca6ea1SDimitry Andric Value *ExtractV = Builder.CreateExtractElement(V, I); 865*0fca6ea1SDimitry Andric Value *ExtractShadowV = Builder.CreateExtractElement(ShadowV, I); 866*0fca6ea1SDimitry Andric Value *ComponentCheckResult = 867*0fca6ea1SDimitry Andric emitCheckInternal(ExtractV, ExtractShadowV, Builder, Loc); 868*0fca6ea1SDimitry Andric CheckResult = CheckResult 869*0fca6ea1SDimitry Andric ? Builder.CreateOr(CheckResult, ComponentCheckResult) 870*0fca6ea1SDimitry Andric : ComponentCheckResult; 871*0fca6ea1SDimitry Andric } 872*0fca6ea1SDimitry Andric return CheckResult; 873*0fca6ea1SDimitry Andric } 874*0fca6ea1SDimitry Andric if (Ty->isArrayTy()) { 875*0fca6ea1SDimitry Andric Value *CheckResult = nullptr; 876*0fca6ea1SDimitry Andric for (auto I : seq(Ty->getArrayNumElements())) { 877*0fca6ea1SDimitry Andric Value *ExtractV = Builder.CreateExtractElement(V, I); 878*0fca6ea1SDimitry Andric Value *ExtractShadowV = Builder.CreateExtractElement(ShadowV, I); 879*0fca6ea1SDimitry Andric Value *ComponentCheckResult = 880*0fca6ea1SDimitry Andric emitCheckInternal(ExtractV, ExtractShadowV, Builder, Loc); 881*0fca6ea1SDimitry Andric CheckResult = CheckResult 882*0fca6ea1SDimitry Andric ? Builder.CreateOr(CheckResult, ComponentCheckResult) 883*0fca6ea1SDimitry Andric : ComponentCheckResult; 884*0fca6ea1SDimitry Andric } 885*0fca6ea1SDimitry Andric return CheckResult; 886*0fca6ea1SDimitry Andric } 887*0fca6ea1SDimitry Andric if (Ty->isStructTy()) { 888*0fca6ea1SDimitry Andric Value *CheckResult = nullptr; 889*0fca6ea1SDimitry Andric for (auto I : seq(Ty->getStructNumElements())) { 890*0fca6ea1SDimitry Andric if (Config.getExtendedFPType(Ty->getStructElementType(I)) == nullptr) 891*0fca6ea1SDimitry Andric continue; // Only check FT values. 892*0fca6ea1SDimitry Andric Value *ExtractV = Builder.CreateExtractValue(V, I); 893*0fca6ea1SDimitry Andric Value *ExtractShadowV = Builder.CreateExtractElement(ShadowV, I); 894*0fca6ea1SDimitry Andric Value *ComponentCheckResult = 895*0fca6ea1SDimitry Andric emitCheckInternal(ExtractV, ExtractShadowV, Builder, Loc); 896*0fca6ea1SDimitry Andric CheckResult = CheckResult 897*0fca6ea1SDimitry Andric ? Builder.CreateOr(CheckResult, ComponentCheckResult) 898*0fca6ea1SDimitry Andric : ComponentCheckResult; 899*0fca6ea1SDimitry Andric } 900*0fca6ea1SDimitry Andric if (!CheckResult) 901*0fca6ea1SDimitry Andric return ConstantInt::get( 902*0fca6ea1SDimitry Andric Builder.getInt32Ty(), 903*0fca6ea1SDimitry Andric static_cast<int>(ContinuationType::ContinueWithShadow)); 904*0fca6ea1SDimitry Andric return CheckResult; 905*0fca6ea1SDimitry Andric } 906*0fca6ea1SDimitry Andric 907*0fca6ea1SDimitry Andric llvm_unreachable("not implemented"); 908*0fca6ea1SDimitry Andric } 909*0fca6ea1SDimitry Andric 910*0fca6ea1SDimitry Andric // Inserts a runtime check of V against its shadow value ShadowV. 911*0fca6ea1SDimitry Andric // We check values whenever they escape: on return, call, stores, and 912*0fca6ea1SDimitry Andric // insertvalue. 913*0fca6ea1SDimitry Andric // Returns the shadow value that should be used to continue the computations, 914*0fca6ea1SDimitry Andric // depending on the answer from the runtime. 915*0fca6ea1SDimitry Andric // TODO: Should we check on select ? phi ? 916*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::emitCheck(Value *V, Value *ShadowV, 917*0fca6ea1SDimitry Andric IRBuilder<> &Builder, 918*0fca6ea1SDimitry Andric CheckLoc Loc) { 919*0fca6ea1SDimitry Andric // Do not emit checks for constant values, this is redundant. 920*0fca6ea1SDimitry Andric if (isa<Constant>(V)) 921*0fca6ea1SDimitry Andric return ShadowV; 922*0fca6ea1SDimitry Andric 923*0fca6ea1SDimitry Andric if (Instruction *Inst = dyn_cast<Instruction>(V)) { 924*0fca6ea1SDimitry Andric Function *F = Inst->getFunction(); 925*0fca6ea1SDimitry Andric if (CheckFunctionsFilter && !CheckFunctionsFilter->match(F->getName())) { 926*0fca6ea1SDimitry Andric return ShadowV; 927*0fca6ea1SDimitry Andric } 928*0fca6ea1SDimitry Andric } 929*0fca6ea1SDimitry Andric 930*0fca6ea1SDimitry Andric Value *CheckResult = emitCheckInternal(V, ShadowV, Builder, Loc); 931*0fca6ea1SDimitry Andric Value *ICmpEQ = Builder.CreateICmpEQ( 932*0fca6ea1SDimitry Andric CheckResult, 933*0fca6ea1SDimitry Andric ConstantInt::get(Builder.getInt32Ty(), 934*0fca6ea1SDimitry Andric static_cast<int>(ContinuationType::ResumeFromValue))); 935*0fca6ea1SDimitry Andric return Builder.CreateSelect( 936*0fca6ea1SDimitry Andric ICmpEQ, Builder.CreateFPExt(V, Config.getExtendedFPType(V->getType())), 937*0fca6ea1SDimitry Andric ShadowV); 938*0fca6ea1SDimitry Andric } 939*0fca6ea1SDimitry Andric 940*0fca6ea1SDimitry Andric // Inserts a check that fcmp on shadow values are consistent with that on base 941*0fca6ea1SDimitry Andric // values. 942*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::emitFCmpCheck(FCmpInst &FCmp, 943*0fca6ea1SDimitry Andric const ValueToShadowMap &Map) { 944*0fca6ea1SDimitry Andric if (!ClInstrumentFCmp) 945*0fca6ea1SDimitry Andric return; 946*0fca6ea1SDimitry Andric 947*0fca6ea1SDimitry Andric Function *F = FCmp.getFunction(); 948*0fca6ea1SDimitry Andric if (CheckFunctionsFilter && !CheckFunctionsFilter->match(F->getName())) 949*0fca6ea1SDimitry Andric return; 950*0fca6ea1SDimitry Andric 951*0fca6ea1SDimitry Andric Value *LHS = FCmp.getOperand(0); 952*0fca6ea1SDimitry Andric if (Config.getExtendedFPType(LHS->getType()) == nullptr) 953*0fca6ea1SDimitry Andric return; 954*0fca6ea1SDimitry Andric Value *RHS = FCmp.getOperand(1); 955*0fca6ea1SDimitry Andric 956*0fca6ea1SDimitry Andric // Split the basic block. On mismatch, we'll jump to the new basic block with 957*0fca6ea1SDimitry Andric // a call to the runtime for error reporting. 958*0fca6ea1SDimitry Andric BasicBlock *FCmpBB = FCmp.getParent(); 959*0fca6ea1SDimitry Andric BasicBlock *NextBB = FCmpBB->splitBasicBlock(FCmp.getNextNode()); 960*0fca6ea1SDimitry Andric // Remove the newly created terminator unconditional branch. 961*0fca6ea1SDimitry Andric FCmpBB->back().eraseFromParent(); 962*0fca6ea1SDimitry Andric BasicBlock *FailBB = 963*0fca6ea1SDimitry Andric BasicBlock::Create(Context, "", FCmpBB->getParent(), NextBB); 964*0fca6ea1SDimitry Andric 965*0fca6ea1SDimitry Andric // Create the shadow fcmp and comparison between the fcmps. 966*0fca6ea1SDimitry Andric IRBuilder<> FCmpBuilder(FCmpBB); 967*0fca6ea1SDimitry Andric FCmpBuilder.SetCurrentDebugLocation(FCmp.getDebugLoc()); 968*0fca6ea1SDimitry Andric Value *ShadowLHS = Map.getShadow(LHS); 969*0fca6ea1SDimitry Andric Value *ShadowRHS = Map.getShadow(RHS); 970*0fca6ea1SDimitry Andric // See comment on ClTruncateFCmpEq. 971*0fca6ea1SDimitry Andric if (FCmp.isEquality() && ClTruncateFCmpEq) { 972*0fca6ea1SDimitry Andric Type *Ty = ShadowLHS->getType(); 973*0fca6ea1SDimitry Andric ShadowLHS = FCmpBuilder.CreateFPExt( 974*0fca6ea1SDimitry Andric FCmpBuilder.CreateFPTrunc(ShadowLHS, LHS->getType()), Ty); 975*0fca6ea1SDimitry Andric ShadowRHS = FCmpBuilder.CreateFPExt( 976*0fca6ea1SDimitry Andric FCmpBuilder.CreateFPTrunc(ShadowRHS, RHS->getType()), Ty); 977*0fca6ea1SDimitry Andric } 978*0fca6ea1SDimitry Andric Value *ShadowFCmp = 979*0fca6ea1SDimitry Andric FCmpBuilder.CreateFCmp(FCmp.getPredicate(), ShadowLHS, ShadowRHS); 980*0fca6ea1SDimitry Andric Value *OriginalAndShadowFcmpMatch = 981*0fca6ea1SDimitry Andric FCmpBuilder.CreateICmpEQ(&FCmp, ShadowFCmp); 982*0fca6ea1SDimitry Andric 983*0fca6ea1SDimitry Andric if (OriginalAndShadowFcmpMatch->getType()->isVectorTy()) { 984*0fca6ea1SDimitry Andric // If we have a vector type, `OriginalAndShadowFcmpMatch` is a vector of i1, 985*0fca6ea1SDimitry Andric // where an element is true if the corresponding elements in original and 986*0fca6ea1SDimitry Andric // shadow are the same. We want all elements to be 1. 987*0fca6ea1SDimitry Andric OriginalAndShadowFcmpMatch = 988*0fca6ea1SDimitry Andric FCmpBuilder.CreateAndReduce(OriginalAndShadowFcmpMatch); 989*0fca6ea1SDimitry Andric } 990*0fca6ea1SDimitry Andric 991*0fca6ea1SDimitry Andric // Use MDBuilder(*C).createLikelyBranchWeights() because "match" is the common 992*0fca6ea1SDimitry Andric // case. 993*0fca6ea1SDimitry Andric FCmpBuilder.CreateCondBr(OriginalAndShadowFcmpMatch, NextBB, FailBB, 994*0fca6ea1SDimitry Andric MDBuilder(Context).createLikelyBranchWeights()); 995*0fca6ea1SDimitry Andric 996*0fca6ea1SDimitry Andric // Fill in FailBB. 997*0fca6ea1SDimitry Andric IRBuilder<> FailBuilder(FailBB); 998*0fca6ea1SDimitry Andric FailBuilder.SetCurrentDebugLocation(FCmp.getDebugLoc()); 999*0fca6ea1SDimitry Andric 1000*0fca6ea1SDimitry Andric const auto EmitFailCall = [this, &FCmp, &FCmpBuilder, 1001*0fca6ea1SDimitry Andric &FailBuilder](Value *L, Value *R, Value *ShadowL, 1002*0fca6ea1SDimitry Andric Value *ShadowR, Value *Result, 1003*0fca6ea1SDimitry Andric Value *ShadowResult) { 1004*0fca6ea1SDimitry Andric Type *FT = L->getType(); 1005*0fca6ea1SDimitry Andric FunctionCallee *Callee = nullptr; 1006*0fca6ea1SDimitry Andric if (FT->isFloatTy()) { 1007*0fca6ea1SDimitry Andric Callee = &(NsanFCmpFail[kFloat]); 1008*0fca6ea1SDimitry Andric } else if (FT->isDoubleTy()) { 1009*0fca6ea1SDimitry Andric Callee = &(NsanFCmpFail[kDouble]); 1010*0fca6ea1SDimitry Andric } else if (FT->isX86_FP80Ty()) { 1011*0fca6ea1SDimitry Andric // TODO: make NsanFCmpFailLongDouble work. 1012*0fca6ea1SDimitry Andric Callee = &(NsanFCmpFail[kDouble]); 1013*0fca6ea1SDimitry Andric L = FailBuilder.CreateFPTrunc(L, Type::getDoubleTy(Context)); 1014*0fca6ea1SDimitry Andric R = FailBuilder.CreateFPTrunc(L, Type::getDoubleTy(Context)); 1015*0fca6ea1SDimitry Andric } else { 1016*0fca6ea1SDimitry Andric llvm_unreachable("not implemented"); 1017*0fca6ea1SDimitry Andric } 1018*0fca6ea1SDimitry Andric FailBuilder.CreateCall(*Callee, {L, R, ShadowL, ShadowR, 1019*0fca6ea1SDimitry Andric ConstantInt::get(FCmpBuilder.getInt32Ty(), 1020*0fca6ea1SDimitry Andric FCmp.getPredicate()), 1021*0fca6ea1SDimitry Andric Result, ShadowResult}); 1022*0fca6ea1SDimitry Andric }; 1023*0fca6ea1SDimitry Andric if (LHS->getType()->isVectorTy()) { 1024*0fca6ea1SDimitry Andric for (int I = 0, E = cast<VectorType>(LHS->getType()) 1025*0fca6ea1SDimitry Andric ->getElementCount() 1026*0fca6ea1SDimitry Andric .getFixedValue(); 1027*0fca6ea1SDimitry Andric I < E; ++I) { 1028*0fca6ea1SDimitry Andric Value *ExtractLHS = FailBuilder.CreateExtractElement(LHS, I); 1029*0fca6ea1SDimitry Andric Value *ExtractRHS = FailBuilder.CreateExtractElement(RHS, I); 1030*0fca6ea1SDimitry Andric Value *ExtractShaodwLHS = FailBuilder.CreateExtractElement(ShadowLHS, I); 1031*0fca6ea1SDimitry Andric Value *ExtractShaodwRHS = FailBuilder.CreateExtractElement(ShadowRHS, I); 1032*0fca6ea1SDimitry Andric Value *ExtractFCmp = FailBuilder.CreateExtractElement(&FCmp, I); 1033*0fca6ea1SDimitry Andric Value *ExtractShadowFCmp = 1034*0fca6ea1SDimitry Andric FailBuilder.CreateExtractElement(ShadowFCmp, I); 1035*0fca6ea1SDimitry Andric EmitFailCall(ExtractLHS, ExtractRHS, ExtractShaodwLHS, ExtractShaodwRHS, 1036*0fca6ea1SDimitry Andric ExtractFCmp, ExtractShadowFCmp); 1037*0fca6ea1SDimitry Andric } 1038*0fca6ea1SDimitry Andric } else { 1039*0fca6ea1SDimitry Andric EmitFailCall(LHS, RHS, ShadowLHS, ShadowRHS, &FCmp, ShadowFCmp); 1040*0fca6ea1SDimitry Andric } 1041*0fca6ea1SDimitry Andric FailBuilder.CreateBr(NextBB); 1042*0fca6ea1SDimitry Andric 1043*0fca6ea1SDimitry Andric ++NumInstrumentedFCmp; 1044*0fca6ea1SDimitry Andric } 1045*0fca6ea1SDimitry Andric 1046*0fca6ea1SDimitry Andric // Creates a shadow phi value for any phi that defines a value of FT type. 1047*0fca6ea1SDimitry Andric PHINode *NumericalStabilitySanitizer::maybeCreateShadowPhi( 1048*0fca6ea1SDimitry Andric PHINode &Phi, const TargetLibraryInfo &TLI) { 1049*0fca6ea1SDimitry Andric Type *VT = Phi.getType(); 1050*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1051*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 1052*0fca6ea1SDimitry Andric return nullptr; // Not an FT value. 1053*0fca6ea1SDimitry Andric // The phi operands are shadow values and are not available when the phi is 1054*0fca6ea1SDimitry Andric // created. They will be populated in a final phase, once all shadow values 1055*0fca6ea1SDimitry Andric // have been created. 1056*0fca6ea1SDimitry Andric PHINode *Shadow = PHINode::Create(ExtendedVT, Phi.getNumIncomingValues()); 1057*0fca6ea1SDimitry Andric Shadow->insertAfter(&Phi); 1058*0fca6ea1SDimitry Andric return Shadow; 1059*0fca6ea1SDimitry Andric } 1060*0fca6ea1SDimitry Andric 1061*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::handleLoad(LoadInst &Load, Type *VT, 1062*0fca6ea1SDimitry Andric Type *ExtendedVT) { 1063*0fca6ea1SDimitry Andric IRBuilder<> Builder(Load.getNextNode()); 1064*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Load.getDebugLoc()); 1065*0fca6ea1SDimitry Andric if (addrPointsToConstantData(Load.getPointerOperand())) { 1066*0fca6ea1SDimitry Andric // No need to look into the shadow memory, the value is a constant. Just 1067*0fca6ea1SDimitry Andric // convert from FT to 2FT. 1068*0fca6ea1SDimitry Andric return Builder.CreateFPExt(&Load, ExtendedVT); 1069*0fca6ea1SDimitry Andric } 1070*0fca6ea1SDimitry Andric 1071*0fca6ea1SDimitry Andric // if (%shadowptr == &) 1072*0fca6ea1SDimitry Andric // %shadow = fpext %v 1073*0fca6ea1SDimitry Andric // else 1074*0fca6ea1SDimitry Andric // %shadow = load (ptrcast %shadow_ptr)) 1075*0fca6ea1SDimitry Andric // Considered options here: 1076*0fca6ea1SDimitry Andric // - Have `NsanGetShadowPtrForLoad` return a fixed address 1077*0fca6ea1SDimitry Andric // &__nsan_unknown_value_shadow_address that is valid to load from, and 1078*0fca6ea1SDimitry Andric // use a select. This has the advantage that the generated IR is simpler. 1079*0fca6ea1SDimitry Andric // - Have `NsanGetShadowPtrForLoad` return nullptr. Because `select` does 1080*0fca6ea1SDimitry Andric // not short-circuit, dereferencing the returned pointer is no longer an 1081*0fca6ea1SDimitry Andric // option, have to split and create a separate basic block. This has the 1082*0fca6ea1SDimitry Andric // advantage of being easier to debug because it crashes if we ever mess 1083*0fca6ea1SDimitry Andric // up. 1084*0fca6ea1SDimitry Andric 1085*0fca6ea1SDimitry Andric const auto Extents = getMemoryExtentsOrDie(VT); 1086*0fca6ea1SDimitry Andric Value *ShadowPtr = Builder.CreateCall( 1087*0fca6ea1SDimitry Andric NsanGetShadowPtrForLoad[Extents.ValueType], 1088*0fca6ea1SDimitry Andric {Load.getPointerOperand(), ConstantInt::get(IntptrTy, Extents.NumElts)}); 1089*0fca6ea1SDimitry Andric ++NumInstrumentedFTLoads; 1090*0fca6ea1SDimitry Andric 1091*0fca6ea1SDimitry Andric // Split the basic block. 1092*0fca6ea1SDimitry Andric BasicBlock *LoadBB = Load.getParent(); 1093*0fca6ea1SDimitry Andric BasicBlock *NextBB = LoadBB->splitBasicBlock(Builder.GetInsertPoint()); 1094*0fca6ea1SDimitry Andric // Create the two options for creating the shadow value. 1095*0fca6ea1SDimitry Andric BasicBlock *ShadowLoadBB = 1096*0fca6ea1SDimitry Andric BasicBlock::Create(Context, "", LoadBB->getParent(), NextBB); 1097*0fca6ea1SDimitry Andric BasicBlock *FExtBB = 1098*0fca6ea1SDimitry Andric BasicBlock::Create(Context, "", LoadBB->getParent(), NextBB); 1099*0fca6ea1SDimitry Andric 1100*0fca6ea1SDimitry Andric // Replace the newly created terminator unconditional branch by a conditional 1101*0fca6ea1SDimitry Andric // branch to one of the options. 1102*0fca6ea1SDimitry Andric { 1103*0fca6ea1SDimitry Andric LoadBB->back().eraseFromParent(); 1104*0fca6ea1SDimitry Andric IRBuilder<> LoadBBBuilder(LoadBB); // The old builder has been invalidated. 1105*0fca6ea1SDimitry Andric LoadBBBuilder.SetCurrentDebugLocation(Load.getDebugLoc()); 1106*0fca6ea1SDimitry Andric LoadBBBuilder.CreateCondBr(LoadBBBuilder.CreateIsNull(ShadowPtr), FExtBB, 1107*0fca6ea1SDimitry Andric ShadowLoadBB); 1108*0fca6ea1SDimitry Andric } 1109*0fca6ea1SDimitry Andric 1110*0fca6ea1SDimitry Andric // Fill in ShadowLoadBB. 1111*0fca6ea1SDimitry Andric IRBuilder<> ShadowLoadBBBuilder(ShadowLoadBB); 1112*0fca6ea1SDimitry Andric ShadowLoadBBBuilder.SetCurrentDebugLocation(Load.getDebugLoc()); 1113*0fca6ea1SDimitry Andric Value *ShadowLoad = ShadowLoadBBBuilder.CreateAlignedLoad( 1114*0fca6ea1SDimitry Andric ExtendedVT, ShadowPtr, Align(1), Load.isVolatile()); 1115*0fca6ea1SDimitry Andric if (ClCheckLoads) { 1116*0fca6ea1SDimitry Andric ShadowLoad = emitCheck(&Load, ShadowLoad, ShadowLoadBBBuilder, 1117*0fca6ea1SDimitry Andric CheckLoc::makeLoad(Load.getPointerOperand())); 1118*0fca6ea1SDimitry Andric } 1119*0fca6ea1SDimitry Andric ShadowLoadBBBuilder.CreateBr(NextBB); 1120*0fca6ea1SDimitry Andric 1121*0fca6ea1SDimitry Andric // Fill in FExtBB. 1122*0fca6ea1SDimitry Andric IRBuilder<> FExtBBBuilder(FExtBB); 1123*0fca6ea1SDimitry Andric FExtBBBuilder.SetCurrentDebugLocation(Load.getDebugLoc()); 1124*0fca6ea1SDimitry Andric Value *FExt = FExtBBBuilder.CreateFPExt(&Load, ExtendedVT); 1125*0fca6ea1SDimitry Andric FExtBBBuilder.CreateBr(NextBB); 1126*0fca6ea1SDimitry Andric 1127*0fca6ea1SDimitry Andric // The shadow value come from any of the options. 1128*0fca6ea1SDimitry Andric IRBuilder<> NextBBBuilder(&*NextBB->begin()); 1129*0fca6ea1SDimitry Andric NextBBBuilder.SetCurrentDebugLocation(Load.getDebugLoc()); 1130*0fca6ea1SDimitry Andric PHINode *ShadowPhi = NextBBBuilder.CreatePHI(ExtendedVT, 2); 1131*0fca6ea1SDimitry Andric ShadowPhi->addIncoming(ShadowLoad, ShadowLoadBB); 1132*0fca6ea1SDimitry Andric ShadowPhi->addIncoming(FExt, FExtBB); 1133*0fca6ea1SDimitry Andric return ShadowPhi; 1134*0fca6ea1SDimitry Andric } 1135*0fca6ea1SDimitry Andric 1136*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::handleTrunc(const FPTruncInst &Trunc, 1137*0fca6ea1SDimitry Andric Type *VT, Type *ExtendedVT, 1138*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, 1139*0fca6ea1SDimitry Andric IRBuilder<> &Builder) { 1140*0fca6ea1SDimitry Andric Value *OrigSource = Trunc.getOperand(0); 1141*0fca6ea1SDimitry Andric Type *OrigSourceTy = OrigSource->getType(); 1142*0fca6ea1SDimitry Andric Type *ExtendedSourceTy = Config.getExtendedFPType(OrigSourceTy); 1143*0fca6ea1SDimitry Andric 1144*0fca6ea1SDimitry Andric // When truncating: 1145*0fca6ea1SDimitry Andric // - (A) If the source has a shadow, we truncate from the shadow, else we 1146*0fca6ea1SDimitry Andric // truncate from the original source. 1147*0fca6ea1SDimitry Andric // - (B) If the shadow of the source is larger than the shadow of the dest, 1148*0fca6ea1SDimitry Andric // we still need a truncate. Else, the shadow of the source is the same 1149*0fca6ea1SDimitry Andric // type as the shadow of the dest (because mappings are non-decreasing), so 1150*0fca6ea1SDimitry Andric // we don't need to emit a truncate. 1151*0fca6ea1SDimitry Andric // Examples, 1152*0fca6ea1SDimitry Andric // with a mapping of {f32->f64;f64->f80;f80->f128} 1153*0fca6ea1SDimitry Andric // fptrunc double %1 to float -> fptrunc x86_fp80 s(%1) to double 1154*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to float -> fptrunc fp128 s(%1) to double 1155*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to float -> fptrunc fp128 %1 to double 1156*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to double -> x86_fp80 s(%1) 1157*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to double -> fptrunc fp128 %1 to x86_fp80 1158*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to x86_fp80 -> fp128 %1 1159*0fca6ea1SDimitry Andric // with a mapping of {f32->f64;f64->f128;f80->f128} 1160*0fca6ea1SDimitry Andric // fptrunc double %1 to float -> fptrunc fp128 s(%1) to double 1161*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to float -> fptrunc fp128 s(%1) to double 1162*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to float -> fptrunc fp128 %1 to double 1163*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to double -> fp128 %1 1164*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to double -> fp128 %1 1165*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to x86_fp80 -> fp128 %1 1166*0fca6ea1SDimitry Andric // with a mapping of {f32->f32;f64->f32;f80->f64} 1167*0fca6ea1SDimitry Andric // fptrunc double %1 to float -> float s(%1) 1168*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to float -> fptrunc double s(%1) to float 1169*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to float -> fptrunc fp128 %1 to float 1170*0fca6ea1SDimitry Andric // fptrunc x86_fp80 %1 to double -> fptrunc double s(%1) to float 1171*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to double -> fptrunc fp128 %1 to float 1172*0fca6ea1SDimitry Andric // fptrunc fp128 %1 to x86_fp80 -> fptrunc fp128 %1 to double 1173*0fca6ea1SDimitry Andric 1174*0fca6ea1SDimitry Andric // See (A) above. 1175*0fca6ea1SDimitry Andric Value *Source = ExtendedSourceTy ? Map.getShadow(OrigSource) : OrigSource; 1176*0fca6ea1SDimitry Andric Type *SourceTy = ExtendedSourceTy ? ExtendedSourceTy : OrigSourceTy; 1177*0fca6ea1SDimitry Andric // See (B) above. 1178*0fca6ea1SDimitry Andric if (SourceTy == ExtendedVT) 1179*0fca6ea1SDimitry Andric return Source; 1180*0fca6ea1SDimitry Andric 1181*0fca6ea1SDimitry Andric return Builder.CreateFPTrunc(Source, ExtendedVT); 1182*0fca6ea1SDimitry Andric } 1183*0fca6ea1SDimitry Andric 1184*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::handleExt(const FPExtInst &Ext, Type *VT, 1185*0fca6ea1SDimitry Andric Type *ExtendedVT, 1186*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, 1187*0fca6ea1SDimitry Andric IRBuilder<> &Builder) { 1188*0fca6ea1SDimitry Andric Value *OrigSource = Ext.getOperand(0); 1189*0fca6ea1SDimitry Andric Type *OrigSourceTy = OrigSource->getType(); 1190*0fca6ea1SDimitry Andric Type *ExtendedSourceTy = Config.getExtendedFPType(OrigSourceTy); 1191*0fca6ea1SDimitry Andric // When extending: 1192*0fca6ea1SDimitry Andric // - (A) If the source has a shadow, we extend from the shadow, else we 1193*0fca6ea1SDimitry Andric // extend from the original source. 1194*0fca6ea1SDimitry Andric // - (B) If the shadow of the dest is larger than the shadow of the source, 1195*0fca6ea1SDimitry Andric // we still need an extend. Else, the shadow of the source is the same 1196*0fca6ea1SDimitry Andric // type as the shadow of the dest (because mappings are non-decreasing), so 1197*0fca6ea1SDimitry Andric // we don't need to emit an extend. 1198*0fca6ea1SDimitry Andric // Examples, 1199*0fca6ea1SDimitry Andric // with a mapping of {f32->f64;f64->f80;f80->f128} 1200*0fca6ea1SDimitry Andric // fpext half %1 to float -> fpext half %1 to double 1201*0fca6ea1SDimitry Andric // fpext half %1 to double -> fpext half %1 to x86_fp80 1202*0fca6ea1SDimitry Andric // fpext half %1 to x86_fp80 -> fpext half %1 to fp128 1203*0fca6ea1SDimitry Andric // fpext float %1 to double -> double s(%1) 1204*0fca6ea1SDimitry Andric // fpext float %1 to x86_fp80 -> fpext double s(%1) to fp128 1205*0fca6ea1SDimitry Andric // fpext double %1 to x86_fp80 -> fpext x86_fp80 s(%1) to fp128 1206*0fca6ea1SDimitry Andric // with a mapping of {f32->f64;f64->f128;f80->f128} 1207*0fca6ea1SDimitry Andric // fpext half %1 to float -> fpext half %1 to double 1208*0fca6ea1SDimitry Andric // fpext half %1 to double -> fpext half %1 to fp128 1209*0fca6ea1SDimitry Andric // fpext half %1 to x86_fp80 -> fpext half %1 to fp128 1210*0fca6ea1SDimitry Andric // fpext float %1 to double -> fpext double s(%1) to fp128 1211*0fca6ea1SDimitry Andric // fpext float %1 to x86_fp80 -> fpext double s(%1) to fp128 1212*0fca6ea1SDimitry Andric // fpext double %1 to x86_fp80 -> fp128 s(%1) 1213*0fca6ea1SDimitry Andric // with a mapping of {f32->f32;f64->f32;f80->f64} 1214*0fca6ea1SDimitry Andric // fpext half %1 to float -> fpext half %1 to float 1215*0fca6ea1SDimitry Andric // fpext half %1 to double -> fpext half %1 to float 1216*0fca6ea1SDimitry Andric // fpext half %1 to x86_fp80 -> fpext half %1 to double 1217*0fca6ea1SDimitry Andric // fpext float %1 to double -> s(%1) 1218*0fca6ea1SDimitry Andric // fpext float %1 to x86_fp80 -> fpext float s(%1) to double 1219*0fca6ea1SDimitry Andric // fpext double %1 to x86_fp80 -> fpext float s(%1) to double 1220*0fca6ea1SDimitry Andric 1221*0fca6ea1SDimitry Andric // See (A) above. 1222*0fca6ea1SDimitry Andric Value *Source = ExtendedSourceTy ? Map.getShadow(OrigSource) : OrigSource; 1223*0fca6ea1SDimitry Andric Type *SourceTy = ExtendedSourceTy ? ExtendedSourceTy : OrigSourceTy; 1224*0fca6ea1SDimitry Andric // See (B) above. 1225*0fca6ea1SDimitry Andric if (SourceTy == ExtendedVT) 1226*0fca6ea1SDimitry Andric return Source; 1227*0fca6ea1SDimitry Andric 1228*0fca6ea1SDimitry Andric return Builder.CreateFPExt(Source, ExtendedVT); 1229*0fca6ea1SDimitry Andric } 1230*0fca6ea1SDimitry Andric 1231*0fca6ea1SDimitry Andric namespace { 1232*0fca6ea1SDimitry Andric // TODO: This should be tablegen-ed. 1233*0fca6ea1SDimitry Andric struct KnownIntrinsic { 1234*0fca6ea1SDimitry Andric struct WidenedIntrinsic { 1235*0fca6ea1SDimitry Andric const char *NarrowName; 1236*0fca6ea1SDimitry Andric Intrinsic::ID ID; // wide id. 1237*0fca6ea1SDimitry Andric using FnTypeFactory = FunctionType *(*)(LLVMContext &); 1238*0fca6ea1SDimitry Andric FnTypeFactory MakeFnTy; 1239*0fca6ea1SDimitry Andric }; 1240*0fca6ea1SDimitry Andric 1241*0fca6ea1SDimitry Andric static const char *get(LibFunc LFunc); 1242*0fca6ea1SDimitry Andric 1243*0fca6ea1SDimitry Andric // Given an intrinsic with an `FT` argument, try to find a wider intrinsic 1244*0fca6ea1SDimitry Andric // that applies the same operation on the shadow argument. 1245*0fca6ea1SDimitry Andric // Options are: 1246*0fca6ea1SDimitry Andric // - pass in the ID and full function type, 1247*0fca6ea1SDimitry Andric // - pass in the name, which includes the function type through mangling. 1248*0fca6ea1SDimitry Andric static const WidenedIntrinsic *widen(StringRef Name); 1249*0fca6ea1SDimitry Andric 1250*0fca6ea1SDimitry Andric private: 1251*0fca6ea1SDimitry Andric struct LFEntry { 1252*0fca6ea1SDimitry Andric LibFunc LFunc; 1253*0fca6ea1SDimitry Andric const char *IntrinsicName; 1254*0fca6ea1SDimitry Andric }; 1255*0fca6ea1SDimitry Andric static const LFEntry kLibfuncIntrinsics[]; 1256*0fca6ea1SDimitry Andric 1257*0fca6ea1SDimitry Andric static const WidenedIntrinsic kWidenedIntrinsics[]; 1258*0fca6ea1SDimitry Andric }; 1259*0fca6ea1SDimitry Andric } // namespace 1260*0fca6ea1SDimitry Andric 1261*0fca6ea1SDimitry Andric static FunctionType *makeDoubleDouble(LLVMContext &C) { 1262*0fca6ea1SDimitry Andric return FunctionType::get(Type::getDoubleTy(C), {Type::getDoubleTy(C)}, false); 1263*0fca6ea1SDimitry Andric } 1264*0fca6ea1SDimitry Andric 1265*0fca6ea1SDimitry Andric static FunctionType *makeX86FP80X86FP80(LLVMContext &C) { 1266*0fca6ea1SDimitry Andric return FunctionType::get(Type::getX86_FP80Ty(C), {Type::getX86_FP80Ty(C)}, 1267*0fca6ea1SDimitry Andric false); 1268*0fca6ea1SDimitry Andric } 1269*0fca6ea1SDimitry Andric 1270*0fca6ea1SDimitry Andric static FunctionType *makeDoubleDoubleI32(LLVMContext &C) { 1271*0fca6ea1SDimitry Andric return FunctionType::get(Type::getDoubleTy(C), 1272*0fca6ea1SDimitry Andric {Type::getDoubleTy(C), Type::getInt32Ty(C)}, false); 1273*0fca6ea1SDimitry Andric } 1274*0fca6ea1SDimitry Andric 1275*0fca6ea1SDimitry Andric static FunctionType *makeX86FP80X86FP80I32(LLVMContext &C) { 1276*0fca6ea1SDimitry Andric return FunctionType::get(Type::getX86_FP80Ty(C), 1277*0fca6ea1SDimitry Andric {Type::getX86_FP80Ty(C), Type::getInt32Ty(C)}, 1278*0fca6ea1SDimitry Andric false); 1279*0fca6ea1SDimitry Andric } 1280*0fca6ea1SDimitry Andric 1281*0fca6ea1SDimitry Andric static FunctionType *makeDoubleDoubleDouble(LLVMContext &C) { 1282*0fca6ea1SDimitry Andric return FunctionType::get(Type::getDoubleTy(C), 1283*0fca6ea1SDimitry Andric {Type::getDoubleTy(C), Type::getDoubleTy(C)}, false); 1284*0fca6ea1SDimitry Andric } 1285*0fca6ea1SDimitry Andric 1286*0fca6ea1SDimitry Andric static FunctionType *makeX86FP80X86FP80X86FP80(LLVMContext &C) { 1287*0fca6ea1SDimitry Andric return FunctionType::get(Type::getX86_FP80Ty(C), 1288*0fca6ea1SDimitry Andric {Type::getX86_FP80Ty(C), Type::getX86_FP80Ty(C)}, 1289*0fca6ea1SDimitry Andric false); 1290*0fca6ea1SDimitry Andric } 1291*0fca6ea1SDimitry Andric 1292*0fca6ea1SDimitry Andric static FunctionType *makeDoubleDoubleDoubleDouble(LLVMContext &C) { 1293*0fca6ea1SDimitry Andric return FunctionType::get( 1294*0fca6ea1SDimitry Andric Type::getDoubleTy(C), 1295*0fca6ea1SDimitry Andric {Type::getDoubleTy(C), Type::getDoubleTy(C), Type::getDoubleTy(C)}, 1296*0fca6ea1SDimitry Andric false); 1297*0fca6ea1SDimitry Andric } 1298*0fca6ea1SDimitry Andric 1299*0fca6ea1SDimitry Andric static FunctionType *makeX86FP80X86FP80X86FP80X86FP80(LLVMContext &C) { 1300*0fca6ea1SDimitry Andric return FunctionType::get( 1301*0fca6ea1SDimitry Andric Type::getX86_FP80Ty(C), 1302*0fca6ea1SDimitry Andric {Type::getX86_FP80Ty(C), Type::getX86_FP80Ty(C), Type::getX86_FP80Ty(C)}, 1303*0fca6ea1SDimitry Andric false); 1304*0fca6ea1SDimitry Andric } 1305*0fca6ea1SDimitry Andric 1306*0fca6ea1SDimitry Andric const KnownIntrinsic::WidenedIntrinsic KnownIntrinsic::kWidenedIntrinsics[] = { 1307*0fca6ea1SDimitry Andric // TODO: Right now we ignore vector intrinsics. 1308*0fca6ea1SDimitry Andric // This is hard because we have to model the semantics of the intrinsics, 1309*0fca6ea1SDimitry Andric // e.g. llvm.x86.sse2.min.sd means extract first element, min, insert back. 1310*0fca6ea1SDimitry Andric // Intrinsics that take any non-vector FT types: 1311*0fca6ea1SDimitry Andric // NOTE: Right now because of 1312*0fca6ea1SDimitry Andric // https://github.com/llvm/llvm-project/issues/44744 1313*0fca6ea1SDimitry Andric // for f128 we need to use makeX86FP80X86FP80 (go to a lower precision and 1314*0fca6ea1SDimitry Andric // come back). 1315*0fca6ea1SDimitry Andric {"llvm.sqrt.f32", Intrinsic::sqrt, makeDoubleDouble}, 1316*0fca6ea1SDimitry Andric {"llvm.sqrt.f64", Intrinsic::sqrt, makeX86FP80X86FP80}, 1317*0fca6ea1SDimitry Andric {"llvm.sqrt.f80", Intrinsic::sqrt, makeX86FP80X86FP80}, 1318*0fca6ea1SDimitry Andric {"llvm.powi.f32", Intrinsic::powi, makeDoubleDoubleI32}, 1319*0fca6ea1SDimitry Andric {"llvm.powi.f64", Intrinsic::powi, makeX86FP80X86FP80I32}, 1320*0fca6ea1SDimitry Andric {"llvm.powi.f80", Intrinsic::powi, makeX86FP80X86FP80I32}, 1321*0fca6ea1SDimitry Andric {"llvm.sin.f32", Intrinsic::sin, makeDoubleDouble}, 1322*0fca6ea1SDimitry Andric {"llvm.sin.f64", Intrinsic::sin, makeX86FP80X86FP80}, 1323*0fca6ea1SDimitry Andric {"llvm.sin.f80", Intrinsic::sin, makeX86FP80X86FP80}, 1324*0fca6ea1SDimitry Andric {"llvm.cos.f32", Intrinsic::cos, makeDoubleDouble}, 1325*0fca6ea1SDimitry Andric {"llvm.cos.f64", Intrinsic::cos, makeX86FP80X86FP80}, 1326*0fca6ea1SDimitry Andric {"llvm.cos.f80", Intrinsic::cos, makeX86FP80X86FP80}, 1327*0fca6ea1SDimitry Andric {"llvm.pow.f32", Intrinsic::pow, makeDoubleDoubleDouble}, 1328*0fca6ea1SDimitry Andric {"llvm.pow.f64", Intrinsic::pow, makeX86FP80X86FP80X86FP80}, 1329*0fca6ea1SDimitry Andric {"llvm.pow.f80", Intrinsic::pow, makeX86FP80X86FP80X86FP80}, 1330*0fca6ea1SDimitry Andric {"llvm.exp.f32", Intrinsic::exp, makeDoubleDouble}, 1331*0fca6ea1SDimitry Andric {"llvm.exp.f64", Intrinsic::exp, makeX86FP80X86FP80}, 1332*0fca6ea1SDimitry Andric {"llvm.exp.f80", Intrinsic::exp, makeX86FP80X86FP80}, 1333*0fca6ea1SDimitry Andric {"llvm.exp2.f32", Intrinsic::exp2, makeDoubleDouble}, 1334*0fca6ea1SDimitry Andric {"llvm.exp2.f64", Intrinsic::exp2, makeX86FP80X86FP80}, 1335*0fca6ea1SDimitry Andric {"llvm.exp2.f80", Intrinsic::exp2, makeX86FP80X86FP80}, 1336*0fca6ea1SDimitry Andric {"llvm.log.f32", Intrinsic::log, makeDoubleDouble}, 1337*0fca6ea1SDimitry Andric {"llvm.log.f64", Intrinsic::log, makeX86FP80X86FP80}, 1338*0fca6ea1SDimitry Andric {"llvm.log.f80", Intrinsic::log, makeX86FP80X86FP80}, 1339*0fca6ea1SDimitry Andric {"llvm.log10.f32", Intrinsic::log10, makeDoubleDouble}, 1340*0fca6ea1SDimitry Andric {"llvm.log10.f64", Intrinsic::log10, makeX86FP80X86FP80}, 1341*0fca6ea1SDimitry Andric {"llvm.log10.f80", Intrinsic::log10, makeX86FP80X86FP80}, 1342*0fca6ea1SDimitry Andric {"llvm.log2.f32", Intrinsic::log2, makeDoubleDouble}, 1343*0fca6ea1SDimitry Andric {"llvm.log2.f64", Intrinsic::log2, makeX86FP80X86FP80}, 1344*0fca6ea1SDimitry Andric {"llvm.log2.f80", Intrinsic::log2, makeX86FP80X86FP80}, 1345*0fca6ea1SDimitry Andric {"llvm.fma.f32", Intrinsic::fma, makeDoubleDoubleDoubleDouble}, 1346*0fca6ea1SDimitry Andric 1347*0fca6ea1SDimitry Andric {"llvm.fmuladd.f32", Intrinsic::fmuladd, makeDoubleDoubleDoubleDouble}, 1348*0fca6ea1SDimitry Andric 1349*0fca6ea1SDimitry Andric {"llvm.fma.f64", Intrinsic::fma, makeX86FP80X86FP80X86FP80X86FP80}, 1350*0fca6ea1SDimitry Andric 1351*0fca6ea1SDimitry Andric {"llvm.fmuladd.f64", Intrinsic::fma, makeX86FP80X86FP80X86FP80X86FP80}, 1352*0fca6ea1SDimitry Andric 1353*0fca6ea1SDimitry Andric {"llvm.fma.f80", Intrinsic::fma, makeX86FP80X86FP80X86FP80X86FP80}, 1354*0fca6ea1SDimitry Andric {"llvm.fabs.f32", Intrinsic::fabs, makeDoubleDouble}, 1355*0fca6ea1SDimitry Andric {"llvm.fabs.f64", Intrinsic::fabs, makeX86FP80X86FP80}, 1356*0fca6ea1SDimitry Andric {"llvm.fabs.f80", Intrinsic::fabs, makeX86FP80X86FP80}, 1357*0fca6ea1SDimitry Andric {"llvm.minnum.f32", Intrinsic::minnum, makeDoubleDoubleDouble}, 1358*0fca6ea1SDimitry Andric {"llvm.minnum.f64", Intrinsic::minnum, makeX86FP80X86FP80X86FP80}, 1359*0fca6ea1SDimitry Andric {"llvm.minnum.f80", Intrinsic::minnum, makeX86FP80X86FP80X86FP80}, 1360*0fca6ea1SDimitry Andric {"llvm.maxnum.f32", Intrinsic::maxnum, makeDoubleDoubleDouble}, 1361*0fca6ea1SDimitry Andric {"llvm.maxnum.f64", Intrinsic::maxnum, makeX86FP80X86FP80X86FP80}, 1362*0fca6ea1SDimitry Andric {"llvm.maxnum.f80", Intrinsic::maxnum, makeX86FP80X86FP80X86FP80}, 1363*0fca6ea1SDimitry Andric {"llvm.minimum.f32", Intrinsic::minimum, makeDoubleDoubleDouble}, 1364*0fca6ea1SDimitry Andric {"llvm.minimum.f64", Intrinsic::minimum, makeX86FP80X86FP80X86FP80}, 1365*0fca6ea1SDimitry Andric {"llvm.minimum.f80", Intrinsic::minimum, makeX86FP80X86FP80X86FP80}, 1366*0fca6ea1SDimitry Andric {"llvm.maximum.f32", Intrinsic::maximum, makeDoubleDoubleDouble}, 1367*0fca6ea1SDimitry Andric {"llvm.maximum.f64", Intrinsic::maximum, makeX86FP80X86FP80X86FP80}, 1368*0fca6ea1SDimitry Andric {"llvm.maximum.f80", Intrinsic::maximum, makeX86FP80X86FP80X86FP80}, 1369*0fca6ea1SDimitry Andric {"llvm.copysign.f32", Intrinsic::copysign, makeDoubleDoubleDouble}, 1370*0fca6ea1SDimitry Andric {"llvm.copysign.f64", Intrinsic::copysign, makeX86FP80X86FP80X86FP80}, 1371*0fca6ea1SDimitry Andric {"llvm.copysign.f80", Intrinsic::copysign, makeX86FP80X86FP80X86FP80}, 1372*0fca6ea1SDimitry Andric {"llvm.floor.f32", Intrinsic::floor, makeDoubleDouble}, 1373*0fca6ea1SDimitry Andric {"llvm.floor.f64", Intrinsic::floor, makeX86FP80X86FP80}, 1374*0fca6ea1SDimitry Andric {"llvm.floor.f80", Intrinsic::floor, makeX86FP80X86FP80}, 1375*0fca6ea1SDimitry Andric {"llvm.ceil.f32", Intrinsic::ceil, makeDoubleDouble}, 1376*0fca6ea1SDimitry Andric {"llvm.ceil.f64", Intrinsic::ceil, makeX86FP80X86FP80}, 1377*0fca6ea1SDimitry Andric {"llvm.ceil.f80", Intrinsic::ceil, makeX86FP80X86FP80}, 1378*0fca6ea1SDimitry Andric {"llvm.trunc.f32", Intrinsic::trunc, makeDoubleDouble}, 1379*0fca6ea1SDimitry Andric {"llvm.trunc.f64", Intrinsic::trunc, makeX86FP80X86FP80}, 1380*0fca6ea1SDimitry Andric {"llvm.trunc.f80", Intrinsic::trunc, makeX86FP80X86FP80}, 1381*0fca6ea1SDimitry Andric {"llvm.rint.f32", Intrinsic::rint, makeDoubleDouble}, 1382*0fca6ea1SDimitry Andric {"llvm.rint.f64", Intrinsic::rint, makeX86FP80X86FP80}, 1383*0fca6ea1SDimitry Andric {"llvm.rint.f80", Intrinsic::rint, makeX86FP80X86FP80}, 1384*0fca6ea1SDimitry Andric {"llvm.nearbyint.f32", Intrinsic::nearbyint, makeDoubleDouble}, 1385*0fca6ea1SDimitry Andric {"llvm.nearbyint.f64", Intrinsic::nearbyint, makeX86FP80X86FP80}, 1386*0fca6ea1SDimitry Andric {"llvm.nearbyin80f64", Intrinsic::nearbyint, makeX86FP80X86FP80}, 1387*0fca6ea1SDimitry Andric {"llvm.round.f32", Intrinsic::round, makeDoubleDouble}, 1388*0fca6ea1SDimitry Andric {"llvm.round.f64", Intrinsic::round, makeX86FP80X86FP80}, 1389*0fca6ea1SDimitry Andric {"llvm.round.f80", Intrinsic::round, makeX86FP80X86FP80}, 1390*0fca6ea1SDimitry Andric {"llvm.lround.f32", Intrinsic::lround, makeDoubleDouble}, 1391*0fca6ea1SDimitry Andric {"llvm.lround.f64", Intrinsic::lround, makeX86FP80X86FP80}, 1392*0fca6ea1SDimitry Andric {"llvm.lround.f80", Intrinsic::lround, makeX86FP80X86FP80}, 1393*0fca6ea1SDimitry Andric {"llvm.llround.f32", Intrinsic::llround, makeDoubleDouble}, 1394*0fca6ea1SDimitry Andric {"llvm.llround.f64", Intrinsic::llround, makeX86FP80X86FP80}, 1395*0fca6ea1SDimitry Andric {"llvm.llround.f80", Intrinsic::llround, makeX86FP80X86FP80}, 1396*0fca6ea1SDimitry Andric {"llvm.lrint.f32", Intrinsic::lrint, makeDoubleDouble}, 1397*0fca6ea1SDimitry Andric {"llvm.lrint.f64", Intrinsic::lrint, makeX86FP80X86FP80}, 1398*0fca6ea1SDimitry Andric {"llvm.lrint.f80", Intrinsic::lrint, makeX86FP80X86FP80}, 1399*0fca6ea1SDimitry Andric {"llvm.llrint.f32", Intrinsic::llrint, makeDoubleDouble}, 1400*0fca6ea1SDimitry Andric {"llvm.llrint.f64", Intrinsic::llrint, makeX86FP80X86FP80}, 1401*0fca6ea1SDimitry Andric {"llvm.llrint.f80", Intrinsic::llrint, makeX86FP80X86FP80}, 1402*0fca6ea1SDimitry Andric }; 1403*0fca6ea1SDimitry Andric 1404*0fca6ea1SDimitry Andric const KnownIntrinsic::LFEntry KnownIntrinsic::kLibfuncIntrinsics[] = { 1405*0fca6ea1SDimitry Andric {LibFunc_sqrtf, "llvm.sqrt.f32"}, 1406*0fca6ea1SDimitry Andric {LibFunc_sqrt, "llvm.sqrt.f64"}, 1407*0fca6ea1SDimitry Andric {LibFunc_sqrtl, "llvm.sqrt.f80"}, 1408*0fca6ea1SDimitry Andric {LibFunc_sinf, "llvm.sin.f32"}, 1409*0fca6ea1SDimitry Andric {LibFunc_sin, "llvm.sin.f64"}, 1410*0fca6ea1SDimitry Andric {LibFunc_sinl, "llvm.sin.f80"}, 1411*0fca6ea1SDimitry Andric {LibFunc_cosf, "llvm.cos.f32"}, 1412*0fca6ea1SDimitry Andric {LibFunc_cos, "llvm.cos.f64"}, 1413*0fca6ea1SDimitry Andric {LibFunc_cosl, "llvm.cos.f80"}, 1414*0fca6ea1SDimitry Andric {LibFunc_powf, "llvm.pow.f32"}, 1415*0fca6ea1SDimitry Andric {LibFunc_pow, "llvm.pow.f64"}, 1416*0fca6ea1SDimitry Andric {LibFunc_powl, "llvm.pow.f80"}, 1417*0fca6ea1SDimitry Andric {LibFunc_expf, "llvm.exp.f32"}, 1418*0fca6ea1SDimitry Andric {LibFunc_exp, "llvm.exp.f64"}, 1419*0fca6ea1SDimitry Andric {LibFunc_expl, "llvm.exp.f80"}, 1420*0fca6ea1SDimitry Andric {LibFunc_exp2f, "llvm.exp2.f32"}, 1421*0fca6ea1SDimitry Andric {LibFunc_exp2, "llvm.exp2.f64"}, 1422*0fca6ea1SDimitry Andric {LibFunc_exp2l, "llvm.exp2.f80"}, 1423*0fca6ea1SDimitry Andric {LibFunc_logf, "llvm.log.f32"}, 1424*0fca6ea1SDimitry Andric {LibFunc_log, "llvm.log.f64"}, 1425*0fca6ea1SDimitry Andric {LibFunc_logl, "llvm.log.f80"}, 1426*0fca6ea1SDimitry Andric {LibFunc_log10f, "llvm.log10.f32"}, 1427*0fca6ea1SDimitry Andric {LibFunc_log10, "llvm.log10.f64"}, 1428*0fca6ea1SDimitry Andric {LibFunc_log10l, "llvm.log10.f80"}, 1429*0fca6ea1SDimitry Andric {LibFunc_log2f, "llvm.log2.f32"}, 1430*0fca6ea1SDimitry Andric {LibFunc_log2, "llvm.log2.f64"}, 1431*0fca6ea1SDimitry Andric {LibFunc_log2l, "llvm.log2.f80"}, 1432*0fca6ea1SDimitry Andric {LibFunc_fabsf, "llvm.fabs.f32"}, 1433*0fca6ea1SDimitry Andric {LibFunc_fabs, "llvm.fabs.f64"}, 1434*0fca6ea1SDimitry Andric {LibFunc_fabsl, "llvm.fabs.f80"}, 1435*0fca6ea1SDimitry Andric {LibFunc_copysignf, "llvm.copysign.f32"}, 1436*0fca6ea1SDimitry Andric {LibFunc_copysign, "llvm.copysign.f64"}, 1437*0fca6ea1SDimitry Andric {LibFunc_copysignl, "llvm.copysign.f80"}, 1438*0fca6ea1SDimitry Andric {LibFunc_floorf, "llvm.floor.f32"}, 1439*0fca6ea1SDimitry Andric {LibFunc_floor, "llvm.floor.f64"}, 1440*0fca6ea1SDimitry Andric {LibFunc_floorl, "llvm.floor.f80"}, 1441*0fca6ea1SDimitry Andric {LibFunc_fmaxf, "llvm.maxnum.f32"}, 1442*0fca6ea1SDimitry Andric {LibFunc_fmax, "llvm.maxnum.f64"}, 1443*0fca6ea1SDimitry Andric {LibFunc_fmaxl, "llvm.maxnum.f80"}, 1444*0fca6ea1SDimitry Andric {LibFunc_fminf, "llvm.minnum.f32"}, 1445*0fca6ea1SDimitry Andric {LibFunc_fmin, "llvm.minnum.f64"}, 1446*0fca6ea1SDimitry Andric {LibFunc_fminl, "llvm.minnum.f80"}, 1447*0fca6ea1SDimitry Andric {LibFunc_ceilf, "llvm.ceil.f32"}, 1448*0fca6ea1SDimitry Andric {LibFunc_ceil, "llvm.ceil.f64"}, 1449*0fca6ea1SDimitry Andric {LibFunc_ceill, "llvm.ceil.f80"}, 1450*0fca6ea1SDimitry Andric {LibFunc_truncf, "llvm.trunc.f32"}, 1451*0fca6ea1SDimitry Andric {LibFunc_trunc, "llvm.trunc.f64"}, 1452*0fca6ea1SDimitry Andric {LibFunc_truncl, "llvm.trunc.f80"}, 1453*0fca6ea1SDimitry Andric {LibFunc_rintf, "llvm.rint.f32"}, 1454*0fca6ea1SDimitry Andric {LibFunc_rint, "llvm.rint.f64"}, 1455*0fca6ea1SDimitry Andric {LibFunc_rintl, "llvm.rint.f80"}, 1456*0fca6ea1SDimitry Andric {LibFunc_nearbyintf, "llvm.nearbyint.f32"}, 1457*0fca6ea1SDimitry Andric {LibFunc_nearbyint, "llvm.nearbyint.f64"}, 1458*0fca6ea1SDimitry Andric {LibFunc_nearbyintl, "llvm.nearbyint.f80"}, 1459*0fca6ea1SDimitry Andric {LibFunc_roundf, "llvm.round.f32"}, 1460*0fca6ea1SDimitry Andric {LibFunc_round, "llvm.round.f64"}, 1461*0fca6ea1SDimitry Andric {LibFunc_roundl, "llvm.round.f80"}, 1462*0fca6ea1SDimitry Andric }; 1463*0fca6ea1SDimitry Andric 1464*0fca6ea1SDimitry Andric const char *KnownIntrinsic::get(LibFunc LFunc) { 1465*0fca6ea1SDimitry Andric for (const auto &E : kLibfuncIntrinsics) { 1466*0fca6ea1SDimitry Andric if (E.LFunc == LFunc) 1467*0fca6ea1SDimitry Andric return E.IntrinsicName; 1468*0fca6ea1SDimitry Andric } 1469*0fca6ea1SDimitry Andric return nullptr; 1470*0fca6ea1SDimitry Andric } 1471*0fca6ea1SDimitry Andric 1472*0fca6ea1SDimitry Andric const KnownIntrinsic::WidenedIntrinsic *KnownIntrinsic::widen(StringRef Name) { 1473*0fca6ea1SDimitry Andric for (const auto &E : kWidenedIntrinsics) { 1474*0fca6ea1SDimitry Andric if (E.NarrowName == Name) 1475*0fca6ea1SDimitry Andric return &E; 1476*0fca6ea1SDimitry Andric } 1477*0fca6ea1SDimitry Andric return nullptr; 1478*0fca6ea1SDimitry Andric } 1479*0fca6ea1SDimitry Andric 1480*0fca6ea1SDimitry Andric // Returns the name of the LLVM intrinsic corresponding to the given function. 1481*0fca6ea1SDimitry Andric static const char *getIntrinsicFromLibfunc(Function &Fn, Type *VT, 1482*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI) { 1483*0fca6ea1SDimitry Andric LibFunc LFunc; 1484*0fca6ea1SDimitry Andric if (!TLI.getLibFunc(Fn, LFunc)) 1485*0fca6ea1SDimitry Andric return nullptr; 1486*0fca6ea1SDimitry Andric 1487*0fca6ea1SDimitry Andric if (const char *Name = KnownIntrinsic::get(LFunc)) 1488*0fca6ea1SDimitry Andric return Name; 1489*0fca6ea1SDimitry Andric 1490*0fca6ea1SDimitry Andric LLVM_DEBUG(errs() << "TODO: LibFunc: " << TLI.getName(LFunc) << "\n"); 1491*0fca6ea1SDimitry Andric return nullptr; 1492*0fca6ea1SDimitry Andric } 1493*0fca6ea1SDimitry Andric 1494*0fca6ea1SDimitry Andric // Try to handle a known function call. 1495*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::maybeHandleKnownCallBase( 1496*0fca6ea1SDimitry Andric CallBase &Call, Type *VT, Type *ExtendedVT, const TargetLibraryInfo &TLI, 1497*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, IRBuilder<> &Builder) { 1498*0fca6ea1SDimitry Andric Function *Fn = Call.getCalledFunction(); 1499*0fca6ea1SDimitry Andric if (Fn == nullptr) 1500*0fca6ea1SDimitry Andric return nullptr; 1501*0fca6ea1SDimitry Andric 1502*0fca6ea1SDimitry Andric Intrinsic::ID WidenedId = Intrinsic::ID(); 1503*0fca6ea1SDimitry Andric FunctionType *WidenedFnTy = nullptr; 1504*0fca6ea1SDimitry Andric if (const auto ID = Fn->getIntrinsicID()) { 1505*0fca6ea1SDimitry Andric const auto *Widened = KnownIntrinsic::widen(Fn->getName()); 1506*0fca6ea1SDimitry Andric if (Widened) { 1507*0fca6ea1SDimitry Andric WidenedId = Widened->ID; 1508*0fca6ea1SDimitry Andric WidenedFnTy = Widened->MakeFnTy(Context); 1509*0fca6ea1SDimitry Andric } else { 1510*0fca6ea1SDimitry Andric // If we don't know how to widen the intrinsic, we have no choice but to 1511*0fca6ea1SDimitry Andric // call the non-wide version on a truncated shadow and extend again 1512*0fca6ea1SDimitry Andric // afterwards. 1513*0fca6ea1SDimitry Andric WidenedId = ID; 1514*0fca6ea1SDimitry Andric WidenedFnTy = Fn->getFunctionType(); 1515*0fca6ea1SDimitry Andric } 1516*0fca6ea1SDimitry Andric } else if (const char *Name = getIntrinsicFromLibfunc(*Fn, VT, TLI)) { 1517*0fca6ea1SDimitry Andric // We might have a call to a library function that we can replace with a 1518*0fca6ea1SDimitry Andric // wider Intrinsic. 1519*0fca6ea1SDimitry Andric const auto *Widened = KnownIntrinsic::widen(Name); 1520*0fca6ea1SDimitry Andric assert(Widened && "make sure KnownIntrinsic entries are consistent"); 1521*0fca6ea1SDimitry Andric WidenedId = Widened->ID; 1522*0fca6ea1SDimitry Andric WidenedFnTy = Widened->MakeFnTy(Context); 1523*0fca6ea1SDimitry Andric } else { 1524*0fca6ea1SDimitry Andric // This is not a known library function or intrinsic. 1525*0fca6ea1SDimitry Andric return nullptr; 1526*0fca6ea1SDimitry Andric } 1527*0fca6ea1SDimitry Andric 1528*0fca6ea1SDimitry Andric // Check that the widened intrinsic is valid. 1529*0fca6ea1SDimitry Andric SmallVector<Intrinsic::IITDescriptor, 8> Table; 1530*0fca6ea1SDimitry Andric getIntrinsicInfoTableEntries(WidenedId, Table); 1531*0fca6ea1SDimitry Andric SmallVector<Type *, 4> ArgTys; 1532*0fca6ea1SDimitry Andric ArrayRef<Intrinsic::IITDescriptor> TableRef = Table; 1533*0fca6ea1SDimitry Andric [[maybe_unused]] Intrinsic::MatchIntrinsicTypesResult MatchResult = 1534*0fca6ea1SDimitry Andric Intrinsic::matchIntrinsicSignature(WidenedFnTy, TableRef, ArgTys); 1535*0fca6ea1SDimitry Andric assert(MatchResult == Intrinsic::MatchIntrinsicTypes_Match && 1536*0fca6ea1SDimitry Andric "invalid widened intrinsic"); 1537*0fca6ea1SDimitry Andric // For known intrinsic functions, we create a second call to the same 1538*0fca6ea1SDimitry Andric // intrinsic with a different type. 1539*0fca6ea1SDimitry Andric SmallVector<Value *, 4> Args; 1540*0fca6ea1SDimitry Andric // The last operand is the intrinsic itself, skip it. 1541*0fca6ea1SDimitry Andric for (unsigned I = 0, E = Call.getNumOperands() - 1; I < E; ++I) { 1542*0fca6ea1SDimitry Andric Value *Arg = Call.getOperand(I); 1543*0fca6ea1SDimitry Andric Type *OrigArgTy = Arg->getType(); 1544*0fca6ea1SDimitry Andric Type *IntrinsicArgTy = WidenedFnTy->getParamType(I); 1545*0fca6ea1SDimitry Andric if (OrigArgTy == IntrinsicArgTy) { 1546*0fca6ea1SDimitry Andric Args.push_back(Arg); // The arg is passed as is. 1547*0fca6ea1SDimitry Andric continue; 1548*0fca6ea1SDimitry Andric } 1549*0fca6ea1SDimitry Andric Type *ShadowArgTy = Config.getExtendedFPType(Arg->getType()); 1550*0fca6ea1SDimitry Andric assert(ShadowArgTy && 1551*0fca6ea1SDimitry Andric "don't know how to get the shadow value for a non-FT"); 1552*0fca6ea1SDimitry Andric Value *Shadow = Map.getShadow(Arg); 1553*0fca6ea1SDimitry Andric if (ShadowArgTy == IntrinsicArgTy) { 1554*0fca6ea1SDimitry Andric // The shadow is the right type for the intrinsic. 1555*0fca6ea1SDimitry Andric assert(Shadow->getType() == ShadowArgTy); 1556*0fca6ea1SDimitry Andric Args.push_back(Shadow); 1557*0fca6ea1SDimitry Andric continue; 1558*0fca6ea1SDimitry Andric } 1559*0fca6ea1SDimitry Andric // There is no intrinsic with his level of precision, truncate the shadow. 1560*0fca6ea1SDimitry Andric Args.push_back(Builder.CreateFPTrunc(Shadow, IntrinsicArgTy)); 1561*0fca6ea1SDimitry Andric } 1562*0fca6ea1SDimitry Andric Value *IntrinsicCall = Builder.CreateIntrinsic(WidenedId, ArgTys, Args); 1563*0fca6ea1SDimitry Andric return WidenedFnTy->getReturnType() == ExtendedVT 1564*0fca6ea1SDimitry Andric ? IntrinsicCall 1565*0fca6ea1SDimitry Andric : Builder.CreateFPExt(IntrinsicCall, ExtendedVT); 1566*0fca6ea1SDimitry Andric } 1567*0fca6ea1SDimitry Andric 1568*0fca6ea1SDimitry Andric // Handle a CallBase, i.e. a function call, an inline asm sequence, or an 1569*0fca6ea1SDimitry Andric // invoke. 1570*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::handleCallBase(CallBase &Call, Type *VT, 1571*0fca6ea1SDimitry Andric Type *ExtendedVT, 1572*0fca6ea1SDimitry Andric const TargetLibraryInfo &TLI, 1573*0fca6ea1SDimitry Andric const ValueToShadowMap &Map, 1574*0fca6ea1SDimitry Andric IRBuilder<> &Builder) { 1575*0fca6ea1SDimitry Andric // We cannot look inside inline asm, just expand the result again. 1576*0fca6ea1SDimitry Andric if (Call.isInlineAsm()) 1577*0fca6ea1SDimitry Andric return Builder.CreateFPExt(&Call, ExtendedVT); 1578*0fca6ea1SDimitry Andric 1579*0fca6ea1SDimitry Andric // Intrinsics and library functions (e.g. sin, exp) are handled 1580*0fca6ea1SDimitry Andric // specifically, because we know their semantics and can do better than 1581*0fca6ea1SDimitry Andric // blindly calling them (e.g. compute the sinus in the actual shadow domain). 1582*0fca6ea1SDimitry Andric if (Value *V = 1583*0fca6ea1SDimitry Andric maybeHandleKnownCallBase(Call, VT, ExtendedVT, TLI, Map, Builder)) 1584*0fca6ea1SDimitry Andric return V; 1585*0fca6ea1SDimitry Andric 1586*0fca6ea1SDimitry Andric // If the return tag matches that of the called function, read the extended 1587*0fca6ea1SDimitry Andric // return value from the shadow ret ptr. Else, just extend the return value. 1588*0fca6ea1SDimitry Andric Value *L = 1589*0fca6ea1SDimitry Andric Builder.CreateLoad(IntptrTy, NsanShadowRetTag, /*isVolatile=*/false); 1590*0fca6ea1SDimitry Andric Value *HasShadowRet = Builder.CreateICmpEQ( 1591*0fca6ea1SDimitry Andric L, Builder.CreatePtrToInt(Call.getCalledOperand(), IntptrTy)); 1592*0fca6ea1SDimitry Andric 1593*0fca6ea1SDimitry Andric Value *ShadowRetVal = Builder.CreateLoad( 1594*0fca6ea1SDimitry Andric ExtendedVT, 1595*0fca6ea1SDimitry Andric Builder.CreateConstGEP2_64(NsanShadowRetType, NsanShadowRetPtr, 0, 0), 1596*0fca6ea1SDimitry Andric /*isVolatile=*/false); 1597*0fca6ea1SDimitry Andric Value *Shadow = Builder.CreateSelect(HasShadowRet, ShadowRetVal, 1598*0fca6ea1SDimitry Andric Builder.CreateFPExt(&Call, ExtendedVT)); 1599*0fca6ea1SDimitry Andric ++NumInstrumentedFTCalls; 1600*0fca6ea1SDimitry Andric return Shadow; 1601*0fca6ea1SDimitry Andric } 1602*0fca6ea1SDimitry Andric 1603*0fca6ea1SDimitry Andric // Creates a shadow value for the given FT value. At that point all operands are 1604*0fca6ea1SDimitry Andric // guaranteed to be available. 1605*0fca6ea1SDimitry Andric Value *NumericalStabilitySanitizer::createShadowValueWithOperandsAvailable( 1606*0fca6ea1SDimitry Andric Instruction &Inst, const TargetLibraryInfo &TLI, 1607*0fca6ea1SDimitry Andric const ValueToShadowMap &Map) { 1608*0fca6ea1SDimitry Andric Type *VT = Inst.getType(); 1609*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1610*0fca6ea1SDimitry Andric assert(ExtendedVT != nullptr && "trying to create a shadow for a non-FT"); 1611*0fca6ea1SDimitry Andric 1612*0fca6ea1SDimitry Andric if (auto *Load = dyn_cast<LoadInst>(&Inst)) 1613*0fca6ea1SDimitry Andric return handleLoad(*Load, VT, ExtendedVT); 1614*0fca6ea1SDimitry Andric 1615*0fca6ea1SDimitry Andric if (auto *Call = dyn_cast<CallInst>(&Inst)) { 1616*0fca6ea1SDimitry Andric // Insert after the call. 1617*0fca6ea1SDimitry Andric BasicBlock::iterator It(Inst); 1618*0fca6ea1SDimitry Andric IRBuilder<> Builder(Call->getParent(), ++It); 1619*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Call->getDebugLoc()); 1620*0fca6ea1SDimitry Andric return handleCallBase(*Call, VT, ExtendedVT, TLI, Map, Builder); 1621*0fca6ea1SDimitry Andric } 1622*0fca6ea1SDimitry Andric 1623*0fca6ea1SDimitry Andric if (auto *Invoke = dyn_cast<InvokeInst>(&Inst)) { 1624*0fca6ea1SDimitry Andric // The Invoke terminates the basic block, create a new basic block in 1625*0fca6ea1SDimitry Andric // between the successful invoke and the next block. 1626*0fca6ea1SDimitry Andric BasicBlock *InvokeBB = Invoke->getParent(); 1627*0fca6ea1SDimitry Andric BasicBlock *NextBB = Invoke->getNormalDest(); 1628*0fca6ea1SDimitry Andric BasicBlock *NewBB = 1629*0fca6ea1SDimitry Andric BasicBlock::Create(Context, "", NextBB->getParent(), NextBB); 1630*0fca6ea1SDimitry Andric Inst.replaceSuccessorWith(NextBB, NewBB); 1631*0fca6ea1SDimitry Andric 1632*0fca6ea1SDimitry Andric IRBuilder<> Builder(NewBB); 1633*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Invoke->getDebugLoc()); 1634*0fca6ea1SDimitry Andric Value *Shadow = handleCallBase(*Invoke, VT, ExtendedVT, TLI, Map, Builder); 1635*0fca6ea1SDimitry Andric Builder.CreateBr(NextBB); 1636*0fca6ea1SDimitry Andric NewBB->replaceSuccessorsPhiUsesWith(InvokeBB, NewBB); 1637*0fca6ea1SDimitry Andric return Shadow; 1638*0fca6ea1SDimitry Andric } 1639*0fca6ea1SDimitry Andric 1640*0fca6ea1SDimitry Andric IRBuilder<> Builder(Inst.getNextNode()); 1641*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Inst.getDebugLoc()); 1642*0fca6ea1SDimitry Andric 1643*0fca6ea1SDimitry Andric if (auto *Trunc = dyn_cast<FPTruncInst>(&Inst)) 1644*0fca6ea1SDimitry Andric return handleTrunc(*Trunc, VT, ExtendedVT, Map, Builder); 1645*0fca6ea1SDimitry Andric if (auto *Ext = dyn_cast<FPExtInst>(&Inst)) 1646*0fca6ea1SDimitry Andric return handleExt(*Ext, VT, ExtendedVT, Map, Builder); 1647*0fca6ea1SDimitry Andric 1648*0fca6ea1SDimitry Andric if (auto *UnaryOp = dyn_cast<UnaryOperator>(&Inst)) 1649*0fca6ea1SDimitry Andric return Builder.CreateUnOp(UnaryOp->getOpcode(), 1650*0fca6ea1SDimitry Andric Map.getShadow(UnaryOp->getOperand(0))); 1651*0fca6ea1SDimitry Andric 1652*0fca6ea1SDimitry Andric if (auto *BinOp = dyn_cast<BinaryOperator>(&Inst)) 1653*0fca6ea1SDimitry Andric return Builder.CreateBinOp(BinOp->getOpcode(), 1654*0fca6ea1SDimitry Andric Map.getShadow(BinOp->getOperand(0)), 1655*0fca6ea1SDimitry Andric Map.getShadow(BinOp->getOperand(1))); 1656*0fca6ea1SDimitry Andric 1657*0fca6ea1SDimitry Andric if (isa<UIToFPInst>(&Inst) || isa<SIToFPInst>(&Inst)) { 1658*0fca6ea1SDimitry Andric auto *Cast = dyn_cast<CastInst>(&Inst); 1659*0fca6ea1SDimitry Andric return Builder.CreateCast(Cast->getOpcode(), Cast->getOperand(0), 1660*0fca6ea1SDimitry Andric ExtendedVT); 1661*0fca6ea1SDimitry Andric } 1662*0fca6ea1SDimitry Andric 1663*0fca6ea1SDimitry Andric if (auto *S = dyn_cast<SelectInst>(&Inst)) 1664*0fca6ea1SDimitry Andric return Builder.CreateSelect(S->getCondition(), 1665*0fca6ea1SDimitry Andric Map.getShadow(S->getTrueValue()), 1666*0fca6ea1SDimitry Andric Map.getShadow(S->getFalseValue())); 1667*0fca6ea1SDimitry Andric 1668*0fca6ea1SDimitry Andric if (auto *Extract = dyn_cast<ExtractElementInst>(&Inst)) 1669*0fca6ea1SDimitry Andric return Builder.CreateExtractElement( 1670*0fca6ea1SDimitry Andric Map.getShadow(Extract->getVectorOperand()), Extract->getIndexOperand()); 1671*0fca6ea1SDimitry Andric 1672*0fca6ea1SDimitry Andric if (auto *Insert = dyn_cast<InsertElementInst>(&Inst)) 1673*0fca6ea1SDimitry Andric return Builder.CreateInsertElement(Map.getShadow(Insert->getOperand(0)), 1674*0fca6ea1SDimitry Andric Map.getShadow(Insert->getOperand(1)), 1675*0fca6ea1SDimitry Andric Insert->getOperand(2)); 1676*0fca6ea1SDimitry Andric 1677*0fca6ea1SDimitry Andric if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(&Inst)) 1678*0fca6ea1SDimitry Andric return Builder.CreateShuffleVector(Map.getShadow(Shuffle->getOperand(0)), 1679*0fca6ea1SDimitry Andric Map.getShadow(Shuffle->getOperand(1)), 1680*0fca6ea1SDimitry Andric Shuffle->getShuffleMask()); 1681*0fca6ea1SDimitry Andric // TODO: We could make aggregate object first class citizens. For now we 1682*0fca6ea1SDimitry Andric // just extend the extracted value. 1683*0fca6ea1SDimitry Andric if (auto *Extract = dyn_cast<ExtractValueInst>(&Inst)) 1684*0fca6ea1SDimitry Andric return Builder.CreateFPExt(Extract, ExtendedVT); 1685*0fca6ea1SDimitry Andric 1686*0fca6ea1SDimitry Andric if (auto *BC = dyn_cast<BitCastInst>(&Inst)) 1687*0fca6ea1SDimitry Andric return Builder.CreateFPExt(BC, ExtendedVT); 1688*0fca6ea1SDimitry Andric 1689*0fca6ea1SDimitry Andric report_fatal_error("Unimplemented support for " + 1690*0fca6ea1SDimitry Andric Twine(Inst.getOpcodeName())); 1691*0fca6ea1SDimitry Andric } 1692*0fca6ea1SDimitry Andric 1693*0fca6ea1SDimitry Andric // Creates a shadow value for an instruction that defines a value of FT type. 1694*0fca6ea1SDimitry Andric // FT operands that do not already have shadow values are created recursively. 1695*0fca6ea1SDimitry Andric // The DFS is guaranteed to not loop as phis and arguments already have 1696*0fca6ea1SDimitry Andric // shadows. 1697*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::maybeCreateShadowValue( 1698*0fca6ea1SDimitry Andric Instruction &Root, const TargetLibraryInfo &TLI, ValueToShadowMap &Map) { 1699*0fca6ea1SDimitry Andric Type *VT = Root.getType(); 1700*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1701*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 1702*0fca6ea1SDimitry Andric return; // Not an FT value. 1703*0fca6ea1SDimitry Andric 1704*0fca6ea1SDimitry Andric if (Map.hasShadow(&Root)) 1705*0fca6ea1SDimitry Andric return; // Shadow already exists. 1706*0fca6ea1SDimitry Andric 1707*0fca6ea1SDimitry Andric assert(!isa<PHINode>(Root) && "phi nodes should already have shadows"); 1708*0fca6ea1SDimitry Andric 1709*0fca6ea1SDimitry Andric std::vector<Instruction *> DfsStack(1, &Root); 1710*0fca6ea1SDimitry Andric while (!DfsStack.empty()) { 1711*0fca6ea1SDimitry Andric // Ensure that all operands to the instruction have shadows before 1712*0fca6ea1SDimitry Andric // proceeding. 1713*0fca6ea1SDimitry Andric Instruction *I = DfsStack.back(); 1714*0fca6ea1SDimitry Andric // The shadow for the instruction might have been created deeper in the DFS, 1715*0fca6ea1SDimitry Andric // see `forward_use_with_two_uses` test. 1716*0fca6ea1SDimitry Andric if (Map.hasShadow(I)) { 1717*0fca6ea1SDimitry Andric DfsStack.pop_back(); 1718*0fca6ea1SDimitry Andric continue; 1719*0fca6ea1SDimitry Andric } 1720*0fca6ea1SDimitry Andric 1721*0fca6ea1SDimitry Andric bool MissingShadow = false; 1722*0fca6ea1SDimitry Andric for (Value *Op : I->operands()) { 1723*0fca6ea1SDimitry Andric Type *VT = Op->getType(); 1724*0fca6ea1SDimitry Andric if (!Config.getExtendedFPType(VT)) 1725*0fca6ea1SDimitry Andric continue; // Not an FT value. 1726*0fca6ea1SDimitry Andric if (Map.hasShadow(Op)) 1727*0fca6ea1SDimitry Andric continue; // Shadow is already available. 1728*0fca6ea1SDimitry Andric MissingShadow = true; 1729*0fca6ea1SDimitry Andric DfsStack.push_back(cast<Instruction>(Op)); 1730*0fca6ea1SDimitry Andric } 1731*0fca6ea1SDimitry Andric if (MissingShadow) 1732*0fca6ea1SDimitry Andric continue; // Process operands and come back to this instruction later. 1733*0fca6ea1SDimitry Andric 1734*0fca6ea1SDimitry Andric // All operands have shadows. Create a shadow for the current value. 1735*0fca6ea1SDimitry Andric Value *Shadow = createShadowValueWithOperandsAvailable(*I, TLI, Map); 1736*0fca6ea1SDimitry Andric Map.setShadow(*I, *Shadow); 1737*0fca6ea1SDimitry Andric DfsStack.pop_back(); 1738*0fca6ea1SDimitry Andric } 1739*0fca6ea1SDimitry Andric } 1740*0fca6ea1SDimitry Andric 1741*0fca6ea1SDimitry Andric // A floating-point store needs its value and type written to shadow memory. 1742*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::propagateFTStore( 1743*0fca6ea1SDimitry Andric StoreInst &Store, Type *VT, Type *ExtendedVT, const ValueToShadowMap &Map) { 1744*0fca6ea1SDimitry Andric Value *StoredValue = Store.getValueOperand(); 1745*0fca6ea1SDimitry Andric IRBuilder<> Builder(&Store); 1746*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Store.getDebugLoc()); 1747*0fca6ea1SDimitry Andric const auto Extents = getMemoryExtentsOrDie(VT); 1748*0fca6ea1SDimitry Andric Value *ShadowPtr = Builder.CreateCall( 1749*0fca6ea1SDimitry Andric NsanGetShadowPtrForStore[Extents.ValueType], 1750*0fca6ea1SDimitry Andric {Store.getPointerOperand(), ConstantInt::get(IntptrTy, Extents.NumElts)}); 1751*0fca6ea1SDimitry Andric 1752*0fca6ea1SDimitry Andric Value *StoredShadow = Map.getShadow(StoredValue); 1753*0fca6ea1SDimitry Andric if (!Store.getParent()->getParent()->hasOptNone()) { 1754*0fca6ea1SDimitry Andric // Only check stores when optimizing, because non-optimized code generates 1755*0fca6ea1SDimitry Andric // too many stores to the stack, creating false positives. 1756*0fca6ea1SDimitry Andric if (ClCheckStores) { 1757*0fca6ea1SDimitry Andric StoredShadow = emitCheck(StoredValue, StoredShadow, Builder, 1758*0fca6ea1SDimitry Andric CheckLoc::makeStore(Store.getPointerOperand())); 1759*0fca6ea1SDimitry Andric ++NumInstrumentedFTStores; 1760*0fca6ea1SDimitry Andric } 1761*0fca6ea1SDimitry Andric } 1762*0fca6ea1SDimitry Andric 1763*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(StoredShadow, ShadowPtr, Align(1), 1764*0fca6ea1SDimitry Andric Store.isVolatile()); 1765*0fca6ea1SDimitry Andric } 1766*0fca6ea1SDimitry Andric 1767*0fca6ea1SDimitry Andric // A non-ft store needs to invalidate shadow memory. Exceptions are: 1768*0fca6ea1SDimitry Andric // - memory transfers of floating-point data through other pointer types (llvm 1769*0fca6ea1SDimitry Andric // optimization passes transform `*(float*)a = *(float*)b` into 1770*0fca6ea1SDimitry Andric // `*(i32*)a = *(i32*)b` ). These have the same semantics as memcpy. 1771*0fca6ea1SDimitry Andric // - Writes of FT-sized constants. LLVM likes to do float stores as bitcasted 1772*0fca6ea1SDimitry Andric // ints. Note that this is not really necessary because if the value is 1773*0fca6ea1SDimitry Andric // unknown the framework will re-extend it on load anyway. It just felt 1774*0fca6ea1SDimitry Andric // easier to debug tests with vectors of FTs. 1775*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::propagateNonFTStore( 1776*0fca6ea1SDimitry Andric StoreInst &Store, Type *VT, const ValueToShadowMap &Map) { 1777*0fca6ea1SDimitry Andric Value *PtrOp = Store.getPointerOperand(); 1778*0fca6ea1SDimitry Andric IRBuilder<> Builder(Store.getNextNode()); 1779*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Store.getDebugLoc()); 1780*0fca6ea1SDimitry Andric Value *Dst = PtrOp; 1781*0fca6ea1SDimitry Andric TypeSize SlotSize = DL.getTypeStoreSize(VT); 1782*0fca6ea1SDimitry Andric assert(!SlotSize.isScalable() && "unsupported"); 1783*0fca6ea1SDimitry Andric const auto LoadSizeBytes = SlotSize.getFixedValue(); 1784*0fca6ea1SDimitry Andric Value *ValueSize = Constant::getIntegerValue( 1785*0fca6ea1SDimitry Andric IntptrTy, APInt(IntptrTy->getPrimitiveSizeInBits(), LoadSizeBytes)); 1786*0fca6ea1SDimitry Andric 1787*0fca6ea1SDimitry Andric ++NumInstrumentedNonFTStores; 1788*0fca6ea1SDimitry Andric Value *StoredValue = Store.getValueOperand(); 1789*0fca6ea1SDimitry Andric if (LoadInst *Load = dyn_cast<LoadInst>(StoredValue)) { 1790*0fca6ea1SDimitry Andric // TODO: Handle the case when the value is from a phi. 1791*0fca6ea1SDimitry Andric // This is a memory transfer with memcpy semantics. Copy the type and 1792*0fca6ea1SDimitry Andric // value from the source. Note that we cannot use __nsan_copy_values() 1793*0fca6ea1SDimitry Andric // here, because that will not work when there is a write to memory in 1794*0fca6ea1SDimitry Andric // between the load and the store, e.g. in the case of a swap. 1795*0fca6ea1SDimitry Andric Type *ShadowTypeIntTy = Type::getIntNTy(Context, 8 * LoadSizeBytes); 1796*0fca6ea1SDimitry Andric Type *ShadowValueIntTy = 1797*0fca6ea1SDimitry Andric Type::getIntNTy(Context, 8 * kShadowScale * LoadSizeBytes); 1798*0fca6ea1SDimitry Andric IRBuilder<> LoadBuilder(Load->getNextNode()); 1799*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(Store.getDebugLoc()); 1800*0fca6ea1SDimitry Andric Value *LoadSrc = Load->getPointerOperand(); 1801*0fca6ea1SDimitry Andric // Read the shadow type and value at load time. The type has the same size 1802*0fca6ea1SDimitry Andric // as the FT value, the value has twice its size. 1803*0fca6ea1SDimitry Andric // TODO: cache them to avoid re-creating them when a load is used by 1804*0fca6ea1SDimitry Andric // several stores. Maybe create them like the FT shadows when a load is 1805*0fca6ea1SDimitry Andric // encountered. 1806*0fca6ea1SDimitry Andric Value *RawShadowType = LoadBuilder.CreateAlignedLoad( 1807*0fca6ea1SDimitry Andric ShadowTypeIntTy, 1808*0fca6ea1SDimitry Andric LoadBuilder.CreateCall(NsanGetRawShadowTypePtr, {LoadSrc}), Align(1), 1809*0fca6ea1SDimitry Andric /*isVolatile=*/false); 1810*0fca6ea1SDimitry Andric Value *RawShadowValue = LoadBuilder.CreateAlignedLoad( 1811*0fca6ea1SDimitry Andric ShadowValueIntTy, 1812*0fca6ea1SDimitry Andric LoadBuilder.CreateCall(NsanGetRawShadowPtr, {LoadSrc}), Align(1), 1813*0fca6ea1SDimitry Andric /*isVolatile=*/false); 1814*0fca6ea1SDimitry Andric 1815*0fca6ea1SDimitry Andric // Write back the shadow type and value at store time. 1816*0fca6ea1SDimitry Andric Builder.CreateAlignedStore( 1817*0fca6ea1SDimitry Andric RawShadowType, Builder.CreateCall(NsanGetRawShadowTypePtr, {Dst}), 1818*0fca6ea1SDimitry Andric Align(1), 1819*0fca6ea1SDimitry Andric /*isVolatile=*/false); 1820*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(RawShadowValue, 1821*0fca6ea1SDimitry Andric Builder.CreateCall(NsanGetRawShadowPtr, {Dst}), 1822*0fca6ea1SDimitry Andric Align(1), 1823*0fca6ea1SDimitry Andric /*isVolatile=*/false); 1824*0fca6ea1SDimitry Andric 1825*0fca6ea1SDimitry Andric ++NumInstrumentedNonFTMemcpyStores; 1826*0fca6ea1SDimitry Andric return; 1827*0fca6ea1SDimitry Andric } 1828*0fca6ea1SDimitry Andric // ClPropagateNonFTConstStoresAsFT is by default false. 1829*0fca6ea1SDimitry Andric if (Constant *C; ClPropagateNonFTConstStoresAsFT && 1830*0fca6ea1SDimitry Andric (C = dyn_cast<Constant>(StoredValue))) { 1831*0fca6ea1SDimitry Andric // This might be a fp constant stored as an int. Bitcast and store if it has 1832*0fca6ea1SDimitry Andric // appropriate size. 1833*0fca6ea1SDimitry Andric Type *BitcastTy = nullptr; // The FT type to bitcast to. 1834*0fca6ea1SDimitry Andric if (auto *CInt = dyn_cast<ConstantInt>(C)) { 1835*0fca6ea1SDimitry Andric switch (CInt->getType()->getScalarSizeInBits()) { 1836*0fca6ea1SDimitry Andric case 32: 1837*0fca6ea1SDimitry Andric BitcastTy = Type::getFloatTy(Context); 1838*0fca6ea1SDimitry Andric break; 1839*0fca6ea1SDimitry Andric case 64: 1840*0fca6ea1SDimitry Andric BitcastTy = Type::getDoubleTy(Context); 1841*0fca6ea1SDimitry Andric break; 1842*0fca6ea1SDimitry Andric case 80: 1843*0fca6ea1SDimitry Andric BitcastTy = Type::getX86_FP80Ty(Context); 1844*0fca6ea1SDimitry Andric break; 1845*0fca6ea1SDimitry Andric default: 1846*0fca6ea1SDimitry Andric break; 1847*0fca6ea1SDimitry Andric } 1848*0fca6ea1SDimitry Andric } else if (auto *CDV = dyn_cast<ConstantDataVector>(C)) { 1849*0fca6ea1SDimitry Andric const int NumElements = 1850*0fca6ea1SDimitry Andric cast<VectorType>(CDV->getType())->getElementCount().getFixedValue(); 1851*0fca6ea1SDimitry Andric switch (CDV->getType()->getScalarSizeInBits()) { 1852*0fca6ea1SDimitry Andric case 32: 1853*0fca6ea1SDimitry Andric BitcastTy = 1854*0fca6ea1SDimitry Andric VectorType::get(Type::getFloatTy(Context), NumElements, false); 1855*0fca6ea1SDimitry Andric break; 1856*0fca6ea1SDimitry Andric case 64: 1857*0fca6ea1SDimitry Andric BitcastTy = 1858*0fca6ea1SDimitry Andric VectorType::get(Type::getDoubleTy(Context), NumElements, false); 1859*0fca6ea1SDimitry Andric break; 1860*0fca6ea1SDimitry Andric case 80: 1861*0fca6ea1SDimitry Andric BitcastTy = 1862*0fca6ea1SDimitry Andric VectorType::get(Type::getX86_FP80Ty(Context), NumElements, false); 1863*0fca6ea1SDimitry Andric break; 1864*0fca6ea1SDimitry Andric default: 1865*0fca6ea1SDimitry Andric break; 1866*0fca6ea1SDimitry Andric } 1867*0fca6ea1SDimitry Andric } 1868*0fca6ea1SDimitry Andric if (BitcastTy) { 1869*0fca6ea1SDimitry Andric const MemoryExtents Extents = getMemoryExtentsOrDie(BitcastTy); 1870*0fca6ea1SDimitry Andric Value *ShadowPtr = Builder.CreateCall( 1871*0fca6ea1SDimitry Andric NsanGetShadowPtrForStore[Extents.ValueType], 1872*0fca6ea1SDimitry Andric {PtrOp, ConstantInt::get(IntptrTy, Extents.NumElts)}); 1873*0fca6ea1SDimitry Andric // Bitcast the integer value to the appropriate FT type and extend to 2FT. 1874*0fca6ea1SDimitry Andric Type *ExtVT = Config.getExtendedFPType(BitcastTy); 1875*0fca6ea1SDimitry Andric Value *Shadow = 1876*0fca6ea1SDimitry Andric Builder.CreateFPExt(Builder.CreateBitCast(C, BitcastTy), ExtVT); 1877*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(Shadow, ShadowPtr, Align(1), 1878*0fca6ea1SDimitry Andric Store.isVolatile()); 1879*0fca6ea1SDimitry Andric return; 1880*0fca6ea1SDimitry Andric } 1881*0fca6ea1SDimitry Andric } 1882*0fca6ea1SDimitry Andric // All other stores just reset the shadow value to unknown. 1883*0fca6ea1SDimitry Andric Builder.CreateCall(NsanSetValueUnknown, {Dst, ValueSize}); 1884*0fca6ea1SDimitry Andric } 1885*0fca6ea1SDimitry Andric 1886*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::propagateShadowValues( 1887*0fca6ea1SDimitry Andric Instruction &Inst, const TargetLibraryInfo &TLI, 1888*0fca6ea1SDimitry Andric const ValueToShadowMap &Map) { 1889*0fca6ea1SDimitry Andric if (auto *Store = dyn_cast<StoreInst>(&Inst)) { 1890*0fca6ea1SDimitry Andric Value *StoredValue = Store->getValueOperand(); 1891*0fca6ea1SDimitry Andric Type *VT = StoredValue->getType(); 1892*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1893*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 1894*0fca6ea1SDimitry Andric return propagateNonFTStore(*Store, VT, Map); 1895*0fca6ea1SDimitry Andric return propagateFTStore(*Store, VT, ExtendedVT, Map); 1896*0fca6ea1SDimitry Andric } 1897*0fca6ea1SDimitry Andric 1898*0fca6ea1SDimitry Andric if (auto *FCmp = dyn_cast<FCmpInst>(&Inst)) { 1899*0fca6ea1SDimitry Andric emitFCmpCheck(*FCmp, Map); 1900*0fca6ea1SDimitry Andric return; 1901*0fca6ea1SDimitry Andric } 1902*0fca6ea1SDimitry Andric 1903*0fca6ea1SDimitry Andric if (auto *CB = dyn_cast<CallBase>(&Inst)) { 1904*0fca6ea1SDimitry Andric maybeAddSuffixForNsanInterface(CB); 1905*0fca6ea1SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(&Inst)) 1906*0fca6ea1SDimitry Andric maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI); 1907*0fca6ea1SDimitry Andric if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&Inst)) { 1908*0fca6ea1SDimitry Andric instrumentMemIntrinsic(MI); 1909*0fca6ea1SDimitry Andric return; 1910*0fca6ea1SDimitry Andric } 1911*0fca6ea1SDimitry Andric populateShadowStack(*CB, TLI, Map); 1912*0fca6ea1SDimitry Andric return; 1913*0fca6ea1SDimitry Andric } 1914*0fca6ea1SDimitry Andric 1915*0fca6ea1SDimitry Andric if (auto *RetInst = dyn_cast<ReturnInst>(&Inst)) { 1916*0fca6ea1SDimitry Andric if (!ClCheckRet) 1917*0fca6ea1SDimitry Andric return; 1918*0fca6ea1SDimitry Andric 1919*0fca6ea1SDimitry Andric Value *RV = RetInst->getReturnValue(); 1920*0fca6ea1SDimitry Andric if (RV == nullptr) 1921*0fca6ea1SDimitry Andric return; // This is a `ret void`. 1922*0fca6ea1SDimitry Andric Type *VT = RV->getType(); 1923*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1924*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 1925*0fca6ea1SDimitry Andric return; // Not an FT ret. 1926*0fca6ea1SDimitry Andric Value *RVShadow = Map.getShadow(RV); 1927*0fca6ea1SDimitry Andric IRBuilder<> Builder(RetInst); 1928*0fca6ea1SDimitry Andric 1929*0fca6ea1SDimitry Andric RVShadow = emitCheck(RV, RVShadow, Builder, CheckLoc::makeRet()); 1930*0fca6ea1SDimitry Andric ++NumInstrumentedFTRets; 1931*0fca6ea1SDimitry Andric // Store tag. 1932*0fca6ea1SDimitry Andric Value *FnAddr = 1933*0fca6ea1SDimitry Andric Builder.CreatePtrToInt(Inst.getParent()->getParent(), IntptrTy); 1934*0fca6ea1SDimitry Andric Builder.CreateStore(FnAddr, NsanShadowRetTag); 1935*0fca6ea1SDimitry Andric // Store value. 1936*0fca6ea1SDimitry Andric Value *ShadowRetValPtr = 1937*0fca6ea1SDimitry Andric Builder.CreateConstGEP2_64(NsanShadowRetType, NsanShadowRetPtr, 0, 0); 1938*0fca6ea1SDimitry Andric Builder.CreateStore(RVShadow, ShadowRetValPtr); 1939*0fca6ea1SDimitry Andric return; 1940*0fca6ea1SDimitry Andric } 1941*0fca6ea1SDimitry Andric 1942*0fca6ea1SDimitry Andric if (InsertValueInst *Insert = dyn_cast<InsertValueInst>(&Inst)) { 1943*0fca6ea1SDimitry Andric Value *V = Insert->getOperand(1); 1944*0fca6ea1SDimitry Andric Type *VT = V->getType(); 1945*0fca6ea1SDimitry Andric Type *ExtendedVT = Config.getExtendedFPType(VT); 1946*0fca6ea1SDimitry Andric if (ExtendedVT == nullptr) 1947*0fca6ea1SDimitry Andric return; 1948*0fca6ea1SDimitry Andric IRBuilder<> Builder(Insert); 1949*0fca6ea1SDimitry Andric emitCheck(V, Map.getShadow(V), Builder, CheckLoc::makeInsert()); 1950*0fca6ea1SDimitry Andric return; 1951*0fca6ea1SDimitry Andric } 1952*0fca6ea1SDimitry Andric } 1953*0fca6ea1SDimitry Andric 1954*0fca6ea1SDimitry Andric // Moves fast math flags from the function to individual instructions, and 1955*0fca6ea1SDimitry Andric // removes the attribute from the function. 1956*0fca6ea1SDimitry Andric // TODO: Make this controllable with a flag. 1957*0fca6ea1SDimitry Andric static void moveFastMathFlags(Function &F, 1958*0fca6ea1SDimitry Andric std::vector<Instruction *> &Instructions) { 1959*0fca6ea1SDimitry Andric FastMathFlags FMF; 1960*0fca6ea1SDimitry Andric #define MOVE_FLAG(attr, setter) \ 1961*0fca6ea1SDimitry Andric if (F.getFnAttribute(attr).getValueAsString() == "true") { \ 1962*0fca6ea1SDimitry Andric F.removeFnAttr(attr); \ 1963*0fca6ea1SDimitry Andric FMF.set##setter(); \ 1964*0fca6ea1SDimitry Andric } 1965*0fca6ea1SDimitry Andric MOVE_FLAG("unsafe-fp-math", Fast) 1966*0fca6ea1SDimitry Andric MOVE_FLAG("no-infs-fp-math", NoInfs) 1967*0fca6ea1SDimitry Andric MOVE_FLAG("no-nans-fp-math", NoNaNs) 1968*0fca6ea1SDimitry Andric MOVE_FLAG("no-signed-zeros-fp-math", NoSignedZeros) 1969*0fca6ea1SDimitry Andric #undef MOVE_FLAG 1970*0fca6ea1SDimitry Andric 1971*0fca6ea1SDimitry Andric for (Instruction *I : Instructions) 1972*0fca6ea1SDimitry Andric if (isa<FPMathOperator>(I)) 1973*0fca6ea1SDimitry Andric I->setFastMathFlags(FMF); 1974*0fca6ea1SDimitry Andric } 1975*0fca6ea1SDimitry Andric 1976*0fca6ea1SDimitry Andric bool NumericalStabilitySanitizer::sanitizeFunction( 1977*0fca6ea1SDimitry Andric Function &F, const TargetLibraryInfo &TLI) { 1978*0fca6ea1SDimitry Andric if (!F.hasFnAttribute(Attribute::SanitizeNumericalStability)) 1979*0fca6ea1SDimitry Andric return false; 1980*0fca6ea1SDimitry Andric 1981*0fca6ea1SDimitry Andric // This is required to prevent instrumenting call to __nsan_init from within 1982*0fca6ea1SDimitry Andric // the module constructor. 1983*0fca6ea1SDimitry Andric if (F.getName() == kNsanModuleCtorName) 1984*0fca6ea1SDimitry Andric return false; 1985*0fca6ea1SDimitry Andric SmallVector<Instruction *, 8> AllLoadsAndStores; 1986*0fca6ea1SDimitry Andric SmallVector<Instruction *, 8> LocalLoadsAndStores; 1987*0fca6ea1SDimitry Andric 1988*0fca6ea1SDimitry Andric // The instrumentation maintains: 1989*0fca6ea1SDimitry Andric // - for each IR value `v` of floating-point (or vector floating-point) type 1990*0fca6ea1SDimitry Andric // FT, a shadow IR value `s(v)` with twice the precision 2FT (e.g. 1991*0fca6ea1SDimitry Andric // double for float and f128 for double). 1992*0fca6ea1SDimitry Andric // - A shadow memory, which stores `s(v)` for any `v` that has been stored, 1993*0fca6ea1SDimitry Andric // along with a shadow memory tag, which stores whether the value in the 1994*0fca6ea1SDimitry Andric // corresponding shadow memory is valid. Note that this might be 1995*0fca6ea1SDimitry Andric // incorrect if a non-instrumented function stores to memory, or if 1996*0fca6ea1SDimitry Andric // memory is stored to through a char pointer. 1997*0fca6ea1SDimitry Andric // - A shadow stack, which holds `s(v)` for any floating-point argument `v` 1998*0fca6ea1SDimitry Andric // of a call to an instrumented function. This allows 1999*0fca6ea1SDimitry Andric // instrumented functions to retrieve the shadow values for their 2000*0fca6ea1SDimitry Andric // arguments. 2001*0fca6ea1SDimitry Andric // Because instrumented functions can be called from non-instrumented 2002*0fca6ea1SDimitry Andric // functions, the stack needs to include a tag so that the instrumented 2003*0fca6ea1SDimitry Andric // function knows whether shadow values are available for their 2004*0fca6ea1SDimitry Andric // parameters (i.e. whether is was called by an instrumented function). 2005*0fca6ea1SDimitry Andric // When shadow arguments are not available, they have to be recreated by 2006*0fca6ea1SDimitry Andric // extending the precision of the non-shadow arguments to the non-shadow 2007*0fca6ea1SDimitry Andric // value. Non-instrumented functions do not modify (or even know about) the 2008*0fca6ea1SDimitry Andric // shadow stack. The shadow stack pointer is __nsan_shadow_args. The shadow 2009*0fca6ea1SDimitry Andric // stack tag is __nsan_shadow_args_tag. The tag is any unique identifier 2010*0fca6ea1SDimitry Andric // for the function (we use the address of the function). Both variables 2011*0fca6ea1SDimitry Andric // are thread local. 2012*0fca6ea1SDimitry Andric // Example: 2013*0fca6ea1SDimitry Andric // calls shadow stack tag shadow stack 2014*0fca6ea1SDimitry Andric // ======================================================================= 2015*0fca6ea1SDimitry Andric // non_instrumented_1() 0 0 2016*0fca6ea1SDimitry Andric // | 2017*0fca6ea1SDimitry Andric // v 2018*0fca6ea1SDimitry Andric // instrumented_2(float a) 0 0 2019*0fca6ea1SDimitry Andric // | 2020*0fca6ea1SDimitry Andric // v 2021*0fca6ea1SDimitry Andric // instrumented_3(float b, double c) &instrumented_3 s(b),s(c) 2022*0fca6ea1SDimitry Andric // | 2023*0fca6ea1SDimitry Andric // v 2024*0fca6ea1SDimitry Andric // instrumented_4(float d) &instrumented_4 s(d) 2025*0fca6ea1SDimitry Andric // | 2026*0fca6ea1SDimitry Andric // v 2027*0fca6ea1SDimitry Andric // non_instrumented_5(float e) &non_instrumented_5 s(e) 2028*0fca6ea1SDimitry Andric // | 2029*0fca6ea1SDimitry Andric // v 2030*0fca6ea1SDimitry Andric // instrumented_6(float f) &non_instrumented_5 s(e) 2031*0fca6ea1SDimitry Andric // 2032*0fca6ea1SDimitry Andric // On entry, instrumented_2 checks whether the tag corresponds to its 2033*0fca6ea1SDimitry Andric // function ptr. 2034*0fca6ea1SDimitry Andric // Note that functions reset the tag to 0 after reading shadow parameters. 2035*0fca6ea1SDimitry Andric // This ensures that the function does not erroneously read invalid data if 2036*0fca6ea1SDimitry Andric // called twice in the same stack, once from an instrumented function and 2037*0fca6ea1SDimitry Andric // once from an uninstrumented one. For example, in the following example, 2038*0fca6ea1SDimitry Andric // resetting the tag in (A) ensures that (B) does not reuse the same the 2039*0fca6ea1SDimitry Andric // shadow arguments (which would be incorrect). 2040*0fca6ea1SDimitry Andric // instrumented_1(float a) 2041*0fca6ea1SDimitry Andric // | 2042*0fca6ea1SDimitry Andric // v 2043*0fca6ea1SDimitry Andric // instrumented_2(float b) (A) 2044*0fca6ea1SDimitry Andric // | 2045*0fca6ea1SDimitry Andric // v 2046*0fca6ea1SDimitry Andric // non_instrumented_3() 2047*0fca6ea1SDimitry Andric // | 2048*0fca6ea1SDimitry Andric // v 2049*0fca6ea1SDimitry Andric // instrumented_2(float b) (B) 2050*0fca6ea1SDimitry Andric // 2051*0fca6ea1SDimitry Andric // - A shadow return slot. Any function that returns a floating-point value 2052*0fca6ea1SDimitry Andric // places a shadow return value in __nsan_shadow_ret_val. Again, because 2053*0fca6ea1SDimitry Andric // we might be calling non-instrumented functions, this value is guarded 2054*0fca6ea1SDimitry Andric // by __nsan_shadow_ret_tag marker indicating which instrumented function 2055*0fca6ea1SDimitry Andric // placed the value in __nsan_shadow_ret_val, so that the caller can check 2056*0fca6ea1SDimitry Andric // that this corresponds to the callee. Both variables are thread local. 2057*0fca6ea1SDimitry Andric // 2058*0fca6ea1SDimitry Andric // For example, in the following example, the instrumentation in 2059*0fca6ea1SDimitry Andric // `instrumented_1` rejects the shadow return value from `instrumented_3` 2060*0fca6ea1SDimitry Andric // because is is not tagged as expected (`&instrumented_3` instead of 2061*0fca6ea1SDimitry Andric // `non_instrumented_2`): 2062*0fca6ea1SDimitry Andric // 2063*0fca6ea1SDimitry Andric // instrumented_1() 2064*0fca6ea1SDimitry Andric // | 2065*0fca6ea1SDimitry Andric // v 2066*0fca6ea1SDimitry Andric // float non_instrumented_2() 2067*0fca6ea1SDimitry Andric // | 2068*0fca6ea1SDimitry Andric // v 2069*0fca6ea1SDimitry Andric // float instrumented_3() 2070*0fca6ea1SDimitry Andric // 2071*0fca6ea1SDimitry Andric // Calls of known math functions (sin, cos, exp, ...) are duplicated to call 2072*0fca6ea1SDimitry Andric // their overload on the shadow type. 2073*0fca6ea1SDimitry Andric 2074*0fca6ea1SDimitry Andric // Collect all instructions before processing, as creating shadow values 2075*0fca6ea1SDimitry Andric // creates new instructions inside the function. 2076*0fca6ea1SDimitry Andric std::vector<Instruction *> OriginalInstructions; 2077*0fca6ea1SDimitry Andric for (BasicBlock &BB : F) 2078*0fca6ea1SDimitry Andric for (Instruction &Inst : BB) 2079*0fca6ea1SDimitry Andric OriginalInstructions.emplace_back(&Inst); 2080*0fca6ea1SDimitry Andric 2081*0fca6ea1SDimitry Andric moveFastMathFlags(F, OriginalInstructions); 2082*0fca6ea1SDimitry Andric ValueToShadowMap ValueToShadow(Config); 2083*0fca6ea1SDimitry Andric 2084*0fca6ea1SDimitry Andric // In the first pass, we create shadow values for all FT function arguments 2085*0fca6ea1SDimitry Andric // and all phis. This ensures that the DFS of the next pass does not have 2086*0fca6ea1SDimitry Andric // any loops. 2087*0fca6ea1SDimitry Andric std::vector<PHINode *> OriginalPhis; 2088*0fca6ea1SDimitry Andric createShadowArguments(F, TLI, ValueToShadow); 2089*0fca6ea1SDimitry Andric for (Instruction *I : OriginalInstructions) { 2090*0fca6ea1SDimitry Andric if (PHINode *Phi = dyn_cast<PHINode>(I)) { 2091*0fca6ea1SDimitry Andric if (PHINode *Shadow = maybeCreateShadowPhi(*Phi, TLI)) { 2092*0fca6ea1SDimitry Andric OriginalPhis.push_back(Phi); 2093*0fca6ea1SDimitry Andric ValueToShadow.setShadow(*Phi, *Shadow); 2094*0fca6ea1SDimitry Andric } 2095*0fca6ea1SDimitry Andric } 2096*0fca6ea1SDimitry Andric } 2097*0fca6ea1SDimitry Andric 2098*0fca6ea1SDimitry Andric // Create shadow values for all instructions creating FT values. 2099*0fca6ea1SDimitry Andric for (Instruction *I : OriginalInstructions) 2100*0fca6ea1SDimitry Andric maybeCreateShadowValue(*I, TLI, ValueToShadow); 2101*0fca6ea1SDimitry Andric 2102*0fca6ea1SDimitry Andric // Propagate shadow values across stores, calls and rets. 2103*0fca6ea1SDimitry Andric for (Instruction *I : OriginalInstructions) 2104*0fca6ea1SDimitry Andric propagateShadowValues(*I, TLI, ValueToShadow); 2105*0fca6ea1SDimitry Andric 2106*0fca6ea1SDimitry Andric // The last pass populates shadow phis with shadow values. 2107*0fca6ea1SDimitry Andric for (PHINode *Phi : OriginalPhis) { 2108*0fca6ea1SDimitry Andric PHINode *ShadowPhi = dyn_cast<PHINode>(ValueToShadow.getShadow(Phi)); 2109*0fca6ea1SDimitry Andric for (unsigned I : seq(Phi->getNumOperands())) { 2110*0fca6ea1SDimitry Andric Value *V = Phi->getOperand(I); 2111*0fca6ea1SDimitry Andric Value *Shadow = ValueToShadow.getShadow(V); 2112*0fca6ea1SDimitry Andric BasicBlock *IncomingBB = Phi->getIncomingBlock(I); 2113*0fca6ea1SDimitry Andric // For some instructions (e.g. invoke), we create the shadow in a separate 2114*0fca6ea1SDimitry Andric // block, different from the block where the original value is created. 2115*0fca6ea1SDimitry Andric // In that case, the shadow phi might need to refer to this block instead 2116*0fca6ea1SDimitry Andric // of the original block. 2117*0fca6ea1SDimitry Andric // Note that this can only happen for instructions as constant shadows are 2118*0fca6ea1SDimitry Andric // always created in the same block. 2119*0fca6ea1SDimitry Andric ShadowPhi->addIncoming(Shadow, IncomingBB); 2120*0fca6ea1SDimitry Andric } 2121*0fca6ea1SDimitry Andric } 2122*0fca6ea1SDimitry Andric 2123*0fca6ea1SDimitry Andric return !ValueToShadow.empty(); 2124*0fca6ea1SDimitry Andric } 2125*0fca6ea1SDimitry Andric 2126*0fca6ea1SDimitry Andric // Instrument the memory intrinsics so that they properly modify the shadow 2127*0fca6ea1SDimitry Andric // memory. 2128*0fca6ea1SDimitry Andric bool NumericalStabilitySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { 2129*0fca6ea1SDimitry Andric IRBuilder<> Builder(MI); 2130*0fca6ea1SDimitry Andric if (auto *M = dyn_cast<MemSetInst>(MI)) { 2131*0fca6ea1SDimitry Andric Builder.CreateCall( 2132*0fca6ea1SDimitry Andric NsanSetValueUnknown, 2133*0fca6ea1SDimitry Andric {/*Address=*/M->getArgOperand(0), 2134*0fca6ea1SDimitry Andric /*Size=*/Builder.CreateIntCast(M->getArgOperand(2), IntptrTy, false)}); 2135*0fca6ea1SDimitry Andric } else if (auto *M = dyn_cast<MemTransferInst>(MI)) { 2136*0fca6ea1SDimitry Andric Builder.CreateCall( 2137*0fca6ea1SDimitry Andric NsanCopyValues, 2138*0fca6ea1SDimitry Andric {/*Destination=*/M->getArgOperand(0), 2139*0fca6ea1SDimitry Andric /*Source=*/M->getArgOperand(1), 2140*0fca6ea1SDimitry Andric /*Size=*/Builder.CreateIntCast(M->getArgOperand(2), IntptrTy, false)}); 2141*0fca6ea1SDimitry Andric } 2142*0fca6ea1SDimitry Andric return false; 2143*0fca6ea1SDimitry Andric } 2144*0fca6ea1SDimitry Andric 2145*0fca6ea1SDimitry Andric void NumericalStabilitySanitizer::maybeAddSuffixForNsanInterface(CallBase *CI) { 2146*0fca6ea1SDimitry Andric Function *Fn = CI->getCalledFunction(); 2147*0fca6ea1SDimitry Andric if (Fn == nullptr) 2148*0fca6ea1SDimitry Andric return; 2149*0fca6ea1SDimitry Andric 2150*0fca6ea1SDimitry Andric if (!Fn->getName().starts_with("__nsan_")) 2151*0fca6ea1SDimitry Andric return; 2152*0fca6ea1SDimitry Andric 2153*0fca6ea1SDimitry Andric if (Fn->getName() == "__nsan_dump_shadow_mem") { 2154*0fca6ea1SDimitry Andric assert(CI->arg_size() == 4 && 2155*0fca6ea1SDimitry Andric "invalid prototype for __nsan_dump_shadow_mem"); 2156*0fca6ea1SDimitry Andric // __nsan_dump_shadow_mem requires an extra parameter with the dynamic 2157*0fca6ea1SDimitry Andric // configuration: 2158*0fca6ea1SDimitry Andric // (shadow_type_id_for_long_double << 16) | (shadow_type_id_for_double << 8) 2159*0fca6ea1SDimitry Andric // | shadow_type_id_for_double 2160*0fca6ea1SDimitry Andric const uint64_t shadow_value_type_ids = 2161*0fca6ea1SDimitry Andric (static_cast<size_t>(Config.byValueType(kLongDouble).getNsanTypeId()) 2162*0fca6ea1SDimitry Andric << 16) | 2163*0fca6ea1SDimitry Andric (static_cast<size_t>(Config.byValueType(kDouble).getNsanTypeId()) 2164*0fca6ea1SDimitry Andric << 8) | 2165*0fca6ea1SDimitry Andric static_cast<size_t>(Config.byValueType(kFloat).getNsanTypeId()); 2166*0fca6ea1SDimitry Andric CI->setArgOperand(3, ConstantInt::get(IntptrTy, shadow_value_type_ids)); 2167*0fca6ea1SDimitry Andric } 2168*0fca6ea1SDimitry Andric } 2169