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:
getNsanTypeId() const167*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'> {
getType(LLVMContext & Context) const173*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'> {
getType(LLVMContext & Context) const180*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'> {
getType(LLVMContext & Context) const187*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'> {
getType(LLVMContext & Context) const194*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>
fromNsanTypeId(const char TypeId)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.
ftValueTypeFromType(Type * FT)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.
typeFromFTValueType(FTValueType VT,LLVMContext & Context)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.
typeNameFromFTValueType(FTValueType VT)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:
MappingConfig(LLVMContext & C)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
byValueType(FTValueType VT) const305*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.
getExtendedFPType(Type * FT) const311*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
getMemoryExtentsOrDie(Type * FT)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.
makeStore(Value * Address)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 }
makeLoad(Value * Address)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.
makeArg(int ArgId)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.
makeRet()373*0fca6ea1SDimitry Andric static CheckLoc makeRet() { return CheckLoc(kRet); }
374*0fca6ea1SDimitry Andric
375*0fca6ea1SDimitry Andric // Creates a location that references a vector insert.
makeInsert()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.
getType(LLVMContext & C) const380*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.
getValue(Type * IntptrTy,IRBuilder<> & Builder) const387*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 };
CheckLoc(CheckType CheckTy)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:
ValueToShadowMap(const MappingConfig & Config)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.
setShadow(Value & V,Value & Shadow)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.
hasShadow(Value * V) const446*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.
getShadow(Value * V) const452*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
empty() const458*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.
extendConstantFP(APFloat CV,const fltSemantics & To) const462*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.
getShadowConstant(Constant * C) const469*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
run(Module & M,ModuleAnalysisManager & MAM)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
createThreadLocalGV(const char * Name,Module & M,Type * Ty)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
NumericalStabilitySanitizer(Module & M)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).
addrPointsToConstantData(Value * Addr)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 // }
createShadowArguments(Function & F,const TargetLibraryInfo & TLI,ValueToShadowMap & Map)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.
shouldCheckArgs(CallBase & CI,const TargetLibraryInfo & TLI,const std::optional<Regex> & CheckFunctionsFilter)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).
populateShadowStack(CallBase & CI,const TargetLibraryInfo & TLI,const ValueToShadowMap & Map)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
emitCheckInternal(Value * V,Value * ShadowV,IRBuilder<> & Builder,CheckLoc Loc)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 ?
emitCheck(Value * V,Value * ShadowV,IRBuilder<> & Builder,CheckLoc Loc)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.
emitFCmpCheck(FCmpInst & FCmp,const ValueToShadowMap & Map)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.
maybeCreateShadowPhi(PHINode & Phi,const TargetLibraryInfo & TLI)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
handleLoad(LoadInst & Load,Type * VT,Type * ExtendedVT)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
handleTrunc(const FPTruncInst & Trunc,Type * VT,Type * ExtendedVT,const ValueToShadowMap & Map,IRBuilder<> & Builder)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
handleExt(const FPExtInst & Ext,Type * VT,Type * ExtendedVT,const ValueToShadowMap & Map,IRBuilder<> & Builder)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
makeDoubleDouble(LLVMContext & C)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
makeX86FP80X86FP80(LLVMContext & C)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
makeDoubleDoubleI32(LLVMContext & C)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
makeX86FP80X86FP80I32(LLVMContext & C)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
makeDoubleDoubleDouble(LLVMContext & C)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
makeX86FP80X86FP80X86FP80(LLVMContext & C)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
makeDoubleDoubleDoubleDouble(LLVMContext & C)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
makeX86FP80X86FP80X86FP80X86FP80(LLVMContext & C)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
get(LibFunc LFunc)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
widen(StringRef Name)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.
getIntrinsicFromLibfunc(Function & Fn,Type * VT,const TargetLibraryInfo & TLI)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.
maybeHandleKnownCallBase(CallBase & Call,Type * VT,Type * ExtendedVT,const TargetLibraryInfo & TLI,const ValueToShadowMap & Map,IRBuilder<> & Builder)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.
handleCallBase(CallBase & Call,Type * VT,Type * ExtendedVT,const TargetLibraryInfo & TLI,const ValueToShadowMap & Map,IRBuilder<> & Builder)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.
createShadowValueWithOperandsAvailable(Instruction & Inst,const TargetLibraryInfo & TLI,const ValueToShadowMap & Map)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.
maybeCreateShadowValue(Instruction & Root,const TargetLibraryInfo & TLI,ValueToShadowMap & Map)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.
propagateFTStore(StoreInst & Store,Type * VT,Type * ExtendedVT,const ValueToShadowMap & Map)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.
propagateNonFTStore(StoreInst & Store,Type * VT,const ValueToShadowMap & Map)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
propagateShadowValues(Instruction & Inst,const TargetLibraryInfo & TLI,const ValueToShadowMap & Map)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.
moveFastMathFlags(Function & F,std::vector<Instruction * > & Instructions)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
sanitizeFunction(Function & F,const TargetLibraryInfo & TLI)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.
instrumentMemIntrinsic(MemIntrinsic * MI)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
maybeAddSuffixForNsanInterface(CallBase * CI)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