8724 lines · cpp
1//===- MemorySanitizer.cpp - detector of uninitialized reads --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// This file is a part of MemorySanitizer, a detector of uninitialized11/// reads.12///13/// The algorithm of the tool is similar to Memcheck14/// (https://static.usenix.org/event/usenix05/tech/general/full_papers/seward/seward_html/usenix2005.html)15/// We associate a few shadow bits with every byte of the application memory,16/// poison the shadow of the malloc-ed or alloca-ed memory, load the shadow,17/// bits on every memory read, propagate the shadow bits through some of the18/// arithmetic instruction (including MOV), store the shadow bits on every19/// memory write, report a bug on some other instructions (e.g. JMP) if the20/// associated shadow is poisoned.21///22/// But there are differences too. The first and the major one:23/// compiler instrumentation instead of binary instrumentation. This24/// gives us much better register allocation, possible compiler25/// optimizations and a fast start-up. But this brings the major issue26/// as well: msan needs to see all program events, including system27/// calls and reads/writes in system libraries, so we either need to28/// compile *everything* with msan or use a binary translation29/// component (e.g. DynamoRIO) to instrument pre-built libraries.30/// Another difference from Memcheck is that we use 8 shadow bits per31/// byte of application memory and use a direct shadow mapping. This32/// greatly simplifies the instrumentation code and avoids races on33/// shadow updates (Memcheck is single-threaded so races are not a34/// concern there. Memcheck uses 2 shadow bits per byte with a slow35/// path storage that uses 8 bits per byte).36///37/// The default value of shadow is 0, which means "clean" (not poisoned).38///39/// Every module initializer should call __msan_init to ensure that the40/// shadow memory is ready. On error, __msan_warning is called. Since41/// parameters and return values may be passed via registers, we have a42/// specialized thread-local shadow for return values43/// (__msan_retval_tls) and parameters (__msan_param_tls).44///45/// Origin tracking.46///47/// MemorySanitizer can track origins (allocation points) of all uninitialized48/// values. This behavior is controlled with a flag (msan-track-origins) and is49/// disabled by default.50///51/// Origins are 4-byte values created and interpreted by the runtime library.52/// They are stored in a second shadow mapping, one 4-byte value for 4 bytes53/// of application memory. Propagation of origins is basically a bunch of54/// "select" instructions that pick the origin of a dirty argument, if an55/// instruction has one.56///57/// Every 4 aligned, consecutive bytes of application memory have one origin58/// value associated with them. If these bytes contain uninitialized data59/// coming from 2 different allocations, the last store wins. Because of this,60/// MemorySanitizer reports can show unrelated origins, but this is unlikely in61/// practice.62///63/// Origins are meaningless for fully initialized values, so MemorySanitizer64/// avoids storing origin to memory when a fully initialized value is stored.65/// This way it avoids needless overwriting origin of the 4-byte region on66/// a short (i.e. 1 byte) clean store, and it is also good for performance.67///68/// Atomic handling.69///70/// Ideally, every atomic store of application value should update the71/// corresponding shadow location in an atomic way. Unfortunately, atomic store72/// of two disjoint locations can not be done without severe slowdown.73///74/// Therefore, we implement an approximation that may err on the safe side.75/// In this implementation, every atomically accessed location in the program76/// may only change from (partially) uninitialized to fully initialized, but77/// not the other way around. We load the shadow _after_ the application load,78/// and we store the shadow _before_ the app store. Also, we always store clean79/// shadow (if the application store is atomic). This way, if the store-load80/// pair constitutes a happens-before arc, shadow store and load are correctly81/// ordered such that the load will get either the value that was stored, or82/// some later value (which is always clean).83///84/// This does not work very well with Compare-And-Swap (CAS) and85/// Read-Modify-Write (RMW) operations. To follow the above logic, CAS and RMW86/// must store the new shadow before the app operation, and load the shadow87/// after the app operation. Computers don't work this way. Current88/// implementation ignores the load aspect of CAS/RMW, always returning a clean89/// value. It implements the store part as a simple atomic store by storing a90/// clean shadow.91///92/// Instrumenting inline assembly.93///94/// For inline assembly code LLVM has little idea about which memory locations95/// become initialized depending on the arguments. It can be possible to figure96/// out which arguments are meant to point to inputs and outputs, but the97/// actual semantics can be only visible at runtime. In the Linux kernel it's98/// also possible that the arguments only indicate the offset for a base taken99/// from a segment register, so it's dangerous to treat any asm() arguments as100/// pointers. We take a conservative approach generating calls to101/// __msan_instrument_asm_store(ptr, size)102/// , which defer the memory unpoisoning to the runtime library.103/// The latter can perform more complex address checks to figure out whether104/// it's safe to touch the shadow memory.105/// Like with atomic operations, we call __msan_instrument_asm_store() before106/// the assembly call, so that changes to the shadow memory will be seen by107/// other threads together with main memory initialization.108///109/// KernelMemorySanitizer (KMSAN) implementation.110///111/// The major differences between KMSAN and MSan instrumentation are:112/// - KMSAN always tracks the origins and implies msan-keep-going=true;113/// - KMSAN allocates shadow and origin memory for each page separately, so114/// there are no explicit accesses to shadow and origin in the115/// instrumentation.116/// Shadow and origin values for a particular X-byte memory location117/// (X=1,2,4,8) are accessed through pointers obtained via the118/// __msan_metadata_ptr_for_load_X(ptr)119/// __msan_metadata_ptr_for_store_X(ptr)120/// functions. The corresponding functions check that the X-byte accesses121/// are possible and returns the pointers to shadow and origin memory.122/// Arbitrary sized accesses are handled with:123/// __msan_metadata_ptr_for_load_n(ptr, size)124/// __msan_metadata_ptr_for_store_n(ptr, size);125/// Note that the sanitizer code has to deal with how shadow/origin pairs126/// returned by the these functions are represented in different ABIs. In127/// the X86_64 ABI they are returned in RDX:RAX, in PowerPC64 they are128/// returned in r3 and r4, and in the SystemZ ABI they are written to memory129/// pointed to by a hidden parameter.130/// - TLS variables are stored in a single per-task struct. A call to a131/// function __msan_get_context_state() returning a pointer to that struct132/// is inserted into every instrumented function before the entry block;133/// - __msan_warning() takes a 32-bit origin parameter;134/// - local variables are poisoned with __msan_poison_alloca() upon function135/// entry and unpoisoned with __msan_unpoison_alloca() before leaving the136/// function;137/// - the pass doesn't declare any global variables or add global constructors138/// to the translation unit.139///140/// Also, KMSAN currently ignores uninitialized memory passed into inline asm141/// calls, making sure we're on the safe side wrt. possible false positives.142///143/// KernelMemorySanitizer only supports X86_64, SystemZ and PowerPC64 at the144/// moment.145///146//147// FIXME: This sanitizer does not yet handle scalable vectors148//149//===----------------------------------------------------------------------===//150 151#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"152#include "llvm/ADT/APInt.h"153#include "llvm/ADT/ArrayRef.h"154#include "llvm/ADT/DenseMap.h"155#include "llvm/ADT/DepthFirstIterator.h"156#include "llvm/ADT/SetVector.h"157#include "llvm/ADT/SmallPtrSet.h"158#include "llvm/ADT/SmallVector.h"159#include "llvm/ADT/StringExtras.h"160#include "llvm/ADT/StringRef.h"161#include "llvm/Analysis/GlobalsModRef.h"162#include "llvm/Analysis/TargetLibraryInfo.h"163#include "llvm/Analysis/ValueTracking.h"164#include "llvm/IR/Argument.h"165#include "llvm/IR/AttributeMask.h"166#include "llvm/IR/Attributes.h"167#include "llvm/IR/BasicBlock.h"168#include "llvm/IR/CallingConv.h"169#include "llvm/IR/Constant.h"170#include "llvm/IR/Constants.h"171#include "llvm/IR/DataLayout.h"172#include "llvm/IR/DerivedTypes.h"173#include "llvm/IR/Function.h"174#include "llvm/IR/GlobalValue.h"175#include "llvm/IR/GlobalVariable.h"176#include "llvm/IR/IRBuilder.h"177#include "llvm/IR/InlineAsm.h"178#include "llvm/IR/InstVisitor.h"179#include "llvm/IR/InstrTypes.h"180#include "llvm/IR/Instruction.h"181#include "llvm/IR/Instructions.h"182#include "llvm/IR/IntrinsicInst.h"183#include "llvm/IR/Intrinsics.h"184#include "llvm/IR/IntrinsicsAArch64.h"185#include "llvm/IR/IntrinsicsX86.h"186#include "llvm/IR/MDBuilder.h"187#include "llvm/IR/Module.h"188#include "llvm/IR/Type.h"189#include "llvm/IR/Value.h"190#include "llvm/IR/ValueMap.h"191#include "llvm/Support/Alignment.h"192#include "llvm/Support/AtomicOrdering.h"193#include "llvm/Support/Casting.h"194#include "llvm/Support/CommandLine.h"195#include "llvm/Support/Debug.h"196#include "llvm/Support/DebugCounter.h"197#include "llvm/Support/ErrorHandling.h"198#include "llvm/Support/MathExtras.h"199#include "llvm/Support/raw_ostream.h"200#include "llvm/TargetParser/Triple.h"201#include "llvm/Transforms/Utils/BasicBlockUtils.h"202#include "llvm/Transforms/Utils/Instrumentation.h"203#include "llvm/Transforms/Utils/Local.h"204#include "llvm/Transforms/Utils/ModuleUtils.h"205#include <algorithm>206#include <cassert>207#include <cstddef>208#include <cstdint>209#include <memory>210#include <numeric>211#include <string>212#include <tuple>213 214using namespace llvm;215 216#define DEBUG_TYPE "msan"217 218DEBUG_COUNTER(DebugInsertCheck, "msan-insert-check",219 "Controls which checks to insert");220 221DEBUG_COUNTER(DebugInstrumentInstruction, "msan-instrument-instruction",222 "Controls which instruction to instrument");223 224static const unsigned kOriginSize = 4;225static const Align kMinOriginAlignment = Align(4);226static const Align kShadowTLSAlignment = Align(8);227 228// These constants must be kept in sync with the ones in msan.h.229// TODO: increase size to match SVE/SVE2/SME/SME2 limits230static const unsigned kParamTLSSize = 800;231static const unsigned kRetvalTLSSize = 800;232 233// Accesses sizes are powers of two: 1, 2, 4, 8.234static const size_t kNumberOfAccessSizes = 4;235 236/// Track origins of uninitialized values.237///238/// Adds a section to MemorySanitizer report that points to the allocation239/// (stack or heap) the uninitialized bits came from originally.240static cl::opt<int> ClTrackOrigins(241 "msan-track-origins",242 cl::desc("Track origins (allocation sites) of poisoned memory"), cl::Hidden,243 cl::init(0));244 245static cl::opt<bool> ClKeepGoing("msan-keep-going",246 cl::desc("keep going after reporting a UMR"),247 cl::Hidden, cl::init(false));248 249static cl::opt<bool>250 ClPoisonStack("msan-poison-stack",251 cl::desc("poison uninitialized stack variables"), cl::Hidden,252 cl::init(true));253 254static cl::opt<bool> ClPoisonStackWithCall(255 "msan-poison-stack-with-call",256 cl::desc("poison uninitialized stack variables with a call"), cl::Hidden,257 cl::init(false));258 259static cl::opt<int> ClPoisonStackPattern(260 "msan-poison-stack-pattern",261 cl::desc("poison uninitialized stack variables with the given pattern"),262 cl::Hidden, cl::init(0xff));263 264static cl::opt<bool>265 ClPrintStackNames("msan-print-stack-names",266 cl::desc("Print name of local stack variable"),267 cl::Hidden, cl::init(true));268 269static cl::opt<bool>270 ClPoisonUndef("msan-poison-undef",271 cl::desc("Poison fully undef temporary values. "272 "Partially undefined constant vectors "273 "are unaffected by this flag (see "274 "-msan-poison-undef-vectors)."),275 cl::Hidden, cl::init(true));276 277static cl::opt<bool> ClPoisonUndefVectors(278 "msan-poison-undef-vectors",279 cl::desc("Precisely poison partially undefined constant vectors. "280 "If false (legacy behavior), the entire vector is "281 "considered fully initialized, which may lead to false "282 "negatives. Fully undefined constant vectors are "283 "unaffected by this flag (see -msan-poison-undef)."),284 cl::Hidden, cl::init(false));285 286static cl::opt<bool> ClPreciseDisjointOr(287 "msan-precise-disjoint-or",288 cl::desc("Precisely poison disjoint OR. If false (legacy behavior), "289 "disjointedness is ignored (i.e., 1|1 is initialized)."),290 cl::Hidden, cl::init(false));291 292static cl::opt<bool>293 ClHandleICmp("msan-handle-icmp",294 cl::desc("propagate shadow through ICmpEQ and ICmpNE"),295 cl::Hidden, cl::init(true));296 297static cl::opt<bool>298 ClHandleICmpExact("msan-handle-icmp-exact",299 cl::desc("exact handling of relational integer ICmp"),300 cl::Hidden, cl::init(true));301 302static cl::opt<bool> ClHandleLifetimeIntrinsics(303 "msan-handle-lifetime-intrinsics",304 cl::desc(305 "when possible, poison scoped variables at the beginning of the scope "306 "(slower, but more precise)"),307 cl::Hidden, cl::init(true));308 309// When compiling the Linux kernel, we sometimes see false positives related to310// MSan being unable to understand that inline assembly calls may initialize311// local variables.312// This flag makes the compiler conservatively unpoison every memory location313// passed into an assembly call. Note that this may cause false positives.314// Because it's impossible to figure out the array sizes, we can only unpoison315// the first sizeof(type) bytes for each type* pointer.316static cl::opt<bool> ClHandleAsmConservative(317 "msan-handle-asm-conservative",318 cl::desc("conservative handling of inline assembly"), cl::Hidden,319 cl::init(true));320 321// This flag controls whether we check the shadow of the address322// operand of load or store. Such bugs are very rare, since load from323// a garbage address typically results in SEGV, but still happen324// (e.g. only lower bits of address are garbage, or the access happens325// early at program startup where malloc-ed memory is more likely to326// be zeroed. As of 2012-08-28 this flag adds 20% slowdown.327static cl::opt<bool> ClCheckAccessAddress(328 "msan-check-access-address",329 cl::desc("report accesses through a pointer which has poisoned shadow"),330 cl::Hidden, cl::init(true));331 332static cl::opt<bool> ClEagerChecks(333 "msan-eager-checks",334 cl::desc("check arguments and return values at function call boundaries"),335 cl::Hidden, cl::init(false));336 337static cl::opt<bool> ClDumpStrictInstructions(338 "msan-dump-strict-instructions",339 cl::desc("print out instructions with default strict semantics i.e.,"340 "check that all the inputs are fully initialized, and mark "341 "the output as fully initialized. These semantics are applied "342 "to instructions that could not be handled explicitly nor "343 "heuristically."),344 cl::Hidden, cl::init(false));345 346// Currently, all the heuristically handled instructions are specifically347// IntrinsicInst. However, we use the broader "HeuristicInstructions" name348// to parallel 'msan-dump-strict-instructions', and to keep the door open to349// handling non-intrinsic instructions heuristically.350static cl::opt<bool> ClDumpHeuristicInstructions(351 "msan-dump-heuristic-instructions",352 cl::desc("Prints 'unknown' instructions that were handled heuristically. "353 "Use -msan-dump-strict-instructions to print instructions that "354 "could not be handled explicitly nor heuristically."),355 cl::Hidden, cl::init(false));356 357static cl::opt<int> ClInstrumentationWithCallThreshold(358 "msan-instrumentation-with-call-threshold",359 cl::desc(360 "If the function being instrumented requires more than "361 "this number of checks and origin stores, use callbacks instead of "362 "inline checks (-1 means never use callbacks)."),363 cl::Hidden, cl::init(3500));364 365static cl::opt<bool>366 ClEnableKmsan("msan-kernel",367 cl::desc("Enable KernelMemorySanitizer instrumentation"),368 cl::Hidden, cl::init(false));369 370static cl::opt<bool>371 ClDisableChecks("msan-disable-checks",372 cl::desc("Apply no_sanitize to the whole file"), cl::Hidden,373 cl::init(false));374 375static cl::opt<bool>376 ClCheckConstantShadow("msan-check-constant-shadow",377 cl::desc("Insert checks for constant shadow values"),378 cl::Hidden, cl::init(true));379 380// This is off by default because of a bug in gold:381// https://sourceware.org/bugzilla/show_bug.cgi?id=19002382static cl::opt<bool>383 ClWithComdat("msan-with-comdat",384 cl::desc("Place MSan constructors in comdat sections"),385 cl::Hidden, cl::init(false));386 387// These options allow to specify custom memory map parameters388// See MemoryMapParams for details.389static cl::opt<uint64_t> ClAndMask("msan-and-mask",390 cl::desc("Define custom MSan AndMask"),391 cl::Hidden, cl::init(0));392 393static cl::opt<uint64_t> ClXorMask("msan-xor-mask",394 cl::desc("Define custom MSan XorMask"),395 cl::Hidden, cl::init(0));396 397static cl::opt<uint64_t> ClShadowBase("msan-shadow-base",398 cl::desc("Define custom MSan ShadowBase"),399 cl::Hidden, cl::init(0));400 401static cl::opt<uint64_t> ClOriginBase("msan-origin-base",402 cl::desc("Define custom MSan OriginBase"),403 cl::Hidden, cl::init(0));404 405static cl::opt<int>406 ClDisambiguateWarning("msan-disambiguate-warning-threshold",407 cl::desc("Define threshold for number of checks per "408 "debug location to force origin update."),409 cl::Hidden, cl::init(3));410 411const char kMsanModuleCtorName[] = "msan.module_ctor";412const char kMsanInitName[] = "__msan_init";413 414namespace {415 416// Memory map parameters used in application-to-shadow address calculation.417// Offset = (Addr & ~AndMask) ^ XorMask418// Shadow = ShadowBase + Offset419// Origin = OriginBase + Offset420struct MemoryMapParams {421 uint64_t AndMask;422 uint64_t XorMask;423 uint64_t ShadowBase;424 uint64_t OriginBase;425};426 427struct PlatformMemoryMapParams {428 const MemoryMapParams *bits32;429 const MemoryMapParams *bits64;430};431 432} // end anonymous namespace433 434// i386 Linux435static const MemoryMapParams Linux_I386_MemoryMapParams = {436 0x000080000000, // AndMask437 0, // XorMask (not used)438 0, // ShadowBase (not used)439 0x000040000000, // OriginBase440};441 442// x86_64 Linux443static const MemoryMapParams Linux_X86_64_MemoryMapParams = {444 0, // AndMask (not used)445 0x500000000000, // XorMask446 0, // ShadowBase (not used)447 0x100000000000, // OriginBase448};449 450// mips32 Linux451// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests452// after picking good constants453 454// mips64 Linux455static const MemoryMapParams Linux_MIPS64_MemoryMapParams = {456 0, // AndMask (not used)457 0x008000000000, // XorMask458 0, // ShadowBase (not used)459 0x002000000000, // OriginBase460};461 462// ppc32 Linux463// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests464// after picking good constants465 466// ppc64 Linux467static const MemoryMapParams Linux_PowerPC64_MemoryMapParams = {468 0xE00000000000, // AndMask469 0x100000000000, // XorMask470 0x080000000000, // ShadowBase471 0x1C0000000000, // OriginBase472};473 474// s390x Linux475static const MemoryMapParams Linux_S390X_MemoryMapParams = {476 0xC00000000000, // AndMask477 0, // XorMask (not used)478 0x080000000000, // ShadowBase479 0x1C0000000000, // OriginBase480};481 482// arm32 Linux483// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests484// after picking good constants485 486// aarch64 Linux487static const MemoryMapParams Linux_AArch64_MemoryMapParams = {488 0, // AndMask (not used)489 0x0B00000000000, // XorMask490 0, // ShadowBase (not used)491 0x0200000000000, // OriginBase492};493 494// loongarch64 Linux495static const MemoryMapParams Linux_LoongArch64_MemoryMapParams = {496 0, // AndMask (not used)497 0x500000000000, // XorMask498 0, // ShadowBase (not used)499 0x100000000000, // OriginBase500};501 502// riscv32 Linux503// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests504// after picking good constants505 506// aarch64 FreeBSD507static const MemoryMapParams FreeBSD_AArch64_MemoryMapParams = {508 0x1800000000000, // AndMask509 0x0400000000000, // XorMask510 0x0200000000000, // ShadowBase511 0x0700000000000, // OriginBase512};513 514// i386 FreeBSD515static const MemoryMapParams FreeBSD_I386_MemoryMapParams = {516 0x000180000000, // AndMask517 0x000040000000, // XorMask518 0x000020000000, // ShadowBase519 0x000700000000, // OriginBase520};521 522// x86_64 FreeBSD523static const MemoryMapParams FreeBSD_X86_64_MemoryMapParams = {524 0xc00000000000, // AndMask525 0x200000000000, // XorMask526 0x100000000000, // ShadowBase527 0x380000000000, // OriginBase528};529 530// x86_64 NetBSD531static const MemoryMapParams NetBSD_X86_64_MemoryMapParams = {532 0, // AndMask533 0x500000000000, // XorMask534 0, // ShadowBase535 0x100000000000, // OriginBase536};537 538static const PlatformMemoryMapParams Linux_X86_MemoryMapParams = {539 &Linux_I386_MemoryMapParams,540 &Linux_X86_64_MemoryMapParams,541};542 543static const PlatformMemoryMapParams Linux_MIPS_MemoryMapParams = {544 nullptr,545 &Linux_MIPS64_MemoryMapParams,546};547 548static const PlatformMemoryMapParams Linux_PowerPC_MemoryMapParams = {549 nullptr,550 &Linux_PowerPC64_MemoryMapParams,551};552 553static const PlatformMemoryMapParams Linux_S390_MemoryMapParams = {554 nullptr,555 &Linux_S390X_MemoryMapParams,556};557 558static const PlatformMemoryMapParams Linux_ARM_MemoryMapParams = {559 nullptr,560 &Linux_AArch64_MemoryMapParams,561};562 563static const PlatformMemoryMapParams Linux_LoongArch_MemoryMapParams = {564 nullptr,565 &Linux_LoongArch64_MemoryMapParams,566};567 568static const PlatformMemoryMapParams FreeBSD_ARM_MemoryMapParams = {569 nullptr,570 &FreeBSD_AArch64_MemoryMapParams,571};572 573static const PlatformMemoryMapParams FreeBSD_X86_MemoryMapParams = {574 &FreeBSD_I386_MemoryMapParams,575 &FreeBSD_X86_64_MemoryMapParams,576};577 578static const PlatformMemoryMapParams NetBSD_X86_MemoryMapParams = {579 nullptr,580 &NetBSD_X86_64_MemoryMapParams,581};582 583namespace {584 585/// Instrument functions of a module to detect uninitialized reads.586///587/// Instantiating MemorySanitizer inserts the msan runtime library API function588/// declarations into the module if they don't exist already. Instantiating589/// ensures the __msan_init function is in the list of global constructors for590/// the module.591class MemorySanitizer {592public:593 MemorySanitizer(Module &M, MemorySanitizerOptions Options)594 : CompileKernel(Options.Kernel), TrackOrigins(Options.TrackOrigins),595 Recover(Options.Recover), EagerChecks(Options.EagerChecks) {596 initializeModule(M);597 }598 599 // MSan cannot be moved or copied because of MapParams.600 MemorySanitizer(MemorySanitizer &&) = delete;601 MemorySanitizer &operator=(MemorySanitizer &&) = delete;602 MemorySanitizer(const MemorySanitizer &) = delete;603 MemorySanitizer &operator=(const MemorySanitizer &) = delete;604 605 bool sanitizeFunction(Function &F, TargetLibraryInfo &TLI);606 607private:608 friend struct MemorySanitizerVisitor;609 friend struct VarArgHelperBase;610 friend struct VarArgAMD64Helper;611 friend struct VarArgAArch64Helper;612 friend struct VarArgPowerPC64Helper;613 friend struct VarArgPowerPC32Helper;614 friend struct VarArgSystemZHelper;615 friend struct VarArgI386Helper;616 friend struct VarArgGenericHelper;617 618 void initializeModule(Module &M);619 void initializeCallbacks(Module &M, const TargetLibraryInfo &TLI);620 void createKernelApi(Module &M, const TargetLibraryInfo &TLI);621 void createUserspaceApi(Module &M, const TargetLibraryInfo &TLI);622 623 template <typename... ArgsTy>624 FunctionCallee getOrInsertMsanMetadataFunction(Module &M, StringRef Name,625 ArgsTy... Args);626 627 /// True if we're compiling the Linux kernel.628 bool CompileKernel;629 /// Track origins (allocation points) of uninitialized values.630 int TrackOrigins;631 bool Recover;632 bool EagerChecks;633 634 Triple TargetTriple;635 LLVMContext *C;636 Type *IntptrTy; ///< Integer type with the size of a ptr in default AS.637 Type *OriginTy;638 PointerType *PtrTy; ///< Integer type with the size of a ptr in default AS.639 640 // XxxTLS variables represent the per-thread state in MSan and per-task state641 // in KMSAN.642 // For the userspace these point to thread-local globals. In the kernel land643 // they point to the members of a per-task struct obtained via a call to644 // __msan_get_context_state().645 646 /// Thread-local shadow storage for function parameters.647 Value *ParamTLS;648 649 /// Thread-local origin storage for function parameters.650 Value *ParamOriginTLS;651 652 /// Thread-local shadow storage for function return value.653 Value *RetvalTLS;654 655 /// Thread-local origin storage for function return value.656 Value *RetvalOriginTLS;657 658 /// Thread-local shadow storage for in-register va_arg function.659 Value *VAArgTLS;660 661 /// Thread-local shadow storage for in-register va_arg function.662 Value *VAArgOriginTLS;663 664 /// Thread-local shadow storage for va_arg overflow area.665 Value *VAArgOverflowSizeTLS;666 667 /// Are the instrumentation callbacks set up?668 bool CallbacksInitialized = false;669 670 /// The run-time callback to print a warning.671 FunctionCallee WarningFn;672 673 // These arrays are indexed by log2(AccessSize).674 FunctionCallee MaybeWarningFn[kNumberOfAccessSizes];675 FunctionCallee MaybeWarningVarSizeFn;676 FunctionCallee MaybeStoreOriginFn[kNumberOfAccessSizes];677 678 /// Run-time helper that generates a new origin value for a stack679 /// allocation.680 FunctionCallee MsanSetAllocaOriginWithDescriptionFn;681 // No description version682 FunctionCallee MsanSetAllocaOriginNoDescriptionFn;683 684 /// Run-time helper that poisons stack on function entry.685 FunctionCallee MsanPoisonStackFn;686 687 /// Run-time helper that records a store (or any event) of an688 /// uninitialized value and returns an updated origin id encoding this info.689 FunctionCallee MsanChainOriginFn;690 691 /// Run-time helper that paints an origin over a region.692 FunctionCallee MsanSetOriginFn;693 694 /// MSan runtime replacements for memmove, memcpy and memset.695 FunctionCallee MemmoveFn, MemcpyFn, MemsetFn;696 697 /// KMSAN callback for task-local function argument shadow.698 StructType *MsanContextStateTy;699 FunctionCallee MsanGetContextStateFn;700 701 /// Functions for poisoning/unpoisoning local variables702 FunctionCallee MsanPoisonAllocaFn, MsanUnpoisonAllocaFn;703 704 /// Pair of shadow/origin pointers.705 Type *MsanMetadata;706 707 /// Each of the MsanMetadataPtrXxx functions returns a MsanMetadata.708 FunctionCallee MsanMetadataPtrForLoadN, MsanMetadataPtrForStoreN;709 FunctionCallee MsanMetadataPtrForLoad_1_8[4];710 FunctionCallee MsanMetadataPtrForStore_1_8[4];711 FunctionCallee MsanInstrumentAsmStoreFn;712 713 /// Storage for return values of the MsanMetadataPtrXxx functions.714 Value *MsanMetadataAlloca;715 716 /// Helper to choose between different MsanMetadataPtrXxx().717 FunctionCallee getKmsanShadowOriginAccessFn(bool isStore, int size);718 719 /// Memory map parameters used in application-to-shadow calculation.720 const MemoryMapParams *MapParams;721 722 /// Custom memory map parameters used when -msan-shadow-base or723 // -msan-origin-base is provided.724 MemoryMapParams CustomMapParams;725 726 MDNode *ColdCallWeights;727 728 /// Branch weights for origin store.729 MDNode *OriginStoreWeights;730};731 732void insertModuleCtor(Module &M) {733 getOrCreateSanitizerCtorAndInitFunctions(734 M, kMsanModuleCtorName, kMsanInitName,735 /*InitArgTypes=*/{},736 /*InitArgs=*/{},737 // This callback is invoked when the functions are created the first738 // time. Hook them into the global ctors list in that case:739 [&](Function *Ctor, FunctionCallee) {740 if (!ClWithComdat) {741 appendToGlobalCtors(M, Ctor, 0);742 return;743 }744 Comdat *MsanCtorComdat = M.getOrInsertComdat(kMsanModuleCtorName);745 Ctor->setComdat(MsanCtorComdat);746 appendToGlobalCtors(M, Ctor, 0, Ctor);747 });748}749 750template <class T> T getOptOrDefault(const cl::opt<T> &Opt, T Default) {751 return (Opt.getNumOccurrences() > 0) ? Opt : Default;752}753 754} // end anonymous namespace755 756MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K,757 bool EagerChecks)758 : Kernel(getOptOrDefault(ClEnableKmsan, K)),759 TrackOrigins(getOptOrDefault(ClTrackOrigins, Kernel ? 2 : TO)),760 Recover(getOptOrDefault(ClKeepGoing, Kernel || R)),761 EagerChecks(getOptOrDefault(ClEagerChecks, EagerChecks)) {}762 763PreservedAnalyses MemorySanitizerPass::run(Module &M,764 ModuleAnalysisManager &AM) {765 // Return early if nosanitize_memory module flag is present for the module.766 if (checkIfAlreadyInstrumented(M, "nosanitize_memory"))767 return PreservedAnalyses::all();768 bool Modified = false;769 if (!Options.Kernel) {770 insertModuleCtor(M);771 Modified = true;772 }773 774 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();775 for (Function &F : M) {776 if (F.empty())777 continue;778 MemorySanitizer Msan(*F.getParent(), Options);779 Modified |=780 Msan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F));781 }782 783 if (!Modified)784 return PreservedAnalyses::all();785 786 PreservedAnalyses PA = PreservedAnalyses::none();787 // GlobalsAA is considered stateless and does not get invalidated unless788 // explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers789 // make changes that require GlobalsAA to be invalidated.790 PA.abandon<GlobalsAA>();791 return PA;792}793 794void MemorySanitizerPass::printPipeline(795 raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {796 static_cast<PassInfoMixin<MemorySanitizerPass> *>(this)->printPipeline(797 OS, MapClassName2PassName);798 OS << '<';799 if (Options.Recover)800 OS << "recover;";801 if (Options.Kernel)802 OS << "kernel;";803 if (Options.EagerChecks)804 OS << "eager-checks;";805 OS << "track-origins=" << Options.TrackOrigins;806 OS << '>';807}808 809/// Create a non-const global initialized with the given string.810///811/// Creates a writable global for Str so that we can pass it to the812/// run-time lib. Runtime uses first 4 bytes of the string to store the813/// frame ID, so the string needs to be mutable.814static GlobalVariable *createPrivateConstGlobalForString(Module &M,815 StringRef Str) {816 Constant *StrConst = ConstantDataArray::getString(M.getContext(), Str);817 return new GlobalVariable(M, StrConst->getType(), /*isConstant=*/true,818 GlobalValue::PrivateLinkage, StrConst, "");819}820 821template <typename... ArgsTy>822FunctionCallee823MemorySanitizer::getOrInsertMsanMetadataFunction(Module &M, StringRef Name,824 ArgsTy... Args) {825 if (TargetTriple.getArch() == Triple::systemz) {826 // SystemZ ABI: shadow/origin pair is returned via a hidden parameter.827 return M.getOrInsertFunction(Name, Type::getVoidTy(*C), PtrTy,828 std::forward<ArgsTy>(Args)...);829 }830 831 return M.getOrInsertFunction(Name, MsanMetadata,832 std::forward<ArgsTy>(Args)...);833}834 835/// Create KMSAN API callbacks.836void MemorySanitizer::createKernelApi(Module &M, const TargetLibraryInfo &TLI) {837 IRBuilder<> IRB(*C);838 839 // These will be initialized in insertKmsanPrologue().840 RetvalTLS = nullptr;841 RetvalOriginTLS = nullptr;842 ParamTLS = nullptr;843 ParamOriginTLS = nullptr;844 VAArgTLS = nullptr;845 VAArgOriginTLS = nullptr;846 VAArgOverflowSizeTLS = nullptr;847 848 WarningFn = M.getOrInsertFunction("__msan_warning",849 TLI.getAttrList(C, {0}, /*Signed=*/false),850 IRB.getVoidTy(), IRB.getInt32Ty());851 852 // Requests the per-task context state (kmsan_context_state*) from the853 // runtime library.854 MsanContextStateTy = StructType::get(855 ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8),856 ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8),857 ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8),858 ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8), /* va_arg_origin */859 IRB.getInt64Ty(), ArrayType::get(OriginTy, kParamTLSSize / 4), OriginTy,860 OriginTy);861 MsanGetContextStateFn =862 M.getOrInsertFunction("__msan_get_context_state", PtrTy);863 864 MsanMetadata = StructType::get(PtrTy, PtrTy);865 866 for (int ind = 0, size = 1; ind < 4; ind++, size <<= 1) {867 std::string name_load =868 "__msan_metadata_ptr_for_load_" + std::to_string(size);869 std::string name_store =870 "__msan_metadata_ptr_for_store_" + std::to_string(size);871 MsanMetadataPtrForLoad_1_8[ind] =872 getOrInsertMsanMetadataFunction(M, name_load, PtrTy);873 MsanMetadataPtrForStore_1_8[ind] =874 getOrInsertMsanMetadataFunction(M, name_store, PtrTy);875 }876 877 MsanMetadataPtrForLoadN = getOrInsertMsanMetadataFunction(878 M, "__msan_metadata_ptr_for_load_n", PtrTy, IntptrTy);879 MsanMetadataPtrForStoreN = getOrInsertMsanMetadataFunction(880 M, "__msan_metadata_ptr_for_store_n", PtrTy, IntptrTy);881 882 // Functions for poisoning and unpoisoning memory.883 MsanPoisonAllocaFn = M.getOrInsertFunction(884 "__msan_poison_alloca", IRB.getVoidTy(), PtrTy, IntptrTy, PtrTy);885 MsanUnpoisonAllocaFn = M.getOrInsertFunction(886 "__msan_unpoison_alloca", IRB.getVoidTy(), PtrTy, IntptrTy);887}888 889static Constant *getOrInsertGlobal(Module &M, StringRef Name, Type *Ty) {890 return M.getOrInsertGlobal(Name, Ty, [&] {891 return new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage,892 nullptr, Name, nullptr,893 GlobalVariable::InitialExecTLSModel);894 });895}896 897/// Insert declarations for userspace-specific functions and globals.898void MemorySanitizer::createUserspaceApi(Module &M,899 const TargetLibraryInfo &TLI) {900 IRBuilder<> IRB(*C);901 902 // Create the callback.903 // FIXME: this function should have "Cold" calling conv,904 // which is not yet implemented.905 if (TrackOrigins) {906 StringRef WarningFnName = Recover ? "__msan_warning_with_origin"907 : "__msan_warning_with_origin_noreturn";908 WarningFn = M.getOrInsertFunction(WarningFnName,909 TLI.getAttrList(C, {0}, /*Signed=*/false),910 IRB.getVoidTy(), IRB.getInt32Ty());911 } else {912 StringRef WarningFnName =913 Recover ? "__msan_warning" : "__msan_warning_noreturn";914 WarningFn = M.getOrInsertFunction(WarningFnName, IRB.getVoidTy());915 }916 917 // Create the global TLS variables.918 RetvalTLS =919 getOrInsertGlobal(M, "__msan_retval_tls",920 ArrayType::get(IRB.getInt64Ty(), kRetvalTLSSize / 8));921 922 RetvalOriginTLS = getOrInsertGlobal(M, "__msan_retval_origin_tls", OriginTy);923 924 ParamTLS =925 getOrInsertGlobal(M, "__msan_param_tls",926 ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8));927 928 ParamOriginTLS =929 getOrInsertGlobal(M, "__msan_param_origin_tls",930 ArrayType::get(OriginTy, kParamTLSSize / 4));931 932 VAArgTLS =933 getOrInsertGlobal(M, "__msan_va_arg_tls",934 ArrayType::get(IRB.getInt64Ty(), kParamTLSSize / 8));935 936 VAArgOriginTLS =937 getOrInsertGlobal(M, "__msan_va_arg_origin_tls",938 ArrayType::get(OriginTy, kParamTLSSize / 4));939 940 VAArgOverflowSizeTLS = getOrInsertGlobal(M, "__msan_va_arg_overflow_size_tls",941 IRB.getIntPtrTy(M.getDataLayout()));942 943 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;944 AccessSizeIndex++) {945 unsigned AccessSize = 1 << AccessSizeIndex;946 std::string FunctionName = "__msan_maybe_warning_" + itostr(AccessSize);947 MaybeWarningFn[AccessSizeIndex] = M.getOrInsertFunction(948 FunctionName, TLI.getAttrList(C, {0, 1}, /*Signed=*/false),949 IRB.getVoidTy(), IRB.getIntNTy(AccessSize * 8), IRB.getInt32Ty());950 MaybeWarningVarSizeFn = M.getOrInsertFunction(951 "__msan_maybe_warning_N", TLI.getAttrList(C, {}, /*Signed=*/false),952 IRB.getVoidTy(), PtrTy, IRB.getInt64Ty(), IRB.getInt32Ty());953 FunctionName = "__msan_maybe_store_origin_" + itostr(AccessSize);954 MaybeStoreOriginFn[AccessSizeIndex] = M.getOrInsertFunction(955 FunctionName, TLI.getAttrList(C, {0, 2}, /*Signed=*/false),956 IRB.getVoidTy(), IRB.getIntNTy(AccessSize * 8), PtrTy,957 IRB.getInt32Ty());958 }959 960 MsanSetAllocaOriginWithDescriptionFn =961 M.getOrInsertFunction("__msan_set_alloca_origin_with_descr",962 IRB.getVoidTy(), PtrTy, IntptrTy, PtrTy, PtrTy);963 MsanSetAllocaOriginNoDescriptionFn =964 M.getOrInsertFunction("__msan_set_alloca_origin_no_descr",965 IRB.getVoidTy(), PtrTy, IntptrTy, PtrTy);966 MsanPoisonStackFn = M.getOrInsertFunction("__msan_poison_stack",967 IRB.getVoidTy(), PtrTy, IntptrTy);968}969 970/// Insert extern declaration of runtime-provided functions and globals.971void MemorySanitizer::initializeCallbacks(Module &M,972 const TargetLibraryInfo &TLI) {973 // Only do this once.974 if (CallbacksInitialized)975 return;976 977 IRBuilder<> IRB(*C);978 // Initialize callbacks that are common for kernel and userspace979 // instrumentation.980 MsanChainOriginFn = M.getOrInsertFunction(981 "__msan_chain_origin",982 TLI.getAttrList(C, {0}, /*Signed=*/false, /*Ret=*/true), IRB.getInt32Ty(),983 IRB.getInt32Ty());984 MsanSetOriginFn = M.getOrInsertFunction(985 "__msan_set_origin", TLI.getAttrList(C, {2}, /*Signed=*/false),986 IRB.getVoidTy(), PtrTy, IntptrTy, IRB.getInt32Ty());987 MemmoveFn =988 M.getOrInsertFunction("__msan_memmove", PtrTy, PtrTy, PtrTy, IntptrTy);989 MemcpyFn =990 M.getOrInsertFunction("__msan_memcpy", PtrTy, PtrTy, PtrTy, IntptrTy);991 MemsetFn = M.getOrInsertFunction("__msan_memset",992 TLI.getAttrList(C, {1}, /*Signed=*/true),993 PtrTy, PtrTy, IRB.getInt32Ty(), IntptrTy);994 995 MsanInstrumentAsmStoreFn = M.getOrInsertFunction(996 "__msan_instrument_asm_store", IRB.getVoidTy(), PtrTy, IntptrTy);997 998 if (CompileKernel) {999 createKernelApi(M, TLI);1000 } else {1001 createUserspaceApi(M, TLI);1002 }1003 CallbacksInitialized = true;1004}1005 1006FunctionCallee MemorySanitizer::getKmsanShadowOriginAccessFn(bool isStore,1007 int size) {1008 FunctionCallee *Fns =1009 isStore ? MsanMetadataPtrForStore_1_8 : MsanMetadataPtrForLoad_1_8;1010 switch (size) {1011 case 1:1012 return Fns[0];1013 case 2:1014 return Fns[1];1015 case 4:1016 return Fns[2];1017 case 8:1018 return Fns[3];1019 default:1020 return nullptr;1021 }1022}1023 1024/// Module-level initialization.1025///1026/// inserts a call to __msan_init to the module's constructor list.1027void MemorySanitizer::initializeModule(Module &M) {1028 auto &DL = M.getDataLayout();1029 1030 TargetTriple = M.getTargetTriple();1031 1032 bool ShadowPassed = ClShadowBase.getNumOccurrences() > 0;1033 bool OriginPassed = ClOriginBase.getNumOccurrences() > 0;1034 // Check the overrides first1035 if (ShadowPassed || OriginPassed) {1036 CustomMapParams.AndMask = ClAndMask;1037 CustomMapParams.XorMask = ClXorMask;1038 CustomMapParams.ShadowBase = ClShadowBase;1039 CustomMapParams.OriginBase = ClOriginBase;1040 MapParams = &CustomMapParams;1041 } else {1042 switch (TargetTriple.getOS()) {1043 case Triple::FreeBSD:1044 switch (TargetTriple.getArch()) {1045 case Triple::aarch64:1046 MapParams = FreeBSD_ARM_MemoryMapParams.bits64;1047 break;1048 case Triple::x86_64:1049 MapParams = FreeBSD_X86_MemoryMapParams.bits64;1050 break;1051 case Triple::x86:1052 MapParams = FreeBSD_X86_MemoryMapParams.bits32;1053 break;1054 default:1055 report_fatal_error("unsupported architecture");1056 }1057 break;1058 case Triple::NetBSD:1059 switch (TargetTriple.getArch()) {1060 case Triple::x86_64:1061 MapParams = NetBSD_X86_MemoryMapParams.bits64;1062 break;1063 default:1064 report_fatal_error("unsupported architecture");1065 }1066 break;1067 case Triple::Linux:1068 switch (TargetTriple.getArch()) {1069 case Triple::x86_64:1070 MapParams = Linux_X86_MemoryMapParams.bits64;1071 break;1072 case Triple::x86:1073 MapParams = Linux_X86_MemoryMapParams.bits32;1074 break;1075 case Triple::mips64:1076 case Triple::mips64el:1077 MapParams = Linux_MIPS_MemoryMapParams.bits64;1078 break;1079 case Triple::ppc64:1080 case Triple::ppc64le:1081 MapParams = Linux_PowerPC_MemoryMapParams.bits64;1082 break;1083 case Triple::systemz:1084 MapParams = Linux_S390_MemoryMapParams.bits64;1085 break;1086 case Triple::aarch64:1087 case Triple::aarch64_be:1088 MapParams = Linux_ARM_MemoryMapParams.bits64;1089 break;1090 case Triple::loongarch64:1091 MapParams = Linux_LoongArch_MemoryMapParams.bits64;1092 break;1093 default:1094 report_fatal_error("unsupported architecture");1095 }1096 break;1097 default:1098 report_fatal_error("unsupported operating system");1099 }1100 }1101 1102 C = &(M.getContext());1103 IRBuilder<> IRB(*C);1104 IntptrTy = IRB.getIntPtrTy(DL);1105 OriginTy = IRB.getInt32Ty();1106 PtrTy = IRB.getPtrTy();1107 1108 ColdCallWeights = MDBuilder(*C).createUnlikelyBranchWeights();1109 OriginStoreWeights = MDBuilder(*C).createUnlikelyBranchWeights();1110 1111 if (!CompileKernel) {1112 if (TrackOrigins)1113 M.getOrInsertGlobal("__msan_track_origins", IRB.getInt32Ty(), [&] {1114 return new GlobalVariable(1115 M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage,1116 IRB.getInt32(TrackOrigins), "__msan_track_origins");1117 });1118 1119 if (Recover)1120 M.getOrInsertGlobal("__msan_keep_going", IRB.getInt32Ty(), [&] {1121 return new GlobalVariable(M, IRB.getInt32Ty(), true,1122 GlobalValue::WeakODRLinkage,1123 IRB.getInt32(Recover), "__msan_keep_going");1124 });1125 }1126}1127 1128namespace {1129 1130/// A helper class that handles instrumentation of VarArg1131/// functions on a particular platform.1132///1133/// Implementations are expected to insert the instrumentation1134/// necessary to propagate argument shadow through VarArg function1135/// calls. Visit* methods are called during an InstVisitor pass over1136/// the function, and should avoid creating new basic blocks. A new1137/// instance of this class is created for each instrumented function.1138struct VarArgHelper {1139 virtual ~VarArgHelper() = default;1140 1141 /// Visit a CallBase.1142 virtual void visitCallBase(CallBase &CB, IRBuilder<> &IRB) = 0;1143 1144 /// Visit a va_start call.1145 virtual void visitVAStartInst(VAStartInst &I) = 0;1146 1147 /// Visit a va_copy call.1148 virtual void visitVACopyInst(VACopyInst &I) = 0;1149 1150 /// Finalize function instrumentation.1151 ///1152 /// This method is called after visiting all interesting (see above)1153 /// instructions in a function.1154 virtual void finalizeInstrumentation() = 0;1155};1156 1157struct MemorySanitizerVisitor;1158 1159} // end anonymous namespace1160 1161static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan,1162 MemorySanitizerVisitor &Visitor);1163 1164static unsigned TypeSizeToSizeIndex(TypeSize TS) {1165 if (TS.isScalable())1166 // Scalable types unconditionally take slowpaths.1167 return kNumberOfAccessSizes;1168 unsigned TypeSizeFixed = TS.getFixedValue();1169 if (TypeSizeFixed <= 8)1170 return 0;1171 return Log2_32_Ceil((TypeSizeFixed + 7) / 8);1172}1173 1174namespace {1175 1176/// Helper class to attach debug information of the given instruction onto new1177/// instructions inserted after.1178class NextNodeIRBuilder : public IRBuilder<> {1179public:1180 explicit NextNodeIRBuilder(Instruction *IP) : IRBuilder<>(IP->getNextNode()) {1181 SetCurrentDebugLocation(IP->getDebugLoc());1182 }1183};1184 1185/// This class does all the work for a given function. Store and Load1186/// instructions store and load corresponding shadow and origin1187/// values. Most instructions propagate shadow from arguments to their1188/// return values. Certain instructions (most importantly, BranchInst)1189/// test their argument shadow and print reports (with a runtime call) if it's1190/// non-zero.1191struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {1192 Function &F;1193 MemorySanitizer &MS;1194 SmallVector<PHINode *, 16> ShadowPHINodes, OriginPHINodes;1195 ValueMap<Value *, Value *> ShadowMap, OriginMap;1196 std::unique_ptr<VarArgHelper> VAHelper;1197 const TargetLibraryInfo *TLI;1198 Instruction *FnPrologueEnd;1199 SmallVector<Instruction *, 16> Instructions;1200 1201 // The following flags disable parts of MSan instrumentation based on1202 // exclusion list contents and command-line options.1203 bool InsertChecks;1204 bool PropagateShadow;1205 bool PoisonStack;1206 bool PoisonUndef;1207 bool PoisonUndefVectors;1208 1209 struct ShadowOriginAndInsertPoint {1210 Value *Shadow;1211 Value *Origin;1212 Instruction *OrigIns;1213 1214 ShadowOriginAndInsertPoint(Value *S, Value *O, Instruction *I)1215 : Shadow(S), Origin(O), OrigIns(I) {}1216 };1217 SmallVector<ShadowOriginAndInsertPoint, 16> InstrumentationList;1218 DenseMap<const DILocation *, int> LazyWarningDebugLocationCount;1219 SmallSetVector<AllocaInst *, 16> AllocaSet;1220 SmallVector<std::pair<IntrinsicInst *, AllocaInst *>, 16> LifetimeStartList;1221 SmallVector<StoreInst *, 16> StoreList;1222 int64_t SplittableBlocksCount = 0;1223 1224 MemorySanitizerVisitor(Function &F, MemorySanitizer &MS,1225 const TargetLibraryInfo &TLI)1226 : F(F), MS(MS), VAHelper(CreateVarArgHelper(F, MS, *this)), TLI(&TLI) {1227 bool SanitizeFunction =1228 F.hasFnAttribute(Attribute::SanitizeMemory) && !ClDisableChecks;1229 InsertChecks = SanitizeFunction;1230 PropagateShadow = SanitizeFunction;1231 PoisonStack = SanitizeFunction && ClPoisonStack;1232 PoisonUndef = SanitizeFunction && ClPoisonUndef;1233 PoisonUndefVectors = SanitizeFunction && ClPoisonUndefVectors;1234 1235 // In the presence of unreachable blocks, we may see Phi nodes with1236 // incoming nodes from such blocks. Since InstVisitor skips unreachable1237 // blocks, such nodes will not have any shadow value associated with them.1238 // It's easier to remove unreachable blocks than deal with missing shadow.1239 removeUnreachableBlocks(F);1240 1241 MS.initializeCallbacks(*F.getParent(), TLI);1242 FnPrologueEnd =1243 IRBuilder<>(&F.getEntryBlock(), F.getEntryBlock().getFirstNonPHIIt())1244 .CreateIntrinsic(Intrinsic::donothing, {});1245 1246 if (MS.CompileKernel) {1247 IRBuilder<> IRB(FnPrologueEnd);1248 insertKmsanPrologue(IRB);1249 }1250 1251 LLVM_DEBUG(if (!InsertChecks) dbgs()1252 << "MemorySanitizer is not inserting checks into '"1253 << F.getName() << "'\n");1254 }1255 1256 bool instrumentWithCalls(Value *V) {1257 // Constants likely will be eliminated by follow-up passes.1258 if (isa<Constant>(V))1259 return false;1260 ++SplittableBlocksCount;1261 return ClInstrumentationWithCallThreshold >= 0 &&1262 SplittableBlocksCount > ClInstrumentationWithCallThreshold;1263 }1264 1265 bool isInPrologue(Instruction &I) {1266 return I.getParent() == FnPrologueEnd->getParent() &&1267 (&I == FnPrologueEnd || I.comesBefore(FnPrologueEnd));1268 }1269 1270 // Creates a new origin and records the stack trace. In general we can call1271 // this function for any origin manipulation we like. However it will cost1272 // runtime resources. So use this wisely only if it can provide additional1273 // information helpful to a user.1274 Value *updateOrigin(Value *V, IRBuilder<> &IRB) {1275 if (MS.TrackOrigins <= 1)1276 return V;1277 return IRB.CreateCall(MS.MsanChainOriginFn, V);1278 }1279 1280 Value *originToIntptr(IRBuilder<> &IRB, Value *Origin) {1281 const DataLayout &DL = F.getDataLayout();1282 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);1283 if (IntptrSize == kOriginSize)1284 return Origin;1285 assert(IntptrSize == kOriginSize * 2);1286 Origin = IRB.CreateIntCast(Origin, MS.IntptrTy, /* isSigned */ false);1287 return IRB.CreateOr(Origin, IRB.CreateShl(Origin, kOriginSize * 8));1288 }1289 1290 /// Fill memory range with the given origin value.1291 void paintOrigin(IRBuilder<> &IRB, Value *Origin, Value *OriginPtr,1292 TypeSize TS, Align Alignment) {1293 const DataLayout &DL = F.getDataLayout();1294 const Align IntptrAlignment = DL.getABITypeAlign(MS.IntptrTy);1295 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);1296 assert(IntptrAlignment >= kMinOriginAlignment);1297 assert(IntptrSize >= kOriginSize);1298 1299 // Note: The loop based formation works for fixed length vectors too,1300 // however we prefer to unroll and specialize alignment below.1301 if (TS.isScalable()) {1302 Value *Size = IRB.CreateTypeSize(MS.IntptrTy, TS);1303 Value *RoundUp =1304 IRB.CreateAdd(Size, ConstantInt::get(MS.IntptrTy, kOriginSize - 1));1305 Value *End =1306 IRB.CreateUDiv(RoundUp, ConstantInt::get(MS.IntptrTy, kOriginSize));1307 auto [InsertPt, Index] =1308 SplitBlockAndInsertSimpleForLoop(End, IRB.GetInsertPoint());1309 IRB.SetInsertPoint(InsertPt);1310 1311 Value *GEP = IRB.CreateGEP(MS.OriginTy, OriginPtr, Index);1312 IRB.CreateAlignedStore(Origin, GEP, kMinOriginAlignment);1313 return;1314 }1315 1316 unsigned Size = TS.getFixedValue();1317 1318 unsigned Ofs = 0;1319 Align CurrentAlignment = Alignment;1320 if (Alignment >= IntptrAlignment && IntptrSize > kOriginSize) {1321 Value *IntptrOrigin = originToIntptr(IRB, Origin);1322 Value *IntptrOriginPtr = IRB.CreatePointerCast(OriginPtr, MS.PtrTy);1323 for (unsigned i = 0; i < Size / IntptrSize; ++i) {1324 Value *Ptr = i ? IRB.CreateConstGEP1_32(MS.IntptrTy, IntptrOriginPtr, i)1325 : IntptrOriginPtr;1326 IRB.CreateAlignedStore(IntptrOrigin, Ptr, CurrentAlignment);1327 Ofs += IntptrSize / kOriginSize;1328 CurrentAlignment = IntptrAlignment;1329 }1330 }1331 1332 for (unsigned i = Ofs; i < (Size + kOriginSize - 1) / kOriginSize; ++i) {1333 Value *GEP =1334 i ? IRB.CreateConstGEP1_32(MS.OriginTy, OriginPtr, i) : OriginPtr;1335 IRB.CreateAlignedStore(Origin, GEP, CurrentAlignment);1336 CurrentAlignment = kMinOriginAlignment;1337 }1338 }1339 1340 void storeOrigin(IRBuilder<> &IRB, Value *Addr, Value *Shadow, Value *Origin,1341 Value *OriginPtr, Align Alignment) {1342 const DataLayout &DL = F.getDataLayout();1343 const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment);1344 TypeSize StoreSize = DL.getTypeStoreSize(Shadow->getType());1345 // ZExt cannot convert between vector and scalar1346 Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB);1347 if (auto *ConstantShadow = dyn_cast<Constant>(ConvertedShadow)) {1348 if (!ClCheckConstantShadow || ConstantShadow->isZeroValue()) {1349 // Origin is not needed: value is initialized or const shadow is1350 // ignored.1351 return;1352 }1353 if (llvm::isKnownNonZero(ConvertedShadow, DL)) {1354 // Copy origin as the value is definitely uninitialized.1355 paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize,1356 OriginAlignment);1357 return;1358 }1359 // Fallback to runtime check, which still can be optimized out later.1360 }1361 1362 TypeSize TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType());1363 unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits);1364 if (instrumentWithCalls(ConvertedShadow) &&1365 SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) {1366 FunctionCallee Fn = MS.MaybeStoreOriginFn[SizeIndex];1367 Value *ConvertedShadow2 =1368 IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex)));1369 CallBase *CB = IRB.CreateCall(Fn, {ConvertedShadow2, Addr, Origin});1370 CB->addParamAttr(0, Attribute::ZExt);1371 CB->addParamAttr(2, Attribute::ZExt);1372 } else {1373 Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp");1374 Instruction *CheckTerm = SplitBlockAndInsertIfThen(1375 Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights);1376 IRBuilder<> IRBNew(CheckTerm);1377 paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), OriginPtr, StoreSize,1378 OriginAlignment);1379 }1380 }1381 1382 void materializeStores() {1383 for (StoreInst *SI : StoreList) {1384 IRBuilder<> IRB(SI);1385 Value *Val = SI->getValueOperand();1386 Value *Addr = SI->getPointerOperand();1387 Value *Shadow = SI->isAtomic() ? getCleanShadow(Val) : getShadow(Val);1388 Value *ShadowPtr, *OriginPtr;1389 Type *ShadowTy = Shadow->getType();1390 const Align Alignment = SI->getAlign();1391 const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment);1392 std::tie(ShadowPtr, OriginPtr) =1393 getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ true);1394 1395 [[maybe_unused]] StoreInst *NewSI =1396 IRB.CreateAlignedStore(Shadow, ShadowPtr, Alignment);1397 LLVM_DEBUG(dbgs() << " STORE: " << *NewSI << "\n");1398 1399 if (SI->isAtomic())1400 SI->setOrdering(addReleaseOrdering(SI->getOrdering()));1401 1402 if (MS.TrackOrigins && !SI->isAtomic())1403 storeOrigin(IRB, Addr, Shadow, getOrigin(Val), OriginPtr,1404 OriginAlignment);1405 }1406 }1407 1408 // Returns true if Debug Location corresponds to multiple warnings.1409 bool shouldDisambiguateWarningLocation(const DebugLoc &DebugLoc) {1410 if (MS.TrackOrigins < 2)1411 return false;1412 1413 if (LazyWarningDebugLocationCount.empty())1414 for (const auto &I : InstrumentationList)1415 ++LazyWarningDebugLocationCount[I.OrigIns->getDebugLoc()];1416 1417 return LazyWarningDebugLocationCount[DebugLoc] >= ClDisambiguateWarning;1418 }1419 1420 /// Helper function to insert a warning at IRB's current insert point.1421 void insertWarningFn(IRBuilder<> &IRB, Value *Origin) {1422 if (!Origin)1423 Origin = (Value *)IRB.getInt32(0);1424 assert(Origin->getType()->isIntegerTy());1425 1426 if (shouldDisambiguateWarningLocation(IRB.getCurrentDebugLocation())) {1427 // Try to create additional origin with debug info of the last origin1428 // instruction. It may provide additional information to the user.1429 if (Instruction *OI = dyn_cast_or_null<Instruction>(Origin)) {1430 assert(MS.TrackOrigins);1431 auto NewDebugLoc = OI->getDebugLoc();1432 // Origin update with missing or the same debug location provides no1433 // additional value.1434 if (NewDebugLoc && NewDebugLoc != IRB.getCurrentDebugLocation()) {1435 // Insert update just before the check, so we call runtime only just1436 // before the report.1437 IRBuilder<> IRBOrigin(&*IRB.GetInsertPoint());1438 IRBOrigin.SetCurrentDebugLocation(NewDebugLoc);1439 Origin = updateOrigin(Origin, IRBOrigin);1440 }1441 }1442 }1443 1444 if (MS.CompileKernel || MS.TrackOrigins)1445 IRB.CreateCall(MS.WarningFn, Origin)->setCannotMerge();1446 else1447 IRB.CreateCall(MS.WarningFn)->setCannotMerge();1448 // FIXME: Insert UnreachableInst if !MS.Recover?1449 // This may invalidate some of the following checks and needs to be done1450 // at the very end.1451 }1452 1453 void materializeOneCheck(IRBuilder<> &IRB, Value *ConvertedShadow,1454 Value *Origin) {1455 const DataLayout &DL = F.getDataLayout();1456 TypeSize TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType());1457 unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits);1458 if (instrumentWithCalls(ConvertedShadow) && !MS.CompileKernel) {1459 // ZExt cannot convert between vector and scalar1460 ConvertedShadow = convertShadowToScalar(ConvertedShadow, IRB);1461 Value *ConvertedShadow2 =1462 IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex)));1463 1464 if (SizeIndex < kNumberOfAccessSizes) {1465 FunctionCallee Fn = MS.MaybeWarningFn[SizeIndex];1466 CallBase *CB = IRB.CreateCall(1467 Fn,1468 {ConvertedShadow2,1469 MS.TrackOrigins && Origin ? Origin : (Value *)IRB.getInt32(0)});1470 CB->addParamAttr(0, Attribute::ZExt);1471 CB->addParamAttr(1, Attribute::ZExt);1472 } else {1473 FunctionCallee Fn = MS.MaybeWarningVarSizeFn;1474 Value *ShadowAlloca = IRB.CreateAlloca(ConvertedShadow2->getType(), 0u);1475 IRB.CreateStore(ConvertedShadow2, ShadowAlloca);1476 unsigned ShadowSize = DL.getTypeAllocSize(ConvertedShadow2->getType());1477 CallBase *CB = IRB.CreateCall(1478 Fn,1479 {ShadowAlloca, ConstantInt::get(IRB.getInt64Ty(), ShadowSize),1480 MS.TrackOrigins && Origin ? Origin : (Value *)IRB.getInt32(0)});1481 CB->addParamAttr(1, Attribute::ZExt);1482 CB->addParamAttr(2, Attribute::ZExt);1483 }1484 } else {1485 Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp");1486 Instruction *CheckTerm = SplitBlockAndInsertIfThen(1487 Cmp, &*IRB.GetInsertPoint(),1488 /* Unreachable */ !MS.Recover, MS.ColdCallWeights);1489 1490 IRB.SetInsertPoint(CheckTerm);1491 insertWarningFn(IRB, Origin);1492 LLVM_DEBUG(dbgs() << " CHECK: " << *Cmp << "\n");1493 }1494 }1495 1496 void materializeInstructionChecks(1497 ArrayRef<ShadowOriginAndInsertPoint> InstructionChecks) {1498 const DataLayout &DL = F.getDataLayout();1499 // Disable combining in some cases. TrackOrigins checks each shadow to pick1500 // correct origin.1501 bool Combine = !MS.TrackOrigins;1502 Instruction *Instruction = InstructionChecks.front().OrigIns;1503 Value *Shadow = nullptr;1504 for (const auto &ShadowData : InstructionChecks) {1505 assert(ShadowData.OrigIns == Instruction);1506 IRBuilder<> IRB(Instruction);1507 1508 Value *ConvertedShadow = ShadowData.Shadow;1509 1510 if (auto *ConstantShadow = dyn_cast<Constant>(ConvertedShadow)) {1511 if (!ClCheckConstantShadow || ConstantShadow->isZeroValue()) {1512 // Skip, value is initialized or const shadow is ignored.1513 continue;1514 }1515 if (llvm::isKnownNonZero(ConvertedShadow, DL)) {1516 // Report as the value is definitely uninitialized.1517 insertWarningFn(IRB, ShadowData.Origin);1518 if (!MS.Recover)1519 return; // Always fail and stop here, not need to check the rest.1520 // Skip entire instruction,1521 continue;1522 }1523 // Fallback to runtime check, which still can be optimized out later.1524 }1525 1526 if (!Combine) {1527 materializeOneCheck(IRB, ConvertedShadow, ShadowData.Origin);1528 continue;1529 }1530 1531 if (!Shadow) {1532 Shadow = ConvertedShadow;1533 continue;1534 }1535 1536 Shadow = convertToBool(Shadow, IRB, "_mscmp");1537 ConvertedShadow = convertToBool(ConvertedShadow, IRB, "_mscmp");1538 Shadow = IRB.CreateOr(Shadow, ConvertedShadow, "_msor");1539 }1540 1541 if (Shadow) {1542 assert(Combine);1543 IRBuilder<> IRB(Instruction);1544 materializeOneCheck(IRB, Shadow, nullptr);1545 }1546 }1547 1548 static bool isAArch64SVCount(Type *Ty) {1549 if (TargetExtType *TTy = dyn_cast<TargetExtType>(Ty))1550 return TTy->getName() == "aarch64.svcount";1551 return false;1552 }1553 1554 // This is intended to match the "AArch64 Predicate-as-Counter Type" (aka1555 // 'target("aarch64.svcount")', but not e.g., <vscale x 4 x i32>.1556 static bool isScalableNonVectorType(Type *Ty) {1557 if (!isAArch64SVCount(Ty))1558 LLVM_DEBUG(dbgs() << "isScalableNonVectorType: Unexpected type " << *Ty1559 << "\n");1560 1561 return Ty->isScalableTy() && !isa<VectorType>(Ty);1562 }1563 1564 void materializeChecks() {1565#ifndef NDEBUG1566 // For assert below.1567 SmallPtrSet<Instruction *, 16> Done;1568#endif1569 1570 for (auto I = InstrumentationList.begin();1571 I != InstrumentationList.end();) {1572 auto OrigIns = I->OrigIns;1573 // Checks are grouped by the original instruction. We call all1574 // `insertShadowCheck` for an instruction at once.1575 assert(Done.insert(OrigIns).second);1576 auto J = std::find_if(I + 1, InstrumentationList.end(),1577 [OrigIns](const ShadowOriginAndInsertPoint &R) {1578 return OrigIns != R.OrigIns;1579 });1580 // Process all checks of instruction at once.1581 materializeInstructionChecks(ArrayRef<ShadowOriginAndInsertPoint>(I, J));1582 I = J;1583 }1584 1585 LLVM_DEBUG(dbgs() << "DONE:\n" << F);1586 }1587 1588 // Returns the last instruction in the new prologue1589 void insertKmsanPrologue(IRBuilder<> &IRB) {1590 Value *ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {});1591 Constant *Zero = IRB.getInt32(0);1592 MS.ParamTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1593 {Zero, IRB.getInt32(0)}, "param_shadow");1594 MS.RetvalTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1595 {Zero, IRB.getInt32(1)}, "retval_shadow");1596 MS.VAArgTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1597 {Zero, IRB.getInt32(2)}, "va_arg_shadow");1598 MS.VAArgOriginTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1599 {Zero, IRB.getInt32(3)}, "va_arg_origin");1600 MS.VAArgOverflowSizeTLS =1601 IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1602 {Zero, IRB.getInt32(4)}, "va_arg_overflow_size");1603 MS.ParamOriginTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1604 {Zero, IRB.getInt32(5)}, "param_origin");1605 MS.RetvalOriginTLS =1606 IRB.CreateGEP(MS.MsanContextStateTy, ContextState,1607 {Zero, IRB.getInt32(6)}, "retval_origin");1608 if (MS.TargetTriple.getArch() == Triple::systemz)1609 MS.MsanMetadataAlloca = IRB.CreateAlloca(MS.MsanMetadata, 0u);1610 }1611 1612 /// Add MemorySanitizer instrumentation to a function.1613 bool runOnFunction() {1614 // Iterate all BBs in depth-first order and create shadow instructions1615 // for all instructions (where applicable).1616 // For PHI nodes we create dummy shadow PHIs which will be finalized later.1617 for (BasicBlock *BB : depth_first(FnPrologueEnd->getParent()))1618 visit(*BB);1619 1620 // `visit` above only collects instructions. Process them after iterating1621 // CFG to avoid requirement on CFG transformations.1622 for (Instruction *I : Instructions)1623 InstVisitor<MemorySanitizerVisitor>::visit(*I);1624 1625 // Finalize PHI nodes.1626 for (PHINode *PN : ShadowPHINodes) {1627 PHINode *PNS = cast<PHINode>(getShadow(PN));1628 PHINode *PNO = MS.TrackOrigins ? cast<PHINode>(getOrigin(PN)) : nullptr;1629 size_t NumValues = PN->getNumIncomingValues();1630 for (size_t v = 0; v < NumValues; v++) {1631 PNS->addIncoming(getShadow(PN, v), PN->getIncomingBlock(v));1632 if (PNO)1633 PNO->addIncoming(getOrigin(PN, v), PN->getIncomingBlock(v));1634 }1635 }1636 1637 VAHelper->finalizeInstrumentation();1638 1639 // Poison llvm.lifetime.start intrinsics, if we haven't fallen back to1640 // instrumenting only allocas.1641 if (ClHandleLifetimeIntrinsics) {1642 for (auto Item : LifetimeStartList) {1643 instrumentAlloca(*Item.second, Item.first);1644 AllocaSet.remove(Item.second);1645 }1646 }1647 // Poison the allocas for which we didn't instrument the corresponding1648 // lifetime intrinsics.1649 for (AllocaInst *AI : AllocaSet)1650 instrumentAlloca(*AI);1651 1652 // Insert shadow value checks.1653 materializeChecks();1654 1655 // Delayed instrumentation of StoreInst.1656 // This may not add new address checks.1657 materializeStores();1658 1659 return true;1660 }1661 1662 /// Compute the shadow type that corresponds to a given Value.1663 Type *getShadowTy(Value *V) { return getShadowTy(V->getType()); }1664 1665 /// Compute the shadow type that corresponds to a given Type.1666 Type *getShadowTy(Type *OrigTy) {1667 if (!OrigTy->isSized()) {1668 return nullptr;1669 }1670 // For integer type, shadow is the same as the original type.1671 // This may return weird-sized types like i1.1672 if (IntegerType *IT = dyn_cast<IntegerType>(OrigTy))1673 return IT;1674 const DataLayout &DL = F.getDataLayout();1675 if (VectorType *VT = dyn_cast<VectorType>(OrigTy)) {1676 uint32_t EltSize = DL.getTypeSizeInBits(VT->getElementType());1677 return VectorType::get(IntegerType::get(*MS.C, EltSize),1678 VT->getElementCount());1679 }1680 if (ArrayType *AT = dyn_cast<ArrayType>(OrigTy)) {1681 return ArrayType::get(getShadowTy(AT->getElementType()),1682 AT->getNumElements());1683 }1684 if (StructType *ST = dyn_cast<StructType>(OrigTy)) {1685 SmallVector<Type *, 4> Elements;1686 for (unsigned i = 0, n = ST->getNumElements(); i < n; i++)1687 Elements.push_back(getShadowTy(ST->getElementType(i)));1688 StructType *Res = StructType::get(*MS.C, Elements, ST->isPacked());1689 LLVM_DEBUG(dbgs() << "getShadowTy: " << *ST << " ===> " << *Res << "\n");1690 return Res;1691 }1692 if (isScalableNonVectorType(OrigTy)) {1693 LLVM_DEBUG(dbgs() << "getShadowTy: Scalable non-vector type: " << *OrigTy1694 << "\n");1695 return OrigTy;1696 }1697 1698 uint32_t TypeSize = DL.getTypeSizeInBits(OrigTy);1699 return IntegerType::get(*MS.C, TypeSize);1700 }1701 1702 /// Extract combined shadow of struct elements as a bool1703 Value *collapseStructShadow(StructType *Struct, Value *Shadow,1704 IRBuilder<> &IRB) {1705 Value *FalseVal = IRB.getIntN(/* width */ 1, /* value */ 0);1706 Value *Aggregator = FalseVal;1707 1708 for (unsigned Idx = 0; Idx < Struct->getNumElements(); Idx++) {1709 // Combine by ORing together each element's bool shadow1710 Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx);1711 Value *ShadowBool = convertToBool(ShadowItem, IRB);1712 1713 if (Aggregator != FalseVal)1714 Aggregator = IRB.CreateOr(Aggregator, ShadowBool);1715 else1716 Aggregator = ShadowBool;1717 }1718 1719 return Aggregator;1720 }1721 1722 // Extract combined shadow of array elements1723 Value *collapseArrayShadow(ArrayType *Array, Value *Shadow,1724 IRBuilder<> &IRB) {1725 if (!Array->getNumElements())1726 return IRB.getIntN(/* width */ 1, /* value */ 0);1727 1728 Value *FirstItem = IRB.CreateExtractValue(Shadow, 0);1729 Value *Aggregator = convertShadowToScalar(FirstItem, IRB);1730 1731 for (unsigned Idx = 1; Idx < Array->getNumElements(); Idx++) {1732 Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx);1733 Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB);1734 Aggregator = IRB.CreateOr(Aggregator, ShadowInner);1735 }1736 return Aggregator;1737 }1738 1739 /// Convert a shadow value to it's flattened variant. The resulting1740 /// shadow may not necessarily have the same bit width as the input1741 /// value, but it will always be comparable to zero.1742 Value *convertShadowToScalar(Value *V, IRBuilder<> &IRB) {1743 if (StructType *Struct = dyn_cast<StructType>(V->getType()))1744 return collapseStructShadow(Struct, V, IRB);1745 if (ArrayType *Array = dyn_cast<ArrayType>(V->getType()))1746 return collapseArrayShadow(Array, V, IRB);1747 if (isa<VectorType>(V->getType())) {1748 if (isa<ScalableVectorType>(V->getType()))1749 return convertShadowToScalar(IRB.CreateOrReduce(V), IRB);1750 unsigned BitWidth =1751 V->getType()->getPrimitiveSizeInBits().getFixedValue();1752 return IRB.CreateBitCast(V, IntegerType::get(*MS.C, BitWidth));1753 }1754 return V;1755 }1756 1757 // Convert a scalar value to an i1 by comparing with 01758 Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &name = "") {1759 Type *VTy = V->getType();1760 if (!VTy->isIntegerTy())1761 return convertToBool(convertShadowToScalar(V, IRB), IRB, name);1762 if (VTy->getIntegerBitWidth() == 1)1763 // Just converting a bool to a bool, so do nothing.1764 return V;1765 return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), name);1766 }1767 1768 Type *ptrToIntPtrType(Type *PtrTy) const {1769 if (VectorType *VectTy = dyn_cast<VectorType>(PtrTy)) {1770 return VectorType::get(ptrToIntPtrType(VectTy->getElementType()),1771 VectTy->getElementCount());1772 }1773 assert(PtrTy->isIntOrPtrTy());1774 return MS.IntptrTy;1775 }1776 1777 Type *getPtrToShadowPtrType(Type *IntPtrTy, Type *ShadowTy) const {1778 if (VectorType *VectTy = dyn_cast<VectorType>(IntPtrTy)) {1779 return VectorType::get(1780 getPtrToShadowPtrType(VectTy->getElementType(), ShadowTy),1781 VectTy->getElementCount());1782 }1783 assert(IntPtrTy == MS.IntptrTy);1784 return MS.PtrTy;1785 }1786 1787 Constant *constToIntPtr(Type *IntPtrTy, uint64_t C) const {1788 if (VectorType *VectTy = dyn_cast<VectorType>(IntPtrTy)) {1789 return ConstantVector::getSplat(1790 VectTy->getElementCount(),1791 constToIntPtr(VectTy->getElementType(), C));1792 }1793 assert(IntPtrTy == MS.IntptrTy);1794 return ConstantInt::get(MS.IntptrTy, C);1795 }1796 1797 /// Returns the integer shadow offset that corresponds to a given1798 /// application address, whereby:1799 ///1800 /// Offset = (Addr & ~AndMask) ^ XorMask1801 /// Shadow = ShadowBase + Offset1802 /// Origin = (OriginBase + Offset) & ~Alignment1803 ///1804 /// Note: for efficiency, many shadow mappings only require use the XorMask1805 /// and OriginBase; the AndMask and ShadowBase are often zero.1806 Value *getShadowPtrOffset(Value *Addr, IRBuilder<> &IRB) {1807 Type *IntptrTy = ptrToIntPtrType(Addr->getType());1808 Value *OffsetLong = IRB.CreatePointerCast(Addr, IntptrTy);1809 1810 if (uint64_t AndMask = MS.MapParams->AndMask)1811 OffsetLong = IRB.CreateAnd(OffsetLong, constToIntPtr(IntptrTy, ~AndMask));1812 1813 if (uint64_t XorMask = MS.MapParams->XorMask)1814 OffsetLong = IRB.CreateXor(OffsetLong, constToIntPtr(IntptrTy, XorMask));1815 return OffsetLong;1816 }1817 1818 /// Compute the shadow and origin addresses corresponding to a given1819 /// application address.1820 ///1821 /// Shadow = ShadowBase + Offset1822 /// Origin = (OriginBase + Offset) & ~3ULL1823 /// Addr can be a ptr or <N x ptr>. In both cases ShadowTy the shadow type of1824 /// a single pointee.1825 /// Returns <shadow_ptr, origin_ptr> or <<N x shadow_ptr>, <N x origin_ptr>>.1826 std::pair<Value *, Value *>1827 getShadowOriginPtrUserspace(Value *Addr, IRBuilder<> &IRB, Type *ShadowTy,1828 MaybeAlign Alignment) {1829 VectorType *VectTy = dyn_cast<VectorType>(Addr->getType());1830 if (!VectTy) {1831 assert(Addr->getType()->isPointerTy());1832 } else {1833 assert(VectTy->getElementType()->isPointerTy());1834 }1835 Type *IntptrTy = ptrToIntPtrType(Addr->getType());1836 Value *ShadowOffset = getShadowPtrOffset(Addr, IRB);1837 Value *ShadowLong = ShadowOffset;1838 if (uint64_t ShadowBase = MS.MapParams->ShadowBase) {1839 ShadowLong =1840 IRB.CreateAdd(ShadowLong, constToIntPtr(IntptrTy, ShadowBase));1841 }1842 Value *ShadowPtr = IRB.CreateIntToPtr(1843 ShadowLong, getPtrToShadowPtrType(IntptrTy, ShadowTy));1844 1845 Value *OriginPtr = nullptr;1846 if (MS.TrackOrigins) {1847 Value *OriginLong = ShadowOffset;1848 uint64_t OriginBase = MS.MapParams->OriginBase;1849 if (OriginBase != 0)1850 OriginLong =1851 IRB.CreateAdd(OriginLong, constToIntPtr(IntptrTy, OriginBase));1852 if (!Alignment || *Alignment < kMinOriginAlignment) {1853 uint64_t Mask = kMinOriginAlignment.value() - 1;1854 OriginLong = IRB.CreateAnd(OriginLong, constToIntPtr(IntptrTy, ~Mask));1855 }1856 OriginPtr = IRB.CreateIntToPtr(1857 OriginLong, getPtrToShadowPtrType(IntptrTy, MS.OriginTy));1858 }1859 return std::make_pair(ShadowPtr, OriginPtr);1860 }1861 1862 template <typename... ArgsTy>1863 Value *createMetadataCall(IRBuilder<> &IRB, FunctionCallee Callee,1864 ArgsTy... Args) {1865 if (MS.TargetTriple.getArch() == Triple::systemz) {1866 IRB.CreateCall(Callee,1867 {MS.MsanMetadataAlloca, std::forward<ArgsTy>(Args)...});1868 return IRB.CreateLoad(MS.MsanMetadata, MS.MsanMetadataAlloca);1869 }1870 1871 return IRB.CreateCall(Callee, {std::forward<ArgsTy>(Args)...});1872 }1873 1874 std::pair<Value *, Value *> getShadowOriginPtrKernelNoVec(Value *Addr,1875 IRBuilder<> &IRB,1876 Type *ShadowTy,1877 bool isStore) {1878 Value *ShadowOriginPtrs;1879 const DataLayout &DL = F.getDataLayout();1880 TypeSize Size = DL.getTypeStoreSize(ShadowTy);1881 1882 FunctionCallee Getter = MS.getKmsanShadowOriginAccessFn(isStore, Size);1883 Value *AddrCast = IRB.CreatePointerCast(Addr, MS.PtrTy);1884 if (Getter) {1885 ShadowOriginPtrs = createMetadataCall(IRB, Getter, AddrCast);1886 } else {1887 Value *SizeVal = ConstantInt::get(MS.IntptrTy, Size);1888 ShadowOriginPtrs = createMetadataCall(1889 IRB,1890 isStore ? MS.MsanMetadataPtrForStoreN : MS.MsanMetadataPtrForLoadN,1891 AddrCast, SizeVal);1892 }1893 Value *ShadowPtr = IRB.CreateExtractValue(ShadowOriginPtrs, 0);1894 ShadowPtr = IRB.CreatePointerCast(ShadowPtr, MS.PtrTy);1895 Value *OriginPtr = IRB.CreateExtractValue(ShadowOriginPtrs, 1);1896 1897 return std::make_pair(ShadowPtr, OriginPtr);1898 }1899 1900 /// Addr can be a ptr or <N x ptr>. In both cases ShadowTy the shadow type of1901 /// a single pointee.1902 /// Returns <shadow_ptr, origin_ptr> or <<N x shadow_ptr>, <N x origin_ptr>>.1903 std::pair<Value *, Value *> getShadowOriginPtrKernel(Value *Addr,1904 IRBuilder<> &IRB,1905 Type *ShadowTy,1906 bool isStore) {1907 VectorType *VectTy = dyn_cast<VectorType>(Addr->getType());1908 if (!VectTy) {1909 assert(Addr->getType()->isPointerTy());1910 return getShadowOriginPtrKernelNoVec(Addr, IRB, ShadowTy, isStore);1911 }1912 1913 // TODO: Support callbacs with vectors of addresses.1914 unsigned NumElements = cast<FixedVectorType>(VectTy)->getNumElements();1915 Value *ShadowPtrs = ConstantInt::getNullValue(1916 FixedVectorType::get(IRB.getPtrTy(), NumElements));1917 Value *OriginPtrs = nullptr;1918 if (MS.TrackOrigins)1919 OriginPtrs = ConstantInt::getNullValue(1920 FixedVectorType::get(IRB.getPtrTy(), NumElements));1921 for (unsigned i = 0; i < NumElements; ++i) {1922 Value *OneAddr =1923 IRB.CreateExtractElement(Addr, ConstantInt::get(IRB.getInt32Ty(), i));1924 auto [ShadowPtr, OriginPtr] =1925 getShadowOriginPtrKernelNoVec(OneAddr, IRB, ShadowTy, isStore);1926 1927 ShadowPtrs = IRB.CreateInsertElement(1928 ShadowPtrs, ShadowPtr, ConstantInt::get(IRB.getInt32Ty(), i));1929 if (MS.TrackOrigins)1930 OriginPtrs = IRB.CreateInsertElement(1931 OriginPtrs, OriginPtr, ConstantInt::get(IRB.getInt32Ty(), i));1932 }1933 return {ShadowPtrs, OriginPtrs};1934 }1935 1936 std::pair<Value *, Value *> getShadowOriginPtr(Value *Addr, IRBuilder<> &IRB,1937 Type *ShadowTy,1938 MaybeAlign Alignment,1939 bool isStore) {1940 if (MS.CompileKernel)1941 return getShadowOriginPtrKernel(Addr, IRB, ShadowTy, isStore);1942 return getShadowOriginPtrUserspace(Addr, IRB, ShadowTy, Alignment);1943 }1944 1945 /// Compute the shadow address for a given function argument.1946 ///1947 /// Shadow = ParamTLS+ArgOffset.1948 Value *getShadowPtrForArgument(IRBuilder<> &IRB, int ArgOffset) {1949 return IRB.CreatePtrAdd(MS.ParamTLS,1950 ConstantInt::get(MS.IntptrTy, ArgOffset), "_msarg");1951 }1952 1953 /// Compute the origin address for a given function argument.1954 Value *getOriginPtrForArgument(IRBuilder<> &IRB, int ArgOffset) {1955 if (!MS.TrackOrigins)1956 return nullptr;1957 return IRB.CreatePtrAdd(MS.ParamOriginTLS,1958 ConstantInt::get(MS.IntptrTy, ArgOffset),1959 "_msarg_o");1960 }1961 1962 /// Compute the shadow address for a retval.1963 Value *getShadowPtrForRetval(IRBuilder<> &IRB) {1964 return IRB.CreatePointerCast(MS.RetvalTLS, IRB.getPtrTy(0), "_msret");1965 }1966 1967 /// Compute the origin address for a retval.1968 Value *getOriginPtrForRetval() {1969 // We keep a single origin for the entire retval. Might be too optimistic.1970 return MS.RetvalOriginTLS;1971 }1972 1973 /// Set SV to be the shadow value for V.1974 void setShadow(Value *V, Value *SV) {1975 assert(!ShadowMap.count(V) && "Values may only have one shadow");1976 ShadowMap[V] = PropagateShadow ? SV : getCleanShadow(V);1977 }1978 1979 /// Set Origin to be the origin value for V.1980 void setOrigin(Value *V, Value *Origin) {1981 if (!MS.TrackOrigins)1982 return;1983 assert(!OriginMap.count(V) && "Values may only have one origin");1984 LLVM_DEBUG(dbgs() << "ORIGIN: " << *V << " ==> " << *Origin << "\n");1985 OriginMap[V] = Origin;1986 }1987 1988 Constant *getCleanShadow(Type *OrigTy) {1989 Type *ShadowTy = getShadowTy(OrigTy);1990 if (!ShadowTy)1991 return nullptr;1992 return Constant::getNullValue(ShadowTy);1993 }1994 1995 /// Create a clean shadow value for a given value.1996 ///1997 /// Clean shadow (all zeroes) means all bits of the value are defined1998 /// (initialized).1999 Constant *getCleanShadow(Value *V) { return getCleanShadow(V->getType()); }2000 2001 /// Create a dirty shadow of a given shadow type.2002 Constant *getPoisonedShadow(Type *ShadowTy) {2003 assert(ShadowTy);2004 if (isa<IntegerType>(ShadowTy) || isa<VectorType>(ShadowTy))2005 return Constant::getAllOnesValue(ShadowTy);2006 if (ArrayType *AT = dyn_cast<ArrayType>(ShadowTy)) {2007 SmallVector<Constant *, 4> Vals(AT->getNumElements(),2008 getPoisonedShadow(AT->getElementType()));2009 return ConstantArray::get(AT, Vals);2010 }2011 if (StructType *ST = dyn_cast<StructType>(ShadowTy)) {2012 SmallVector<Constant *, 4> Vals;2013 for (unsigned i = 0, n = ST->getNumElements(); i < n; i++)2014 Vals.push_back(getPoisonedShadow(ST->getElementType(i)));2015 return ConstantStruct::get(ST, Vals);2016 }2017 llvm_unreachable("Unexpected shadow type");2018 }2019 2020 /// Create a dirty shadow for a given value.2021 Constant *getPoisonedShadow(Value *V) {2022 Type *ShadowTy = getShadowTy(V);2023 if (!ShadowTy)2024 return nullptr;2025 return getPoisonedShadow(ShadowTy);2026 }2027 2028 /// Create a clean (zero) origin.2029 Value *getCleanOrigin() { return Constant::getNullValue(MS.OriginTy); }2030 2031 /// Get the shadow value for a given Value.2032 ///2033 /// This function either returns the value set earlier with setShadow,2034 /// or extracts if from ParamTLS (for function arguments).2035 Value *getShadow(Value *V) {2036 if (Instruction *I = dyn_cast<Instruction>(V)) {2037 if (!PropagateShadow || I->getMetadata(LLVMContext::MD_nosanitize))2038 return getCleanShadow(V);2039 // For instructions the shadow is already stored in the map.2040 Value *Shadow = ShadowMap[V];2041 if (!Shadow) {2042 LLVM_DEBUG(dbgs() << "No shadow: " << *V << "\n" << *(I->getParent()));2043 assert(Shadow && "No shadow for a value");2044 }2045 return Shadow;2046 }2047 // Handle fully undefined values2048 // (partially undefined constant vectors are handled later)2049 if ([[maybe_unused]] UndefValue *U = dyn_cast<UndefValue>(V)) {2050 Value *AllOnes = (PropagateShadow && PoisonUndef) ? getPoisonedShadow(V)2051 : getCleanShadow(V);2052 LLVM_DEBUG(dbgs() << "Undef: " << *U << " ==> " << *AllOnes << "\n");2053 return AllOnes;2054 }2055 if (Argument *A = dyn_cast<Argument>(V)) {2056 // For arguments we compute the shadow on demand and store it in the map.2057 Value *&ShadowPtr = ShadowMap[V];2058 if (ShadowPtr)2059 return ShadowPtr;2060 Function *F = A->getParent();2061 IRBuilder<> EntryIRB(FnPrologueEnd);2062 unsigned ArgOffset = 0;2063 const DataLayout &DL = F->getDataLayout();2064 for (auto &FArg : F->args()) {2065 if (!FArg.getType()->isSized() || FArg.getType()->isScalableTy()) {2066 LLVM_DEBUG(dbgs() << (FArg.getType()->isScalableTy()2067 ? "vscale not fully supported\n"2068 : "Arg is not sized\n"));2069 if (A == &FArg) {2070 ShadowPtr = getCleanShadow(V);2071 setOrigin(A, getCleanOrigin());2072 break;2073 }2074 continue;2075 }2076 2077 unsigned Size = FArg.hasByValAttr()2078 ? DL.getTypeAllocSize(FArg.getParamByValType())2079 : DL.getTypeAllocSize(FArg.getType());2080 2081 if (A == &FArg) {2082 bool Overflow = ArgOffset + Size > kParamTLSSize;2083 if (FArg.hasByValAttr()) {2084 // ByVal pointer itself has clean shadow. We copy the actual2085 // argument shadow to the underlying memory.2086 // Figure out maximal valid memcpy alignment.2087 const Align ArgAlign = DL.getValueOrABITypeAlignment(2088 FArg.getParamAlign(), FArg.getParamByValType());2089 Value *CpShadowPtr, *CpOriginPtr;2090 std::tie(CpShadowPtr, CpOriginPtr) =2091 getShadowOriginPtr(V, EntryIRB, EntryIRB.getInt8Ty(), ArgAlign,2092 /*isStore*/ true);2093 if (!PropagateShadow || Overflow) {2094 // ParamTLS overflow.2095 EntryIRB.CreateMemSet(2096 CpShadowPtr, Constant::getNullValue(EntryIRB.getInt8Ty()),2097 Size, ArgAlign);2098 } else {2099 Value *Base = getShadowPtrForArgument(EntryIRB, ArgOffset);2100 const Align CopyAlign = std::min(ArgAlign, kShadowTLSAlignment);2101 [[maybe_unused]] Value *Cpy = EntryIRB.CreateMemCpy(2102 CpShadowPtr, CopyAlign, Base, CopyAlign, Size);2103 LLVM_DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n");2104 2105 if (MS.TrackOrigins) {2106 Value *OriginPtr = getOriginPtrForArgument(EntryIRB, ArgOffset);2107 // FIXME: OriginSize should be:2108 // alignTo(V % kMinOriginAlignment + Size, kMinOriginAlignment)2109 unsigned OriginSize = alignTo(Size, kMinOriginAlignment);2110 EntryIRB.CreateMemCpy(2111 CpOriginPtr,2112 /* by getShadowOriginPtr */ kMinOriginAlignment, OriginPtr,2113 /* by origin_tls[ArgOffset] */ kMinOriginAlignment,2114 OriginSize);2115 }2116 }2117 }2118 2119 if (!PropagateShadow || Overflow || FArg.hasByValAttr() ||2120 (MS.EagerChecks && FArg.hasAttribute(Attribute::NoUndef))) {2121 ShadowPtr = getCleanShadow(V);2122 setOrigin(A, getCleanOrigin());2123 } else {2124 // Shadow over TLS2125 Value *Base = getShadowPtrForArgument(EntryIRB, ArgOffset);2126 ShadowPtr = EntryIRB.CreateAlignedLoad(getShadowTy(&FArg), Base,2127 kShadowTLSAlignment);2128 if (MS.TrackOrigins) {2129 Value *OriginPtr = getOriginPtrForArgument(EntryIRB, ArgOffset);2130 setOrigin(A, EntryIRB.CreateLoad(MS.OriginTy, OriginPtr));2131 }2132 }2133 LLVM_DEBUG(dbgs()2134 << " ARG: " << FArg << " ==> " << *ShadowPtr << "\n");2135 break;2136 }2137 2138 ArgOffset += alignTo(Size, kShadowTLSAlignment);2139 }2140 assert(ShadowPtr && "Could not find shadow for an argument");2141 return ShadowPtr;2142 }2143 2144 // Check for partially-undefined constant vectors2145 // TODO: scalable vectors (this is hard because we do not have IRBuilder)2146 if (isa<FixedVectorType>(V->getType()) && isa<Constant>(V) &&2147 cast<Constant>(V)->containsUndefOrPoisonElement() && PropagateShadow &&2148 PoisonUndefVectors) {2149 unsigned NumElems = cast<FixedVectorType>(V->getType())->getNumElements();2150 SmallVector<Constant *, 32> ShadowVector(NumElems);2151 for (unsigned i = 0; i != NumElems; ++i) {2152 Constant *Elem = cast<Constant>(V)->getAggregateElement(i);2153 ShadowVector[i] = isa<UndefValue>(Elem) ? getPoisonedShadow(Elem)2154 : getCleanShadow(Elem);2155 }2156 2157 Value *ShadowConstant = ConstantVector::get(ShadowVector);2158 LLVM_DEBUG(dbgs() << "Partial undef constant vector: " << *V << " ==> "2159 << *ShadowConstant << "\n");2160 2161 return ShadowConstant;2162 }2163 2164 // TODO: partially-undefined constant arrays, structures, and nested types2165 2166 // For everything else the shadow is zero.2167 return getCleanShadow(V);2168 }2169 2170 /// Get the shadow for i-th argument of the instruction I.2171 Value *getShadow(Instruction *I, int i) {2172 return getShadow(I->getOperand(i));2173 }2174 2175 /// Get the origin for a value.2176 Value *getOrigin(Value *V) {2177 if (!MS.TrackOrigins)2178 return nullptr;2179 if (!PropagateShadow || isa<Constant>(V) || isa<InlineAsm>(V))2180 return getCleanOrigin();2181 assert((isa<Instruction>(V) || isa<Argument>(V)) &&2182 "Unexpected value type in getOrigin()");2183 if (Instruction *I = dyn_cast<Instruction>(V)) {2184 if (I->getMetadata(LLVMContext::MD_nosanitize))2185 return getCleanOrigin();2186 }2187 Value *Origin = OriginMap[V];2188 assert(Origin && "Missing origin");2189 return Origin;2190 }2191 2192 /// Get the origin for i-th argument of the instruction I.2193 Value *getOrigin(Instruction *I, int i) {2194 return getOrigin(I->getOperand(i));2195 }2196 2197 /// Remember the place where a shadow check should be inserted.2198 ///2199 /// This location will be later instrumented with a check that will print a2200 /// UMR warning in runtime if the shadow value is not 0.2201 void insertCheckShadow(Value *Shadow, Value *Origin, Instruction *OrigIns) {2202 assert(Shadow);2203 if (!InsertChecks)2204 return;2205 2206 if (!DebugCounter::shouldExecute(DebugInsertCheck)) {2207 LLVM_DEBUG(dbgs() << "Skipping check of " << *Shadow << " before "2208 << *OrigIns << "\n");2209 return;2210 }2211 2212 Type *ShadowTy = Shadow->getType();2213 if (isScalableNonVectorType(ShadowTy)) {2214 LLVM_DEBUG(dbgs() << "Skipping check of scalable non-vector " << *Shadow2215 << " before " << *OrigIns << "\n");2216 return;2217 }2218#ifndef NDEBUG2219 assert((isa<IntegerType>(ShadowTy) || isa<VectorType>(ShadowTy) ||2220 isa<StructType>(ShadowTy) || isa<ArrayType>(ShadowTy)) &&2221 "Can only insert checks for integer, vector, and aggregate shadow "2222 "types");2223#endif2224 InstrumentationList.push_back(2225 ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns));2226 }2227 2228 /// Get shadow for value, and remember the place where a shadow check should2229 /// be inserted.2230 ///2231 /// This location will be later instrumented with a check that will print a2232 /// UMR warning in runtime if the value is not fully defined.2233 void insertCheckShadowOf(Value *Val, Instruction *OrigIns) {2234 assert(Val);2235 Value *Shadow, *Origin;2236 if (ClCheckConstantShadow) {2237 Shadow = getShadow(Val);2238 if (!Shadow)2239 return;2240 Origin = getOrigin(Val);2241 } else {2242 Shadow = dyn_cast_or_null<Instruction>(getShadow(Val));2243 if (!Shadow)2244 return;2245 Origin = dyn_cast_or_null<Instruction>(getOrigin(Val));2246 }2247 insertCheckShadow(Shadow, Origin, OrigIns);2248 }2249 2250 AtomicOrdering addReleaseOrdering(AtomicOrdering a) {2251 switch (a) {2252 case AtomicOrdering::NotAtomic:2253 return AtomicOrdering::NotAtomic;2254 case AtomicOrdering::Unordered:2255 case AtomicOrdering::Monotonic:2256 case AtomicOrdering::Release:2257 return AtomicOrdering::Release;2258 case AtomicOrdering::Acquire:2259 case AtomicOrdering::AcquireRelease:2260 return AtomicOrdering::AcquireRelease;2261 case AtomicOrdering::SequentiallyConsistent:2262 return AtomicOrdering::SequentiallyConsistent;2263 }2264 llvm_unreachable("Unknown ordering");2265 }2266 2267 Value *makeAddReleaseOrderingTable(IRBuilder<> &IRB) {2268 constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1;2269 uint32_t OrderingTable[NumOrderings] = {};2270 2271 OrderingTable[(int)AtomicOrderingCABI::relaxed] =2272 OrderingTable[(int)AtomicOrderingCABI::release] =2273 (int)AtomicOrderingCABI::release;2274 OrderingTable[(int)AtomicOrderingCABI::consume] =2275 OrderingTable[(int)AtomicOrderingCABI::acquire] =2276 OrderingTable[(int)AtomicOrderingCABI::acq_rel] =2277 (int)AtomicOrderingCABI::acq_rel;2278 OrderingTable[(int)AtomicOrderingCABI::seq_cst] =2279 (int)AtomicOrderingCABI::seq_cst;2280 2281 return ConstantDataVector::get(IRB.getContext(), OrderingTable);2282 }2283 2284 AtomicOrdering addAcquireOrdering(AtomicOrdering a) {2285 switch (a) {2286 case AtomicOrdering::NotAtomic:2287 return AtomicOrdering::NotAtomic;2288 case AtomicOrdering::Unordered:2289 case AtomicOrdering::Monotonic:2290 case AtomicOrdering::Acquire:2291 return AtomicOrdering::Acquire;2292 case AtomicOrdering::Release:2293 case AtomicOrdering::AcquireRelease:2294 return AtomicOrdering::AcquireRelease;2295 case AtomicOrdering::SequentiallyConsistent:2296 return AtomicOrdering::SequentiallyConsistent;2297 }2298 llvm_unreachable("Unknown ordering");2299 }2300 2301 Value *makeAddAcquireOrderingTable(IRBuilder<> &IRB) {2302 constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1;2303 uint32_t OrderingTable[NumOrderings] = {};2304 2305 OrderingTable[(int)AtomicOrderingCABI::relaxed] =2306 OrderingTable[(int)AtomicOrderingCABI::acquire] =2307 OrderingTable[(int)AtomicOrderingCABI::consume] =2308 (int)AtomicOrderingCABI::acquire;2309 OrderingTable[(int)AtomicOrderingCABI::release] =2310 OrderingTable[(int)AtomicOrderingCABI::acq_rel] =2311 (int)AtomicOrderingCABI::acq_rel;2312 OrderingTable[(int)AtomicOrderingCABI::seq_cst] =2313 (int)AtomicOrderingCABI::seq_cst;2314 2315 return ConstantDataVector::get(IRB.getContext(), OrderingTable);2316 }2317 2318 // ------------------- Visitors.2319 using InstVisitor<MemorySanitizerVisitor>::visit;2320 void visit(Instruction &I) {2321 if (I.getMetadata(LLVMContext::MD_nosanitize))2322 return;2323 // Don't want to visit if we're in the prologue2324 if (isInPrologue(I))2325 return;2326 if (!DebugCounter::shouldExecute(DebugInstrumentInstruction)) {2327 LLVM_DEBUG(dbgs() << "Skipping instruction: " << I << "\n");2328 // We still need to set the shadow and origin to clean values.2329 setShadow(&I, getCleanShadow(&I));2330 setOrigin(&I, getCleanOrigin());2331 return;2332 }2333 2334 Instructions.push_back(&I);2335 }2336 2337 /// Instrument LoadInst2338 ///2339 /// Loads the corresponding shadow and (optionally) origin.2340 /// Optionally, checks that the load address is fully defined.2341 void visitLoadInst(LoadInst &I) {2342 assert(I.getType()->isSized() && "Load type must have size");2343 assert(!I.getMetadata(LLVMContext::MD_nosanitize));2344 NextNodeIRBuilder IRB(&I);2345 Type *ShadowTy = getShadowTy(&I);2346 Value *Addr = I.getPointerOperand();2347 Value *ShadowPtr = nullptr, *OriginPtr = nullptr;2348 const Align Alignment = I.getAlign();2349 if (PropagateShadow) {2350 std::tie(ShadowPtr, OriginPtr) =2351 getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ false);2352 setShadow(&I,2353 IRB.CreateAlignedLoad(ShadowTy, ShadowPtr, Alignment, "_msld"));2354 } else {2355 setShadow(&I, getCleanShadow(&I));2356 }2357 2358 if (ClCheckAccessAddress)2359 insertCheckShadowOf(I.getPointerOperand(), &I);2360 2361 if (I.isAtomic())2362 I.setOrdering(addAcquireOrdering(I.getOrdering()));2363 2364 if (MS.TrackOrigins) {2365 if (PropagateShadow) {2366 const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment);2367 setOrigin(2368 &I, IRB.CreateAlignedLoad(MS.OriginTy, OriginPtr, OriginAlignment));2369 } else {2370 setOrigin(&I, getCleanOrigin());2371 }2372 }2373 }2374 2375 /// Instrument StoreInst2376 ///2377 /// Stores the corresponding shadow and (optionally) origin.2378 /// Optionally, checks that the store address is fully defined.2379 void visitStoreInst(StoreInst &I) {2380 StoreList.push_back(&I);2381 if (ClCheckAccessAddress)2382 insertCheckShadowOf(I.getPointerOperand(), &I);2383 }2384 2385 void handleCASOrRMW(Instruction &I) {2386 assert(isa<AtomicRMWInst>(I) || isa<AtomicCmpXchgInst>(I));2387 2388 IRBuilder<> IRB(&I);2389 Value *Addr = I.getOperand(0);2390 Value *Val = I.getOperand(1);2391 Value *ShadowPtr = getShadowOriginPtr(Addr, IRB, getShadowTy(Val), Align(1),2392 /*isStore*/ true)2393 .first;2394 2395 if (ClCheckAccessAddress)2396 insertCheckShadowOf(Addr, &I);2397 2398 // Only test the conditional argument of cmpxchg instruction.2399 // The other argument can potentially be uninitialized, but we can not2400 // detect this situation reliably without possible false positives.2401 if (isa<AtomicCmpXchgInst>(I))2402 insertCheckShadowOf(Val, &I);2403 2404 IRB.CreateStore(getCleanShadow(Val), ShadowPtr);2405 2406 setShadow(&I, getCleanShadow(&I));2407 setOrigin(&I, getCleanOrigin());2408 }2409 2410 void visitAtomicRMWInst(AtomicRMWInst &I) {2411 handleCASOrRMW(I);2412 I.setOrdering(addReleaseOrdering(I.getOrdering()));2413 }2414 2415 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {2416 handleCASOrRMW(I);2417 I.setSuccessOrdering(addReleaseOrdering(I.getSuccessOrdering()));2418 }2419 2420 // Vector manipulation.2421 void visitExtractElementInst(ExtractElementInst &I) {2422 insertCheckShadowOf(I.getOperand(1), &I);2423 IRBuilder<> IRB(&I);2424 setShadow(&I, IRB.CreateExtractElement(getShadow(&I, 0), I.getOperand(1),2425 "_msprop"));2426 setOrigin(&I, getOrigin(&I, 0));2427 }2428 2429 void visitInsertElementInst(InsertElementInst &I) {2430 insertCheckShadowOf(I.getOperand(2), &I);2431 IRBuilder<> IRB(&I);2432 auto *Shadow0 = getShadow(&I, 0);2433 auto *Shadow1 = getShadow(&I, 1);2434 setShadow(&I, IRB.CreateInsertElement(Shadow0, Shadow1, I.getOperand(2),2435 "_msprop"));2436 setOriginForNaryOp(I);2437 }2438 2439 void visitShuffleVectorInst(ShuffleVectorInst &I) {2440 IRBuilder<> IRB(&I);2441 auto *Shadow0 = getShadow(&I, 0);2442 auto *Shadow1 = getShadow(&I, 1);2443 setShadow(&I, IRB.CreateShuffleVector(Shadow0, Shadow1, I.getShuffleMask(),2444 "_msprop"));2445 setOriginForNaryOp(I);2446 }2447 2448 // Casts.2449 void visitSExtInst(SExtInst &I) {2450 IRBuilder<> IRB(&I);2451 setShadow(&I, IRB.CreateSExt(getShadow(&I, 0), I.getType(), "_msprop"));2452 setOrigin(&I, getOrigin(&I, 0));2453 }2454 2455 void visitZExtInst(ZExtInst &I) {2456 IRBuilder<> IRB(&I);2457 setShadow(&I, IRB.CreateZExt(getShadow(&I, 0), I.getType(), "_msprop"));2458 setOrigin(&I, getOrigin(&I, 0));2459 }2460 2461 void visitTruncInst(TruncInst &I) {2462 IRBuilder<> IRB(&I);2463 setShadow(&I, IRB.CreateTrunc(getShadow(&I, 0), I.getType(), "_msprop"));2464 setOrigin(&I, getOrigin(&I, 0));2465 }2466 2467 void visitBitCastInst(BitCastInst &I) {2468 // Special case: if this is the bitcast (there is exactly 1 allowed) between2469 // a musttail call and a ret, don't instrument. New instructions are not2470 // allowed after a musttail call.2471 if (auto *CI = dyn_cast<CallInst>(I.getOperand(0)))2472 if (CI->isMustTailCall())2473 return;2474 IRBuilder<> IRB(&I);2475 setShadow(&I, IRB.CreateBitCast(getShadow(&I, 0), getShadowTy(&I)));2476 setOrigin(&I, getOrigin(&I, 0));2477 }2478 2479 void visitPtrToIntInst(PtrToIntInst &I) {2480 IRBuilder<> IRB(&I);2481 setShadow(&I, IRB.CreateIntCast(getShadow(&I, 0), getShadowTy(&I), false,2482 "_msprop_ptrtoint"));2483 setOrigin(&I, getOrigin(&I, 0));2484 }2485 2486 void visitIntToPtrInst(IntToPtrInst &I) {2487 IRBuilder<> IRB(&I);2488 setShadow(&I, IRB.CreateIntCast(getShadow(&I, 0), getShadowTy(&I), false,2489 "_msprop_inttoptr"));2490 setOrigin(&I, getOrigin(&I, 0));2491 }2492 2493 void visitFPToSIInst(CastInst &I) { handleShadowOr(I); }2494 void visitFPToUIInst(CastInst &I) { handleShadowOr(I); }2495 void visitSIToFPInst(CastInst &I) { handleShadowOr(I); }2496 void visitUIToFPInst(CastInst &I) { handleShadowOr(I); }2497 void visitFPExtInst(CastInst &I) { handleShadowOr(I); }2498 void visitFPTruncInst(CastInst &I) { handleShadowOr(I); }2499 2500 /// Propagate shadow for bitwise AND.2501 ///2502 /// This code is exact, i.e. if, for example, a bit in the left argument2503 /// is defined and 0, then neither the value not definedness of the2504 /// corresponding bit in B don't affect the resulting shadow.2505 void visitAnd(BinaryOperator &I) {2506 IRBuilder<> IRB(&I);2507 // "And" of 0 and a poisoned value results in unpoisoned value.2508 // 1&1 => 1; 0&1 => 0; p&1 => p;2509 // 1&0 => 0; 0&0 => 0; p&0 => 0;2510 // 1&p => p; 0&p => 0; p&p => p;2511 // S = (S1 & S2) | (V1 & S2) | (S1 & V2)2512 Value *S1 = getShadow(&I, 0);2513 Value *S2 = getShadow(&I, 1);2514 Value *V1 = I.getOperand(0);2515 Value *V2 = I.getOperand(1);2516 if (V1->getType() != S1->getType()) {2517 V1 = IRB.CreateIntCast(V1, S1->getType(), false);2518 V2 = IRB.CreateIntCast(V2, S2->getType(), false);2519 }2520 Value *S1S2 = IRB.CreateAnd(S1, S2);2521 Value *V1S2 = IRB.CreateAnd(V1, S2);2522 Value *S1V2 = IRB.CreateAnd(S1, V2);2523 setShadow(&I, IRB.CreateOr({S1S2, V1S2, S1V2}));2524 setOriginForNaryOp(I);2525 }2526 2527 void visitOr(BinaryOperator &I) {2528 IRBuilder<> IRB(&I);2529 // "Or" of 1 and a poisoned value results in unpoisoned value:2530 // 1|1 => 1; 0|1 => 1; p|1 => 1;2531 // 1|0 => 1; 0|0 => 0; p|0 => p;2532 // 1|p => 1; 0|p => p; p|p => p;2533 //2534 // S = (S1 & S2) | (~V1 & S2) | (S1 & ~V2)2535 //2536 // If the "disjoint OR" property is violated, the result is poison, and2537 // hence the entire shadow is uninitialized:2538 // S = S | SignExt(V1 & V2 != 0)2539 Value *S1 = getShadow(&I, 0);2540 Value *S2 = getShadow(&I, 1);2541 Value *V1 = I.getOperand(0);2542 Value *V2 = I.getOperand(1);2543 if (V1->getType() != S1->getType()) {2544 V1 = IRB.CreateIntCast(V1, S1->getType(), false);2545 V2 = IRB.CreateIntCast(V2, S2->getType(), false);2546 }2547 2548 Value *NotV1 = IRB.CreateNot(V1);2549 Value *NotV2 = IRB.CreateNot(V2);2550 2551 Value *S1S2 = IRB.CreateAnd(S1, S2);2552 Value *S2NotV1 = IRB.CreateAnd(NotV1, S2);2553 Value *S1NotV2 = IRB.CreateAnd(S1, NotV2);2554 2555 Value *S = IRB.CreateOr({S1S2, S2NotV1, S1NotV2});2556 2557 if (ClPreciseDisjointOr && cast<PossiblyDisjointInst>(&I)->isDisjoint()) {2558 Value *V1V2 = IRB.CreateAnd(V1, V2);2559 Value *DisjointOrShadow = IRB.CreateSExt(2560 IRB.CreateICmpNE(V1V2, getCleanShadow(V1V2)), V1V2->getType());2561 S = IRB.CreateOr(S, DisjointOrShadow, "_ms_disjoint");2562 }2563 2564 setShadow(&I, S);2565 setOriginForNaryOp(I);2566 }2567 2568 /// Default propagation of shadow and/or origin.2569 ///2570 /// This class implements the general case of shadow propagation, used in all2571 /// cases where we don't know and/or don't care about what the operation2572 /// actually does. It converts all input shadow values to a common type2573 /// (extending or truncating as necessary), and bitwise OR's them.2574 ///2575 /// This is much cheaper than inserting checks (i.e. requiring inputs to be2576 /// fully initialized), and less prone to false positives.2577 ///2578 /// This class also implements the general case of origin propagation. For a2579 /// Nary operation, result origin is set to the origin of an argument that is2580 /// not entirely initialized. If there is more than one such arguments, the2581 /// rightmost of them is picked. It does not matter which one is picked if all2582 /// arguments are initialized.2583 template <bool CombineShadow> class Combiner {2584 Value *Shadow = nullptr;2585 Value *Origin = nullptr;2586 IRBuilder<> &IRB;2587 MemorySanitizerVisitor *MSV;2588 2589 public:2590 Combiner(MemorySanitizerVisitor *MSV, IRBuilder<> &IRB)2591 : IRB(IRB), MSV(MSV) {}2592 2593 /// Add a pair of shadow and origin values to the mix.2594 Combiner &Add(Value *OpShadow, Value *OpOrigin) {2595 if (CombineShadow) {2596 assert(OpShadow);2597 if (!Shadow)2598 Shadow = OpShadow;2599 else {2600 OpShadow = MSV->CreateShadowCast(IRB, OpShadow, Shadow->getType());2601 Shadow = IRB.CreateOr(Shadow, OpShadow, "_msprop");2602 }2603 }2604 2605 if (MSV->MS.TrackOrigins) {2606 assert(OpOrigin);2607 if (!Origin) {2608 Origin = OpOrigin;2609 } else {2610 Constant *ConstOrigin = dyn_cast<Constant>(OpOrigin);2611 // No point in adding something that might result in 0 origin value.2612 if (!ConstOrigin || !ConstOrigin->isNullValue()) {2613 Value *Cond = MSV->convertToBool(OpShadow, IRB);2614 Origin = IRB.CreateSelect(Cond, OpOrigin, Origin);2615 }2616 }2617 }2618 return *this;2619 }2620 2621 /// Add an application value to the mix.2622 Combiner &Add(Value *V) {2623 Value *OpShadow = MSV->getShadow(V);2624 Value *OpOrigin = MSV->MS.TrackOrigins ? MSV->getOrigin(V) : nullptr;2625 return Add(OpShadow, OpOrigin);2626 }2627 2628 /// Set the current combined values as the given instruction's shadow2629 /// and origin.2630 void Done(Instruction *I) {2631 if (CombineShadow) {2632 assert(Shadow);2633 Shadow = MSV->CreateShadowCast(IRB, Shadow, MSV->getShadowTy(I));2634 MSV->setShadow(I, Shadow);2635 }2636 if (MSV->MS.TrackOrigins) {2637 assert(Origin);2638 MSV->setOrigin(I, Origin);2639 }2640 }2641 2642 /// Store the current combined value at the specified origin2643 /// location.2644 void DoneAndStoreOrigin(TypeSize TS, Value *OriginPtr) {2645 if (MSV->MS.TrackOrigins) {2646 assert(Origin);2647 MSV->paintOrigin(IRB, Origin, OriginPtr, TS, kMinOriginAlignment);2648 }2649 }2650 };2651 2652 using ShadowAndOriginCombiner = Combiner<true>;2653 using OriginCombiner = Combiner<false>;2654 2655 /// Propagate origin for arbitrary operation.2656 void setOriginForNaryOp(Instruction &I) {2657 if (!MS.TrackOrigins)2658 return;2659 IRBuilder<> IRB(&I);2660 OriginCombiner OC(this, IRB);2661 for (Use &Op : I.operands())2662 OC.Add(Op.get());2663 OC.Done(&I);2664 }2665 2666 size_t VectorOrPrimitiveTypeSizeInBits(Type *Ty) {2667 assert(!(Ty->isVectorTy() && Ty->getScalarType()->isPointerTy()) &&2668 "Vector of pointers is not a valid shadow type");2669 return Ty->isVectorTy() ? cast<FixedVectorType>(Ty)->getNumElements() *2670 Ty->getScalarSizeInBits()2671 : Ty->getPrimitiveSizeInBits();2672 }2673 2674 /// Cast between two shadow types, extending or truncating as2675 /// necessary.2676 Value *CreateShadowCast(IRBuilder<> &IRB, Value *V, Type *dstTy,2677 bool Signed = false) {2678 Type *srcTy = V->getType();2679 if (srcTy == dstTy)2680 return V;2681 size_t srcSizeInBits = VectorOrPrimitiveTypeSizeInBits(srcTy);2682 size_t dstSizeInBits = VectorOrPrimitiveTypeSizeInBits(dstTy);2683 if (srcSizeInBits > 1 && dstSizeInBits == 1)2684 return IRB.CreateICmpNE(V, getCleanShadow(V));2685 2686 if (dstTy->isIntegerTy() && srcTy->isIntegerTy())2687 return IRB.CreateIntCast(V, dstTy, Signed);2688 if (dstTy->isVectorTy() && srcTy->isVectorTy() &&2689 cast<VectorType>(dstTy)->getElementCount() ==2690 cast<VectorType>(srcTy)->getElementCount())2691 return IRB.CreateIntCast(V, dstTy, Signed);2692 Value *V1 = IRB.CreateBitCast(V, Type::getIntNTy(*MS.C, srcSizeInBits));2693 Value *V2 =2694 IRB.CreateIntCast(V1, Type::getIntNTy(*MS.C, dstSizeInBits), Signed);2695 return IRB.CreateBitCast(V2, dstTy);2696 // TODO: handle struct types.2697 }2698 2699 /// Cast an application value to the type of its own shadow.2700 Value *CreateAppToShadowCast(IRBuilder<> &IRB, Value *V) {2701 Type *ShadowTy = getShadowTy(V);2702 if (V->getType() == ShadowTy)2703 return V;2704 if (V->getType()->isPtrOrPtrVectorTy())2705 return IRB.CreatePtrToInt(V, ShadowTy);2706 else2707 return IRB.CreateBitCast(V, ShadowTy);2708 }2709 2710 /// Propagate shadow for arbitrary operation.2711 void handleShadowOr(Instruction &I) {2712 IRBuilder<> IRB(&I);2713 ShadowAndOriginCombiner SC(this, IRB);2714 for (Use &Op : I.operands())2715 SC.Add(Op.get());2716 SC.Done(&I);2717 }2718 2719 // Perform a bitwise OR on the horizontal pairs (or other specified grouping)2720 // of elements.2721 //2722 // For example, suppose we have:2723 // VectorA: <a0, a1, a2, a3, a4, a5>2724 // VectorB: <b0, b1, b2, b3, b4, b5>2725 // ReductionFactor: 32726 // Shards: 12727 // The output would be:2728 // <a0|a1|a2, a3|a4|a5, b0|b1|b2, b3|b4|b5>2729 //2730 // If we have:2731 // VectorA: <a0, a1, a2, a3, a4, a5, a6, a7>2732 // VectorB: <b0, b1, b2, b3, b4, b5, b6, b7>2733 // ReductionFactor: 22734 // Shards: 22735 // then a and be each have 2 "shards", resulting in the output being2736 // interleaved:2737 // <a0|a1, a2|a3, b0|b1, b2|b3, a4|a5, a6|a7, b4|b5, b6|b7>2738 //2739 // This is convenient for instrumenting horizontal add/sub.2740 // For bitwise OR on "vertical" pairs, see maybeHandleSimpleNomemIntrinsic().2741 Value *horizontalReduce(IntrinsicInst &I, unsigned ReductionFactor,2742 unsigned Shards, Value *VectorA, Value *VectorB) {2743 assert(isa<FixedVectorType>(VectorA->getType()));2744 unsigned NumElems =2745 cast<FixedVectorType>(VectorA->getType())->getNumElements();2746 2747 [[maybe_unused]] unsigned TotalNumElems = NumElems;2748 if (VectorB) {2749 assert(VectorA->getType() == VectorB->getType());2750 TotalNumElems *= 2;2751 }2752 2753 assert(NumElems % (ReductionFactor * Shards) == 0);2754 2755 Value *Or = nullptr;2756 2757 IRBuilder<> IRB(&I);2758 for (unsigned i = 0; i < ReductionFactor; i++) {2759 SmallVector<int, 16> Mask;2760 2761 for (unsigned j = 0; j < Shards; j++) {2762 unsigned Offset = NumElems / Shards * j;2763 2764 for (unsigned X = 0; X < NumElems / Shards; X += ReductionFactor)2765 Mask.push_back(Offset + X + i);2766 2767 if (VectorB) {2768 for (unsigned X = 0; X < NumElems / Shards; X += ReductionFactor)2769 Mask.push_back(NumElems + Offset + X + i);2770 }2771 }2772 2773 Value *Masked;2774 if (VectorB)2775 Masked = IRB.CreateShuffleVector(VectorA, VectorB, Mask);2776 else2777 Masked = IRB.CreateShuffleVector(VectorA, Mask);2778 2779 if (Or)2780 Or = IRB.CreateOr(Or, Masked);2781 else2782 Or = Masked;2783 }2784 2785 return Or;2786 }2787 2788 /// Propagate shadow for 1- or 2-vector intrinsics that combine adjacent2789 /// fields.2790 ///2791 /// e.g., <2 x i32> @llvm.aarch64.neon.saddlp.v2i32.v4i16(<4 x i16>)2792 /// <16 x i8> @llvm.aarch64.neon.addp.v16i8(<16 x i8>, <16 x i8>)2793 void handlePairwiseShadowOrIntrinsic(IntrinsicInst &I, unsigned Shards) {2794 assert(I.arg_size() == 1 || I.arg_size() == 2);2795 2796 assert(I.getType()->isVectorTy());2797 assert(I.getArgOperand(0)->getType()->isVectorTy());2798 2799 [[maybe_unused]] FixedVectorType *ParamType =2800 cast<FixedVectorType>(I.getArgOperand(0)->getType());2801 assert((I.arg_size() != 2) ||2802 (ParamType == cast<FixedVectorType>(I.getArgOperand(1)->getType())));2803 [[maybe_unused]] FixedVectorType *ReturnType =2804 cast<FixedVectorType>(I.getType());2805 assert(ParamType->getNumElements() * I.arg_size() ==2806 2 * ReturnType->getNumElements());2807 2808 IRBuilder<> IRB(&I);2809 2810 // Horizontal OR of shadow2811 Value *FirstArgShadow = getShadow(&I, 0);2812 Value *SecondArgShadow = nullptr;2813 if (I.arg_size() == 2)2814 SecondArgShadow = getShadow(&I, 1);2815 2816 Value *OrShadow = horizontalReduce(I, /*ReductionFactor=*/2, Shards,2817 FirstArgShadow, SecondArgShadow);2818 2819 OrShadow = CreateShadowCast(IRB, OrShadow, getShadowTy(&I));2820 2821 setShadow(&I, OrShadow);2822 setOriginForNaryOp(I);2823 }2824 2825 /// Propagate shadow for 1- or 2-vector intrinsics that combine adjacent2826 /// fields, with the parameters reinterpreted to have elements of a specified2827 /// width. For example:2828 /// @llvm.x86.ssse3.phadd.w(<1 x i64> [[VAR1]], <1 x i64> [[VAR2]])2829 /// conceptually operates on2830 /// (<4 x i16> [[VAR1]], <4 x i16> [[VAR2]])2831 /// and can be handled with ReinterpretElemWidth == 16.2832 void handlePairwiseShadowOrIntrinsic(IntrinsicInst &I, unsigned Shards,2833 int ReinterpretElemWidth) {2834 assert(I.arg_size() == 1 || I.arg_size() == 2);2835 2836 assert(I.getType()->isVectorTy());2837 assert(I.getArgOperand(0)->getType()->isVectorTy());2838 2839 FixedVectorType *ParamType =2840 cast<FixedVectorType>(I.getArgOperand(0)->getType());2841 assert((I.arg_size() != 2) ||2842 (ParamType == cast<FixedVectorType>(I.getArgOperand(1)->getType())));2843 2844 [[maybe_unused]] FixedVectorType *ReturnType =2845 cast<FixedVectorType>(I.getType());2846 assert(ParamType->getNumElements() * I.arg_size() ==2847 2 * ReturnType->getNumElements());2848 2849 IRBuilder<> IRB(&I);2850 2851 FixedVectorType *ReinterpretShadowTy = nullptr;2852 assert(isAligned(Align(ReinterpretElemWidth),2853 ParamType->getPrimitiveSizeInBits()));2854 ReinterpretShadowTy = FixedVectorType::get(2855 IRB.getIntNTy(ReinterpretElemWidth),2856 ParamType->getPrimitiveSizeInBits() / ReinterpretElemWidth);2857 2858 // Horizontal OR of shadow2859 Value *FirstArgShadow = getShadow(&I, 0);2860 FirstArgShadow = IRB.CreateBitCast(FirstArgShadow, ReinterpretShadowTy);2861 2862 // If we had two parameters each with an odd number of elements, the total2863 // number of elements is even, but we have never seen this in extant2864 // instruction sets, so we enforce that each parameter must have an even2865 // number of elements.2866 assert(isAligned(2867 Align(2),2868 cast<FixedVectorType>(FirstArgShadow->getType())->getNumElements()));2869 2870 Value *SecondArgShadow = nullptr;2871 if (I.arg_size() == 2) {2872 SecondArgShadow = getShadow(&I, 1);2873 SecondArgShadow = IRB.CreateBitCast(SecondArgShadow, ReinterpretShadowTy);2874 }2875 2876 Value *OrShadow = horizontalReduce(I, /*ReductionFactor=*/2, Shards,2877 FirstArgShadow, SecondArgShadow);2878 2879 OrShadow = CreateShadowCast(IRB, OrShadow, getShadowTy(&I));2880 2881 setShadow(&I, OrShadow);2882 setOriginForNaryOp(I);2883 }2884 2885 void visitFNeg(UnaryOperator &I) { handleShadowOr(I); }2886 2887 // Handle multiplication by constant.2888 //2889 // Handle a special case of multiplication by constant that may have one or2890 // more zeros in the lower bits. This makes corresponding number of lower bits2891 // of the result zero as well. We model it by shifting the other operand2892 // shadow left by the required number of bits. Effectively, we transform2893 // (X * (A * 2**B)) to ((X << B) * A) and instrument (X << B) as (Sx << B).2894 // We use multiplication by 2**N instead of shift to cover the case of2895 // multiplication by 0, which may occur in some elements of a vector operand.2896 void handleMulByConstant(BinaryOperator &I, Constant *ConstArg,2897 Value *OtherArg) {2898 Constant *ShadowMul;2899 Type *Ty = ConstArg->getType();2900 if (auto *VTy = dyn_cast<VectorType>(Ty)) {2901 unsigned NumElements = cast<FixedVectorType>(VTy)->getNumElements();2902 Type *EltTy = VTy->getElementType();2903 SmallVector<Constant *, 16> Elements;2904 for (unsigned Idx = 0; Idx < NumElements; ++Idx) {2905 if (ConstantInt *Elt =2906 dyn_cast<ConstantInt>(ConstArg->getAggregateElement(Idx))) {2907 const APInt &V = Elt->getValue();2908 APInt V2 = APInt(V.getBitWidth(), 1) << V.countr_zero();2909 Elements.push_back(ConstantInt::get(EltTy, V2));2910 } else {2911 Elements.push_back(ConstantInt::get(EltTy, 1));2912 }2913 }2914 ShadowMul = ConstantVector::get(Elements);2915 } else {2916 if (ConstantInt *Elt = dyn_cast<ConstantInt>(ConstArg)) {2917 const APInt &V = Elt->getValue();2918 APInt V2 = APInt(V.getBitWidth(), 1) << V.countr_zero();2919 ShadowMul = ConstantInt::get(Ty, V2);2920 } else {2921 ShadowMul = ConstantInt::get(Ty, 1);2922 }2923 }2924 2925 IRBuilder<> IRB(&I);2926 setShadow(&I,2927 IRB.CreateMul(getShadow(OtherArg), ShadowMul, "msprop_mul_cst"));2928 setOrigin(&I, getOrigin(OtherArg));2929 }2930 2931 void visitMul(BinaryOperator &I) {2932 Constant *constOp0 = dyn_cast<Constant>(I.getOperand(0));2933 Constant *constOp1 = dyn_cast<Constant>(I.getOperand(1));2934 if (constOp0 && !constOp1)2935 handleMulByConstant(I, constOp0, I.getOperand(1));2936 else if (constOp1 && !constOp0)2937 handleMulByConstant(I, constOp1, I.getOperand(0));2938 else2939 handleShadowOr(I);2940 }2941 2942 void visitFAdd(BinaryOperator &I) { handleShadowOr(I); }2943 void visitFSub(BinaryOperator &I) { handleShadowOr(I); }2944 void visitFMul(BinaryOperator &I) { handleShadowOr(I); }2945 void visitAdd(BinaryOperator &I) { handleShadowOr(I); }2946 void visitSub(BinaryOperator &I) { handleShadowOr(I); }2947 void visitXor(BinaryOperator &I) { handleShadowOr(I); }2948 2949 void handleIntegerDiv(Instruction &I) {2950 IRBuilder<> IRB(&I);2951 // Strict on the second argument.2952 insertCheckShadowOf(I.getOperand(1), &I);2953 setShadow(&I, getShadow(&I, 0));2954 setOrigin(&I, getOrigin(&I, 0));2955 }2956 2957 void visitUDiv(BinaryOperator &I) { handleIntegerDiv(I); }2958 void visitSDiv(BinaryOperator &I) { handleIntegerDiv(I); }2959 void visitURem(BinaryOperator &I) { handleIntegerDiv(I); }2960 void visitSRem(BinaryOperator &I) { handleIntegerDiv(I); }2961 2962 // Floating point division is side-effect free. We can not require that the2963 // divisor is fully initialized and must propagate shadow. See PR37523.2964 void visitFDiv(BinaryOperator &I) { handleShadowOr(I); }2965 void visitFRem(BinaryOperator &I) { handleShadowOr(I); }2966 2967 /// Instrument == and != comparisons.2968 ///2969 /// Sometimes the comparison result is known even if some of the bits of the2970 /// arguments are not.2971 void handleEqualityComparison(ICmpInst &I) {2972 IRBuilder<> IRB(&I);2973 Value *A = I.getOperand(0);2974 Value *B = I.getOperand(1);2975 Value *Sa = getShadow(A);2976 Value *Sb = getShadow(B);2977 2978 // Get rid of pointers and vectors of pointers.2979 // For ints (and vectors of ints), types of A and Sa match,2980 // and this is a no-op.2981 A = IRB.CreatePointerCast(A, Sa->getType());2982 B = IRB.CreatePointerCast(B, Sb->getType());2983 2984 // A == B <==> (C = A^B) == 02985 // A != B <==> (C = A^B) != 02986 // Sc = Sa | Sb2987 Value *C = IRB.CreateXor(A, B);2988 Value *Sc = IRB.CreateOr(Sa, Sb);2989 // Now dealing with i = (C == 0) comparison (or C != 0, does not matter now)2990 // Result is defined if one of the following is true2991 // * there is a defined 1 bit in C2992 // * C is fully defined2993 // Si = !(C & ~Sc) && Sc2994 Value *Zero = Constant::getNullValue(Sc->getType());2995 Value *MinusOne = Constant::getAllOnesValue(Sc->getType());2996 Value *LHS = IRB.CreateICmpNE(Sc, Zero);2997 Value *RHS =2998 IRB.CreateICmpEQ(IRB.CreateAnd(IRB.CreateXor(Sc, MinusOne), C), Zero);2999 Value *Si = IRB.CreateAnd(LHS, RHS);3000 Si->setName("_msprop_icmp");3001 setShadow(&I, Si);3002 setOriginForNaryOp(I);3003 }3004 3005 /// Instrument relational comparisons.3006 ///3007 /// This function does exact shadow propagation for all relational3008 /// comparisons of integers, pointers and vectors of those.3009 /// FIXME: output seems suboptimal when one of the operands is a constant3010 void handleRelationalComparisonExact(ICmpInst &I) {3011 IRBuilder<> IRB(&I);3012 Value *A = I.getOperand(0);3013 Value *B = I.getOperand(1);3014 Value *Sa = getShadow(A);3015 Value *Sb = getShadow(B);3016 3017 // Get rid of pointers and vectors of pointers.3018 // For ints (and vectors of ints), types of A and Sa match,3019 // and this is a no-op.3020 A = IRB.CreatePointerCast(A, Sa->getType());3021 B = IRB.CreatePointerCast(B, Sb->getType());3022 3023 // Let [a0, a1] be the interval of possible values of A, taking into account3024 // its undefined bits. Let [b0, b1] be the interval of possible values of B.3025 // Then (A cmp B) is defined iff (a0 cmp b1) == (a1 cmp b0).3026 bool IsSigned = I.isSigned();3027 3028 auto GetMinMaxUnsigned = [&](Value *V, Value *S) {3029 if (IsSigned) {3030 // Sign-flip to map from signed range to unsigned range. Relation A vs B3031 // should be preserved, if checked with `getUnsignedPredicate()`.3032 // Relationship between Amin, Amax, Bmin, Bmax also will not be3033 // affected, as they are created by effectively adding/substructing from3034 // A (or B) a value, derived from shadow, with no overflow, either3035 // before or after sign flip.3036 APInt MinVal =3037 APInt::getSignedMinValue(V->getType()->getScalarSizeInBits());3038 V = IRB.CreateXor(V, ConstantInt::get(V->getType(), MinVal));3039 }3040 // Minimize undefined bits.3041 Value *Min = IRB.CreateAnd(V, IRB.CreateNot(S));3042 Value *Max = IRB.CreateOr(V, S);3043 return std::make_pair(Min, Max);3044 };3045 3046 auto [Amin, Amax] = GetMinMaxUnsigned(A, Sa);3047 auto [Bmin, Bmax] = GetMinMaxUnsigned(B, Sb);3048 Value *S1 = IRB.CreateICmp(I.getUnsignedPredicate(), Amin, Bmax);3049 Value *S2 = IRB.CreateICmp(I.getUnsignedPredicate(), Amax, Bmin);3050 3051 Value *Si = IRB.CreateXor(S1, S2);3052 setShadow(&I, Si);3053 setOriginForNaryOp(I);3054 }3055 3056 /// Instrument signed relational comparisons.3057 ///3058 /// Handle sign bit tests: x<0, x>=0, x<=-1, x>-1 by propagating the highest3059 /// bit of the shadow. Everything else is delegated to handleShadowOr().3060 void handleSignedRelationalComparison(ICmpInst &I) {3061 Constant *constOp;3062 Value *op = nullptr;3063 CmpInst::Predicate pre;3064 if ((constOp = dyn_cast<Constant>(I.getOperand(1)))) {3065 op = I.getOperand(0);3066 pre = I.getPredicate();3067 } else if ((constOp = dyn_cast<Constant>(I.getOperand(0)))) {3068 op = I.getOperand(1);3069 pre = I.getSwappedPredicate();3070 } else {3071 handleShadowOr(I);3072 return;3073 }3074 3075 if ((constOp->isNullValue() &&3076 (pre == CmpInst::ICMP_SLT || pre == CmpInst::ICMP_SGE)) ||3077 (constOp->isAllOnesValue() &&3078 (pre == CmpInst::ICMP_SGT || pre == CmpInst::ICMP_SLE))) {3079 IRBuilder<> IRB(&I);3080 Value *Shadow = IRB.CreateICmpSLT(getShadow(op), getCleanShadow(op),3081 "_msprop_icmp_s");3082 setShadow(&I, Shadow);3083 setOrigin(&I, getOrigin(op));3084 } else {3085 handleShadowOr(I);3086 }3087 }3088 3089 void visitICmpInst(ICmpInst &I) {3090 if (!ClHandleICmp) {3091 handleShadowOr(I);3092 return;3093 }3094 if (I.isEquality()) {3095 handleEqualityComparison(I);3096 return;3097 }3098 3099 assert(I.isRelational());3100 if (ClHandleICmpExact) {3101 handleRelationalComparisonExact(I);3102 return;3103 }3104 if (I.isSigned()) {3105 handleSignedRelationalComparison(I);3106 return;3107 }3108 3109 assert(I.isUnsigned());3110 if ((isa<Constant>(I.getOperand(0)) || isa<Constant>(I.getOperand(1)))) {3111 handleRelationalComparisonExact(I);3112 return;3113 }3114 3115 handleShadowOr(I);3116 }3117 3118 void visitFCmpInst(FCmpInst &I) { handleShadowOr(I); }3119 3120 void handleShift(BinaryOperator &I) {3121 IRBuilder<> IRB(&I);3122 // If any of the S2 bits are poisoned, the whole thing is poisoned.3123 // Otherwise perform the same shift on S1.3124 Value *S1 = getShadow(&I, 0);3125 Value *S2 = getShadow(&I, 1);3126 Value *S2Conv =3127 IRB.CreateSExt(IRB.CreateICmpNE(S2, getCleanShadow(S2)), S2->getType());3128 Value *V2 = I.getOperand(1);3129 Value *Shift = IRB.CreateBinOp(I.getOpcode(), S1, V2);3130 setShadow(&I, IRB.CreateOr(Shift, S2Conv));3131 setOriginForNaryOp(I);3132 }3133 3134 void visitShl(BinaryOperator &I) { handleShift(I); }3135 void visitAShr(BinaryOperator &I) { handleShift(I); }3136 void visitLShr(BinaryOperator &I) { handleShift(I); }3137 3138 void handleFunnelShift(IntrinsicInst &I) {3139 IRBuilder<> IRB(&I);3140 // If any of the S2 bits are poisoned, the whole thing is poisoned.3141 // Otherwise perform the same shift on S0 and S1.3142 Value *S0 = getShadow(&I, 0);3143 Value *S1 = getShadow(&I, 1);3144 Value *S2 = getShadow(&I, 2);3145 Value *S2Conv =3146 IRB.CreateSExt(IRB.CreateICmpNE(S2, getCleanShadow(S2)), S2->getType());3147 Value *V2 = I.getOperand(2);3148 Value *Shift = IRB.CreateIntrinsic(I.getIntrinsicID(), S2Conv->getType(),3149 {S0, S1, V2});3150 setShadow(&I, IRB.CreateOr(Shift, S2Conv));3151 setOriginForNaryOp(I);3152 }3153 3154 /// Instrument llvm.memmove3155 ///3156 /// At this point we don't know if llvm.memmove will be inlined or not.3157 /// If we don't instrument it and it gets inlined,3158 /// our interceptor will not kick in and we will lose the memmove.3159 /// If we instrument the call here, but it does not get inlined,3160 /// we will memmove the shadow twice: which is bad in case3161 /// of overlapping regions. So, we simply lower the intrinsic to a call.3162 ///3163 /// Similar situation exists for memcpy and memset.3164 void visitMemMoveInst(MemMoveInst &I) {3165 getShadow(I.getArgOperand(1)); // Ensure shadow initialized3166 IRBuilder<> IRB(&I);3167 IRB.CreateCall(MS.MemmoveFn,3168 {I.getArgOperand(0), I.getArgOperand(1),3169 IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)});3170 I.eraseFromParent();3171 }3172 3173 /// Instrument memcpy3174 ///3175 /// Similar to memmove: avoid copying shadow twice. This is somewhat3176 /// unfortunate as it may slowdown small constant memcpys.3177 /// FIXME: consider doing manual inline for small constant sizes and proper3178 /// alignment.3179 ///3180 /// Note: This also handles memcpy.inline, which promises no calls to external3181 /// functions as an optimization. However, with instrumentation enabled this3182 /// is difficult to promise; additionally, we know that the MSan runtime3183 /// exists and provides __msan_memcpy(). Therefore, we assume that with3184 /// instrumentation it's safe to turn memcpy.inline into a call to3185 /// __msan_memcpy(). Should this be wrong, such as when implementing memcpy()3186 /// itself, instrumentation should be disabled with the no_sanitize attribute.3187 void visitMemCpyInst(MemCpyInst &I) {3188 getShadow(I.getArgOperand(1)); // Ensure shadow initialized3189 IRBuilder<> IRB(&I);3190 IRB.CreateCall(MS.MemcpyFn,3191 {I.getArgOperand(0), I.getArgOperand(1),3192 IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)});3193 I.eraseFromParent();3194 }3195 3196 // Same as memcpy.3197 void visitMemSetInst(MemSetInst &I) {3198 IRBuilder<> IRB(&I);3199 IRB.CreateCall(3200 MS.MemsetFn,3201 {I.getArgOperand(0),3202 IRB.CreateIntCast(I.getArgOperand(1), IRB.getInt32Ty(), false),3203 IRB.CreateIntCast(I.getArgOperand(2), MS.IntptrTy, false)});3204 I.eraseFromParent();3205 }3206 3207 void visitVAStartInst(VAStartInst &I) { VAHelper->visitVAStartInst(I); }3208 3209 void visitVACopyInst(VACopyInst &I) { VAHelper->visitVACopyInst(I); }3210 3211 /// Handle vector store-like intrinsics.3212 ///3213 /// Instrument intrinsics that look like a simple SIMD store: writes memory,3214 /// has 1 pointer argument and 1 vector argument, returns void.3215 bool handleVectorStoreIntrinsic(IntrinsicInst &I) {3216 assert(I.arg_size() == 2);3217 3218 IRBuilder<> IRB(&I);3219 Value *Addr = I.getArgOperand(0);3220 Value *Shadow = getShadow(&I, 1);3221 Value *ShadowPtr, *OriginPtr;3222 3223 // We don't know the pointer alignment (could be unaligned SSE store!).3224 // Have to assume to worst case.3225 std::tie(ShadowPtr, OriginPtr) = getShadowOriginPtr(3226 Addr, IRB, Shadow->getType(), Align(1), /*isStore*/ true);3227 IRB.CreateAlignedStore(Shadow, ShadowPtr, Align(1));3228 3229 if (ClCheckAccessAddress)3230 insertCheckShadowOf(Addr, &I);3231 3232 // FIXME: factor out common code from materializeStores3233 if (MS.TrackOrigins)3234 IRB.CreateStore(getOrigin(&I, 1), OriginPtr);3235 return true;3236 }3237 3238 /// Handle vector load-like intrinsics.3239 ///3240 /// Instrument intrinsics that look like a simple SIMD load: reads memory,3241 /// has 1 pointer argument, returns a vector.3242 bool handleVectorLoadIntrinsic(IntrinsicInst &I) {3243 assert(I.arg_size() == 1);3244 3245 IRBuilder<> IRB(&I);3246 Value *Addr = I.getArgOperand(0);3247 3248 Type *ShadowTy = getShadowTy(&I);3249 Value *ShadowPtr = nullptr, *OriginPtr = nullptr;3250 if (PropagateShadow) {3251 // We don't know the pointer alignment (could be unaligned SSE load!).3252 // Have to assume to worst case.3253 const Align Alignment = Align(1);3254 std::tie(ShadowPtr, OriginPtr) =3255 getShadowOriginPtr(Addr, IRB, ShadowTy, Alignment, /*isStore*/ false);3256 setShadow(&I,3257 IRB.CreateAlignedLoad(ShadowTy, ShadowPtr, Alignment, "_msld"));3258 } else {3259 setShadow(&I, getCleanShadow(&I));3260 }3261 3262 if (ClCheckAccessAddress)3263 insertCheckShadowOf(Addr, &I);3264 3265 if (MS.TrackOrigins) {3266 if (PropagateShadow)3267 setOrigin(&I, IRB.CreateLoad(MS.OriginTy, OriginPtr));3268 else3269 setOrigin(&I, getCleanOrigin());3270 }3271 return true;3272 }3273 3274 /// Handle (SIMD arithmetic)-like intrinsics.3275 ///3276 /// Instrument intrinsics with any number of arguments of the same type [*],3277 /// equal to the return type, plus a specified number of trailing flags of3278 /// any type.3279 ///3280 /// [*] The type should be simple (no aggregates or pointers; vectors are3281 /// fine).3282 ///3283 /// Caller guarantees that this intrinsic does not access memory.3284 ///3285 /// TODO: "horizontal"/"pairwise" intrinsics are often incorrectly matched by3286 /// by this handler. See horizontalReduce().3287 ///3288 /// TODO: permutation intrinsics are also often incorrectly matched.3289 [[maybe_unused]] bool3290 maybeHandleSimpleNomemIntrinsic(IntrinsicInst &I,3291 unsigned int trailingFlags) {3292 Type *RetTy = I.getType();3293 if (!(RetTy->isIntOrIntVectorTy() || RetTy->isFPOrFPVectorTy()))3294 return false;3295 3296 unsigned NumArgOperands = I.arg_size();3297 assert(NumArgOperands >= trailingFlags);3298 for (unsigned i = 0; i < NumArgOperands - trailingFlags; ++i) {3299 Type *Ty = I.getArgOperand(i)->getType();3300 if (Ty != RetTy)3301 return false;3302 }3303 3304 IRBuilder<> IRB(&I);3305 ShadowAndOriginCombiner SC(this, IRB);3306 for (unsigned i = 0; i < NumArgOperands; ++i)3307 SC.Add(I.getArgOperand(i));3308 SC.Done(&I);3309 3310 return true;3311 }3312 3313 /// Returns whether it was able to heuristically instrument unknown3314 /// intrinsics.3315 ///3316 /// The main purpose of this code is to do something reasonable with all3317 /// random intrinsics we might encounter, most importantly - SIMD intrinsics.3318 /// We recognize several classes of intrinsics by their argument types and3319 /// ModRefBehaviour and apply special instrumentation when we are reasonably3320 /// sure that we know what the intrinsic does.3321 ///3322 /// We special-case intrinsics where this approach fails. See llvm.bswap3323 /// handling as an example of that.3324 bool maybeHandleUnknownIntrinsicUnlogged(IntrinsicInst &I) {3325 unsigned NumArgOperands = I.arg_size();3326 if (NumArgOperands == 0)3327 return false;3328 3329 if (NumArgOperands == 2 && I.getArgOperand(0)->getType()->isPointerTy() &&3330 I.getArgOperand(1)->getType()->isVectorTy() &&3331 I.getType()->isVoidTy() && !I.onlyReadsMemory()) {3332 // This looks like a vector store.3333 return handleVectorStoreIntrinsic(I);3334 }3335 3336 if (NumArgOperands == 1 && I.getArgOperand(0)->getType()->isPointerTy() &&3337 I.getType()->isVectorTy() && I.onlyReadsMemory()) {3338 // This looks like a vector load.3339 return handleVectorLoadIntrinsic(I);3340 }3341 3342 if (I.doesNotAccessMemory())3343 if (maybeHandleSimpleNomemIntrinsic(I, /*trailingFlags=*/0))3344 return true;3345 3346 // FIXME: detect and handle SSE maskstore/maskload?3347 // Some cases are now handled in handleAVXMasked{Load,Store}.3348 return false;3349 }3350 3351 bool maybeHandleUnknownIntrinsic(IntrinsicInst &I) {3352 if (maybeHandleUnknownIntrinsicUnlogged(I)) {3353 if (ClDumpHeuristicInstructions)3354 dumpInst(I);3355 3356 LLVM_DEBUG(dbgs() << "UNKNOWN INSTRUCTION HANDLED HEURISTICALLY: " << I3357 << "\n");3358 return true;3359 } else3360 return false;3361 }3362 3363 void handleInvariantGroup(IntrinsicInst &I) {3364 setShadow(&I, getShadow(&I, 0));3365 setOrigin(&I, getOrigin(&I, 0));3366 }3367 3368 void handleLifetimeStart(IntrinsicInst &I) {3369 if (!PoisonStack)3370 return;3371 AllocaInst *AI = dyn_cast<AllocaInst>(I.getArgOperand(0));3372 if (AI)3373 LifetimeStartList.push_back(std::make_pair(&I, AI));3374 }3375 3376 void handleBswap(IntrinsicInst &I) {3377 IRBuilder<> IRB(&I);3378 Value *Op = I.getArgOperand(0);3379 Type *OpType = Op->getType();3380 setShadow(&I, IRB.CreateIntrinsic(Intrinsic::bswap, ArrayRef(&OpType, 1),3381 getShadow(Op)));3382 setOrigin(&I, getOrigin(Op));3383 }3384 3385 // Uninitialized bits are ok if they appear after the leading/trailing 0's3386 // and a 1. If the input is all zero, it is fully initialized iff3387 // !is_zero_poison.3388 //3389 // e.g., for ctlz, with little-endian, if 0/1 are initialized bits with3390 // concrete value 0/1, and ? is an uninitialized bit:3391 // - 0001 0??? is fully initialized3392 // - 000? ???? is fully uninitialized (*)3393 // - ???? ???? is fully uninitialized3394 // - 0000 0000 is fully uninitialized if is_zero_poison,3395 // fully initialized otherwise3396 //3397 // (*) TODO: arguably, since the number of zeros is in the range [3, 8], we3398 // only need to poison 4 bits.3399 //3400 // OutputShadow =3401 // ((ConcreteZerosCount >= ShadowZerosCount) && !AllZeroShadow)3402 // || (is_zero_poison && AllZeroSrc)3403 void handleCountLeadingTrailingZeros(IntrinsicInst &I) {3404 IRBuilder<> IRB(&I);3405 Value *Src = I.getArgOperand(0);3406 Value *SrcShadow = getShadow(Src);3407 3408 Value *False = IRB.getInt1(false);3409 Value *ConcreteZerosCount = IRB.CreateIntrinsic(3410 I.getType(), I.getIntrinsicID(), {Src, /*is_zero_poison=*/False});3411 Value *ShadowZerosCount = IRB.CreateIntrinsic(3412 I.getType(), I.getIntrinsicID(), {SrcShadow, /*is_zero_poison=*/False});3413 3414 Value *CompareConcreteZeros = IRB.CreateICmpUGE(3415 ConcreteZerosCount, ShadowZerosCount, "_mscz_cmp_zeros");3416 3417 Value *NotAllZeroShadow =3418 IRB.CreateIsNotNull(SrcShadow, "_mscz_shadow_not_null");3419 Value *OutputShadow =3420 IRB.CreateAnd(CompareConcreteZeros, NotAllZeroShadow, "_mscz_main");3421 3422 // If zero poison is requested, mix in with the shadow3423 Constant *IsZeroPoison = cast<Constant>(I.getOperand(1));3424 if (!IsZeroPoison->isZeroValue()) {3425 Value *BoolZeroPoison = IRB.CreateIsNull(Src, "_mscz_bzp");3426 OutputShadow = IRB.CreateOr(OutputShadow, BoolZeroPoison, "_mscz_bs");3427 }3428 3429 OutputShadow = IRB.CreateSExt(OutputShadow, getShadowTy(Src), "_mscz_os");3430 3431 setShadow(&I, OutputShadow);3432 setOriginForNaryOp(I);3433 }3434 3435 /// Handle Arm NEON vector convert intrinsics.3436 ///3437 /// e.g., <4 x i32> @llvm.aarch64.neon.fcvtpu.v4i32.v4f32(<4 x float>)3438 /// i32 @llvm.aarch64.neon.fcvtms.i32.f64(double)3439 ///3440 /// For x86 SSE vector convert intrinsics, see3441 /// handleSSEVectorConvertIntrinsic().3442 void handleNEONVectorConvertIntrinsic(IntrinsicInst &I) {3443 assert(I.arg_size() == 1);3444 3445 IRBuilder<> IRB(&I);3446 Value *S0 = getShadow(&I, 0);3447 3448 /// For scalars:3449 /// Since they are converting from floating-point to integer, the output is3450 /// - fully uninitialized if *any* bit of the input is uninitialized3451 /// - fully ininitialized if all bits of the input are ininitialized3452 /// We apply the same principle on a per-field basis for vectors.3453 Value *OutShadow = IRB.CreateSExt(IRB.CreateICmpNE(S0, getCleanShadow(S0)),3454 getShadowTy(&I));3455 setShadow(&I, OutShadow);3456 setOriginForNaryOp(I);3457 }3458 3459 /// Some instructions have additional zero-elements in the return type3460 /// e.g., <16 x i8> @llvm.x86.avx512.mask.pmov.qb.512(<8 x i64>, ...)3461 ///3462 /// This function will return a vector type with the same number of elements3463 /// as the input, but same per-element width as the return value e.g.,3464 /// <8 x i8>.3465 FixedVectorType *maybeShrinkVectorShadowType(Value *Src, IntrinsicInst &I) {3466 assert(isa<FixedVectorType>(getShadowTy(&I)));3467 FixedVectorType *ShadowType = cast<FixedVectorType>(getShadowTy(&I));3468 3469 // TODO: generalize beyond 2x?3470 if (ShadowType->getElementCount() ==3471 cast<VectorType>(Src->getType())->getElementCount() * 2)3472 ShadowType = FixedVectorType::getHalfElementsVectorType(ShadowType);3473 3474 assert(ShadowType->getElementCount() ==3475 cast<VectorType>(Src->getType())->getElementCount());3476 3477 return ShadowType;3478 }3479 3480 /// Doubles the length of a vector shadow (extending with zeros) if necessary3481 /// to match the length of the shadow for the instruction.3482 /// If scalar types of the vectors are different, it will use the type of the3483 /// input vector.3484 /// This is more type-safe than CreateShadowCast().3485 Value *maybeExtendVectorShadowWithZeros(Value *Shadow, IntrinsicInst &I) {3486 IRBuilder<> IRB(&I);3487 assert(isa<FixedVectorType>(Shadow->getType()));3488 assert(isa<FixedVectorType>(I.getType()));3489 3490 Value *FullShadow = getCleanShadow(&I);3491 unsigned ShadowNumElems =3492 cast<FixedVectorType>(Shadow->getType())->getNumElements();3493 unsigned FullShadowNumElems =3494 cast<FixedVectorType>(FullShadow->getType())->getNumElements();3495 3496 assert((ShadowNumElems == FullShadowNumElems) ||3497 (ShadowNumElems * 2 == FullShadowNumElems));3498 3499 if (ShadowNumElems == FullShadowNumElems) {3500 FullShadow = Shadow;3501 } else {3502 // TODO: generalize beyond 2x?3503 SmallVector<int, 32> ShadowMask(FullShadowNumElems);3504 std::iota(ShadowMask.begin(), ShadowMask.end(), 0);3505 3506 // Append zeros3507 FullShadow =3508 IRB.CreateShuffleVector(Shadow, getCleanShadow(Shadow), ShadowMask);3509 }3510 3511 return FullShadow;3512 }3513 3514 /// Handle x86 SSE vector conversion.3515 ///3516 /// e.g., single-precision to half-precision conversion:3517 /// <8 x i16> @llvm.x86.vcvtps2ph.256(<8 x float> %a0, i32 0)3518 /// <8 x i16> @llvm.x86.vcvtps2ph.128(<4 x float> %a0, i32 0)3519 ///3520 /// floating-point to integer:3521 /// <4 x i32> @llvm.x86.sse2.cvtps2dq(<4 x float>)3522 /// <4 x i32> @llvm.x86.sse2.cvtpd2dq(<2 x double>)3523 ///3524 /// Note: if the output has more elements, they are zero-initialized (and3525 /// therefore the shadow will also be initialized).3526 ///3527 /// This differs from handleSSEVectorConvertIntrinsic() because it3528 /// propagates uninitialized shadow (instead of checking the shadow).3529 void handleSSEVectorConvertIntrinsicByProp(IntrinsicInst &I,3530 bool HasRoundingMode) {3531 if (HasRoundingMode) {3532 assert(I.arg_size() == 2);3533 [[maybe_unused]] Value *RoundingMode = I.getArgOperand(1);3534 assert(RoundingMode->getType()->isIntegerTy());3535 } else {3536 assert(I.arg_size() == 1);3537 }3538 3539 Value *Src = I.getArgOperand(0);3540 assert(Src->getType()->isVectorTy());3541 3542 // The return type might have more elements than the input.3543 // Temporarily shrink the return type's number of elements.3544 VectorType *ShadowType = maybeShrinkVectorShadowType(Src, I);3545 3546 IRBuilder<> IRB(&I);3547 Value *S0 = getShadow(&I, 0);3548 3549 /// For scalars:3550 /// Since they are converting to and/or from floating-point, the output is:3551 /// - fully uninitialized if *any* bit of the input is uninitialized3552 /// - fully ininitialized if all bits of the input are ininitialized3553 /// We apply the same principle on a per-field basis for vectors.3554 Value *Shadow =3555 IRB.CreateSExt(IRB.CreateICmpNE(S0, getCleanShadow(S0)), ShadowType);3556 3557 // The return type might have more elements than the input.3558 // Extend the return type back to its original width if necessary.3559 Value *FullShadow = maybeExtendVectorShadowWithZeros(Shadow, I);3560 3561 setShadow(&I, FullShadow);3562 setOriginForNaryOp(I);3563 }3564 3565 // Instrument x86 SSE vector convert intrinsic.3566 //3567 // This function instruments intrinsics like cvtsi2ss:3568 // %Out = int_xxx_cvtyyy(%ConvertOp)3569 // or3570 // %Out = int_xxx_cvtyyy(%CopyOp, %ConvertOp)3571 // Intrinsic converts \p NumUsedElements elements of \p ConvertOp to the same3572 // number \p Out elements, and (if has 2 arguments) copies the rest of the3573 // elements from \p CopyOp.3574 // In most cases conversion involves floating-point value which may trigger a3575 // hardware exception when not fully initialized. For this reason we require3576 // \p ConvertOp[0:NumUsedElements] to be fully initialized and trap otherwise.3577 // We copy the shadow of \p CopyOp[NumUsedElements:] to \p3578 // Out[NumUsedElements:]. This means that intrinsics without \p CopyOp always3579 // return a fully initialized value.3580 //3581 // For Arm NEON vector convert intrinsics, see3582 // handleNEONVectorConvertIntrinsic().3583 void handleSSEVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements,3584 bool HasRoundingMode = false) {3585 IRBuilder<> IRB(&I);3586 Value *CopyOp, *ConvertOp;3587 3588 assert((!HasRoundingMode ||3589 isa<ConstantInt>(I.getArgOperand(I.arg_size() - 1))) &&3590 "Invalid rounding mode");3591 3592 switch (I.arg_size() - HasRoundingMode) {3593 case 2:3594 CopyOp = I.getArgOperand(0);3595 ConvertOp = I.getArgOperand(1);3596 break;3597 case 1:3598 ConvertOp = I.getArgOperand(0);3599 CopyOp = nullptr;3600 break;3601 default:3602 llvm_unreachable("Cvt intrinsic with unsupported number of arguments.");3603 }3604 3605 // The first *NumUsedElements* elements of ConvertOp are converted to the3606 // same number of output elements. The rest of the output is copied from3607 // CopyOp, or (if not available) filled with zeroes.3608 // Combine shadow for elements of ConvertOp that are used in this operation,3609 // and insert a check.3610 // FIXME: consider propagating shadow of ConvertOp, at least in the case of3611 // int->any conversion.3612 Value *ConvertShadow = getShadow(ConvertOp);3613 Value *AggShadow = nullptr;3614 if (ConvertOp->getType()->isVectorTy()) {3615 AggShadow = IRB.CreateExtractElement(3616 ConvertShadow, ConstantInt::get(IRB.getInt32Ty(), 0));3617 for (int i = 1; i < NumUsedElements; ++i) {3618 Value *MoreShadow = IRB.CreateExtractElement(3619 ConvertShadow, ConstantInt::get(IRB.getInt32Ty(), i));3620 AggShadow = IRB.CreateOr(AggShadow, MoreShadow);3621 }3622 } else {3623 AggShadow = ConvertShadow;3624 }3625 assert(AggShadow->getType()->isIntegerTy());3626 insertCheckShadow(AggShadow, getOrigin(ConvertOp), &I);3627 3628 // Build result shadow by zero-filling parts of CopyOp shadow that come from3629 // ConvertOp.3630 if (CopyOp) {3631 assert(CopyOp->getType() == I.getType());3632 assert(CopyOp->getType()->isVectorTy());3633 Value *ResultShadow = getShadow(CopyOp);3634 Type *EltTy = cast<VectorType>(ResultShadow->getType())->getElementType();3635 for (int i = 0; i < NumUsedElements; ++i) {3636 ResultShadow = IRB.CreateInsertElement(3637 ResultShadow, ConstantInt::getNullValue(EltTy),3638 ConstantInt::get(IRB.getInt32Ty(), i));3639 }3640 setShadow(&I, ResultShadow);3641 setOrigin(&I, getOrigin(CopyOp));3642 } else {3643 setShadow(&I, getCleanShadow(&I));3644 setOrigin(&I, getCleanOrigin());3645 }3646 }3647 3648 // Given a scalar or vector, extract lower 64 bits (or less), and return all3649 // zeroes if it is zero, and all ones otherwise.3650 Value *Lower64ShadowExtend(IRBuilder<> &IRB, Value *S, Type *T) {3651 if (S->getType()->isVectorTy())3652 S = CreateShadowCast(IRB, S, IRB.getInt64Ty(), /* Signed */ true);3653 assert(S->getType()->getPrimitiveSizeInBits() <= 64);3654 Value *S2 = IRB.CreateICmpNE(S, getCleanShadow(S));3655 return CreateShadowCast(IRB, S2, T, /* Signed */ true);3656 }3657 3658 // Given a vector, extract its first element, and return all3659 // zeroes if it is zero, and all ones otherwise.3660 Value *LowerElementShadowExtend(IRBuilder<> &IRB, Value *S, Type *T) {3661 Value *S1 = IRB.CreateExtractElement(S, (uint64_t)0);3662 Value *S2 = IRB.CreateICmpNE(S1, getCleanShadow(S1));3663 return CreateShadowCast(IRB, S2, T, /* Signed */ true);3664 }3665 3666 Value *VariableShadowExtend(IRBuilder<> &IRB, Value *S) {3667 Type *T = S->getType();3668 assert(T->isVectorTy());3669 Value *S2 = IRB.CreateICmpNE(S, getCleanShadow(S));3670 return IRB.CreateSExt(S2, T);3671 }3672 3673 // Instrument vector shift intrinsic.3674 //3675 // This function instruments intrinsics like int_x86_avx2_psll_w.3676 // Intrinsic shifts %In by %ShiftSize bits.3677 // %ShiftSize may be a vector. In that case the lower 64 bits determine shift3678 // size, and the rest is ignored. Behavior is defined even if shift size is3679 // greater than register (or field) width.3680 void handleVectorShiftIntrinsic(IntrinsicInst &I, bool Variable) {3681 assert(I.arg_size() == 2);3682 IRBuilder<> IRB(&I);3683 // If any of the S2 bits are poisoned, the whole thing is poisoned.3684 // Otherwise perform the same shift on S1.3685 Value *S1 = getShadow(&I, 0);3686 Value *S2 = getShadow(&I, 1);3687 Value *S2Conv = Variable ? VariableShadowExtend(IRB, S2)3688 : Lower64ShadowExtend(IRB, S2, getShadowTy(&I));3689 Value *V1 = I.getOperand(0);3690 Value *V2 = I.getOperand(1);3691 Value *Shift = IRB.CreateCall(I.getFunctionType(), I.getCalledOperand(),3692 {IRB.CreateBitCast(S1, V1->getType()), V2});3693 Shift = IRB.CreateBitCast(Shift, getShadowTy(&I));3694 setShadow(&I, IRB.CreateOr(Shift, S2Conv));3695 setOriginForNaryOp(I);3696 }3697 3698 // Get an MMX-sized (64-bit) vector type, or optionally, other sized3699 // vectors.3700 Type *getMMXVectorTy(unsigned EltSizeInBits,3701 unsigned X86_MMXSizeInBits = 64) {3702 assert(EltSizeInBits != 0 && (X86_MMXSizeInBits % EltSizeInBits) == 0 &&3703 "Illegal MMX vector element size");3704 return FixedVectorType::get(IntegerType::get(*MS.C, EltSizeInBits),3705 X86_MMXSizeInBits / EltSizeInBits);3706 }3707 3708 // Returns a signed counterpart for an (un)signed-saturate-and-pack3709 // intrinsic.3710 Intrinsic::ID getSignedPackIntrinsic(Intrinsic::ID id) {3711 switch (id) {3712 case Intrinsic::x86_sse2_packsswb_128:3713 case Intrinsic::x86_sse2_packuswb_128:3714 return Intrinsic::x86_sse2_packsswb_128;3715 3716 case Intrinsic::x86_sse2_packssdw_128:3717 case Intrinsic::x86_sse41_packusdw:3718 return Intrinsic::x86_sse2_packssdw_128;3719 3720 case Intrinsic::x86_avx2_packsswb:3721 case Intrinsic::x86_avx2_packuswb:3722 return Intrinsic::x86_avx2_packsswb;3723 3724 case Intrinsic::x86_avx2_packssdw:3725 case Intrinsic::x86_avx2_packusdw:3726 return Intrinsic::x86_avx2_packssdw;3727 3728 case Intrinsic::x86_mmx_packsswb:3729 case Intrinsic::x86_mmx_packuswb:3730 return Intrinsic::x86_mmx_packsswb;3731 3732 case Intrinsic::x86_mmx_packssdw:3733 return Intrinsic::x86_mmx_packssdw;3734 3735 case Intrinsic::x86_avx512_packssdw_512:3736 case Intrinsic::x86_avx512_packusdw_512:3737 return Intrinsic::x86_avx512_packssdw_512;3738 3739 case Intrinsic::x86_avx512_packsswb_512:3740 case Intrinsic::x86_avx512_packuswb_512:3741 return Intrinsic::x86_avx512_packsswb_512;3742 3743 default:3744 llvm_unreachable("unexpected intrinsic id");3745 }3746 }3747 3748 // Instrument vector pack intrinsic.3749 //3750 // This function instruments intrinsics like x86_mmx_packsswb, that3751 // packs elements of 2 input vectors into half as many bits with saturation.3752 // Shadow is propagated with the signed variant of the same intrinsic applied3753 // to sext(Sa != zeroinitializer), sext(Sb != zeroinitializer).3754 // MMXEltSizeInBits is used only for x86mmx arguments.3755 //3756 // TODO: consider using GetMinMaxUnsigned() to handle saturation precisely3757 void handleVectorPackIntrinsic(IntrinsicInst &I,3758 unsigned MMXEltSizeInBits = 0) {3759 assert(I.arg_size() == 2);3760 IRBuilder<> IRB(&I);3761 Value *S1 = getShadow(&I, 0);3762 Value *S2 = getShadow(&I, 1);3763 assert(S1->getType()->isVectorTy());3764 3765 // SExt and ICmpNE below must apply to individual elements of input vectors.3766 // In case of x86mmx arguments, cast them to appropriate vector types and3767 // back.3768 Type *T =3769 MMXEltSizeInBits ? getMMXVectorTy(MMXEltSizeInBits) : S1->getType();3770 if (MMXEltSizeInBits) {3771 S1 = IRB.CreateBitCast(S1, T);3772 S2 = IRB.CreateBitCast(S2, T);3773 }3774 Value *S1_ext =3775 IRB.CreateSExt(IRB.CreateICmpNE(S1, Constant::getNullValue(T)), T);3776 Value *S2_ext =3777 IRB.CreateSExt(IRB.CreateICmpNE(S2, Constant::getNullValue(T)), T);3778 if (MMXEltSizeInBits) {3779 S1_ext = IRB.CreateBitCast(S1_ext, getMMXVectorTy(64));3780 S2_ext = IRB.CreateBitCast(S2_ext, getMMXVectorTy(64));3781 }3782 3783 Value *S = IRB.CreateIntrinsic(getSignedPackIntrinsic(I.getIntrinsicID()),3784 {S1_ext, S2_ext}, /*FMFSource=*/nullptr,3785 "_msprop_vector_pack");3786 if (MMXEltSizeInBits)3787 S = IRB.CreateBitCast(S, getShadowTy(&I));3788 setShadow(&I, S);3789 setOriginForNaryOp(I);3790 }3791 3792 // Convert `Mask` into `<n x i1>`.3793 Constant *createDppMask(unsigned Width, unsigned Mask) {3794 SmallVector<Constant *, 4> R(Width);3795 for (auto &M : R) {3796 M = ConstantInt::getBool(F.getContext(), Mask & 1);3797 Mask >>= 1;3798 }3799 return ConstantVector::get(R);3800 }3801 3802 // Calculate output shadow as array of booleans `<n x i1>`, assuming if any3803 // arg is poisoned, entire dot product is poisoned.3804 Value *findDppPoisonedOutput(IRBuilder<> &IRB, Value *S, unsigned SrcMask,3805 unsigned DstMask) {3806 const unsigned Width =3807 cast<FixedVectorType>(S->getType())->getNumElements();3808 3809 S = IRB.CreateSelect(createDppMask(Width, SrcMask), S,3810 Constant::getNullValue(S->getType()));3811 Value *SElem = IRB.CreateOrReduce(S);3812 Value *IsClean = IRB.CreateIsNull(SElem, "_msdpp");3813 Value *DstMaskV = createDppMask(Width, DstMask);3814 3815 return IRB.CreateSelect(3816 IsClean, Constant::getNullValue(DstMaskV->getType()), DstMaskV);3817 }3818 3819 // See `Intel Intrinsics Guide` for `_dp_p*` instructions.3820 //3821 // 2 and 4 element versions produce single scalar of dot product, and then3822 // puts it into elements of output vector, selected by 4 lowest bits of the3823 // mask. Top 4 bits of the mask control which elements of input to use for dot3824 // product.3825 //3826 // 8 element version mask still has only 4 bit for input, and 4 bit for output3827 // mask. According to the spec it just operates as 4 element version on first3828 // 4 elements of inputs and output, and then on last 4 elements of inputs and3829 // output.3830 void handleDppIntrinsic(IntrinsicInst &I) {3831 IRBuilder<> IRB(&I);3832 3833 Value *S0 = getShadow(&I, 0);3834 Value *S1 = getShadow(&I, 1);3835 Value *S = IRB.CreateOr(S0, S1);3836 3837 const unsigned Width =3838 cast<FixedVectorType>(S->getType())->getNumElements();3839 assert(Width == 2 || Width == 4 || Width == 8);3840 3841 const unsigned Mask = cast<ConstantInt>(I.getArgOperand(2))->getZExtValue();3842 const unsigned SrcMask = Mask >> 4;3843 const unsigned DstMask = Mask & 0xf;3844 3845 // Calculate shadow as `<n x i1>`.3846 Value *SI1 = findDppPoisonedOutput(IRB, S, SrcMask, DstMask);3847 if (Width == 8) {3848 // First 4 elements of shadow are already calculated. `makeDppShadow`3849 // operats on 32 bit masks, so we can just shift masks, and repeat.3850 SI1 = IRB.CreateOr(3851 SI1, findDppPoisonedOutput(IRB, S, SrcMask << 4, DstMask << 4));3852 }3853 // Extend to real size of shadow, poisoning either all or none bits of an3854 // element.3855 S = IRB.CreateSExt(SI1, S->getType(), "_msdpp");3856 3857 setShadow(&I, S);3858 setOriginForNaryOp(I);3859 }3860 3861 Value *convertBlendvToSelectMask(IRBuilder<> &IRB, Value *C) {3862 C = CreateAppToShadowCast(IRB, C);3863 FixedVectorType *FVT = cast<FixedVectorType>(C->getType());3864 unsigned ElSize = FVT->getElementType()->getPrimitiveSizeInBits();3865 C = IRB.CreateAShr(C, ElSize - 1);3866 FVT = FixedVectorType::get(IRB.getInt1Ty(), FVT->getNumElements());3867 return IRB.CreateTrunc(C, FVT);3868 }3869 3870 // `blendv(f, t, c)` is effectively `select(c[top_bit], t, f)`.3871 void handleBlendvIntrinsic(IntrinsicInst &I) {3872 Value *C = I.getOperand(2);3873 Value *T = I.getOperand(1);3874 Value *F = I.getOperand(0);3875 3876 Value *Sc = getShadow(&I, 2);3877 Value *Oc = MS.TrackOrigins ? getOrigin(C) : nullptr;3878 3879 {3880 IRBuilder<> IRB(&I);3881 // Extract top bit from condition and its shadow.3882 C = convertBlendvToSelectMask(IRB, C);3883 Sc = convertBlendvToSelectMask(IRB, Sc);3884 3885 setShadow(C, Sc);3886 setOrigin(C, Oc);3887 }3888 3889 handleSelectLikeInst(I, C, T, F);3890 }3891 3892 // Instrument sum-of-absolute-differences intrinsic.3893 void handleVectorSadIntrinsic(IntrinsicInst &I, bool IsMMX = false) {3894 const unsigned SignificantBitsPerResultElement = 16;3895 Type *ResTy = IsMMX ? IntegerType::get(*MS.C, 64) : I.getType();3896 unsigned ZeroBitsPerResultElement =3897 ResTy->getScalarSizeInBits() - SignificantBitsPerResultElement;3898 3899 IRBuilder<> IRB(&I);3900 auto *Shadow0 = getShadow(&I, 0);3901 auto *Shadow1 = getShadow(&I, 1);3902 Value *S = IRB.CreateOr(Shadow0, Shadow1);3903 S = IRB.CreateBitCast(S, ResTy);3904 S = IRB.CreateSExt(IRB.CreateICmpNE(S, Constant::getNullValue(ResTy)),3905 ResTy);3906 S = IRB.CreateLShr(S, ZeroBitsPerResultElement);3907 S = IRB.CreateBitCast(S, getShadowTy(&I));3908 setShadow(&I, S);3909 setOriginForNaryOp(I);3910 }3911 3912 // Instrument multiply-add(-accumulate)? intrinsics.3913 //3914 // e.g., Two operands:3915 // <4 x i32> @llvm.x86.sse2.pmadd.wd(<8 x i16> %a, <8 x i16> %b)3916 //3917 // Two operands which require an EltSizeInBits override:3918 // <1 x i64> @llvm.x86.mmx.pmadd.wd(<1 x i64> %a, <1 x i64> %b)3919 //3920 // Three operands:3921 // <4 x i32> @llvm.x86.avx512.vpdpbusd.1283922 // (<4 x i32> %s, <16 x i8> %a, <16 x i8> %b)3923 // (this is equivalent to multiply-add on %a and %b, followed by3924 // adding/"accumulating" %s. "Accumulation" stores the result in one3925 // of the source registers, but this accumulate vs. add distinction3926 // is lost when dealing with LLVM intrinsics.)3927 //3928 // ZeroPurifies means that multiplying a known-zero with an uninitialized3929 // value results in an initialized value. This is applicable for integer3930 // multiplication, but not floating-point (counter-example: NaN).3931 void handleVectorPmaddIntrinsic(IntrinsicInst &I, unsigned ReductionFactor,3932 bool ZeroPurifies,3933 unsigned EltSizeInBits = 0) {3934 IRBuilder<> IRB(&I);3935 3936 [[maybe_unused]] FixedVectorType *ReturnType =3937 cast<FixedVectorType>(I.getType());3938 assert(isa<FixedVectorType>(ReturnType));3939 3940 // Vectors A and B, and shadows3941 Value *Va = nullptr;3942 Value *Vb = nullptr;3943 Value *Sa = nullptr;3944 Value *Sb = nullptr;3945 3946 assert(I.arg_size() == 2 || I.arg_size() == 3);3947 if (I.arg_size() == 2) {3948 Va = I.getOperand(0);3949 Vb = I.getOperand(1);3950 3951 Sa = getShadow(&I, 0);3952 Sb = getShadow(&I, 1);3953 } else if (I.arg_size() == 3) {3954 // Operand 0 is the accumulator. We will deal with that below.3955 Va = I.getOperand(1);3956 Vb = I.getOperand(2);3957 3958 Sa = getShadow(&I, 1);3959 Sb = getShadow(&I, 2);3960 }3961 3962 FixedVectorType *ParamType = cast<FixedVectorType>(Va->getType());3963 assert(ParamType == Vb->getType());3964 3965 assert(ParamType->getPrimitiveSizeInBits() ==3966 ReturnType->getPrimitiveSizeInBits());3967 3968 if (I.arg_size() == 3) {3969 [[maybe_unused]] auto *AccumulatorType =3970 cast<FixedVectorType>(I.getOperand(0)->getType());3971 assert(AccumulatorType == ReturnType);3972 }3973 3974 FixedVectorType *ImplicitReturnType =3975 cast<FixedVectorType>(getShadowTy(ReturnType));3976 // Step 1: instrument multiplication of corresponding vector elements3977 if (EltSizeInBits) {3978 ImplicitReturnType = cast<FixedVectorType>(3979 getMMXVectorTy(EltSizeInBits * ReductionFactor,3980 ParamType->getPrimitiveSizeInBits()));3981 ParamType = cast<FixedVectorType>(3982 getMMXVectorTy(EltSizeInBits, ParamType->getPrimitiveSizeInBits()));3983 3984 Va = IRB.CreateBitCast(Va, ParamType);3985 Vb = IRB.CreateBitCast(Vb, ParamType);3986 3987 Sa = IRB.CreateBitCast(Sa, getShadowTy(ParamType));3988 Sb = IRB.CreateBitCast(Sb, getShadowTy(ParamType));3989 } else {3990 assert(ParamType->getNumElements() ==3991 ReturnType->getNumElements() * ReductionFactor);3992 }3993 3994 // Each element of the vector is represented by a single bit (poisoned or3995 // not) e.g., <8 x i1>.3996 Value *SaNonZero = IRB.CreateIsNotNull(Sa);3997 Value *SbNonZero = IRB.CreateIsNotNull(Sb);3998 Value *And;3999 if (ZeroPurifies) {4000 // Multiplying an *initialized* zero by an uninitialized element results4001 // in an initialized zero element.4002 //4003 // This is analogous to bitwise AND, where "AND" of 0 and a poisoned value4004 // results in an unpoisoned value. We can therefore adapt the visitAnd()4005 // instrumentation:4006 // OutShadow = (SaNonZero & SbNonZero)4007 // | (VaNonZero & SbNonZero)4008 // | (SaNonZero & VbNonZero)4009 // where non-zero is checked on a per-element basis (not per bit).4010 Value *VaInt = Va;4011 Value *VbInt = Vb;4012 if (!Va->getType()->isIntegerTy()) {4013 VaInt = CreateAppToShadowCast(IRB, Va);4014 VbInt = CreateAppToShadowCast(IRB, Vb);4015 }4016 4017 Value *VaNonZero = IRB.CreateIsNotNull(VaInt);4018 Value *VbNonZero = IRB.CreateIsNotNull(VbInt);4019 4020 Value *SaAndSbNonZero = IRB.CreateAnd(SaNonZero, SbNonZero);4021 Value *VaAndSbNonZero = IRB.CreateAnd(VaNonZero, SbNonZero);4022 Value *SaAndVbNonZero = IRB.CreateAnd(SaNonZero, VbNonZero);4023 4024 And = IRB.CreateOr({SaAndSbNonZero, VaAndSbNonZero, SaAndVbNonZero});4025 } else {4026 And = IRB.CreateOr({SaNonZero, SbNonZero});4027 }4028 4029 // Extend <8 x i1> to <8 x i16>.4030 // (The real pmadd intrinsic would have computed intermediate values of4031 // <8 x i32>, but that is irrelevant for our shadow purposes because we4032 // consider each element to be either fully initialized or fully4033 // uninitialized.)4034 And = IRB.CreateSExt(And, Sa->getType());4035 4036 // Step 2: instrument horizontal add4037 // We don't need bit-precise horizontalReduce because we only want to check4038 // if each pair/quad of elements is fully zero.4039 // Cast to <4 x i32>.4040 Value *Horizontal = IRB.CreateBitCast(And, ImplicitReturnType);4041 4042 // Compute <4 x i1>, then extend back to <4 x i32>.4043 Value *OutShadow = IRB.CreateSExt(4044 IRB.CreateICmpNE(Horizontal,4045 Constant::getNullValue(Horizontal->getType())),4046 ImplicitReturnType);4047 4048 // Cast it back to the required fake return type (if MMX: <1 x i64>; for4049 // AVX, it is already correct).4050 if (EltSizeInBits)4051 OutShadow = CreateShadowCast(IRB, OutShadow, getShadowTy(&I));4052 4053 // Step 3 (if applicable): instrument accumulator4054 if (I.arg_size() == 3)4055 OutShadow = IRB.CreateOr(OutShadow, getShadow(&I, 0));4056 4057 setShadow(&I, OutShadow);4058 setOriginForNaryOp(I);4059 }4060 4061 // Instrument compare-packed intrinsic.4062 // Basically, an or followed by sext(icmp ne 0) to end up with all-zeros or4063 // all-ones shadow.4064 void handleVectorComparePackedIntrinsic(IntrinsicInst &I) {4065 IRBuilder<> IRB(&I);4066 Type *ResTy = getShadowTy(&I);4067 auto *Shadow0 = getShadow(&I, 0);4068 auto *Shadow1 = getShadow(&I, 1);4069 Value *S0 = IRB.CreateOr(Shadow0, Shadow1);4070 Value *S = IRB.CreateSExt(4071 IRB.CreateICmpNE(S0, Constant::getNullValue(ResTy)), ResTy);4072 setShadow(&I, S);4073 setOriginForNaryOp(I);4074 }4075 4076 // Instrument compare-scalar intrinsic.4077 // This handles both cmp* intrinsics which return the result in the first4078 // element of a vector, and comi* which return the result as i32.4079 void handleVectorCompareScalarIntrinsic(IntrinsicInst &I) {4080 IRBuilder<> IRB(&I);4081 auto *Shadow0 = getShadow(&I, 0);4082 auto *Shadow1 = getShadow(&I, 1);4083 Value *S0 = IRB.CreateOr(Shadow0, Shadow1);4084 Value *S = LowerElementShadowExtend(IRB, S0, getShadowTy(&I));4085 setShadow(&I, S);4086 setOriginForNaryOp(I);4087 }4088 4089 // Instrument generic vector reduction intrinsics4090 // by ORing together all their fields.4091 //4092 // If AllowShadowCast is true, the return type does not need to be the same4093 // type as the fields4094 // e.g., declare i32 @llvm.aarch64.neon.uaddv.i32.v16i8(<16 x i8>)4095 void handleVectorReduceIntrinsic(IntrinsicInst &I, bool AllowShadowCast) {4096 assert(I.arg_size() == 1);4097 4098 IRBuilder<> IRB(&I);4099 Value *S = IRB.CreateOrReduce(getShadow(&I, 0));4100 if (AllowShadowCast)4101 S = CreateShadowCast(IRB, S, getShadowTy(&I));4102 else4103 assert(S->getType() == getShadowTy(&I));4104 setShadow(&I, S);4105 setOriginForNaryOp(I);4106 }4107 4108 // Similar to handleVectorReduceIntrinsic but with an initial starting value.4109 // e.g., call float @llvm.vector.reduce.fadd.f32.v2f32(float %a0, <2 x float>4110 // %a1)4111 // shadow = shadow[a0] | shadow[a1.0] | shadow[a1.1]4112 //4113 // The type of the return value, initial starting value, and elements of the4114 // vector must be identical.4115 void handleVectorReduceWithStarterIntrinsic(IntrinsicInst &I) {4116 assert(I.arg_size() == 2);4117 4118 IRBuilder<> IRB(&I);4119 Value *Shadow0 = getShadow(&I, 0);4120 Value *Shadow1 = IRB.CreateOrReduce(getShadow(&I, 1));4121 assert(Shadow0->getType() == Shadow1->getType());4122 Value *S = IRB.CreateOr(Shadow0, Shadow1);4123 assert(S->getType() == getShadowTy(&I));4124 setShadow(&I, S);4125 setOriginForNaryOp(I);4126 }4127 4128 // Instrument vector.reduce.or intrinsic.4129 // Valid (non-poisoned) set bits in the operand pull low the4130 // corresponding shadow bits.4131 void handleVectorReduceOrIntrinsic(IntrinsicInst &I) {4132 assert(I.arg_size() == 1);4133 4134 IRBuilder<> IRB(&I);4135 Value *OperandShadow = getShadow(&I, 0);4136 Value *OperandUnsetBits = IRB.CreateNot(I.getOperand(0));4137 Value *OperandUnsetOrPoison = IRB.CreateOr(OperandUnsetBits, OperandShadow);4138 // Bit N is clean if any field's bit N is 1 and unpoison4139 Value *OutShadowMask = IRB.CreateAndReduce(OperandUnsetOrPoison);4140 // Otherwise, it is clean if every field's bit N is unpoison4141 Value *OrShadow = IRB.CreateOrReduce(OperandShadow);4142 Value *S = IRB.CreateAnd(OutShadowMask, OrShadow);4143 4144 setShadow(&I, S);4145 setOrigin(&I, getOrigin(&I, 0));4146 }4147 4148 // Instrument vector.reduce.and intrinsic.4149 // Valid (non-poisoned) unset bits in the operand pull down the4150 // corresponding shadow bits.4151 void handleVectorReduceAndIntrinsic(IntrinsicInst &I) {4152 assert(I.arg_size() == 1);4153 4154 IRBuilder<> IRB(&I);4155 Value *OperandShadow = getShadow(&I, 0);4156 Value *OperandSetOrPoison = IRB.CreateOr(I.getOperand(0), OperandShadow);4157 // Bit N is clean if any field's bit N is 0 and unpoison4158 Value *OutShadowMask = IRB.CreateAndReduce(OperandSetOrPoison);4159 // Otherwise, it is clean if every field's bit N is unpoison4160 Value *OrShadow = IRB.CreateOrReduce(OperandShadow);4161 Value *S = IRB.CreateAnd(OutShadowMask, OrShadow);4162 4163 setShadow(&I, S);4164 setOrigin(&I, getOrigin(&I, 0));4165 }4166 4167 void handleStmxcsr(IntrinsicInst &I) {4168 IRBuilder<> IRB(&I);4169 Value *Addr = I.getArgOperand(0);4170 Type *Ty = IRB.getInt32Ty();4171 Value *ShadowPtr =4172 getShadowOriginPtr(Addr, IRB, Ty, Align(1), /*isStore*/ true).first;4173 4174 IRB.CreateStore(getCleanShadow(Ty), ShadowPtr);4175 4176 if (ClCheckAccessAddress)4177 insertCheckShadowOf(Addr, &I);4178 }4179 4180 void handleLdmxcsr(IntrinsicInst &I) {4181 if (!InsertChecks)4182 return;4183 4184 IRBuilder<> IRB(&I);4185 Value *Addr = I.getArgOperand(0);4186 Type *Ty = IRB.getInt32Ty();4187 const Align Alignment = Align(1);4188 Value *ShadowPtr, *OriginPtr;4189 std::tie(ShadowPtr, OriginPtr) =4190 getShadowOriginPtr(Addr, IRB, Ty, Alignment, /*isStore*/ false);4191 4192 if (ClCheckAccessAddress)4193 insertCheckShadowOf(Addr, &I);4194 4195 Value *Shadow = IRB.CreateAlignedLoad(Ty, ShadowPtr, Alignment, "_ldmxcsr");4196 Value *Origin = MS.TrackOrigins ? IRB.CreateLoad(MS.OriginTy, OriginPtr)4197 : getCleanOrigin();4198 insertCheckShadow(Shadow, Origin, &I);4199 }4200 4201 void handleMaskedExpandLoad(IntrinsicInst &I) {4202 IRBuilder<> IRB(&I);4203 Value *Ptr = I.getArgOperand(0);4204 MaybeAlign Align = I.getParamAlign(0);4205 Value *Mask = I.getArgOperand(1);4206 Value *PassThru = I.getArgOperand(2);4207 4208 if (ClCheckAccessAddress) {4209 insertCheckShadowOf(Ptr, &I);4210 insertCheckShadowOf(Mask, &I);4211 }4212 4213 if (!PropagateShadow) {4214 setShadow(&I, getCleanShadow(&I));4215 setOrigin(&I, getCleanOrigin());4216 return;4217 }4218 4219 Type *ShadowTy = getShadowTy(&I);4220 Type *ElementShadowTy = cast<VectorType>(ShadowTy)->getElementType();4221 auto [ShadowPtr, OriginPtr] =4222 getShadowOriginPtr(Ptr, IRB, ElementShadowTy, Align, /*isStore*/ false);4223 4224 Value *Shadow =4225 IRB.CreateMaskedExpandLoad(ShadowTy, ShadowPtr, Align, Mask,4226 getShadow(PassThru), "_msmaskedexpload");4227 4228 setShadow(&I, Shadow);4229 4230 // TODO: Store origins.4231 setOrigin(&I, getCleanOrigin());4232 }4233 4234 void handleMaskedCompressStore(IntrinsicInst &I) {4235 IRBuilder<> IRB(&I);4236 Value *Values = I.getArgOperand(0);4237 Value *Ptr = I.getArgOperand(1);4238 MaybeAlign Align = I.getParamAlign(1);4239 Value *Mask = I.getArgOperand(2);4240 4241 if (ClCheckAccessAddress) {4242 insertCheckShadowOf(Ptr, &I);4243 insertCheckShadowOf(Mask, &I);4244 }4245 4246 Value *Shadow = getShadow(Values);4247 Type *ElementShadowTy =4248 getShadowTy(cast<VectorType>(Values->getType())->getElementType());4249 auto [ShadowPtr, OriginPtrs] =4250 getShadowOriginPtr(Ptr, IRB, ElementShadowTy, Align, /*isStore*/ true);4251 4252 IRB.CreateMaskedCompressStore(Shadow, ShadowPtr, Align, Mask);4253 4254 // TODO: Store origins.4255 }4256 4257 void handleMaskedGather(IntrinsicInst &I) {4258 IRBuilder<> IRB(&I);4259 Value *Ptrs = I.getArgOperand(0);4260 const Align Alignment = I.getParamAlign(0).valueOrOne();4261 Value *Mask = I.getArgOperand(1);4262 Value *PassThru = I.getArgOperand(2);4263 4264 Type *PtrsShadowTy = getShadowTy(Ptrs);4265 if (ClCheckAccessAddress) {4266 insertCheckShadowOf(Mask, &I);4267 Value *MaskedPtrShadow = IRB.CreateSelect(4268 Mask, getShadow(Ptrs), Constant::getNullValue((PtrsShadowTy)),4269 "_msmaskedptrs");4270 insertCheckShadow(MaskedPtrShadow, getOrigin(Ptrs), &I);4271 }4272 4273 if (!PropagateShadow) {4274 setShadow(&I, getCleanShadow(&I));4275 setOrigin(&I, getCleanOrigin());4276 return;4277 }4278 4279 Type *ShadowTy = getShadowTy(&I);4280 Type *ElementShadowTy = cast<VectorType>(ShadowTy)->getElementType();4281 auto [ShadowPtrs, OriginPtrs] = getShadowOriginPtr(4282 Ptrs, IRB, ElementShadowTy, Alignment, /*isStore*/ false);4283 4284 Value *Shadow =4285 IRB.CreateMaskedGather(ShadowTy, ShadowPtrs, Alignment, Mask,4286 getShadow(PassThru), "_msmaskedgather");4287 4288 setShadow(&I, Shadow);4289 4290 // TODO: Store origins.4291 setOrigin(&I, getCleanOrigin());4292 }4293 4294 void handleMaskedScatter(IntrinsicInst &I) {4295 IRBuilder<> IRB(&I);4296 Value *Values = I.getArgOperand(0);4297 Value *Ptrs = I.getArgOperand(1);4298 const Align Alignment = I.getParamAlign(1).valueOrOne();4299 Value *Mask = I.getArgOperand(2);4300 4301 Type *PtrsShadowTy = getShadowTy(Ptrs);4302 if (ClCheckAccessAddress) {4303 insertCheckShadowOf(Mask, &I);4304 Value *MaskedPtrShadow = IRB.CreateSelect(4305 Mask, getShadow(Ptrs), Constant::getNullValue((PtrsShadowTy)),4306 "_msmaskedptrs");4307 insertCheckShadow(MaskedPtrShadow, getOrigin(Ptrs), &I);4308 }4309 4310 Value *Shadow = getShadow(Values);4311 Type *ElementShadowTy =4312 getShadowTy(cast<VectorType>(Values->getType())->getElementType());4313 auto [ShadowPtrs, OriginPtrs] = getShadowOriginPtr(4314 Ptrs, IRB, ElementShadowTy, Alignment, /*isStore*/ true);4315 4316 IRB.CreateMaskedScatter(Shadow, ShadowPtrs, Alignment, Mask);4317 4318 // TODO: Store origin.4319 }4320 4321 // Intrinsic::masked_store4322 //4323 // Note: handleAVXMaskedStore handles AVX/AVX2 variants, though AVX512 masked4324 // stores are lowered to Intrinsic::masked_store.4325 void handleMaskedStore(IntrinsicInst &I) {4326 IRBuilder<> IRB(&I);4327 Value *V = I.getArgOperand(0);4328 Value *Ptr = I.getArgOperand(1);4329 const Align Alignment = I.getParamAlign(1).valueOrOne();4330 Value *Mask = I.getArgOperand(2);4331 Value *Shadow = getShadow(V);4332 4333 if (ClCheckAccessAddress) {4334 insertCheckShadowOf(Ptr, &I);4335 insertCheckShadowOf(Mask, &I);4336 }4337 4338 Value *ShadowPtr;4339 Value *OriginPtr;4340 std::tie(ShadowPtr, OriginPtr) = getShadowOriginPtr(4341 Ptr, IRB, Shadow->getType(), Alignment, /*isStore*/ true);4342 4343 IRB.CreateMaskedStore(Shadow, ShadowPtr, Alignment, Mask);4344 4345 if (!MS.TrackOrigins)4346 return;4347 4348 auto &DL = F.getDataLayout();4349 paintOrigin(IRB, getOrigin(V), OriginPtr,4350 DL.getTypeStoreSize(Shadow->getType()),4351 std::max(Alignment, kMinOriginAlignment));4352 }4353 4354 // Intrinsic::masked_load4355 //4356 // Note: handleAVXMaskedLoad handles AVX/AVX2 variants, though AVX512 masked4357 // loads are lowered to Intrinsic::masked_load.4358 void handleMaskedLoad(IntrinsicInst &I) {4359 IRBuilder<> IRB(&I);4360 Value *Ptr = I.getArgOperand(0);4361 const Align Alignment = I.getParamAlign(0).valueOrOne();4362 Value *Mask = I.getArgOperand(1);4363 Value *PassThru = I.getArgOperand(2);4364 4365 if (ClCheckAccessAddress) {4366 insertCheckShadowOf(Ptr, &I);4367 insertCheckShadowOf(Mask, &I);4368 }4369 4370 if (!PropagateShadow) {4371 setShadow(&I, getCleanShadow(&I));4372 setOrigin(&I, getCleanOrigin());4373 return;4374 }4375 4376 Type *ShadowTy = getShadowTy(&I);4377 Value *ShadowPtr, *OriginPtr;4378 std::tie(ShadowPtr, OriginPtr) =4379 getShadowOriginPtr(Ptr, IRB, ShadowTy, Alignment, /*isStore*/ false);4380 setShadow(&I, IRB.CreateMaskedLoad(ShadowTy, ShadowPtr, Alignment, Mask,4381 getShadow(PassThru), "_msmaskedld"));4382 4383 if (!MS.TrackOrigins)4384 return;4385 4386 // Choose between PassThru's and the loaded value's origins.4387 Value *MaskedPassThruShadow = IRB.CreateAnd(4388 getShadow(PassThru), IRB.CreateSExt(IRB.CreateNeg(Mask), ShadowTy));4389 4390 Value *NotNull = convertToBool(MaskedPassThruShadow, IRB, "_mscmp");4391 4392 Value *PtrOrigin = IRB.CreateLoad(MS.OriginTy, OriginPtr);4393 Value *Origin = IRB.CreateSelect(NotNull, getOrigin(PassThru), PtrOrigin);4394 4395 setOrigin(&I, Origin);4396 }4397 4398 // e.g., void @llvm.x86.avx.maskstore.ps.256(ptr, <8 x i32>, <8 x float>)4399 // dst mask src4400 //4401 // AVX512 masked stores are lowered to Intrinsic::masked_load and are handled4402 // by handleMaskedStore.4403 //4404 // This function handles AVX and AVX2 masked stores; these use the MSBs of a4405 // vector of integers, unlike the LLVM masked intrinsics, which require a4406 // vector of booleans. X86InstCombineIntrinsic.cpp::simplifyX86MaskedLoad4407 // mentions that the x86 backend does not know how to efficiently convert4408 // from a vector of booleans back into the AVX mask format; therefore, they4409 // (and we) do not reduce AVX/AVX2 masked intrinsics into LLVM masked4410 // intrinsics.4411 void handleAVXMaskedStore(IntrinsicInst &I) {4412 assert(I.arg_size() == 3);4413 4414 IRBuilder<> IRB(&I);4415 4416 Value *Dst = I.getArgOperand(0);4417 assert(Dst->getType()->isPointerTy() && "Destination is not a pointer!");4418 4419 Value *Mask = I.getArgOperand(1);4420 assert(isa<VectorType>(Mask->getType()) && "Mask is not a vector!");4421 4422 Value *Src = I.getArgOperand(2);4423 assert(isa<VectorType>(Src->getType()) && "Source is not a vector!");4424 4425 const Align Alignment = Align(1);4426 4427 Value *SrcShadow = getShadow(Src);4428 4429 if (ClCheckAccessAddress) {4430 insertCheckShadowOf(Dst, &I);4431 insertCheckShadowOf(Mask, &I);4432 }4433 4434 Value *DstShadowPtr;4435 Value *DstOriginPtr;4436 std::tie(DstShadowPtr, DstOriginPtr) = getShadowOriginPtr(4437 Dst, IRB, SrcShadow->getType(), Alignment, /*isStore*/ true);4438 4439 SmallVector<Value *, 2> ShadowArgs;4440 ShadowArgs.append(1, DstShadowPtr);4441 ShadowArgs.append(1, Mask);4442 // The intrinsic may require floating-point but shadows can be arbitrary4443 // bit patterns, of which some would be interpreted as "invalid"4444 // floating-point values (NaN etc.); we assume the intrinsic will happily4445 // copy them.4446 ShadowArgs.append(1, IRB.CreateBitCast(SrcShadow, Src->getType()));4447 4448 CallInst *CI =4449 IRB.CreateIntrinsic(IRB.getVoidTy(), I.getIntrinsicID(), ShadowArgs);4450 setShadow(&I, CI);4451 4452 if (!MS.TrackOrigins)4453 return;4454 4455 // Approximation only4456 auto &DL = F.getDataLayout();4457 paintOrigin(IRB, getOrigin(Src), DstOriginPtr,4458 DL.getTypeStoreSize(SrcShadow->getType()),4459 std::max(Alignment, kMinOriginAlignment));4460 }4461 4462 // e.g., <8 x float> @llvm.x86.avx.maskload.ps.256(ptr, <8 x i32>)4463 // return src mask4464 //4465 // Masked-off values are replaced with 0, which conveniently also represents4466 // initialized memory.4467 //4468 // AVX512 masked stores are lowered to Intrinsic::masked_load and are handled4469 // by handleMaskedStore.4470 //4471 // We do not combine this with handleMaskedLoad; see comment in4472 // handleAVXMaskedStore for the rationale.4473 //4474 // This is subtly different than handleIntrinsicByApplyingToShadow(I, 1)4475 // because we need to apply getShadowOriginPtr, not getShadow, to the first4476 // parameter.4477 void handleAVXMaskedLoad(IntrinsicInst &I) {4478 assert(I.arg_size() == 2);4479 4480 IRBuilder<> IRB(&I);4481 4482 Value *Src = I.getArgOperand(0);4483 assert(Src->getType()->isPointerTy() && "Source is not a pointer!");4484 4485 Value *Mask = I.getArgOperand(1);4486 assert(isa<VectorType>(Mask->getType()) && "Mask is not a vector!");4487 4488 const Align Alignment = Align(1);4489 4490 if (ClCheckAccessAddress) {4491 insertCheckShadowOf(Mask, &I);4492 }4493 4494 Type *SrcShadowTy = getShadowTy(Src);4495 Value *SrcShadowPtr, *SrcOriginPtr;4496 std::tie(SrcShadowPtr, SrcOriginPtr) =4497 getShadowOriginPtr(Src, IRB, SrcShadowTy, Alignment, /*isStore*/ false);4498 4499 SmallVector<Value *, 2> ShadowArgs;4500 ShadowArgs.append(1, SrcShadowPtr);4501 ShadowArgs.append(1, Mask);4502 4503 CallInst *CI =4504 IRB.CreateIntrinsic(I.getType(), I.getIntrinsicID(), ShadowArgs);4505 // The AVX masked load intrinsics do not have integer variants. We use the4506 // floating-point variants, which will happily copy the shadows even if4507 // they are interpreted as "invalid" floating-point values (NaN etc.).4508 setShadow(&I, IRB.CreateBitCast(CI, getShadowTy(&I)));4509 4510 if (!MS.TrackOrigins)4511 return;4512 4513 // The "pass-through" value is always zero (initialized). To the extent4514 // that that results in initialized aligned 4-byte chunks, the origin value4515 // is ignored. It is therefore correct to simply copy the origin from src.4516 Value *PtrSrcOrigin = IRB.CreateLoad(MS.OriginTy, SrcOriginPtr);4517 setOrigin(&I, PtrSrcOrigin);4518 }4519 4520 // Test whether the mask indices are initialized, only checking the bits that4521 // are actually used.4522 //4523 // e.g., if Idx is <32 x i16>, only (log2(32) == 5) bits of each index are4524 // used/checked.4525 void maskedCheckAVXIndexShadow(IRBuilder<> &IRB, Value *Idx, Instruction *I) {4526 assert(isFixedIntVector(Idx));4527 auto IdxVectorSize =4528 cast<FixedVectorType>(Idx->getType())->getNumElements();4529 assert(isPowerOf2_64(IdxVectorSize));4530 4531 // Compiler isn't smart enough, let's help it4532 if (isa<Constant>(Idx))4533 return;4534 4535 auto *IdxShadow = getShadow(Idx);4536 Value *Truncated = IRB.CreateTrunc(4537 IdxShadow,4538 FixedVectorType::get(Type::getIntNTy(*MS.C, Log2_64(IdxVectorSize)),4539 IdxVectorSize));4540 insertCheckShadow(Truncated, getOrigin(Idx), I);4541 }4542 4543 // Instrument AVX permutation intrinsic.4544 // We apply the same permutation (argument index 1) to the shadow.4545 void handleAVXVpermilvar(IntrinsicInst &I) {4546 IRBuilder<> IRB(&I);4547 Value *Shadow = getShadow(&I, 0);4548 maskedCheckAVXIndexShadow(IRB, I.getArgOperand(1), &I);4549 4550 // Shadows are integer-ish types but some intrinsics require a4551 // different (e.g., floating-point) type.4552 Shadow = IRB.CreateBitCast(Shadow, I.getArgOperand(0)->getType());4553 CallInst *CI = IRB.CreateIntrinsic(I.getType(), I.getIntrinsicID(),4554 {Shadow, I.getArgOperand(1)});4555 4556 setShadow(&I, IRB.CreateBitCast(CI, getShadowTy(&I)));4557 setOriginForNaryOp(I);4558 }4559 4560 // Instrument AVX permutation intrinsic.4561 // We apply the same permutation (argument index 1) to the shadows.4562 void handleAVXVpermi2var(IntrinsicInst &I) {4563 assert(I.arg_size() == 3);4564 assert(isa<FixedVectorType>(I.getArgOperand(0)->getType()));4565 assert(isa<FixedVectorType>(I.getArgOperand(1)->getType()));4566 assert(isa<FixedVectorType>(I.getArgOperand(2)->getType()));4567 [[maybe_unused]] auto ArgVectorSize =4568 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements();4569 assert(cast<FixedVectorType>(I.getArgOperand(1)->getType())4570 ->getNumElements() == ArgVectorSize);4571 assert(cast<FixedVectorType>(I.getArgOperand(2)->getType())4572 ->getNumElements() == ArgVectorSize);4573 assert(I.getArgOperand(0)->getType() == I.getArgOperand(2)->getType());4574 assert(I.getType() == I.getArgOperand(0)->getType());4575 assert(I.getArgOperand(1)->getType()->isIntOrIntVectorTy());4576 IRBuilder<> IRB(&I);4577 Value *AShadow = getShadow(&I, 0);4578 Value *Idx = I.getArgOperand(1);4579 Value *BShadow = getShadow(&I, 2);4580 4581 maskedCheckAVXIndexShadow(IRB, Idx, &I);4582 4583 // Shadows are integer-ish types but some intrinsics require a4584 // different (e.g., floating-point) type.4585 AShadow = IRB.CreateBitCast(AShadow, I.getArgOperand(0)->getType());4586 BShadow = IRB.CreateBitCast(BShadow, I.getArgOperand(2)->getType());4587 CallInst *CI = IRB.CreateIntrinsic(I.getType(), I.getIntrinsicID(),4588 {AShadow, Idx, BShadow});4589 setShadow(&I, IRB.CreateBitCast(CI, getShadowTy(&I)));4590 setOriginForNaryOp(I);4591 }4592 4593 [[maybe_unused]] static bool isFixedIntVectorTy(const Type *T) {4594 return isa<FixedVectorType>(T) && T->isIntOrIntVectorTy();4595 }4596 4597 [[maybe_unused]] static bool isFixedFPVectorTy(const Type *T) {4598 return isa<FixedVectorType>(T) && T->isFPOrFPVectorTy();4599 }4600 4601 [[maybe_unused]] static bool isFixedIntVector(const Value *V) {4602 return isFixedIntVectorTy(V->getType());4603 }4604 4605 [[maybe_unused]] static bool isFixedFPVector(const Value *V) {4606 return isFixedFPVectorTy(V->getType());4607 }4608 4609 // e.g., <16 x i32> @llvm.x86.avx512.mask.cvtps2dq.5124610 // (<16 x float> a, <16 x i32> writethru, i16 mask,4611 // i32 rounding)4612 //4613 // Inconveniently, some similar intrinsics have a different operand order:4614 // <16 x i16> @llvm.x86.avx512.mask.vcvtps2ph.5124615 // (<16 x float> a, i32 rounding, <16 x i16> writethru,4616 // i16 mask)4617 //4618 // If the return type has more elements than A, the excess elements are4619 // zeroed (and the corresponding shadow is initialized).4620 // <8 x i16> @llvm.x86.avx512.mask.vcvtps2ph.1284621 // (<4 x float> a, i32 rounding, <8 x i16> writethru,4622 // i8 mask)4623 //4624 // dst[i] = mask[i] ? convert(a[i]) : writethru[i]4625 // dst_shadow[i] = mask[i] ? all_or_nothing(a_shadow[i]) : writethru_shadow[i]4626 // where all_or_nothing(x) is fully uninitialized if x has any4627 // uninitialized bits4628 void handleAVX512VectorConvertFPToInt(IntrinsicInst &I, bool LastMask) {4629 IRBuilder<> IRB(&I);4630 4631 assert(I.arg_size() == 4);4632 Value *A = I.getOperand(0);4633 Value *WriteThrough;4634 Value *Mask;4635 Value *RoundingMode;4636 if (LastMask) {4637 WriteThrough = I.getOperand(2);4638 Mask = I.getOperand(3);4639 RoundingMode = I.getOperand(1);4640 } else {4641 WriteThrough = I.getOperand(1);4642 Mask = I.getOperand(2);4643 RoundingMode = I.getOperand(3);4644 }4645 4646 assert(isFixedFPVector(A));4647 assert(isFixedIntVector(WriteThrough));4648 4649 unsigned ANumElements =4650 cast<FixedVectorType>(A->getType())->getNumElements();4651 [[maybe_unused]] unsigned WriteThruNumElements =4652 cast<FixedVectorType>(WriteThrough->getType())->getNumElements();4653 assert(ANumElements == WriteThruNumElements ||4654 ANumElements * 2 == WriteThruNumElements);4655 4656 assert(Mask->getType()->isIntegerTy());4657 unsigned MaskNumElements = Mask->getType()->getScalarSizeInBits();4658 assert(ANumElements == MaskNumElements ||4659 ANumElements * 2 == MaskNumElements);4660 4661 assert(WriteThruNumElements == MaskNumElements);4662 4663 // Some bits of the mask may be unused, though it's unusual to have partly4664 // uninitialized bits.4665 insertCheckShadowOf(Mask, &I);4666 4667 assert(RoundingMode->getType()->isIntegerTy());4668 // Only some bits of the rounding mode are used, though it's very4669 // unusual to have uninitialized bits there (more commonly, it's a4670 // constant).4671 insertCheckShadowOf(RoundingMode, &I);4672 4673 assert(I.getType() == WriteThrough->getType());4674 4675 Value *AShadow = getShadow(A);4676 AShadow = maybeExtendVectorShadowWithZeros(AShadow, I);4677 4678 if (ANumElements * 2 == MaskNumElements) {4679 // Ensure that the irrelevant bits of the mask are zero, hence selecting4680 // from the zeroed shadow instead of the writethrough's shadow.4681 Mask =4682 IRB.CreateTrunc(Mask, IRB.getIntNTy(ANumElements), "_ms_mask_trunc");4683 Mask =4684 IRB.CreateZExt(Mask, IRB.getIntNTy(MaskNumElements), "_ms_mask_zext");4685 }4686 4687 // Convert i16 mask to <16 x i1>4688 Mask = IRB.CreateBitCast(4689 Mask, FixedVectorType::get(IRB.getInt1Ty(), MaskNumElements),4690 "_ms_mask_bitcast");4691 4692 /// For floating-point to integer conversion, the output is:4693 /// - fully uninitialized if *any* bit of the input is uninitialized4694 /// - fully ininitialized if all bits of the input are ininitialized4695 /// We apply the same principle on a per-element basis for vectors.4696 ///4697 /// We use the scalar width of the return type instead of A's.4698 AShadow = IRB.CreateSExt(4699 IRB.CreateICmpNE(AShadow, getCleanShadow(AShadow->getType())),4700 getShadowTy(&I), "_ms_a_shadow");4701 4702 Value *WriteThroughShadow = getShadow(WriteThrough);4703 Value *Shadow = IRB.CreateSelect(Mask, AShadow, WriteThroughShadow,4704 "_ms_writethru_select");4705 4706 setShadow(&I, Shadow);4707 setOriginForNaryOp(I);4708 }4709 4710 // Instrument BMI / BMI2 intrinsics.4711 // All of these intrinsics are Z = I(X, Y)4712 // where the types of all operands and the result match, and are either i32 or4713 // i64. The following instrumentation happens to work for all of them:4714 // Sz = I(Sx, Y) | (sext (Sy != 0))4715 void handleBmiIntrinsic(IntrinsicInst &I) {4716 IRBuilder<> IRB(&I);4717 Type *ShadowTy = getShadowTy(&I);4718 4719 // If any bit of the mask operand is poisoned, then the whole thing is.4720 Value *SMask = getShadow(&I, 1);4721 SMask = IRB.CreateSExt(IRB.CreateICmpNE(SMask, getCleanShadow(ShadowTy)),4722 ShadowTy);4723 // Apply the same intrinsic to the shadow of the first operand.4724 Value *S = IRB.CreateCall(I.getCalledFunction(),4725 {getShadow(&I, 0), I.getOperand(1)});4726 S = IRB.CreateOr(SMask, S);4727 setShadow(&I, S);4728 setOriginForNaryOp(I);4729 }4730 4731 static SmallVector<int, 8> getPclmulMask(unsigned Width, bool OddElements) {4732 SmallVector<int, 8> Mask;4733 for (unsigned X = OddElements ? 1 : 0; X < Width; X += 2) {4734 Mask.append(2, X);4735 }4736 return Mask;4737 }4738 4739 // Instrument pclmul intrinsics.4740 // These intrinsics operate either on odd or on even elements of the input4741 // vectors, depending on the constant in the 3rd argument, ignoring the rest.4742 // Replace the unused elements with copies of the used ones, ex:4743 // (0, 1, 2, 3) -> (0, 0, 2, 2) (even case)4744 // or4745 // (0, 1, 2, 3) -> (1, 1, 3, 3) (odd case)4746 // and then apply the usual shadow combining logic.4747 void handlePclmulIntrinsic(IntrinsicInst &I) {4748 IRBuilder<> IRB(&I);4749 unsigned Width =4750 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements();4751 assert(isa<ConstantInt>(I.getArgOperand(2)) &&4752 "pclmul 3rd operand must be a constant");4753 unsigned Imm = cast<ConstantInt>(I.getArgOperand(2))->getZExtValue();4754 Value *Shuf0 = IRB.CreateShuffleVector(getShadow(&I, 0),4755 getPclmulMask(Width, Imm & 0x01));4756 Value *Shuf1 = IRB.CreateShuffleVector(getShadow(&I, 1),4757 getPclmulMask(Width, Imm & 0x10));4758 ShadowAndOriginCombiner SOC(this, IRB);4759 SOC.Add(Shuf0, getOrigin(&I, 0));4760 SOC.Add(Shuf1, getOrigin(&I, 1));4761 SOC.Done(&I);4762 }4763 4764 // Instrument _mm_*_sd|ss intrinsics4765 void handleUnarySdSsIntrinsic(IntrinsicInst &I) {4766 IRBuilder<> IRB(&I);4767 unsigned Width =4768 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements();4769 Value *First = getShadow(&I, 0);4770 Value *Second = getShadow(&I, 1);4771 // First element of second operand, remaining elements of first operand4772 SmallVector<int, 16> Mask;4773 Mask.push_back(Width);4774 for (unsigned i = 1; i < Width; i++)4775 Mask.push_back(i);4776 Value *Shadow = IRB.CreateShuffleVector(First, Second, Mask);4777 4778 setShadow(&I, Shadow);4779 setOriginForNaryOp(I);4780 }4781 4782 void handleVtestIntrinsic(IntrinsicInst &I) {4783 IRBuilder<> IRB(&I);4784 Value *Shadow0 = getShadow(&I, 0);4785 Value *Shadow1 = getShadow(&I, 1);4786 Value *Or = IRB.CreateOr(Shadow0, Shadow1);4787 Value *NZ = IRB.CreateICmpNE(Or, Constant::getNullValue(Or->getType()));4788 Value *Scalar = convertShadowToScalar(NZ, IRB);4789 Value *Shadow = IRB.CreateZExt(Scalar, getShadowTy(&I));4790 4791 setShadow(&I, Shadow);4792 setOriginForNaryOp(I);4793 }4794 4795 void handleBinarySdSsIntrinsic(IntrinsicInst &I) {4796 IRBuilder<> IRB(&I);4797 unsigned Width =4798 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements();4799 Value *First = getShadow(&I, 0);4800 Value *Second = getShadow(&I, 1);4801 Value *OrShadow = IRB.CreateOr(First, Second);4802 // First element of both OR'd together, remaining elements of first operand4803 SmallVector<int, 16> Mask;4804 Mask.push_back(Width);4805 for (unsigned i = 1; i < Width; i++)4806 Mask.push_back(i);4807 Value *Shadow = IRB.CreateShuffleVector(First, OrShadow, Mask);4808 4809 setShadow(&I, Shadow);4810 setOriginForNaryOp(I);4811 }4812 4813 // _mm_round_ps / _mm_round_ps.4814 // Similar to maybeHandleSimpleNomemIntrinsic except4815 // the second argument is guaranteed to be a constant integer.4816 void handleRoundPdPsIntrinsic(IntrinsicInst &I) {4817 assert(I.getArgOperand(0)->getType() == I.getType());4818 assert(I.arg_size() == 2);4819 assert(isa<ConstantInt>(I.getArgOperand(1)));4820 4821 IRBuilder<> IRB(&I);4822 ShadowAndOriginCombiner SC(this, IRB);4823 SC.Add(I.getArgOperand(0));4824 SC.Done(&I);4825 }4826 4827 // Instrument @llvm.abs intrinsic.4828 //4829 // e.g., i32 @llvm.abs.i32 (i32 <Src>, i1 <is_int_min_poison>)4830 // <4 x i32> @llvm.abs.v4i32(<4 x i32> <Src>, i1 <is_int_min_poison>)4831 void handleAbsIntrinsic(IntrinsicInst &I) {4832 assert(I.arg_size() == 2);4833 Value *Src = I.getArgOperand(0);4834 Value *IsIntMinPoison = I.getArgOperand(1);4835 4836 assert(I.getType()->isIntOrIntVectorTy());4837 4838 assert(Src->getType() == I.getType());4839 4840 assert(IsIntMinPoison->getType()->isIntegerTy());4841 assert(IsIntMinPoison->getType()->getIntegerBitWidth() == 1);4842 4843 IRBuilder<> IRB(&I);4844 Value *SrcShadow = getShadow(Src);4845 4846 APInt MinVal =4847 APInt::getSignedMinValue(Src->getType()->getScalarSizeInBits());4848 Value *MinValVec = ConstantInt::get(Src->getType(), MinVal);4849 Value *SrcIsMin = IRB.CreateICmp(CmpInst::ICMP_EQ, Src, MinValVec);4850 4851 Value *PoisonedShadow = getPoisonedShadow(Src);4852 Value *PoisonedIfIntMinShadow =4853 IRB.CreateSelect(SrcIsMin, PoisonedShadow, SrcShadow);4854 Value *Shadow =4855 IRB.CreateSelect(IsIntMinPoison, PoisonedIfIntMinShadow, SrcShadow);4856 4857 setShadow(&I, Shadow);4858 setOrigin(&I, getOrigin(&I, 0));4859 }4860 4861 void handleIsFpClass(IntrinsicInst &I) {4862 IRBuilder<> IRB(&I);4863 Value *Shadow = getShadow(&I, 0);4864 setShadow(&I, IRB.CreateICmpNE(Shadow, getCleanShadow(Shadow)));4865 setOrigin(&I, getOrigin(&I, 0));4866 }4867 4868 void handleArithmeticWithOverflow(IntrinsicInst &I) {4869 IRBuilder<> IRB(&I);4870 Value *Shadow0 = getShadow(&I, 0);4871 Value *Shadow1 = getShadow(&I, 1);4872 Value *ShadowElt0 = IRB.CreateOr(Shadow0, Shadow1);4873 Value *ShadowElt1 =4874 IRB.CreateICmpNE(ShadowElt0, getCleanShadow(ShadowElt0));4875 4876 Value *Shadow = PoisonValue::get(getShadowTy(&I));4877 Shadow = IRB.CreateInsertValue(Shadow, ShadowElt0, 0);4878 Shadow = IRB.CreateInsertValue(Shadow, ShadowElt1, 1);4879 4880 setShadow(&I, Shadow);4881 setOriginForNaryOp(I);4882 }4883 4884 Value *extractLowerShadow(IRBuilder<> &IRB, Value *V) {4885 assert(isa<FixedVectorType>(V->getType()));4886 assert(cast<FixedVectorType>(V->getType())->getNumElements() > 0);4887 Value *Shadow = getShadow(V);4888 return IRB.CreateExtractElement(Shadow,4889 ConstantInt::get(IRB.getInt32Ty(), 0));4890 }4891 4892 // Handle llvm.x86.avx512.mask.pmov{,s,us}.*.5124893 //4894 // e.g., call <16 x i8> @llvm.x86.avx512.mask.pmov.qb.5124895 // (<8 x i64>, <16 x i8>, i8)4896 // A WriteThru Mask4897 //4898 // call <16 x i8> @llvm.x86.avx512.mask.pmovs.db.5124899 // (<16 x i32>, <16 x i8>, i16)4900 //4901 // Dst[i] = Mask[i] ? truncate_or_saturate(A[i]) : WriteThru[i]4902 // Dst_shadow[i] = Mask[i] ? truncate(A_shadow[i]) : WriteThru_shadow[i]4903 //4904 // If Dst has more elements than A, the excess elements are zeroed (and the4905 // corresponding shadow is initialized).4906 //4907 // Note: for PMOV (truncation), handleIntrinsicByApplyingToShadow is precise4908 // and is much faster than this handler.4909 void handleAVX512VectorDownConvert(IntrinsicInst &I) {4910 IRBuilder<> IRB(&I);4911 4912 assert(I.arg_size() == 3);4913 Value *A = I.getOperand(0);4914 Value *WriteThrough = I.getOperand(1);4915 Value *Mask = I.getOperand(2);4916 4917 assert(isFixedIntVector(A));4918 assert(isFixedIntVector(WriteThrough));4919 4920 unsigned ANumElements =4921 cast<FixedVectorType>(A->getType())->getNumElements();4922 unsigned OutputNumElements =4923 cast<FixedVectorType>(WriteThrough->getType())->getNumElements();4924 assert(ANumElements == OutputNumElements ||4925 ANumElements * 2 == OutputNumElements);4926 4927 assert(Mask->getType()->isIntegerTy());4928 assert(Mask->getType()->getScalarSizeInBits() == ANumElements);4929 insertCheckShadowOf(Mask, &I);4930 4931 assert(I.getType() == WriteThrough->getType());4932 4933 // Widen the mask, if necessary, to have one bit per element of the output4934 // vector.4935 // We want the extra bits to have '1's, so that the CreateSelect will4936 // select the values from AShadow instead of WriteThroughShadow ("maskless"4937 // versions of the intrinsics are sometimes implemented using an all-1's4938 // mask and an undefined value for WriteThroughShadow). We accomplish this4939 // by using bitwise NOT before and after the ZExt.4940 if (ANumElements != OutputNumElements) {4941 Mask = IRB.CreateNot(Mask);4942 Mask = IRB.CreateZExt(Mask, Type::getIntNTy(*MS.C, OutputNumElements),4943 "_ms_widen_mask");4944 Mask = IRB.CreateNot(Mask);4945 }4946 Mask = IRB.CreateBitCast(4947 Mask, FixedVectorType::get(IRB.getInt1Ty(), OutputNumElements));4948 4949 Value *AShadow = getShadow(A);4950 4951 // The return type might have more elements than the input.4952 // Temporarily shrink the return type's number of elements.4953 VectorType *ShadowType = maybeShrinkVectorShadowType(A, I);4954 4955 // PMOV truncates; PMOVS/PMOVUS uses signed/unsigned saturation.4956 // This handler treats them all as truncation, which leads to some rare4957 // false positives in the cases where the truncated bytes could4958 // unambiguously saturate the value e.g., if A = ??????10 ????????4959 // (big-endian), the unsigned saturated byte conversion is 11111111 i.e.,4960 // fully defined, but the truncated byte is ????????.4961 //4962 // TODO: use GetMinMaxUnsigned() to handle saturation precisely.4963 AShadow = IRB.CreateTrunc(AShadow, ShadowType, "_ms_trunc_shadow");4964 AShadow = maybeExtendVectorShadowWithZeros(AShadow, I);4965 4966 Value *WriteThroughShadow = getShadow(WriteThrough);4967 4968 Value *Shadow = IRB.CreateSelect(Mask, AShadow, WriteThroughShadow);4969 setShadow(&I, Shadow);4970 setOriginForNaryOp(I);4971 }4972 4973 // Handle llvm.x86.avx512.* instructions that take a vector of floating-point4974 // values and perform an operation whose shadow propagation should be handled4975 // as all-or-nothing [*], with masking provided by a vector and a mask4976 // supplied as an integer.4977 //4978 // [*] if all bits of a vector element are initialized, the output is fully4979 // initialized; otherwise, the output is fully uninitialized4980 //4981 // e.g., <16 x float> @llvm.x86.avx512.rsqrt14.ps.5124982 // (<16 x float>, <16 x float>, i16)4983 // A WriteThru Mask4984 //4985 // <2 x double> @llvm.x86.avx512.rcp14.pd.1284986 // (<2 x double>, <2 x double>, i8)4987 //4988 // <8 x double> @llvm.x86.avx512.mask.rndscale.pd.5124989 // (<8 x double>, i32, <8 x double>, i8, i32)4990 // A Imm WriteThru Mask Rounding4991 //4992 // All operands other than A and WriteThru (e.g., Mask, Imm, Rounding) must4993 // be fully initialized.4994 //4995 // Dst[i] = Mask[i] ? some_op(A[i]) : WriteThru[i]4996 // Dst_shadow[i] = Mask[i] ? all_or_nothing(A_shadow[i]) : WriteThru_shadow[i]4997 void handleAVX512VectorGenericMaskedFP(IntrinsicInst &I, unsigned AIndex,4998 unsigned WriteThruIndex,4999 unsigned MaskIndex) {5000 IRBuilder<> IRB(&I);5001 5002 unsigned NumArgs = I.arg_size();5003 assert(AIndex < NumArgs);5004 assert(WriteThruIndex < NumArgs);5005 assert(MaskIndex < NumArgs);5006 assert(AIndex != WriteThruIndex);5007 assert(AIndex != MaskIndex);5008 assert(WriteThruIndex != MaskIndex);5009 5010 Value *A = I.getOperand(AIndex);5011 Value *WriteThru = I.getOperand(WriteThruIndex);5012 Value *Mask = I.getOperand(MaskIndex);5013 5014 assert(isFixedFPVector(A));5015 assert(isFixedFPVector(WriteThru));5016 5017 [[maybe_unused]] unsigned ANumElements =5018 cast<FixedVectorType>(A->getType())->getNumElements();5019 unsigned OutputNumElements =5020 cast<FixedVectorType>(WriteThru->getType())->getNumElements();5021 assert(ANumElements == OutputNumElements);5022 5023 for (unsigned i = 0; i < NumArgs; ++i) {5024 if (i != AIndex && i != WriteThruIndex) {5025 // Imm, Mask, Rounding etc. are "control" data, hence we require that5026 // they be fully initialized.5027 assert(I.getOperand(i)->getType()->isIntegerTy());5028 insertCheckShadowOf(I.getOperand(i), &I);5029 }5030 }5031 5032 // The mask has 1 bit per element of A, but a minimum of 8 bits.5033 if (Mask->getType()->getScalarSizeInBits() == 8 && ANumElements < 8)5034 Mask = IRB.CreateTrunc(Mask, Type::getIntNTy(*MS.C, ANumElements));5035 assert(Mask->getType()->getScalarSizeInBits() == ANumElements);5036 5037 assert(I.getType() == WriteThru->getType());5038 5039 Mask = IRB.CreateBitCast(5040 Mask, FixedVectorType::get(IRB.getInt1Ty(), OutputNumElements));5041 5042 Value *AShadow = getShadow(A);5043 5044 // All-or-nothing shadow5045 AShadow = IRB.CreateSExt(IRB.CreateICmpNE(AShadow, getCleanShadow(AShadow)),5046 AShadow->getType());5047 5048 Value *WriteThruShadow = getShadow(WriteThru);5049 5050 Value *Shadow = IRB.CreateSelect(Mask, AShadow, WriteThruShadow);5051 setShadow(&I, Shadow);5052 5053 setOriginForNaryOp(I);5054 }5055 5056 // For sh.* compiler intrinsics:5057 // llvm.x86.avx512fp16.mask.{add/sub/mul/div/max/min}.sh.round5058 // (<8 x half>, <8 x half>, <8 x half>, i8, i32)5059 // A B WriteThru Mask RoundingMode5060 //5061 // DstShadow[0] = Mask[0] ? (AShadow[0] | BShadow[0]) : WriteThruShadow[0]5062 // DstShadow[1..7] = AShadow[1..7]5063 void visitGenericScalarHalfwordInst(IntrinsicInst &I) {5064 IRBuilder<> IRB(&I);5065 5066 assert(I.arg_size() == 5);5067 Value *A = I.getOperand(0);5068 Value *B = I.getOperand(1);5069 Value *WriteThrough = I.getOperand(2);5070 Value *Mask = I.getOperand(3);5071 Value *RoundingMode = I.getOperand(4);5072 5073 // Technically, we could probably just check whether the LSB is5074 // initialized, but intuitively it feels like a partly uninitialized mask5075 // is unintended, and we should warn the user immediately.5076 insertCheckShadowOf(Mask, &I);5077 insertCheckShadowOf(RoundingMode, &I);5078 5079 assert(isa<FixedVectorType>(A->getType()));5080 unsigned NumElements =5081 cast<FixedVectorType>(A->getType())->getNumElements();5082 assert(NumElements == 8);5083 assert(A->getType() == B->getType());5084 assert(B->getType() == WriteThrough->getType());5085 assert(Mask->getType()->getPrimitiveSizeInBits() == NumElements);5086 assert(RoundingMode->getType()->isIntegerTy());5087 5088 Value *ALowerShadow = extractLowerShadow(IRB, A);5089 Value *BLowerShadow = extractLowerShadow(IRB, B);5090 5091 Value *ABLowerShadow = IRB.CreateOr(ALowerShadow, BLowerShadow);5092 5093 Value *WriteThroughLowerShadow = extractLowerShadow(IRB, WriteThrough);5094 5095 Mask = IRB.CreateBitCast(5096 Mask, FixedVectorType::get(IRB.getInt1Ty(), NumElements));5097 Value *MaskLower =5098 IRB.CreateExtractElement(Mask, ConstantInt::get(IRB.getInt32Ty(), 0));5099 5100 Value *AShadow = getShadow(A);5101 Value *DstLowerShadow =5102 IRB.CreateSelect(MaskLower, ABLowerShadow, WriteThroughLowerShadow);5103 Value *DstShadow = IRB.CreateInsertElement(5104 AShadow, DstLowerShadow, ConstantInt::get(IRB.getInt32Ty(), 0),5105 "_msprop");5106 5107 setShadow(&I, DstShadow);5108 setOriginForNaryOp(I);5109 }5110 5111 // Approximately handle AVX Galois Field Affine Transformation5112 //5113 // e.g.,5114 // <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8>, <16 x i8>, i8)5115 // <32 x i8> @llvm.x86.vgf2p8affineqb.256(<32 x i8>, <32 x i8>, i8)5116 // <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8>, <64 x i8>, i8)5117 // Out A x b5118 // where A and x are packed matrices, b is a vector,5119 // Out = A * x + b in GF(2)5120 //5121 // Multiplication in GF(2) is equivalent to bitwise AND. However, the matrix5122 // computation also includes a parity calculation.5123 //5124 // For the bitwise AND of bits V1 and V2, the exact shadow is:5125 // Out_Shadow = (V1_Shadow & V2_Shadow)5126 // | (V1 & V2_Shadow)5127 // | (V1_Shadow & V2 )5128 //5129 // We approximate the shadow of gf2p8affineqb using:5130 // Out_Shadow = gf2p8affineqb(x_Shadow, A_shadow, 0)5131 // | gf2p8affineqb(x, A_shadow, 0)5132 // | gf2p8affineqb(x_Shadow, A, 0)5133 // | set1_epi8(b_Shadow)5134 //5135 // This approximation has false negatives: if an intermediate dot-product5136 // contains an even number of 1's, the parity is 0.5137 // It has no false positives.5138 void handleAVXGF2P8Affine(IntrinsicInst &I) {5139 IRBuilder<> IRB(&I);5140 5141 assert(I.arg_size() == 3);5142 Value *A = I.getOperand(0);5143 Value *X = I.getOperand(1);5144 Value *B = I.getOperand(2);5145 5146 assert(isFixedIntVector(A));5147 assert(cast<VectorType>(A->getType())5148 ->getElementType()5149 ->getScalarSizeInBits() == 8);5150 5151 assert(A->getType() == X->getType());5152 5153 assert(B->getType()->isIntegerTy());5154 assert(B->getType()->getScalarSizeInBits() == 8);5155 5156 assert(I.getType() == A->getType());5157 5158 Value *AShadow = getShadow(A);5159 Value *XShadow = getShadow(X);5160 Value *BZeroShadow = getCleanShadow(B);5161 5162 CallInst *AShadowXShadow = IRB.CreateIntrinsic(5163 I.getType(), I.getIntrinsicID(), {XShadow, AShadow, BZeroShadow});5164 CallInst *AShadowX = IRB.CreateIntrinsic(I.getType(), I.getIntrinsicID(),5165 {X, AShadow, BZeroShadow});5166 CallInst *XShadowA = IRB.CreateIntrinsic(I.getType(), I.getIntrinsicID(),5167 {XShadow, A, BZeroShadow});5168 5169 unsigned NumElements = cast<FixedVectorType>(I.getType())->getNumElements();5170 Value *BShadow = getShadow(B);5171 Value *BBroadcastShadow = getCleanShadow(AShadow);5172 // There is no LLVM IR intrinsic for _mm512_set1_epi8.5173 // This loop generates a lot of LLVM IR, which we expect that CodeGen will5174 // lower appropriately (e.g., VPBROADCASTB).5175 // Besides, b is often a constant, in which case it is fully initialized.5176 for (unsigned i = 0; i < NumElements; i++)5177 BBroadcastShadow = IRB.CreateInsertElement(BBroadcastShadow, BShadow, i);5178 5179 setShadow(&I, IRB.CreateOr(5180 {AShadowXShadow, AShadowX, XShadowA, BBroadcastShadow}));5181 setOriginForNaryOp(I);5182 }5183 5184 // Handle Arm NEON vector load intrinsics (vld*).5185 //5186 // The WithLane instructions (ld[234]lane) are similar to:5187 // call {<4 x i32>, <4 x i32>, <4 x i32>}5188 // @llvm.aarch64.neon.ld3lane.v4i32.p05189 // (<4 x i32> %L1, <4 x i32> %L2, <4 x i32> %L3, i64 %lane, ptr5190 // %A)5191 //5192 // The non-WithLane instructions (ld[234], ld1x[234], ld[234]r) are similar5193 // to:5194 // call {<8 x i8>, <8 x i8>} @llvm.aarch64.neon.ld2.v8i8.p0(ptr %A)5195 void handleNEONVectorLoad(IntrinsicInst &I, bool WithLane) {5196 unsigned int numArgs = I.arg_size();5197 5198 // Return type is a struct of vectors of integers or floating-point5199 assert(I.getType()->isStructTy());5200 [[maybe_unused]] StructType *RetTy = cast<StructType>(I.getType());5201 assert(RetTy->getNumElements() > 0);5202 assert(RetTy->getElementType(0)->isIntOrIntVectorTy() ||5203 RetTy->getElementType(0)->isFPOrFPVectorTy());5204 for (unsigned int i = 0; i < RetTy->getNumElements(); i++)5205 assert(RetTy->getElementType(i) == RetTy->getElementType(0));5206 5207 if (WithLane) {5208 // 2, 3 or 4 vectors, plus lane number, plus input pointer5209 assert(4 <= numArgs && numArgs <= 6);5210 5211 // Return type is a struct of the input vectors5212 assert(RetTy->getNumElements() + 2 == numArgs);5213 for (unsigned int i = 0; i < RetTy->getNumElements(); i++)5214 assert(I.getArgOperand(i)->getType() == RetTy->getElementType(0));5215 } else {5216 assert(numArgs == 1);5217 }5218 5219 IRBuilder<> IRB(&I);5220 5221 SmallVector<Value *, 6> ShadowArgs;5222 if (WithLane) {5223 for (unsigned int i = 0; i < numArgs - 2; i++)5224 ShadowArgs.push_back(getShadow(I.getArgOperand(i)));5225 5226 // Lane number, passed verbatim5227 Value *LaneNumber = I.getArgOperand(numArgs - 2);5228 ShadowArgs.push_back(LaneNumber);5229 5230 // TODO: blend shadow of lane number into output shadow?5231 insertCheckShadowOf(LaneNumber, &I);5232 }5233 5234 Value *Src = I.getArgOperand(numArgs - 1);5235 assert(Src->getType()->isPointerTy() && "Source is not a pointer!");5236 5237 Type *SrcShadowTy = getShadowTy(Src);5238 auto [SrcShadowPtr, SrcOriginPtr] =5239 getShadowOriginPtr(Src, IRB, SrcShadowTy, Align(1), /*isStore*/ false);5240 ShadowArgs.push_back(SrcShadowPtr);5241 5242 // The NEON vector load instructions handled by this function all have5243 // integer variants. It is easier to use those rather than trying to cast5244 // a struct of vectors of floats into a struct of vectors of integers.5245 CallInst *CI =5246 IRB.CreateIntrinsic(getShadowTy(&I), I.getIntrinsicID(), ShadowArgs);5247 setShadow(&I, CI);5248 5249 if (!MS.TrackOrigins)5250 return;5251 5252 Value *PtrSrcOrigin = IRB.CreateLoad(MS.OriginTy, SrcOriginPtr);5253 setOrigin(&I, PtrSrcOrigin);5254 }5255 5256 /// Handle Arm NEON vector store intrinsics (vst{2,3,4}, vst1x_{2,3,4},5257 /// and vst{2,3,4}lane).5258 ///5259 /// Arm NEON vector store intrinsics have the output address (pointer) as the5260 /// last argument, with the initial arguments being the inputs (and lane5261 /// number for vst{2,3,4}lane). They return void.5262 ///5263 /// - st4 interleaves the output e.g., st4 (inA, inB, inC, inD, outP) writes5264 /// abcdabcdabcdabcd... into *outP5265 /// - st1_x4 is non-interleaved e.g., st1_x4 (inA, inB, inC, inD, outP)5266 /// writes aaaa...bbbb...cccc...dddd... into *outP5267 /// - st4lane has arguments of (inA, inB, inC, inD, lane, outP)5268 /// These instructions can all be instrumented with essentially the same5269 /// MSan logic, simply by applying the corresponding intrinsic to the shadow.5270 void handleNEONVectorStoreIntrinsic(IntrinsicInst &I, bool useLane) {5271 IRBuilder<> IRB(&I);5272 5273 // Don't use getNumOperands() because it includes the callee5274 int numArgOperands = I.arg_size();5275 5276 // The last arg operand is the output (pointer)5277 assert(numArgOperands >= 1);5278 Value *Addr = I.getArgOperand(numArgOperands - 1);5279 assert(Addr->getType()->isPointerTy());5280 int skipTrailingOperands = 1;5281 5282 if (ClCheckAccessAddress)5283 insertCheckShadowOf(Addr, &I);5284 5285 // Second-last operand is the lane number (for vst{2,3,4}lane)5286 if (useLane) {5287 skipTrailingOperands++;5288 assert(numArgOperands >= static_cast<int>(skipTrailingOperands));5289 assert(isa<IntegerType>(5290 I.getArgOperand(numArgOperands - skipTrailingOperands)->getType()));5291 }5292 5293 SmallVector<Value *, 8> ShadowArgs;5294 // All the initial operands are the inputs5295 for (int i = 0; i < numArgOperands - skipTrailingOperands; i++) {5296 assert(isa<FixedVectorType>(I.getArgOperand(i)->getType()));5297 Value *Shadow = getShadow(&I, i);5298 ShadowArgs.append(1, Shadow);5299 }5300 5301 // MSan's GetShadowTy assumes the LHS is the type we want the shadow for5302 // e.g., for:5303 // [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to i1285304 // we know the type of the output (and its shadow) is <16 x i8>.5305 //5306 // Arm NEON VST is unusual because the last argument is the output address:5307 // define void @st2_16b(<16 x i8> %A, <16 x i8> %B, ptr %P) {5308 // call void @llvm.aarch64.neon.st2.v16i8.p05309 // (<16 x i8> [[A]], <16 x i8> [[B]], ptr [[P]])5310 // and we have no type information about P's operand. We must manually5311 // compute the type (<16 x i8> x 2).5312 FixedVectorType *OutputVectorTy = FixedVectorType::get(5313 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getElementType(),5314 cast<FixedVectorType>(I.getArgOperand(0)->getType())->getNumElements() *5315 (numArgOperands - skipTrailingOperands));5316 Type *OutputShadowTy = getShadowTy(OutputVectorTy);5317 5318 if (useLane)5319 ShadowArgs.append(1,5320 I.getArgOperand(numArgOperands - skipTrailingOperands));5321 5322 Value *OutputShadowPtr, *OutputOriginPtr;5323 // AArch64 NEON does not need alignment (unless OS requires it)5324 std::tie(OutputShadowPtr, OutputOriginPtr) = getShadowOriginPtr(5325 Addr, IRB, OutputShadowTy, Align(1), /*isStore*/ true);5326 ShadowArgs.append(1, OutputShadowPtr);5327 5328 CallInst *CI =5329 IRB.CreateIntrinsic(IRB.getVoidTy(), I.getIntrinsicID(), ShadowArgs);5330 setShadow(&I, CI);5331 5332 if (MS.TrackOrigins) {5333 // TODO: if we modelled the vst* instruction more precisely, we could5334 // more accurately track the origins (e.g., if both inputs are5335 // uninitialized for vst2, we currently blame the second input, even5336 // though part of the output depends only on the first input).5337 //5338 // This is particularly imprecise for vst{2,3,4}lane, since only one5339 // lane of each input is actually copied to the output.5340 OriginCombiner OC(this, IRB);5341 for (int i = 0; i < numArgOperands - skipTrailingOperands; i++)5342 OC.Add(I.getArgOperand(i));5343 5344 const DataLayout &DL = F.getDataLayout();5345 OC.DoneAndStoreOrigin(DL.getTypeStoreSize(OutputVectorTy),5346 OutputOriginPtr);5347 }5348 }5349 5350 /// Handle intrinsics by applying the intrinsic to the shadows.5351 ///5352 /// The trailing arguments are passed verbatim to the intrinsic, though any5353 /// uninitialized trailing arguments can also taint the shadow e.g., for an5354 /// intrinsic with one trailing verbatim argument:5355 /// out = intrinsic(var1, var2, opType)5356 /// we compute:5357 /// shadow[out] =5358 /// intrinsic(shadow[var1], shadow[var2], opType) | shadow[opType]5359 ///5360 /// Typically, shadowIntrinsicID will be specified by the caller to be5361 /// I.getIntrinsicID(), but the caller can choose to replace it with another5362 /// intrinsic of the same type.5363 ///5364 /// CAUTION: this assumes that the intrinsic will handle arbitrary5365 /// bit-patterns (for example, if the intrinsic accepts floats for5366 /// var1, we require that it doesn't care if inputs are NaNs).5367 ///5368 /// For example, this can be applied to the Arm NEON vector table intrinsics5369 /// (tbl{1,2,3,4}).5370 ///5371 /// The origin is approximated using setOriginForNaryOp.5372 void handleIntrinsicByApplyingToShadow(IntrinsicInst &I,5373 Intrinsic::ID shadowIntrinsicID,5374 unsigned int trailingVerbatimArgs) {5375 IRBuilder<> IRB(&I);5376 5377 assert(trailingVerbatimArgs < I.arg_size());5378 5379 SmallVector<Value *, 8> ShadowArgs;5380 // Don't use getNumOperands() because it includes the callee5381 for (unsigned int i = 0; i < I.arg_size() - trailingVerbatimArgs; i++) {5382 Value *Shadow = getShadow(&I, i);5383 5384 // Shadows are integer-ish types but some intrinsics require a5385 // different (e.g., floating-point) type.5386 ShadowArgs.push_back(5387 IRB.CreateBitCast(Shadow, I.getArgOperand(i)->getType()));5388 }5389 5390 for (unsigned int i = I.arg_size() - trailingVerbatimArgs; i < I.arg_size();5391 i++) {5392 Value *Arg = I.getArgOperand(i);5393 ShadowArgs.push_back(Arg);5394 }5395 5396 CallInst *CI =5397 IRB.CreateIntrinsic(I.getType(), shadowIntrinsicID, ShadowArgs);5398 Value *CombinedShadow = CI;5399 5400 // Combine the computed shadow with the shadow of trailing args5401 for (unsigned int i = I.arg_size() - trailingVerbatimArgs; i < I.arg_size();5402 i++) {5403 Value *Shadow =5404 CreateShadowCast(IRB, getShadow(&I, i), CombinedShadow->getType());5405 CombinedShadow = IRB.CreateOr(Shadow, CombinedShadow, "_msprop");5406 }5407 5408 setShadow(&I, IRB.CreateBitCast(CombinedShadow, getShadowTy(&I)));5409 5410 setOriginForNaryOp(I);5411 }5412 5413 // Approximation only5414 //5415 // e.g., <16 x i8> @llvm.aarch64.neon.pmull64(i64, i64)5416 void handleNEONVectorMultiplyIntrinsic(IntrinsicInst &I) {5417 assert(I.arg_size() == 2);5418 5419 handleShadowOr(I);5420 }5421 5422 bool maybeHandleCrossPlatformIntrinsic(IntrinsicInst &I) {5423 switch (I.getIntrinsicID()) {5424 case Intrinsic::uadd_with_overflow:5425 case Intrinsic::sadd_with_overflow:5426 case Intrinsic::usub_with_overflow:5427 case Intrinsic::ssub_with_overflow:5428 case Intrinsic::umul_with_overflow:5429 case Intrinsic::smul_with_overflow:5430 handleArithmeticWithOverflow(I);5431 break;5432 case Intrinsic::abs:5433 handleAbsIntrinsic(I);5434 break;5435 case Intrinsic::bitreverse:5436 handleIntrinsicByApplyingToShadow(I, I.getIntrinsicID(),5437 /*trailingVerbatimArgs*/ 0);5438 break;5439 case Intrinsic::is_fpclass:5440 handleIsFpClass(I);5441 break;5442 case Intrinsic::lifetime_start:5443 handleLifetimeStart(I);5444 break;5445 case Intrinsic::launder_invariant_group:5446 case Intrinsic::strip_invariant_group:5447 handleInvariantGroup(I);5448 break;5449 case Intrinsic::bswap:5450 handleBswap(I);5451 break;5452 case Intrinsic::ctlz:5453 case Intrinsic::cttz:5454 handleCountLeadingTrailingZeros(I);5455 break;5456 case Intrinsic::masked_compressstore:5457 handleMaskedCompressStore(I);5458 break;5459 case Intrinsic::masked_expandload:5460 handleMaskedExpandLoad(I);5461 break;5462 case Intrinsic::masked_gather:5463 handleMaskedGather(I);5464 break;5465 case Intrinsic::masked_scatter:5466 handleMaskedScatter(I);5467 break;5468 case Intrinsic::masked_store:5469 handleMaskedStore(I);5470 break;5471 case Intrinsic::masked_load:5472 handleMaskedLoad(I);5473 break;5474 case Intrinsic::vector_reduce_and:5475 handleVectorReduceAndIntrinsic(I);5476 break;5477 case Intrinsic::vector_reduce_or:5478 handleVectorReduceOrIntrinsic(I);5479 break;5480 5481 case Intrinsic::vector_reduce_add:5482 case Intrinsic::vector_reduce_xor:5483 case Intrinsic::vector_reduce_mul:5484 // Signed/Unsigned Min/Max5485 // TODO: handling similarly to AND/OR may be more precise.5486 case Intrinsic::vector_reduce_smax:5487 case Intrinsic::vector_reduce_smin:5488 case Intrinsic::vector_reduce_umax:5489 case Intrinsic::vector_reduce_umin:5490 // TODO: this has no false positives, but arguably we should check that all5491 // the bits are initialized.5492 case Intrinsic::vector_reduce_fmax:5493 case Intrinsic::vector_reduce_fmin:5494 handleVectorReduceIntrinsic(I, /*AllowShadowCast=*/false);5495 break;5496 5497 case Intrinsic::vector_reduce_fadd:5498 case Intrinsic::vector_reduce_fmul:5499 handleVectorReduceWithStarterIntrinsic(I);5500 break;5501 5502 case Intrinsic::scmp:5503 case Intrinsic::ucmp: {5504 handleShadowOr(I);5505 break;5506 }5507 5508 case Intrinsic::fshl:5509 case Intrinsic::fshr:5510 handleFunnelShift(I);5511 break;5512 5513 case Intrinsic::is_constant:5514 // The result of llvm.is.constant() is always defined.5515 setShadow(&I, getCleanShadow(&I));5516 setOrigin(&I, getCleanOrigin());5517 break;5518 5519 default:5520 return false;5521 }5522 5523 return true;5524 }5525 5526 bool maybeHandleX86SIMDIntrinsic(IntrinsicInst &I) {5527 switch (I.getIntrinsicID()) {5528 case Intrinsic::x86_sse_stmxcsr:5529 handleStmxcsr(I);5530 break;5531 case Intrinsic::x86_sse_ldmxcsr:5532 handleLdmxcsr(I);5533 break;5534 5535 // Convert Scalar Double Precision Floating-Point Value5536 // to Unsigned Doubleword Integer5537 // etc.5538 case Intrinsic::x86_avx512_vcvtsd2usi64:5539 case Intrinsic::x86_avx512_vcvtsd2usi32:5540 case Intrinsic::x86_avx512_vcvtss2usi64:5541 case Intrinsic::x86_avx512_vcvtss2usi32:5542 case Intrinsic::x86_avx512_cvttss2usi64:5543 case Intrinsic::x86_avx512_cvttss2usi:5544 case Intrinsic::x86_avx512_cvttsd2usi64:5545 case Intrinsic::x86_avx512_cvttsd2usi:5546 case Intrinsic::x86_avx512_cvtusi2ss:5547 case Intrinsic::x86_avx512_cvtusi642sd:5548 case Intrinsic::x86_avx512_cvtusi642ss:5549 handleSSEVectorConvertIntrinsic(I, 1, true);5550 break;5551 case Intrinsic::x86_sse2_cvtsd2si64:5552 case Intrinsic::x86_sse2_cvtsd2si:5553 case Intrinsic::x86_sse2_cvtsd2ss:5554 case Intrinsic::x86_sse2_cvttsd2si64:5555 case Intrinsic::x86_sse2_cvttsd2si:5556 case Intrinsic::x86_sse_cvtss2si64:5557 case Intrinsic::x86_sse_cvtss2si:5558 case Intrinsic::x86_sse_cvttss2si64:5559 case Intrinsic::x86_sse_cvttss2si:5560 handleSSEVectorConvertIntrinsic(I, 1);5561 break;5562 case Intrinsic::x86_sse_cvtps2pi:5563 case Intrinsic::x86_sse_cvttps2pi:5564 handleSSEVectorConvertIntrinsic(I, 2);5565 break;5566 5567 // TODO:5568 // <1 x i64> @llvm.x86.sse.cvtpd2pi(<2 x double>)5569 // <2 x double> @llvm.x86.sse.cvtpi2pd(<1 x i64>)5570 // <4 x float> @llvm.x86.sse.cvtpi2ps(<4 x float>, <1 x i64>)5571 5572 case Intrinsic::x86_vcvtps2ph_128:5573 case Intrinsic::x86_vcvtps2ph_256: {5574 handleSSEVectorConvertIntrinsicByProp(I, /*HasRoundingMode=*/true);5575 break;5576 }5577 5578 // Convert Packed Single Precision Floating-Point Values5579 // to Packed Signed Doubleword Integer Values5580 //5581 // <16 x i32> @llvm.x86.avx512.mask.cvtps2dq.5125582 // (<16 x float>, <16 x i32>, i16, i32)5583 case Intrinsic::x86_avx512_mask_cvtps2dq_512:5584 handleAVX512VectorConvertFPToInt(I, /*LastMask=*/false);5585 break;5586 5587 // Convert Packed Double Precision Floating-Point Values5588 // to Packed Single Precision Floating-Point Values5589 case Intrinsic::x86_sse2_cvtpd2ps:5590 case Intrinsic::x86_sse2_cvtps2dq:5591 case Intrinsic::x86_sse2_cvtpd2dq:5592 case Intrinsic::x86_sse2_cvttps2dq:5593 case Intrinsic::x86_sse2_cvttpd2dq:5594 case Intrinsic::x86_avx_cvt_pd2_ps_256:5595 case Intrinsic::x86_avx_cvt_ps2dq_256:5596 case Intrinsic::x86_avx_cvt_pd2dq_256:5597 case Intrinsic::x86_avx_cvtt_ps2dq_256:5598 case Intrinsic::x86_avx_cvtt_pd2dq_256: {5599 handleSSEVectorConvertIntrinsicByProp(I, /*HasRoundingMode=*/false);5600 break;5601 }5602 5603 // Convert Single-Precision FP Value to 16-bit FP Value5604 // <16 x i16> @llvm.x86.avx512.mask.vcvtps2ph.5125605 // (<16 x float>, i32, <16 x i16>, i16)5606 // <8 x i16> @llvm.x86.avx512.mask.vcvtps2ph.1285607 // (<4 x float>, i32, <8 x i16>, i8)5608 // <8 x i16> @llvm.x86.avx512.mask.vcvtps2ph.2565609 // (<8 x float>, i32, <8 x i16>, i8)5610 case Intrinsic::x86_avx512_mask_vcvtps2ph_512:5611 case Intrinsic::x86_avx512_mask_vcvtps2ph_256:5612 case Intrinsic::x86_avx512_mask_vcvtps2ph_128:5613 handleAVX512VectorConvertFPToInt(I, /*LastMask=*/true);5614 break;5615 5616 // Shift Packed Data (Left Logical, Right Arithmetic, Right Logical)5617 case Intrinsic::x86_avx512_psll_w_512:5618 case Intrinsic::x86_avx512_psll_d_512:5619 case Intrinsic::x86_avx512_psll_q_512:5620 case Intrinsic::x86_avx512_pslli_w_512:5621 case Intrinsic::x86_avx512_pslli_d_512:5622 case Intrinsic::x86_avx512_pslli_q_512:5623 case Intrinsic::x86_avx512_psrl_w_512:5624 case Intrinsic::x86_avx512_psrl_d_512:5625 case Intrinsic::x86_avx512_psrl_q_512:5626 case Intrinsic::x86_avx512_psra_w_512:5627 case Intrinsic::x86_avx512_psra_d_512:5628 case Intrinsic::x86_avx512_psra_q_512:5629 case Intrinsic::x86_avx512_psrli_w_512:5630 case Intrinsic::x86_avx512_psrli_d_512:5631 case Intrinsic::x86_avx512_psrli_q_512:5632 case Intrinsic::x86_avx512_psrai_w_512:5633 case Intrinsic::x86_avx512_psrai_d_512:5634 case Intrinsic::x86_avx512_psrai_q_512:5635 case Intrinsic::x86_avx512_psra_q_256:5636 case Intrinsic::x86_avx512_psra_q_128:5637 case Intrinsic::x86_avx512_psrai_q_256:5638 case Intrinsic::x86_avx512_psrai_q_128:5639 case Intrinsic::x86_avx2_psll_w:5640 case Intrinsic::x86_avx2_psll_d:5641 case Intrinsic::x86_avx2_psll_q:5642 case Intrinsic::x86_avx2_pslli_w:5643 case Intrinsic::x86_avx2_pslli_d:5644 case Intrinsic::x86_avx2_pslli_q:5645 case Intrinsic::x86_avx2_psrl_w:5646 case Intrinsic::x86_avx2_psrl_d:5647 case Intrinsic::x86_avx2_psrl_q:5648 case Intrinsic::x86_avx2_psra_w:5649 case Intrinsic::x86_avx2_psra_d:5650 case Intrinsic::x86_avx2_psrli_w:5651 case Intrinsic::x86_avx2_psrli_d:5652 case Intrinsic::x86_avx2_psrli_q:5653 case Intrinsic::x86_avx2_psrai_w:5654 case Intrinsic::x86_avx2_psrai_d:5655 case Intrinsic::x86_sse2_psll_w:5656 case Intrinsic::x86_sse2_psll_d:5657 case Intrinsic::x86_sse2_psll_q:5658 case Intrinsic::x86_sse2_pslli_w:5659 case Intrinsic::x86_sse2_pslli_d:5660 case Intrinsic::x86_sse2_pslli_q:5661 case Intrinsic::x86_sse2_psrl_w:5662 case Intrinsic::x86_sse2_psrl_d:5663 case Intrinsic::x86_sse2_psrl_q:5664 case Intrinsic::x86_sse2_psra_w:5665 case Intrinsic::x86_sse2_psra_d:5666 case Intrinsic::x86_sse2_psrli_w:5667 case Intrinsic::x86_sse2_psrli_d:5668 case Intrinsic::x86_sse2_psrli_q:5669 case Intrinsic::x86_sse2_psrai_w:5670 case Intrinsic::x86_sse2_psrai_d:5671 case Intrinsic::x86_mmx_psll_w:5672 case Intrinsic::x86_mmx_psll_d:5673 case Intrinsic::x86_mmx_psll_q:5674 case Intrinsic::x86_mmx_pslli_w:5675 case Intrinsic::x86_mmx_pslli_d:5676 case Intrinsic::x86_mmx_pslli_q:5677 case Intrinsic::x86_mmx_psrl_w:5678 case Intrinsic::x86_mmx_psrl_d:5679 case Intrinsic::x86_mmx_psrl_q:5680 case Intrinsic::x86_mmx_psra_w:5681 case Intrinsic::x86_mmx_psra_d:5682 case Intrinsic::x86_mmx_psrli_w:5683 case Intrinsic::x86_mmx_psrli_d:5684 case Intrinsic::x86_mmx_psrli_q:5685 case Intrinsic::x86_mmx_psrai_w:5686 case Intrinsic::x86_mmx_psrai_d:5687 handleVectorShiftIntrinsic(I, /* Variable */ false);5688 break;5689 case Intrinsic::x86_avx2_psllv_d:5690 case Intrinsic::x86_avx2_psllv_d_256:5691 case Intrinsic::x86_avx512_psllv_d_512:5692 case Intrinsic::x86_avx2_psllv_q:5693 case Intrinsic::x86_avx2_psllv_q_256:5694 case Intrinsic::x86_avx512_psllv_q_512:5695 case Intrinsic::x86_avx2_psrlv_d:5696 case Intrinsic::x86_avx2_psrlv_d_256:5697 case Intrinsic::x86_avx512_psrlv_d_512:5698 case Intrinsic::x86_avx2_psrlv_q:5699 case Intrinsic::x86_avx2_psrlv_q_256:5700 case Intrinsic::x86_avx512_psrlv_q_512:5701 case Intrinsic::x86_avx2_psrav_d:5702 case Intrinsic::x86_avx2_psrav_d_256:5703 case Intrinsic::x86_avx512_psrav_d_512:5704 case Intrinsic::x86_avx512_psrav_q_128:5705 case Intrinsic::x86_avx512_psrav_q_256:5706 case Intrinsic::x86_avx512_psrav_q_512:5707 handleVectorShiftIntrinsic(I, /* Variable */ true);5708 break;5709 5710 // Pack with Signed/Unsigned Saturation5711 case Intrinsic::x86_sse2_packsswb_128:5712 case Intrinsic::x86_sse2_packssdw_128:5713 case Intrinsic::x86_sse2_packuswb_128:5714 case Intrinsic::x86_sse41_packusdw:5715 case Intrinsic::x86_avx2_packsswb:5716 case Intrinsic::x86_avx2_packssdw:5717 case Intrinsic::x86_avx2_packuswb:5718 case Intrinsic::x86_avx2_packusdw:5719 // e.g., <64 x i8> @llvm.x86.avx512.packsswb.5125720 // (<32 x i16> %a, <32 x i16> %b)5721 // <32 x i16> @llvm.x86.avx512.packssdw.5125722 // (<16 x i32> %a, <16 x i32> %b)5723 // Note: AVX512 masked variants are auto-upgraded by LLVM.5724 case Intrinsic::x86_avx512_packsswb_512:5725 case Intrinsic::x86_avx512_packssdw_512:5726 case Intrinsic::x86_avx512_packuswb_512:5727 case Intrinsic::x86_avx512_packusdw_512:5728 handleVectorPackIntrinsic(I);5729 break;5730 5731 case Intrinsic::x86_sse41_pblendvb:5732 case Intrinsic::x86_sse41_blendvpd:5733 case Intrinsic::x86_sse41_blendvps:5734 case Intrinsic::x86_avx_blendv_pd_256:5735 case Intrinsic::x86_avx_blendv_ps_256:5736 case Intrinsic::x86_avx2_pblendvb:5737 handleBlendvIntrinsic(I);5738 break;5739 5740 case Intrinsic::x86_avx_dp_ps_256:5741 case Intrinsic::x86_sse41_dppd:5742 case Intrinsic::x86_sse41_dpps:5743 handleDppIntrinsic(I);5744 break;5745 5746 case Intrinsic::x86_mmx_packsswb:5747 case Intrinsic::x86_mmx_packuswb:5748 handleVectorPackIntrinsic(I, 16);5749 break;5750 5751 case Intrinsic::x86_mmx_packssdw:5752 handleVectorPackIntrinsic(I, 32);5753 break;5754 5755 case Intrinsic::x86_mmx_psad_bw:5756 handleVectorSadIntrinsic(I, true);5757 break;5758 case Intrinsic::x86_sse2_psad_bw:5759 case Intrinsic::x86_avx2_psad_bw:5760 handleVectorSadIntrinsic(I);5761 break;5762 5763 // Multiply and Add Packed Words5764 // < 4 x i32> @llvm.x86.sse2.pmadd.wd(<8 x i16>, <8 x i16>)5765 // < 8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16>, <16 x i16>)5766 // <16 x i32> @llvm.x86.avx512.pmaddw.d.512(<32 x i16>, <32 x i16>)5767 //5768 // Multiply and Add Packed Signed and Unsigned Bytes5769 // < 8 x i16> @llvm.x86.ssse3.pmadd.ub.sw.128(<16 x i8>, <16 x i8>)5770 // <16 x i16> @llvm.x86.avx2.pmadd.ub.sw(<32 x i8>, <32 x i8>)5771 // <32 x i16> @llvm.x86.avx512.pmaddubs.w.512(<64 x i8>, <64 x i8>)5772 //5773 // These intrinsics are auto-upgraded into non-masked forms:5774 // < 4 x i32> @llvm.x86.avx512.mask.pmaddw.d.1285775 // (<8 x i16>, <8 x i16>, <4 x i32>, i8)5776 // < 8 x i32> @llvm.x86.avx512.mask.pmaddw.d.2565777 // (<16 x i16>, <16 x i16>, <8 x i32>, i8)5778 // <16 x i32> @llvm.x86.avx512.mask.pmaddw.d.5125779 // (<32 x i16>, <32 x i16>, <16 x i32>, i16)5780 // < 8 x i16> @llvm.x86.avx512.mask.pmaddubs.w.1285781 // (<16 x i8>, <16 x i8>, <8 x i16>, i8)5782 // <16 x i16> @llvm.x86.avx512.mask.pmaddubs.w.2565783 // (<32 x i8>, <32 x i8>, <16 x i16>, i16)5784 // <32 x i16> @llvm.x86.avx512.mask.pmaddubs.w.5125785 // (<64 x i8>, <64 x i8>, <32 x i16>, i32)5786 case Intrinsic::x86_sse2_pmadd_wd:5787 case Intrinsic::x86_avx2_pmadd_wd:5788 case Intrinsic::x86_avx512_pmaddw_d_512:5789 case Intrinsic::x86_ssse3_pmadd_ub_sw_128:5790 case Intrinsic::x86_avx2_pmadd_ub_sw:5791 case Intrinsic::x86_avx512_pmaddubs_w_512:5792 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/2,5793 /*ZeroPurifies=*/true);5794 break;5795 5796 // <1 x i64> @llvm.x86.ssse3.pmadd.ub.sw(<1 x i64>, <1 x i64>)5797 case Intrinsic::x86_ssse3_pmadd_ub_sw:5798 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/2,5799 /*ZeroPurifies=*/true, /*EltSizeInBits=*/8);5800 break;5801 5802 // <1 x i64> @llvm.x86.mmx.pmadd.wd(<1 x i64>, <1 x i64>)5803 case Intrinsic::x86_mmx_pmadd_wd:5804 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/2,5805 /*ZeroPurifies=*/true, /*EltSizeInBits=*/16);5806 break;5807 5808 // AVX Vector Neural Network Instructions: bytes5809 //5810 // Multiply and Add Packed Signed and Unsigned Bytes5811 // < 4 x i32> @llvm.x86.avx512.vpdpbusd.1285812 // (< 4 x i32>, <16 x i8>, <16 x i8>)5813 // < 8 x i32> @llvm.x86.avx512.vpdpbusd.2565814 // (< 8 x i32>, <32 x i8>, <32 x i8>)5815 // <16 x i32> @llvm.x86.avx512.vpdpbusd.5125816 // (<16 x i32>, <64 x i8>, <64 x i8>)5817 //5818 // Multiply and Add Unsigned and Signed Bytes With Saturation5819 // < 4 x i32> @llvm.x86.avx512.vpdpbusds.1285820 // (< 4 x i32>, <16 x i8>, <16 x i8>)5821 // < 8 x i32> @llvm.x86.avx512.vpdpbusds.2565822 // (< 8 x i32>, <32 x i8>, <32 x i8>)5823 // <16 x i32> @llvm.x86.avx512.vpdpbusds.5125824 // (<16 x i32>, <64 x i8>, <64 x i8>)5825 //5826 // < 4 x i32> @llvm.x86.avx2.vpdpbssd.1285827 // (< 4 x i32>, < 4 x i32>, < 4 x i32>)5828 // < 8 x i32> @llvm.x86.avx2.vpdpbssd.2565829 // (< 8 x i32>, < 8 x i32>, < 8 x i32>)5830 //5831 // < 4 x i32> @llvm.x86.avx2.vpdpbssds.1285832 // (< 4 x i32>, < 4 x i32>, < 4 x i32>)5833 // < 8 x i32> @llvm.x86.avx2.vpdpbssds.2565834 // (< 8 x i32>, < 8 x i32>, < 8 x i32>)5835 //5836 // <16 x i32> @llvm.x86.avx10.vpdpbssd.5125837 // (<16 x i32>, <16 x i32>, <16 x i32>)5838 // <16 x i32> @llvm.x86.avx10.vpdpbssds.5125839 // (<16 x i32>, <16 x i32>, <16 x i32>)5840 //5841 // These intrinsics are auto-upgraded into non-masked forms:5842 // <4 x i32> @llvm.x86.avx512.mask.vpdpbusd.1285843 // (<4 x i32>, <16 x i8>, <16 x i8>, i8)5844 // <4 x i32> @llvm.x86.avx512.maskz.vpdpbusd.1285845 // (<4 x i32>, <16 x i8>, <16 x i8>, i8)5846 // <8 x i32> @llvm.x86.avx512.mask.vpdpbusd.2565847 // (<8 x i32>, <32 x i8>, <32 x i8>, i8)5848 // <8 x i32> @llvm.x86.avx512.maskz.vpdpbusd.2565849 // (<8 x i32>, <32 x i8>, <32 x i8>, i8)5850 // <16 x i32> @llvm.x86.avx512.mask.vpdpbusd.5125851 // (<16 x i32>, <64 x i8>, <64 x i8>, i16)5852 // <16 x i32> @llvm.x86.avx512.maskz.vpdpbusd.5125853 // (<16 x i32>, <64 x i8>, <64 x i8>, i16)5854 //5855 // <4 x i32> @llvm.x86.avx512.mask.vpdpbusds.1285856 // (<4 x i32>, <16 x i8>, <16 x i8>, i8)5857 // <4 x i32> @llvm.x86.avx512.maskz.vpdpbusds.1285858 // (<4 x i32>, <16 x i8>, <16 x i8>, i8)5859 // <8 x i32> @llvm.x86.avx512.mask.vpdpbusds.2565860 // (<8 x i32>, <32 x i8>, <32 x i8>, i8)5861 // <8 x i32> @llvm.x86.avx512.maskz.vpdpbusds.2565862 // (<8 x i32>, <32 x i8>, <32 x i8>, i8)5863 // <16 x i32> @llvm.x86.avx512.mask.vpdpbusds.5125864 // (<16 x i32>, <64 x i8>, <64 x i8>, i16)5865 // <16 x i32> @llvm.x86.avx512.maskz.vpdpbusds.5125866 // (<16 x i32>, <64 x i8>, <64 x i8>, i16)5867 case Intrinsic::x86_avx512_vpdpbusd_128:5868 case Intrinsic::x86_avx512_vpdpbusd_256:5869 case Intrinsic::x86_avx512_vpdpbusd_512:5870 case Intrinsic::x86_avx512_vpdpbusds_128:5871 case Intrinsic::x86_avx512_vpdpbusds_256:5872 case Intrinsic::x86_avx512_vpdpbusds_512:5873 case Intrinsic::x86_avx2_vpdpbssd_128:5874 case Intrinsic::x86_avx2_vpdpbssd_256:5875 case Intrinsic::x86_avx10_vpdpbssd_512:5876 case Intrinsic::x86_avx2_vpdpbssds_128:5877 case Intrinsic::x86_avx2_vpdpbssds_256:5878 case Intrinsic::x86_avx10_vpdpbssds_512:5879 case Intrinsic::x86_avx2_vpdpbsud_128:5880 case Intrinsic::x86_avx2_vpdpbsud_256:5881 case Intrinsic::x86_avx10_vpdpbsud_512:5882 case Intrinsic::x86_avx2_vpdpbsuds_128:5883 case Intrinsic::x86_avx2_vpdpbsuds_256:5884 case Intrinsic::x86_avx10_vpdpbsuds_512:5885 case Intrinsic::x86_avx2_vpdpbuud_128:5886 case Intrinsic::x86_avx2_vpdpbuud_256:5887 case Intrinsic::x86_avx10_vpdpbuud_512:5888 case Intrinsic::x86_avx2_vpdpbuuds_128:5889 case Intrinsic::x86_avx2_vpdpbuuds_256:5890 case Intrinsic::x86_avx10_vpdpbuuds_512:5891 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/4,5892 /*ZeroPurifies=*/true, /*EltSizeInBits=*/8);5893 break;5894 5895 // AVX Vector Neural Network Instructions: words5896 //5897 // Multiply and Add Signed Word Integers5898 // < 4 x i32> @llvm.x86.avx512.vpdpwssd.1285899 // (< 4 x i32>, < 4 x i32>, < 4 x i32>)5900 // < 8 x i32> @llvm.x86.avx512.vpdpwssd.2565901 // (< 8 x i32>, < 8 x i32>, < 8 x i32>)5902 // <16 x i32> @llvm.x86.avx512.vpdpwssd.5125903 // (<16 x i32>, <16 x i32>, <16 x i32>)5904 //5905 // Multiply and Add Signed Word Integers With Saturation5906 // < 4 x i32> @llvm.x86.avx512.vpdpwssds.1285907 // (< 4 x i32>, < 4 x i32>, < 4 x i32>)5908 // < 8 x i32> @llvm.x86.avx512.vpdpwssds.2565909 // (< 8 x i32>, < 8 x i32>, < 8 x i32>)5910 // <16 x i32> @llvm.x86.avx512.vpdpwssds.5125911 // (<16 x i32>, <16 x i32>, <16 x i32>)5912 //5913 // These intrinsics are auto-upgraded into non-masked forms:5914 // <4 x i32> @llvm.x86.avx512.mask.vpdpwssd.1285915 // (<4 x i32>, <4 x i32>, <4 x i32>, i8)5916 // <4 x i32> @llvm.x86.avx512.maskz.vpdpwssd.1285917 // (<4 x i32>, <4 x i32>, <4 x i32>, i8)5918 // <8 x i32> @llvm.x86.avx512.mask.vpdpwssd.2565919 // (<8 x i32>, <8 x i32>, <8 x i32>, i8)5920 // <8 x i32> @llvm.x86.avx512.maskz.vpdpwssd.2565921 // (<8 x i32>, <8 x i32>, <8 x i32>, i8)5922 // <16 x i32> @llvm.x86.avx512.mask.vpdpwssd.5125923 // (<16 x i32>, <16 x i32>, <16 x i32>, i16)5924 // <16 x i32> @llvm.x86.avx512.maskz.vpdpwssd.5125925 // (<16 x i32>, <16 x i32>, <16 x i32>, i16)5926 //5927 // <4 x i32> @llvm.x86.avx512.mask.vpdpwssds.1285928 // (<4 x i32>, <4 x i32>, <4 x i32>, i8)5929 // <4 x i32> @llvm.x86.avx512.maskz.vpdpwssds.1285930 // (<4 x i32>, <4 x i32>, <4 x i32>, i8)5931 // <8 x i32> @llvm.x86.avx512.mask.vpdpwssds.2565932 // (<8 x i32>, <8 x i32>, <8 x i32>, i8)5933 // <8 x i32> @llvm.x86.avx512.maskz.vpdpwssds.2565934 // (<8 x i32>, <8 x i32>, <8 x i32>, i8)5935 // <16 x i32> @llvm.x86.avx512.mask.vpdpwssds.5125936 // (<16 x i32>, <16 x i32>, <16 x i32>, i16)5937 // <16 x i32> @llvm.x86.avx512.maskz.vpdpwssds.5125938 // (<16 x i32>, <16 x i32>, <16 x i32>, i16)5939 case Intrinsic::x86_avx512_vpdpwssd_128:5940 case Intrinsic::x86_avx512_vpdpwssd_256:5941 case Intrinsic::x86_avx512_vpdpwssd_512:5942 case Intrinsic::x86_avx512_vpdpwssds_128:5943 case Intrinsic::x86_avx512_vpdpwssds_256:5944 case Intrinsic::x86_avx512_vpdpwssds_512:5945 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/2,5946 /*ZeroPurifies=*/true, /*EltSizeInBits=*/16);5947 break;5948 5949 // Dot Product of BF16 Pairs Accumulated Into Packed Single5950 // Precision5951 // <4 x float> @llvm.x86.avx512bf16.dpbf16ps.1285952 // (<4 x float>, <8 x bfloat>, <8 x bfloat>)5953 // <8 x float> @llvm.x86.avx512bf16.dpbf16ps.2565954 // (<8 x float>, <16 x bfloat>, <16 x bfloat>)5955 // <16 x float> @llvm.x86.avx512bf16.dpbf16ps.5125956 // (<16 x float>, <32 x bfloat>, <32 x bfloat>)5957 case Intrinsic::x86_avx512bf16_dpbf16ps_128:5958 case Intrinsic::x86_avx512bf16_dpbf16ps_256:5959 case Intrinsic::x86_avx512bf16_dpbf16ps_512:5960 handleVectorPmaddIntrinsic(I, /*ReductionFactor=*/2,5961 /*ZeroPurifies=*/false);5962 break;5963 5964 case Intrinsic::x86_sse_cmp_ss:5965 case Intrinsic::x86_sse2_cmp_sd:5966 case Intrinsic::x86_sse_comieq_ss:5967 case Intrinsic::x86_sse_comilt_ss:5968 case Intrinsic::x86_sse_comile_ss:5969 case Intrinsic::x86_sse_comigt_ss:5970 case Intrinsic::x86_sse_comige_ss:5971 case Intrinsic::x86_sse_comineq_ss:5972 case Intrinsic::x86_sse_ucomieq_ss:5973 case Intrinsic::x86_sse_ucomilt_ss:5974 case Intrinsic::x86_sse_ucomile_ss:5975 case Intrinsic::x86_sse_ucomigt_ss:5976 case Intrinsic::x86_sse_ucomige_ss:5977 case Intrinsic::x86_sse_ucomineq_ss:5978 case Intrinsic::x86_sse2_comieq_sd:5979 case Intrinsic::x86_sse2_comilt_sd:5980 case Intrinsic::x86_sse2_comile_sd:5981 case Intrinsic::x86_sse2_comigt_sd:5982 case Intrinsic::x86_sse2_comige_sd:5983 case Intrinsic::x86_sse2_comineq_sd:5984 case Intrinsic::x86_sse2_ucomieq_sd:5985 case Intrinsic::x86_sse2_ucomilt_sd:5986 case Intrinsic::x86_sse2_ucomile_sd:5987 case Intrinsic::x86_sse2_ucomigt_sd:5988 case Intrinsic::x86_sse2_ucomige_sd:5989 case Intrinsic::x86_sse2_ucomineq_sd:5990 handleVectorCompareScalarIntrinsic(I);5991 break;5992 5993 case Intrinsic::x86_avx_cmp_pd_256:5994 case Intrinsic::x86_avx_cmp_ps_256:5995 case Intrinsic::x86_sse2_cmp_pd:5996 case Intrinsic::x86_sse_cmp_ps:5997 handleVectorComparePackedIntrinsic(I);5998 break;5999 6000 case Intrinsic::x86_bmi_bextr_32:6001 case Intrinsic::x86_bmi_bextr_64:6002 case Intrinsic::x86_bmi_bzhi_32:6003 case Intrinsic::x86_bmi_bzhi_64:6004 case Intrinsic::x86_bmi_pdep_32:6005 case Intrinsic::x86_bmi_pdep_64:6006 case Intrinsic::x86_bmi_pext_32:6007 case Intrinsic::x86_bmi_pext_64:6008 handleBmiIntrinsic(I);6009 break;6010 6011 case Intrinsic::x86_pclmulqdq:6012 case Intrinsic::x86_pclmulqdq_256:6013 case Intrinsic::x86_pclmulqdq_512:6014 handlePclmulIntrinsic(I);6015 break;6016 6017 case Intrinsic::x86_avx_round_pd_256:6018 case Intrinsic::x86_avx_round_ps_256:6019 case Intrinsic::x86_sse41_round_pd:6020 case Intrinsic::x86_sse41_round_ps:6021 handleRoundPdPsIntrinsic(I);6022 break;6023 6024 case Intrinsic::x86_sse41_round_sd:6025 case Intrinsic::x86_sse41_round_ss:6026 handleUnarySdSsIntrinsic(I);6027 break;6028 6029 case Intrinsic::x86_sse2_max_sd:6030 case Intrinsic::x86_sse_max_ss:6031 case Intrinsic::x86_sse2_min_sd:6032 case Intrinsic::x86_sse_min_ss:6033 handleBinarySdSsIntrinsic(I);6034 break;6035 6036 case Intrinsic::x86_avx_vtestc_pd:6037 case Intrinsic::x86_avx_vtestc_pd_256:6038 case Intrinsic::x86_avx_vtestc_ps:6039 case Intrinsic::x86_avx_vtestc_ps_256:6040 case Intrinsic::x86_avx_vtestnzc_pd:6041 case Intrinsic::x86_avx_vtestnzc_pd_256:6042 case Intrinsic::x86_avx_vtestnzc_ps:6043 case Intrinsic::x86_avx_vtestnzc_ps_256:6044 case Intrinsic::x86_avx_vtestz_pd:6045 case Intrinsic::x86_avx_vtestz_pd_256:6046 case Intrinsic::x86_avx_vtestz_ps:6047 case Intrinsic::x86_avx_vtestz_ps_256:6048 case Intrinsic::x86_avx_ptestc_256:6049 case Intrinsic::x86_avx_ptestnzc_256:6050 case Intrinsic::x86_avx_ptestz_256:6051 case Intrinsic::x86_sse41_ptestc:6052 case Intrinsic::x86_sse41_ptestnzc:6053 case Intrinsic::x86_sse41_ptestz:6054 handleVtestIntrinsic(I);6055 break;6056 6057 // Packed Horizontal Add/Subtract6058 case Intrinsic::x86_ssse3_phadd_w:6059 case Intrinsic::x86_ssse3_phadd_w_128:6060 case Intrinsic::x86_ssse3_phsub_w:6061 case Intrinsic::x86_ssse3_phsub_w_128:6062 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/1,6063 /*ReinterpretElemWidth=*/16);6064 break;6065 6066 case Intrinsic::x86_avx2_phadd_w:6067 case Intrinsic::x86_avx2_phsub_w:6068 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/2,6069 /*ReinterpretElemWidth=*/16);6070 break;6071 6072 // Packed Horizontal Add/Subtract6073 case Intrinsic::x86_ssse3_phadd_d:6074 case Intrinsic::x86_ssse3_phadd_d_128:6075 case Intrinsic::x86_ssse3_phsub_d:6076 case Intrinsic::x86_ssse3_phsub_d_128:6077 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/1,6078 /*ReinterpretElemWidth=*/32);6079 break;6080 6081 case Intrinsic::x86_avx2_phadd_d:6082 case Intrinsic::x86_avx2_phsub_d:6083 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/2,6084 /*ReinterpretElemWidth=*/32);6085 break;6086 6087 // Packed Horizontal Add/Subtract and Saturate6088 case Intrinsic::x86_ssse3_phadd_sw:6089 case Intrinsic::x86_ssse3_phadd_sw_128:6090 case Intrinsic::x86_ssse3_phsub_sw:6091 case Intrinsic::x86_ssse3_phsub_sw_128:6092 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/1,6093 /*ReinterpretElemWidth=*/16);6094 break;6095 6096 case Intrinsic::x86_avx2_phadd_sw:6097 case Intrinsic::x86_avx2_phsub_sw:6098 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/2,6099 /*ReinterpretElemWidth=*/16);6100 break;6101 6102 // Packed Single/Double Precision Floating-Point Horizontal Add6103 case Intrinsic::x86_sse3_hadd_ps:6104 case Intrinsic::x86_sse3_hadd_pd:6105 case Intrinsic::x86_sse3_hsub_ps:6106 case Intrinsic::x86_sse3_hsub_pd:6107 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/1);6108 break;6109 6110 case Intrinsic::x86_avx_hadd_pd_256:6111 case Intrinsic::x86_avx_hadd_ps_256:6112 case Intrinsic::x86_avx_hsub_pd_256:6113 case Intrinsic::x86_avx_hsub_ps_256:6114 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/2);6115 break;6116 6117 case Intrinsic::x86_avx_maskstore_ps:6118 case Intrinsic::x86_avx_maskstore_pd:6119 case Intrinsic::x86_avx_maskstore_ps_256:6120 case Intrinsic::x86_avx_maskstore_pd_256:6121 case Intrinsic::x86_avx2_maskstore_d:6122 case Intrinsic::x86_avx2_maskstore_q:6123 case Intrinsic::x86_avx2_maskstore_d_256:6124 case Intrinsic::x86_avx2_maskstore_q_256: {6125 handleAVXMaskedStore(I);6126 break;6127 }6128 6129 case Intrinsic::x86_avx_maskload_ps:6130 case Intrinsic::x86_avx_maskload_pd:6131 case Intrinsic::x86_avx_maskload_ps_256:6132 case Intrinsic::x86_avx_maskload_pd_256:6133 case Intrinsic::x86_avx2_maskload_d:6134 case Intrinsic::x86_avx2_maskload_q:6135 case Intrinsic::x86_avx2_maskload_d_256:6136 case Intrinsic::x86_avx2_maskload_q_256: {6137 handleAVXMaskedLoad(I);6138 break;6139 }6140 6141 // Packed6142 case Intrinsic::x86_avx512fp16_add_ph_512:6143 case Intrinsic::x86_avx512fp16_sub_ph_512:6144 case Intrinsic::x86_avx512fp16_mul_ph_512:6145 case Intrinsic::x86_avx512fp16_div_ph_512:6146 case Intrinsic::x86_avx512fp16_max_ph_512:6147 case Intrinsic::x86_avx512fp16_min_ph_512:6148 case Intrinsic::x86_avx512_min_ps_512:6149 case Intrinsic::x86_avx512_min_pd_512:6150 case Intrinsic::x86_avx512_max_ps_512:6151 case Intrinsic::x86_avx512_max_pd_512: {6152 // These AVX512 variants contain the rounding mode as a trailing flag.6153 // Earlier variants do not have a trailing flag and are already handled6154 // by maybeHandleSimpleNomemIntrinsic(I, 0) via6155 // maybeHandleUnknownIntrinsic.6156 [[maybe_unused]] bool Success =6157 maybeHandleSimpleNomemIntrinsic(I, /*trailingFlags=*/1);6158 assert(Success);6159 break;6160 }6161 6162 case Intrinsic::x86_avx_vpermilvar_pd:6163 case Intrinsic::x86_avx_vpermilvar_pd_256:6164 case Intrinsic::x86_avx512_vpermilvar_pd_512:6165 case Intrinsic::x86_avx_vpermilvar_ps:6166 case Intrinsic::x86_avx_vpermilvar_ps_256:6167 case Intrinsic::x86_avx512_vpermilvar_ps_512: {6168 handleAVXVpermilvar(I);6169 break;6170 }6171 6172 case Intrinsic::x86_avx512_vpermi2var_d_128:6173 case Intrinsic::x86_avx512_vpermi2var_d_256:6174 case Intrinsic::x86_avx512_vpermi2var_d_512:6175 case Intrinsic::x86_avx512_vpermi2var_hi_128:6176 case Intrinsic::x86_avx512_vpermi2var_hi_256:6177 case Intrinsic::x86_avx512_vpermi2var_hi_512:6178 case Intrinsic::x86_avx512_vpermi2var_pd_128:6179 case Intrinsic::x86_avx512_vpermi2var_pd_256:6180 case Intrinsic::x86_avx512_vpermi2var_pd_512:6181 case Intrinsic::x86_avx512_vpermi2var_ps_128:6182 case Intrinsic::x86_avx512_vpermi2var_ps_256:6183 case Intrinsic::x86_avx512_vpermi2var_ps_512:6184 case Intrinsic::x86_avx512_vpermi2var_q_128:6185 case Intrinsic::x86_avx512_vpermi2var_q_256:6186 case Intrinsic::x86_avx512_vpermi2var_q_512:6187 case Intrinsic::x86_avx512_vpermi2var_qi_128:6188 case Intrinsic::x86_avx512_vpermi2var_qi_256:6189 case Intrinsic::x86_avx512_vpermi2var_qi_512:6190 handleAVXVpermi2var(I);6191 break;6192 6193 // Packed Shuffle6194 // llvm.x86.sse.pshuf.w(<1 x i64>, i8)6195 // llvm.x86.ssse3.pshuf.b(<1 x i64>, <1 x i64>)6196 // llvm.x86.ssse3.pshuf.b.128(<16 x i8>, <16 x i8>)6197 // llvm.x86.avx2.pshuf.b(<32 x i8>, <32 x i8>)6198 // llvm.x86.avx512.pshuf.b.512(<64 x i8>, <64 x i8>)6199 //6200 // The following intrinsics are auto-upgraded:6201 // llvm.x86.sse2.pshuf.d(<4 x i32>, i8)6202 // llvm.x86.sse2.gpshufh.w(<8 x i16>, i8)6203 // llvm.x86.sse2.pshufl.w(<8 x i16>, i8)6204 case Intrinsic::x86_avx2_pshuf_b:6205 case Intrinsic::x86_sse_pshuf_w:6206 case Intrinsic::x86_ssse3_pshuf_b_128:6207 case Intrinsic::x86_ssse3_pshuf_b:6208 case Intrinsic::x86_avx512_pshuf_b_512:6209 handleIntrinsicByApplyingToShadow(I, I.getIntrinsicID(),6210 /*trailingVerbatimArgs=*/1);6211 break;6212 6213 // AVX512 PMOV: Packed MOV, with truncation6214 // Precisely handled by applying the same intrinsic to the shadow6215 case Intrinsic::x86_avx512_mask_pmov_dw_512:6216 case Intrinsic::x86_avx512_mask_pmov_db_512:6217 case Intrinsic::x86_avx512_mask_pmov_qb_512:6218 case Intrinsic::x86_avx512_mask_pmov_qw_512: {6219 // Intrinsic::x86_avx512_mask_pmov_{qd,wb}_512 were removed in6220 // f608dc1f5775ee880e8ea30e2d06ab5a4a935c226221 handleIntrinsicByApplyingToShadow(I, I.getIntrinsicID(),6222 /*trailingVerbatimArgs=*/1);6223 break;6224 }6225 6226 // AVX512 PMVOV{S,US}: Packed MOV, with signed/unsigned saturation6227 // Approximately handled using the corresponding truncation intrinsic6228 // TODO: improve handleAVX512VectorDownConvert to precisely model saturation6229 case Intrinsic::x86_avx512_mask_pmovs_dw_512:6230 case Intrinsic::x86_avx512_mask_pmovus_dw_512: {6231 handleIntrinsicByApplyingToShadow(I,6232 Intrinsic::x86_avx512_mask_pmov_dw_512,6233 /* trailingVerbatimArgs=*/1);6234 break;6235 }6236 6237 case Intrinsic::x86_avx512_mask_pmovs_db_512:6238 case Intrinsic::x86_avx512_mask_pmovus_db_512: {6239 handleIntrinsicByApplyingToShadow(I,6240 Intrinsic::x86_avx512_mask_pmov_db_512,6241 /* trailingVerbatimArgs=*/1);6242 break;6243 }6244 6245 case Intrinsic::x86_avx512_mask_pmovs_qb_512:6246 case Intrinsic::x86_avx512_mask_pmovus_qb_512: {6247 handleIntrinsicByApplyingToShadow(I,6248 Intrinsic::x86_avx512_mask_pmov_qb_512,6249 /* trailingVerbatimArgs=*/1);6250 break;6251 }6252 6253 case Intrinsic::x86_avx512_mask_pmovs_qw_512:6254 case Intrinsic::x86_avx512_mask_pmovus_qw_512: {6255 handleIntrinsicByApplyingToShadow(I,6256 Intrinsic::x86_avx512_mask_pmov_qw_512,6257 /* trailingVerbatimArgs=*/1);6258 break;6259 }6260 6261 case Intrinsic::x86_avx512_mask_pmovs_qd_512:6262 case Intrinsic::x86_avx512_mask_pmovus_qd_512:6263 case Intrinsic::x86_avx512_mask_pmovs_wb_512:6264 case Intrinsic::x86_avx512_mask_pmovus_wb_512: {6265 // Since Intrinsic::x86_avx512_mask_pmov_{qd,wb}_512 do not exist, we6266 // cannot use handleIntrinsicByApplyingToShadow. Instead, we call the6267 // slow-path handler.6268 handleAVX512VectorDownConvert(I);6269 break;6270 }6271 6272 // AVX512/AVX10 Reciprocal6273 // <16 x float> @llvm.x86.avx512.rsqrt14.ps.5126274 // (<16 x float>, <16 x float>, i16)6275 // <8 x float> @llvm.x86.avx512.rsqrt14.ps.2566276 // (<8 x float>, <8 x float>, i8)6277 // <4 x float> @llvm.x86.avx512.rsqrt14.ps.1286278 // (<4 x float>, <4 x float>, i8)6279 //6280 // <8 x double> @llvm.x86.avx512.rsqrt14.pd.5126281 // (<8 x double>, <8 x double>, i8)6282 // <4 x double> @llvm.x86.avx512.rsqrt14.pd.2566283 // (<4 x double>, <4 x double>, i8)6284 // <2 x double> @llvm.x86.avx512.rsqrt14.pd.1286285 // (<2 x double>, <2 x double>, i8)6286 //6287 // <32 x bfloat> @llvm.x86.avx10.mask.rsqrt.bf16.5126288 // (<32 x bfloat>, <32 x bfloat>, i32)6289 // <16 x bfloat> @llvm.x86.avx10.mask.rsqrt.bf16.2566290 // (<16 x bfloat>, <16 x bfloat>, i16)6291 // <8 x bfloat> @llvm.x86.avx10.mask.rsqrt.bf16.1286292 // (<8 x bfloat>, <8 x bfloat>, i8)6293 //6294 // <32 x half> @llvm.x86.avx512fp16.mask.rsqrt.ph.5126295 // (<32 x half>, <32 x half>, i32)6296 // <16 x half> @llvm.x86.avx512fp16.mask.rsqrt.ph.2566297 // (<16 x half>, <16 x half>, i16)6298 // <8 x half> @llvm.x86.avx512fp16.mask.rsqrt.ph.1286299 // (<8 x half>, <8 x half>, i8)6300 //6301 // TODO: 3-operand variants are not handled:6302 // <2 x double> @llvm.x86.avx512.rsqrt14.sd6303 // (<2 x double>, <2 x double>, <2 x double>, i8)6304 // <4 x float> @llvm.x86.avx512.rsqrt14.ss6305 // (<4 x float>, <4 x float>, <4 x float>, i8)6306 // <8 x half> @llvm.x86.avx512fp16.mask.rsqrt.sh6307 // (<8 x half>, <8 x half>, <8 x half>, i8)6308 case Intrinsic::x86_avx512_rsqrt14_ps_512:6309 case Intrinsic::x86_avx512_rsqrt14_ps_256:6310 case Intrinsic::x86_avx512_rsqrt14_ps_128:6311 case Intrinsic::x86_avx512_rsqrt14_pd_512:6312 case Intrinsic::x86_avx512_rsqrt14_pd_256:6313 case Intrinsic::x86_avx512_rsqrt14_pd_128:6314 case Intrinsic::x86_avx10_mask_rsqrt_bf16_512:6315 case Intrinsic::x86_avx10_mask_rsqrt_bf16_256:6316 case Intrinsic::x86_avx10_mask_rsqrt_bf16_128:6317 case Intrinsic::x86_avx512fp16_mask_rsqrt_ph_512:6318 case Intrinsic::x86_avx512fp16_mask_rsqrt_ph_256:6319 case Intrinsic::x86_avx512fp16_mask_rsqrt_ph_128:6320 handleAVX512VectorGenericMaskedFP(I, /*AIndex=*/0, /*WriteThruIndex=*/1,6321 /*MaskIndex=*/2);6322 break;6323 6324 // AVX512/AVX10 Reciprocal Square Root6325 // <16 x float> @llvm.x86.avx512.rcp14.ps.5126326 // (<16 x float>, <16 x float>, i16)6327 // <8 x float> @llvm.x86.avx512.rcp14.ps.2566328 // (<8 x float>, <8 x float>, i8)6329 // <4 x float> @llvm.x86.avx512.rcp14.ps.1286330 // (<4 x float>, <4 x float>, i8)6331 //6332 // <8 x double> @llvm.x86.avx512.rcp14.pd.5126333 // (<8 x double>, <8 x double>, i8)6334 // <4 x double> @llvm.x86.avx512.rcp14.pd.2566335 // (<4 x double>, <4 x double>, i8)6336 // <2 x double> @llvm.x86.avx512.rcp14.pd.1286337 // (<2 x double>, <2 x double>, i8)6338 //6339 // <32 x bfloat> @llvm.x86.avx10.mask.rcp.bf16.5126340 // (<32 x bfloat>, <32 x bfloat>, i32)6341 // <16 x bfloat> @llvm.x86.avx10.mask.rcp.bf16.2566342 // (<16 x bfloat>, <16 x bfloat>, i16)6343 // <8 x bfloat> @llvm.x86.avx10.mask.rcp.bf16.1286344 // (<8 x bfloat>, <8 x bfloat>, i8)6345 //6346 // <32 x half> @llvm.x86.avx512fp16.mask.rcp.ph.5126347 // (<32 x half>, <32 x half>, i32)6348 // <16 x half> @llvm.x86.avx512fp16.mask.rcp.ph.2566349 // (<16 x half>, <16 x half>, i16)6350 // <8 x half> @llvm.x86.avx512fp16.mask.rcp.ph.1286351 // (<8 x half>, <8 x half>, i8)6352 //6353 // TODO: 3-operand variants are not handled:6354 // <2 x double> @llvm.x86.avx512.rcp14.sd6355 // (<2 x double>, <2 x double>, <2 x double>, i8)6356 // <4 x float> @llvm.x86.avx512.rcp14.ss6357 // (<4 x float>, <4 x float>, <4 x float>, i8)6358 // <8 x half> @llvm.x86.avx512fp16.mask.rcp.sh6359 // (<8 x half>, <8 x half>, <8 x half>, i8)6360 case Intrinsic::x86_avx512_rcp14_ps_512:6361 case Intrinsic::x86_avx512_rcp14_ps_256:6362 case Intrinsic::x86_avx512_rcp14_ps_128:6363 case Intrinsic::x86_avx512_rcp14_pd_512:6364 case Intrinsic::x86_avx512_rcp14_pd_256:6365 case Intrinsic::x86_avx512_rcp14_pd_128:6366 case Intrinsic::x86_avx10_mask_rcp_bf16_512:6367 case Intrinsic::x86_avx10_mask_rcp_bf16_256:6368 case Intrinsic::x86_avx10_mask_rcp_bf16_128:6369 case Intrinsic::x86_avx512fp16_mask_rcp_ph_512:6370 case Intrinsic::x86_avx512fp16_mask_rcp_ph_256:6371 case Intrinsic::x86_avx512fp16_mask_rcp_ph_128:6372 handleAVX512VectorGenericMaskedFP(I, /*AIndex=*/0, /*WriteThruIndex=*/1,6373 /*MaskIndex=*/2);6374 break;6375 6376 // <32 x half> @llvm.x86.avx512fp16.mask.rndscale.ph.5126377 // (<32 x half>, i32, <32 x half>, i32, i32)6378 // <16 x half> @llvm.x86.avx512fp16.mask.rndscale.ph.2566379 // (<16 x half>, i32, <16 x half>, i32, i16)6380 // <8 x half> @llvm.x86.avx512fp16.mask.rndscale.ph.1286381 // (<8 x half>, i32, <8 x half>, i32, i8)6382 //6383 // <16 x float> @llvm.x86.avx512.mask.rndscale.ps.5126384 // (<16 x float>, i32, <16 x float>, i16, i32)6385 // <8 x float> @llvm.x86.avx512.mask.rndscale.ps.2566386 // (<8 x float>, i32, <8 x float>, i8)6387 // <4 x float> @llvm.x86.avx512.mask.rndscale.ps.1286388 // (<4 x float>, i32, <4 x float>, i8)6389 //6390 // <8 x double> @llvm.x86.avx512.mask.rndscale.pd.5126391 // (<8 x double>, i32, <8 x double>, i8, i32)6392 // A Imm WriteThru Mask Rounding6393 // <4 x double> @llvm.x86.avx512.mask.rndscale.pd.2566394 // (<4 x double>, i32, <4 x double>, i8)6395 // <2 x double> @llvm.x86.avx512.mask.rndscale.pd.1286396 // (<2 x double>, i32, <2 x double>, i8)6397 // A Imm WriteThru Mask6398 //6399 // <32 x bfloat> @llvm.x86.avx10.mask.rndscale.bf16.5126400 // (<32 x bfloat>, i32, <32 x bfloat>, i32)6401 // <16 x bfloat> @llvm.x86.avx10.mask.rndscale.bf16.2566402 // (<16 x bfloat>, i32, <16 x bfloat>, i16)6403 // <8 x bfloat> @llvm.x86.avx10.mask.rndscale.bf16.1286404 // (<8 x bfloat>, i32, <8 x bfloat>, i8)6405 //6406 // Not supported: three vectors6407 // - <8 x half> @llvm.x86.avx512fp16.mask.rndscale.sh6408 // (<8 x half>, <8 x half>,<8 x half>, i8, i32, i32)6409 // - <4 x float> @llvm.x86.avx512.mask.rndscale.ss6410 // (<4 x float>, <4 x float>, <4 x float>, i8, i32, i32)6411 // - <2 x double> @llvm.x86.avx512.mask.rndscale.sd6412 // (<2 x double>, <2 x double>, <2 x double>, i8, i32,6413 // i32)6414 // A B WriteThru Mask Imm6415 // Rounding6416 case Intrinsic::x86_avx512fp16_mask_rndscale_ph_512:6417 case Intrinsic::x86_avx512fp16_mask_rndscale_ph_256:6418 case Intrinsic::x86_avx512fp16_mask_rndscale_ph_128:6419 case Intrinsic::x86_avx512_mask_rndscale_ps_512:6420 case Intrinsic::x86_avx512_mask_rndscale_ps_256:6421 case Intrinsic::x86_avx512_mask_rndscale_ps_128:6422 case Intrinsic::x86_avx512_mask_rndscale_pd_512:6423 case Intrinsic::x86_avx512_mask_rndscale_pd_256:6424 case Intrinsic::x86_avx512_mask_rndscale_pd_128:6425 case Intrinsic::x86_avx10_mask_rndscale_bf16_512:6426 case Intrinsic::x86_avx10_mask_rndscale_bf16_256:6427 case Intrinsic::x86_avx10_mask_rndscale_bf16_128:6428 handleAVX512VectorGenericMaskedFP(I, /*AIndex=*/0, /*WriteThruIndex=*/2,6429 /*MaskIndex=*/3);6430 break;6431 6432 // AVX512 FP16 Arithmetic6433 case Intrinsic::x86_avx512fp16_mask_add_sh_round:6434 case Intrinsic::x86_avx512fp16_mask_sub_sh_round:6435 case Intrinsic::x86_avx512fp16_mask_mul_sh_round:6436 case Intrinsic::x86_avx512fp16_mask_div_sh_round:6437 case Intrinsic::x86_avx512fp16_mask_max_sh_round:6438 case Intrinsic::x86_avx512fp16_mask_min_sh_round: {6439 visitGenericScalarHalfwordInst(I);6440 break;6441 }6442 6443 // AVX Galois Field New Instructions6444 case Intrinsic::x86_vgf2p8affineqb_128:6445 case Intrinsic::x86_vgf2p8affineqb_256:6446 case Intrinsic::x86_vgf2p8affineqb_512:6447 handleAVXGF2P8Affine(I);6448 break;6449 6450 default:6451 return false;6452 }6453 6454 return true;6455 }6456 6457 bool maybeHandleArmSIMDIntrinsic(IntrinsicInst &I) {6458 switch (I.getIntrinsicID()) {6459 case Intrinsic::aarch64_neon_rshrn:6460 case Intrinsic::aarch64_neon_sqrshl:6461 case Intrinsic::aarch64_neon_sqrshrn:6462 case Intrinsic::aarch64_neon_sqrshrun:6463 case Intrinsic::aarch64_neon_sqshl:6464 case Intrinsic::aarch64_neon_sqshlu:6465 case Intrinsic::aarch64_neon_sqshrn:6466 case Intrinsic::aarch64_neon_sqshrun:6467 case Intrinsic::aarch64_neon_srshl:6468 case Intrinsic::aarch64_neon_sshl:6469 case Intrinsic::aarch64_neon_uqrshl:6470 case Intrinsic::aarch64_neon_uqrshrn:6471 case Intrinsic::aarch64_neon_uqshl:6472 case Intrinsic::aarch64_neon_uqshrn:6473 case Intrinsic::aarch64_neon_urshl:6474 case Intrinsic::aarch64_neon_ushl:6475 // Not handled here: aarch64_neon_vsli (vector shift left and insert)6476 handleVectorShiftIntrinsic(I, /* Variable */ false);6477 break;6478 6479 // TODO: handling max/min similarly to AND/OR may be more precise6480 // Floating-Point Maximum/Minimum Pairwise6481 case Intrinsic::aarch64_neon_fmaxp:6482 case Intrinsic::aarch64_neon_fminp:6483 // Floating-Point Maximum/Minimum Number Pairwise6484 case Intrinsic::aarch64_neon_fmaxnmp:6485 case Intrinsic::aarch64_neon_fminnmp:6486 // Signed/Unsigned Maximum/Minimum Pairwise6487 case Intrinsic::aarch64_neon_smaxp:6488 case Intrinsic::aarch64_neon_sminp:6489 case Intrinsic::aarch64_neon_umaxp:6490 case Intrinsic::aarch64_neon_uminp:6491 // Add Pairwise6492 case Intrinsic::aarch64_neon_addp:6493 // Floating-point Add Pairwise6494 case Intrinsic::aarch64_neon_faddp:6495 // Add Long Pairwise6496 case Intrinsic::aarch64_neon_saddlp:6497 case Intrinsic::aarch64_neon_uaddlp: {6498 handlePairwiseShadowOrIntrinsic(I, /*Shards=*/1);6499 break;6500 }6501 6502 // Floating-point Convert to integer, rounding to nearest with ties to Away6503 case Intrinsic::aarch64_neon_fcvtas:6504 case Intrinsic::aarch64_neon_fcvtau:6505 // Floating-point convert to integer, rounding toward minus infinity6506 case Intrinsic::aarch64_neon_fcvtms:6507 case Intrinsic::aarch64_neon_fcvtmu:6508 // Floating-point convert to integer, rounding to nearest with ties to even6509 case Intrinsic::aarch64_neon_fcvtns:6510 case Intrinsic::aarch64_neon_fcvtnu:6511 // Floating-point convert to integer, rounding toward plus infinity6512 case Intrinsic::aarch64_neon_fcvtps:6513 case Intrinsic::aarch64_neon_fcvtpu:6514 // Floating-point Convert to integer, rounding toward Zero6515 case Intrinsic::aarch64_neon_fcvtzs:6516 case Intrinsic::aarch64_neon_fcvtzu:6517 // Floating-point convert to lower precision narrow, rounding to odd6518 case Intrinsic::aarch64_neon_fcvtxn: {6519 handleNEONVectorConvertIntrinsic(I);6520 break;6521 }6522 6523 // Add reduction to scalar6524 case Intrinsic::aarch64_neon_faddv:6525 case Intrinsic::aarch64_neon_saddv:6526 case Intrinsic::aarch64_neon_uaddv:6527 // Signed/Unsigned min/max (Vector)6528 // TODO: handling similarly to AND/OR may be more precise.6529 case Intrinsic::aarch64_neon_smaxv:6530 case Intrinsic::aarch64_neon_sminv:6531 case Intrinsic::aarch64_neon_umaxv:6532 case Intrinsic::aarch64_neon_uminv:6533 // Floating-point min/max (vector)6534 // The f{min,max}"nm"v variants handle NaN differently than f{min,max}v,6535 // but our shadow propagation is the same.6536 case Intrinsic::aarch64_neon_fmaxv:6537 case Intrinsic::aarch64_neon_fminv:6538 case Intrinsic::aarch64_neon_fmaxnmv:6539 case Intrinsic::aarch64_neon_fminnmv:6540 // Sum long across vector6541 case Intrinsic::aarch64_neon_saddlv:6542 case Intrinsic::aarch64_neon_uaddlv:6543 handleVectorReduceIntrinsic(I, /*AllowShadowCast=*/true);6544 break;6545 6546 case Intrinsic::aarch64_neon_ld1x2:6547 case Intrinsic::aarch64_neon_ld1x3:6548 case Intrinsic::aarch64_neon_ld1x4:6549 case Intrinsic::aarch64_neon_ld2:6550 case Intrinsic::aarch64_neon_ld3:6551 case Intrinsic::aarch64_neon_ld4:6552 case Intrinsic::aarch64_neon_ld2r:6553 case Intrinsic::aarch64_neon_ld3r:6554 case Intrinsic::aarch64_neon_ld4r: {6555 handleNEONVectorLoad(I, /*WithLane=*/false);6556 break;6557 }6558 6559 case Intrinsic::aarch64_neon_ld2lane:6560 case Intrinsic::aarch64_neon_ld3lane:6561 case Intrinsic::aarch64_neon_ld4lane: {6562 handleNEONVectorLoad(I, /*WithLane=*/true);6563 break;6564 }6565 6566 // Saturating extract narrow6567 case Intrinsic::aarch64_neon_sqxtn:6568 case Intrinsic::aarch64_neon_sqxtun:6569 case Intrinsic::aarch64_neon_uqxtn:6570 // These only have one argument, but we (ab)use handleShadowOr because it6571 // does work on single argument intrinsics and will typecast the shadow6572 // (and update the origin).6573 handleShadowOr(I);6574 break;6575 6576 case Intrinsic::aarch64_neon_st1x2:6577 case Intrinsic::aarch64_neon_st1x3:6578 case Intrinsic::aarch64_neon_st1x4:6579 case Intrinsic::aarch64_neon_st2:6580 case Intrinsic::aarch64_neon_st3:6581 case Intrinsic::aarch64_neon_st4: {6582 handleNEONVectorStoreIntrinsic(I, false);6583 break;6584 }6585 6586 case Intrinsic::aarch64_neon_st2lane:6587 case Intrinsic::aarch64_neon_st3lane:6588 case Intrinsic::aarch64_neon_st4lane: {6589 handleNEONVectorStoreIntrinsic(I, true);6590 break;6591 }6592 6593 // Arm NEON vector table intrinsics have the source/table register(s) as6594 // arguments, followed by the index register. They return the output.6595 //6596 // 'TBL writes a zero if an index is out-of-range, while TBX leaves the6597 // original value unchanged in the destination register.'6598 // Conveniently, zero denotes a clean shadow, which means out-of-range6599 // indices for TBL will initialize the user data with zero and also clean6600 // the shadow. (For TBX, neither the user data nor the shadow will be6601 // updated, which is also correct.)6602 case Intrinsic::aarch64_neon_tbl1:6603 case Intrinsic::aarch64_neon_tbl2:6604 case Intrinsic::aarch64_neon_tbl3:6605 case Intrinsic::aarch64_neon_tbl4:6606 case Intrinsic::aarch64_neon_tbx1:6607 case Intrinsic::aarch64_neon_tbx2:6608 case Intrinsic::aarch64_neon_tbx3:6609 case Intrinsic::aarch64_neon_tbx4: {6610 // The last trailing argument (index register) should be handled verbatim6611 handleIntrinsicByApplyingToShadow(6612 I, /*shadowIntrinsicID=*/I.getIntrinsicID(),6613 /*trailingVerbatimArgs*/ 1);6614 break;6615 }6616 6617 case Intrinsic::aarch64_neon_fmulx:6618 case Intrinsic::aarch64_neon_pmul:6619 case Intrinsic::aarch64_neon_pmull:6620 case Intrinsic::aarch64_neon_smull:6621 case Intrinsic::aarch64_neon_pmull64:6622 case Intrinsic::aarch64_neon_umull: {6623 handleNEONVectorMultiplyIntrinsic(I);6624 break;6625 }6626 6627 default:6628 return false;6629 }6630 6631 return true;6632 }6633 6634 void visitIntrinsicInst(IntrinsicInst &I) {6635 if (maybeHandleCrossPlatformIntrinsic(I))6636 return;6637 6638 if (maybeHandleX86SIMDIntrinsic(I))6639 return;6640 6641 if (maybeHandleArmSIMDIntrinsic(I))6642 return;6643 6644 if (maybeHandleUnknownIntrinsic(I))6645 return;6646 6647 visitInstruction(I);6648 }6649 6650 void visitLibAtomicLoad(CallBase &CB) {6651 // Since we use getNextNode here, we can't have CB terminate the BB.6652 assert(isa<CallInst>(CB));6653 6654 IRBuilder<> IRB(&CB);6655 Value *Size = CB.getArgOperand(0);6656 Value *SrcPtr = CB.getArgOperand(1);6657 Value *DstPtr = CB.getArgOperand(2);6658 Value *Ordering = CB.getArgOperand(3);6659 // Convert the call to have at least Acquire ordering to make sure6660 // the shadow operations aren't reordered before it.6661 Value *NewOrdering =6662 IRB.CreateExtractElement(makeAddAcquireOrderingTable(IRB), Ordering);6663 CB.setArgOperand(3, NewOrdering);6664 6665 NextNodeIRBuilder NextIRB(&CB);6666 Value *SrcShadowPtr, *SrcOriginPtr;6667 std::tie(SrcShadowPtr, SrcOriginPtr) =6668 getShadowOriginPtr(SrcPtr, NextIRB, NextIRB.getInt8Ty(), Align(1),6669 /*isStore*/ false);6670 Value *DstShadowPtr =6671 getShadowOriginPtr(DstPtr, NextIRB, NextIRB.getInt8Ty(), Align(1),6672 /*isStore*/ true)6673 .first;6674 6675 NextIRB.CreateMemCpy(DstShadowPtr, Align(1), SrcShadowPtr, Align(1), Size);6676 if (MS.TrackOrigins) {6677 Value *SrcOrigin = NextIRB.CreateAlignedLoad(MS.OriginTy, SrcOriginPtr,6678 kMinOriginAlignment);6679 Value *NewOrigin = updateOrigin(SrcOrigin, NextIRB);6680 NextIRB.CreateCall(MS.MsanSetOriginFn, {DstPtr, Size, NewOrigin});6681 }6682 }6683 6684 void visitLibAtomicStore(CallBase &CB) {6685 IRBuilder<> IRB(&CB);6686 Value *Size = CB.getArgOperand(0);6687 Value *DstPtr = CB.getArgOperand(2);6688 Value *Ordering = CB.getArgOperand(3);6689 // Convert the call to have at least Release ordering to make sure6690 // the shadow operations aren't reordered after it.6691 Value *NewOrdering =6692 IRB.CreateExtractElement(makeAddReleaseOrderingTable(IRB), Ordering);6693 CB.setArgOperand(3, NewOrdering);6694 6695 Value *DstShadowPtr =6696 getShadowOriginPtr(DstPtr, IRB, IRB.getInt8Ty(), Align(1),6697 /*isStore*/ true)6698 .first;6699 6700 // Atomic store always paints clean shadow/origin. See file header.6701 IRB.CreateMemSet(DstShadowPtr, getCleanShadow(IRB.getInt8Ty()), Size,6702 Align(1));6703 }6704 6705 void visitCallBase(CallBase &CB) {6706 assert(!CB.getMetadata(LLVMContext::MD_nosanitize));6707 if (CB.isInlineAsm()) {6708 // For inline asm (either a call to asm function, or callbr instruction),6709 // do the usual thing: check argument shadow and mark all outputs as6710 // clean. Note that any side effects of the inline asm that are not6711 // immediately visible in its constraints are not handled.6712 if (ClHandleAsmConservative)6713 visitAsmInstruction(CB);6714 else6715 visitInstruction(CB);6716 return;6717 }6718 LibFunc LF;6719 if (TLI->getLibFunc(CB, LF)) {6720 // libatomic.a functions need to have special handling because there isn't6721 // a good way to intercept them or compile the library with6722 // instrumentation.6723 switch (LF) {6724 case LibFunc_atomic_load:6725 if (!isa<CallInst>(CB)) {6726 llvm::errs() << "MSAN -- cannot instrument invoke of libatomic load."6727 "Ignoring!\n";6728 break;6729 }6730 visitLibAtomicLoad(CB);6731 return;6732 case LibFunc_atomic_store:6733 visitLibAtomicStore(CB);6734 return;6735 default:6736 break;6737 }6738 }6739 6740 if (auto *Call = dyn_cast<CallInst>(&CB)) {6741 assert(!isa<IntrinsicInst>(Call) && "intrinsics are handled elsewhere");6742 6743 // We are going to insert code that relies on the fact that the callee6744 // will become a non-readonly function after it is instrumented by us. To6745 // prevent this code from being optimized out, mark that function6746 // non-readonly in advance.6747 // TODO: We can likely do better than dropping memory() completely here.6748 AttributeMask B;6749 B.addAttribute(Attribute::Memory).addAttribute(Attribute::Speculatable);6750 6751 Call->removeFnAttrs(B);6752 if (Function *Func = Call->getCalledFunction()) {6753 Func->removeFnAttrs(B);6754 }6755 6756 maybeMarkSanitizerLibraryCallNoBuiltin(Call, TLI);6757 }6758 IRBuilder<> IRB(&CB);6759 bool MayCheckCall = MS.EagerChecks;6760 if (Function *Func = CB.getCalledFunction()) {6761 // __sanitizer_unaligned_{load,store} functions may be called by users6762 // and always expects shadows in the TLS. So don't check them.6763 MayCheckCall &= !Func->getName().starts_with("__sanitizer_unaligned_");6764 }6765 6766 unsigned ArgOffset = 0;6767 LLVM_DEBUG(dbgs() << " CallSite: " << CB << "\n");6768 for (const auto &[i, A] : llvm::enumerate(CB.args())) {6769 if (!A->getType()->isSized()) {6770 LLVM_DEBUG(dbgs() << "Arg " << i << " is not sized: " << CB << "\n");6771 continue;6772 }6773 6774 if (A->getType()->isScalableTy()) {6775 LLVM_DEBUG(dbgs() << "Arg " << i << " is vscale: " << CB << "\n");6776 // Handle as noundef, but don't reserve tls slots.6777 insertCheckShadowOf(A, &CB);6778 continue;6779 }6780 6781 unsigned Size = 0;6782 const DataLayout &DL = F.getDataLayout();6783 6784 bool ByVal = CB.paramHasAttr(i, Attribute::ByVal);6785 bool NoUndef = CB.paramHasAttr(i, Attribute::NoUndef);6786 bool EagerCheck = MayCheckCall && !ByVal && NoUndef;6787 6788 if (EagerCheck) {6789 insertCheckShadowOf(A, &CB);6790 Size = DL.getTypeAllocSize(A->getType());6791 } else {6792 [[maybe_unused]] Value *Store = nullptr;6793 // Compute the Shadow for arg even if it is ByVal, because6794 // in that case getShadow() will copy the actual arg shadow to6795 // __msan_param_tls.6796 Value *ArgShadow = getShadow(A);6797 Value *ArgShadowBase = getShadowPtrForArgument(IRB, ArgOffset);6798 LLVM_DEBUG(dbgs() << " Arg#" << i << ": " << *A6799 << " Shadow: " << *ArgShadow << "\n");6800 if (ByVal) {6801 // ByVal requires some special handling as it's too big for a single6802 // load6803 assert(A->getType()->isPointerTy() &&6804 "ByVal argument is not a pointer!");6805 Size = DL.getTypeAllocSize(CB.getParamByValType(i));6806 if (ArgOffset + Size > kParamTLSSize)6807 break;6808 const MaybeAlign ParamAlignment(CB.getParamAlign(i));6809 MaybeAlign Alignment = std::nullopt;6810 if (ParamAlignment)6811 Alignment = std::min(*ParamAlignment, kShadowTLSAlignment);6812 Value *AShadowPtr, *AOriginPtr;6813 std::tie(AShadowPtr, AOriginPtr) =6814 getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), Alignment,6815 /*isStore*/ false);6816 if (!PropagateShadow) {6817 Store = IRB.CreateMemSet(ArgShadowBase,6818 Constant::getNullValue(IRB.getInt8Ty()),6819 Size, Alignment);6820 } else {6821 Store = IRB.CreateMemCpy(ArgShadowBase, Alignment, AShadowPtr,6822 Alignment, Size);6823 if (MS.TrackOrigins) {6824 Value *ArgOriginBase = getOriginPtrForArgument(IRB, ArgOffset);6825 // FIXME: OriginSize should be:6826 // alignTo(A % kMinOriginAlignment + Size, kMinOriginAlignment)6827 unsigned OriginSize = alignTo(Size, kMinOriginAlignment);6828 IRB.CreateMemCpy(6829 ArgOriginBase,6830 /* by origin_tls[ArgOffset] */ kMinOriginAlignment,6831 AOriginPtr,6832 /* by getShadowOriginPtr */ kMinOriginAlignment, OriginSize);6833 }6834 }6835 } else {6836 // Any other parameters mean we need bit-grained tracking of uninit6837 // data6838 Size = DL.getTypeAllocSize(A->getType());6839 if (ArgOffset + Size > kParamTLSSize)6840 break;6841 Store = IRB.CreateAlignedStore(ArgShadow, ArgShadowBase,6842 kShadowTLSAlignment);6843 Constant *Cst = dyn_cast<Constant>(ArgShadow);6844 if (MS.TrackOrigins && !(Cst && Cst->isNullValue())) {6845 IRB.CreateStore(getOrigin(A),6846 getOriginPtrForArgument(IRB, ArgOffset));6847 }6848 }6849 assert(Store != nullptr);6850 LLVM_DEBUG(dbgs() << " Param:" << *Store << "\n");6851 }6852 assert(Size != 0);6853 ArgOffset += alignTo(Size, kShadowTLSAlignment);6854 }6855 LLVM_DEBUG(dbgs() << " done with call args\n");6856 6857 FunctionType *FT = CB.getFunctionType();6858 if (FT->isVarArg()) {6859 VAHelper->visitCallBase(CB, IRB);6860 }6861 6862 // Now, get the shadow for the RetVal.6863 if (!CB.getType()->isSized())6864 return;6865 // Don't emit the epilogue for musttail call returns.6866 if (isa<CallInst>(CB) && cast<CallInst>(CB).isMustTailCall())6867 return;6868 6869 if (MayCheckCall && CB.hasRetAttr(Attribute::NoUndef)) {6870 setShadow(&CB, getCleanShadow(&CB));6871 setOrigin(&CB, getCleanOrigin());6872 return;6873 }6874 6875 IRBuilder<> IRBBefore(&CB);6876 // Until we have full dynamic coverage, make sure the retval shadow is 0.6877 Value *Base = getShadowPtrForRetval(IRBBefore);6878 IRBBefore.CreateAlignedStore(getCleanShadow(&CB), Base,6879 kShadowTLSAlignment);6880 BasicBlock::iterator NextInsn;6881 if (isa<CallInst>(CB)) {6882 NextInsn = ++CB.getIterator();6883 assert(NextInsn != CB.getParent()->end());6884 } else {6885 BasicBlock *NormalDest = cast<InvokeInst>(CB).getNormalDest();6886 if (!NormalDest->getSinglePredecessor()) {6887 // FIXME: this case is tricky, so we are just conservative here.6888 // Perhaps we need to split the edge between this BB and NormalDest,6889 // but a naive attempt to use SplitEdge leads to a crash.6890 setShadow(&CB, getCleanShadow(&CB));6891 setOrigin(&CB, getCleanOrigin());6892 return;6893 }6894 // FIXME: NextInsn is likely in a basic block that has not been visited6895 // yet. Anything inserted there will be instrumented by MSan later!6896 NextInsn = NormalDest->getFirstInsertionPt();6897 assert(NextInsn != NormalDest->end() &&6898 "Could not find insertion point for retval shadow load");6899 }6900 IRBuilder<> IRBAfter(&*NextInsn);6901 Value *RetvalShadow = IRBAfter.CreateAlignedLoad(6902 getShadowTy(&CB), getShadowPtrForRetval(IRBAfter), kShadowTLSAlignment,6903 "_msret");6904 setShadow(&CB, RetvalShadow);6905 if (MS.TrackOrigins)6906 setOrigin(&CB, IRBAfter.CreateLoad(MS.OriginTy, getOriginPtrForRetval()));6907 }6908 6909 bool isAMustTailRetVal(Value *RetVal) {6910 if (auto *I = dyn_cast<BitCastInst>(RetVal)) {6911 RetVal = I->getOperand(0);6912 }6913 if (auto *I = dyn_cast<CallInst>(RetVal)) {6914 return I->isMustTailCall();6915 }6916 return false;6917 }6918 6919 void visitReturnInst(ReturnInst &I) {6920 IRBuilder<> IRB(&I);6921 Value *RetVal = I.getReturnValue();6922 if (!RetVal)6923 return;6924 // Don't emit the epilogue for musttail call returns.6925 if (isAMustTailRetVal(RetVal))6926 return;6927 Value *ShadowPtr = getShadowPtrForRetval(IRB);6928 bool HasNoUndef = F.hasRetAttribute(Attribute::NoUndef);6929 bool StoreShadow = !(MS.EagerChecks && HasNoUndef);6930 // FIXME: Consider using SpecialCaseList to specify a list of functions that6931 // must always return fully initialized values. For now, we hardcode "main".6932 bool EagerCheck = (MS.EagerChecks && HasNoUndef) || (F.getName() == "main");6933 6934 Value *Shadow = getShadow(RetVal);6935 bool StoreOrigin = true;6936 if (EagerCheck) {6937 insertCheckShadowOf(RetVal, &I);6938 Shadow = getCleanShadow(RetVal);6939 StoreOrigin = false;6940 }6941 6942 // The caller may still expect information passed over TLS if we pass our6943 // check6944 if (StoreShadow) {6945 IRB.CreateAlignedStore(Shadow, ShadowPtr, kShadowTLSAlignment);6946 if (MS.TrackOrigins && StoreOrigin)6947 IRB.CreateStore(getOrigin(RetVal), getOriginPtrForRetval());6948 }6949 }6950 6951 void visitPHINode(PHINode &I) {6952 IRBuilder<> IRB(&I);6953 if (!PropagateShadow) {6954 setShadow(&I, getCleanShadow(&I));6955 setOrigin(&I, getCleanOrigin());6956 return;6957 }6958 6959 ShadowPHINodes.push_back(&I);6960 setShadow(&I, IRB.CreatePHI(getShadowTy(&I), I.getNumIncomingValues(),6961 "_msphi_s"));6962 if (MS.TrackOrigins)6963 setOrigin(6964 &I, IRB.CreatePHI(MS.OriginTy, I.getNumIncomingValues(), "_msphi_o"));6965 }6966 6967 Value *getLocalVarIdptr(AllocaInst &I) {6968 ConstantInt *IntConst =6969 ConstantInt::get(Type::getInt32Ty((*F.getParent()).getContext()), 0);6970 return new GlobalVariable(*F.getParent(), IntConst->getType(),6971 /*isConstant=*/false, GlobalValue::PrivateLinkage,6972 IntConst);6973 }6974 6975 Value *getLocalVarDescription(AllocaInst &I) {6976 return createPrivateConstGlobalForString(*F.getParent(), I.getName());6977 }6978 6979 void poisonAllocaUserspace(AllocaInst &I, IRBuilder<> &IRB, Value *Len) {6980 if (PoisonStack && ClPoisonStackWithCall) {6981 IRB.CreateCall(MS.MsanPoisonStackFn, {&I, Len});6982 } else {6983 Value *ShadowBase, *OriginBase;6984 std::tie(ShadowBase, OriginBase) = getShadowOriginPtr(6985 &I, IRB, IRB.getInt8Ty(), Align(1), /*isStore*/ true);6986 6987 Value *PoisonValue = IRB.getInt8(PoisonStack ? ClPoisonStackPattern : 0);6988 IRB.CreateMemSet(ShadowBase, PoisonValue, Len, I.getAlign());6989 }6990 6991 if (PoisonStack && MS.TrackOrigins) {6992 Value *Idptr = getLocalVarIdptr(I);6993 if (ClPrintStackNames) {6994 Value *Descr = getLocalVarDescription(I);6995 IRB.CreateCall(MS.MsanSetAllocaOriginWithDescriptionFn,6996 {&I, Len, Idptr, Descr});6997 } else {6998 IRB.CreateCall(MS.MsanSetAllocaOriginNoDescriptionFn, {&I, Len, Idptr});6999 }7000 }7001 }7002 7003 void poisonAllocaKmsan(AllocaInst &I, IRBuilder<> &IRB, Value *Len) {7004 Value *Descr = getLocalVarDescription(I);7005 if (PoisonStack) {7006 IRB.CreateCall(MS.MsanPoisonAllocaFn, {&I, Len, Descr});7007 } else {7008 IRB.CreateCall(MS.MsanUnpoisonAllocaFn, {&I, Len});7009 }7010 }7011 7012 void instrumentAlloca(AllocaInst &I, Instruction *InsPoint = nullptr) {7013 if (!InsPoint)7014 InsPoint = &I;7015 NextNodeIRBuilder IRB(InsPoint);7016 const DataLayout &DL = F.getDataLayout();7017 TypeSize TS = DL.getTypeAllocSize(I.getAllocatedType());7018 Value *Len = IRB.CreateTypeSize(MS.IntptrTy, TS);7019 if (I.isArrayAllocation())7020 Len = IRB.CreateMul(Len,7021 IRB.CreateZExtOrTrunc(I.getArraySize(), MS.IntptrTy));7022 7023 if (MS.CompileKernel)7024 poisonAllocaKmsan(I, IRB, Len);7025 else7026 poisonAllocaUserspace(I, IRB, Len);7027 }7028 7029 void visitAllocaInst(AllocaInst &I) {7030 setShadow(&I, getCleanShadow(&I));7031 setOrigin(&I, getCleanOrigin());7032 // We'll get to this alloca later unless it's poisoned at the corresponding7033 // llvm.lifetime.start.7034 AllocaSet.insert(&I);7035 }7036 7037 void visitSelectInst(SelectInst &I) {7038 // a = select b, c, d7039 Value *B = I.getCondition();7040 Value *C = I.getTrueValue();7041 Value *D = I.getFalseValue();7042 7043 handleSelectLikeInst(I, B, C, D);7044 }7045 7046 void handleSelectLikeInst(Instruction &I, Value *B, Value *C, Value *D) {7047 IRBuilder<> IRB(&I);7048 7049 Value *Sb = getShadow(B);7050 Value *Sc = getShadow(C);7051 Value *Sd = getShadow(D);7052 7053 Value *Ob = MS.TrackOrigins ? getOrigin(B) : nullptr;7054 Value *Oc = MS.TrackOrigins ? getOrigin(C) : nullptr;7055 Value *Od = MS.TrackOrigins ? getOrigin(D) : nullptr;7056 7057 // Result shadow if condition shadow is 0.7058 Value *Sa0 = IRB.CreateSelect(B, Sc, Sd);7059 Value *Sa1;7060 if (I.getType()->isAggregateType()) {7061 // To avoid "sign extending" i1 to an arbitrary aggregate type, we just do7062 // an extra "select". This results in much more compact IR.7063 // Sa = select Sb, poisoned, (select b, Sc, Sd)7064 Sa1 = getPoisonedShadow(getShadowTy(I.getType()));7065 } else if (isScalableNonVectorType(I.getType())) {7066 // This is intended to handle target("aarch64.svcount"), which can't be7067 // handled in the else branch because of incompatibility with CreateXor7068 // ("The supported LLVM operations on this type are limited to load,7069 // store, phi, select and alloca instructions").7070 7071 // TODO: this currently underapproximates. Use Arm SVE EOR in the else7072 // branch as needed instead.7073 Sa1 = getCleanShadow(getShadowTy(I.getType()));7074 } else {7075 // Sa = select Sb, [ (c^d) | Sc | Sd ], [ b ? Sc : Sd ]7076 // If Sb (condition is poisoned), look for bits in c and d that are equal7077 // and both unpoisoned.7078 // If !Sb (condition is unpoisoned), simply pick one of Sc and Sd.7079 7080 // Cast arguments to shadow-compatible type.7081 C = CreateAppToShadowCast(IRB, C);7082 D = CreateAppToShadowCast(IRB, D);7083 7084 // Result shadow if condition shadow is 1.7085 Sa1 = IRB.CreateOr({IRB.CreateXor(C, D), Sc, Sd});7086 }7087 Value *Sa = IRB.CreateSelect(Sb, Sa1, Sa0, "_msprop_select");7088 setShadow(&I, Sa);7089 if (MS.TrackOrigins) {7090 // Origins are always i32, so any vector conditions must be flattened.7091 // FIXME: consider tracking vector origins for app vectors?7092 if (B->getType()->isVectorTy()) {7093 B = convertToBool(B, IRB);7094 Sb = convertToBool(Sb, IRB);7095 }7096 // a = select b, c, d7097 // Oa = Sb ? Ob : (b ? Oc : Od)7098 setOrigin(&I, IRB.CreateSelect(Sb, Ob, IRB.CreateSelect(B, Oc, Od)));7099 }7100 }7101 7102 void visitLandingPadInst(LandingPadInst &I) {7103 // Do nothing.7104 // See https://github.com/google/sanitizers/issues/5047105 setShadow(&I, getCleanShadow(&I));7106 setOrigin(&I, getCleanOrigin());7107 }7108 7109 void visitCatchSwitchInst(CatchSwitchInst &I) {7110 setShadow(&I, getCleanShadow(&I));7111 setOrigin(&I, getCleanOrigin());7112 }7113 7114 void visitFuncletPadInst(FuncletPadInst &I) {7115 setShadow(&I, getCleanShadow(&I));7116 setOrigin(&I, getCleanOrigin());7117 }7118 7119 void visitGetElementPtrInst(GetElementPtrInst &I) { handleShadowOr(I); }7120 7121 void visitExtractValueInst(ExtractValueInst &I) {7122 IRBuilder<> IRB(&I);7123 Value *Agg = I.getAggregateOperand();7124 LLVM_DEBUG(dbgs() << "ExtractValue: " << I << "\n");7125 Value *AggShadow = getShadow(Agg);7126 LLVM_DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n");7127 Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices());7128 LLVM_DEBUG(dbgs() << " ResShadow: " << *ResShadow << "\n");7129 setShadow(&I, ResShadow);7130 setOriginForNaryOp(I);7131 }7132 7133 void visitInsertValueInst(InsertValueInst &I) {7134 IRBuilder<> IRB(&I);7135 LLVM_DEBUG(dbgs() << "InsertValue: " << I << "\n");7136 Value *AggShadow = getShadow(I.getAggregateOperand());7137 Value *InsShadow = getShadow(I.getInsertedValueOperand());7138 LLVM_DEBUG(dbgs() << " AggShadow: " << *AggShadow << "\n");7139 LLVM_DEBUG(dbgs() << " InsShadow: " << *InsShadow << "\n");7140 Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices());7141 LLVM_DEBUG(dbgs() << " Res: " << *Res << "\n");7142 setShadow(&I, Res);7143 setOriginForNaryOp(I);7144 }7145 7146 void dumpInst(Instruction &I) {7147 if (CallInst *CI = dyn_cast<CallInst>(&I)) {7148 errs() << "ZZZ call " << CI->getCalledFunction()->getName() << "\n";7149 } else {7150 errs() << "ZZZ " << I.getOpcodeName() << "\n";7151 }7152 errs() << "QQQ " << I << "\n";7153 }7154 7155 void visitResumeInst(ResumeInst &I) {7156 LLVM_DEBUG(dbgs() << "Resume: " << I << "\n");7157 // Nothing to do here.7158 }7159 7160 void visitCleanupReturnInst(CleanupReturnInst &CRI) {7161 LLVM_DEBUG(dbgs() << "CleanupReturn: " << CRI << "\n");7162 // Nothing to do here.7163 }7164 7165 void visitCatchReturnInst(CatchReturnInst &CRI) {7166 LLVM_DEBUG(dbgs() << "CatchReturn: " << CRI << "\n");7167 // Nothing to do here.7168 }7169 7170 void instrumentAsmArgument(Value *Operand, Type *ElemTy, Instruction &I,7171 IRBuilder<> &IRB, const DataLayout &DL,7172 bool isOutput) {7173 // For each assembly argument, we check its value for being initialized.7174 // If the argument is a pointer, we assume it points to a single element7175 // of the corresponding type (or to a 8-byte word, if the type is unsized).7176 // Each such pointer is instrumented with a call to the runtime library.7177 Type *OpType = Operand->getType();7178 // Check the operand value itself.7179 insertCheckShadowOf(Operand, &I);7180 if (!OpType->isPointerTy() || !isOutput) {7181 assert(!isOutput);7182 return;7183 }7184 if (!ElemTy->isSized())7185 return;7186 auto Size = DL.getTypeStoreSize(ElemTy);7187 Value *SizeVal = IRB.CreateTypeSize(MS.IntptrTy, Size);7188 if (MS.CompileKernel) {7189 IRB.CreateCall(MS.MsanInstrumentAsmStoreFn, {Operand, SizeVal});7190 } else {7191 // ElemTy, derived from elementtype(), does not encode the alignment of7192 // the pointer. Conservatively assume that the shadow memory is unaligned.7193 // When Size is large, avoid StoreInst as it would expand to many7194 // instructions.7195 auto [ShadowPtr, _] =7196 getShadowOriginPtrUserspace(Operand, IRB, IRB.getInt8Ty(), Align(1));7197 if (Size <= 32)7198 IRB.CreateAlignedStore(getCleanShadow(ElemTy), ShadowPtr, Align(1));7199 else7200 IRB.CreateMemSet(ShadowPtr, ConstantInt::getNullValue(IRB.getInt8Ty()),7201 SizeVal, Align(1));7202 }7203 }7204 7205 /// Get the number of output arguments returned by pointers.7206 int getNumOutputArgs(InlineAsm *IA, CallBase *CB) {7207 int NumRetOutputs = 0;7208 int NumOutputs = 0;7209 Type *RetTy = cast<Value>(CB)->getType();7210 if (!RetTy->isVoidTy()) {7211 // Register outputs are returned via the CallInst return value.7212 auto *ST = dyn_cast<StructType>(RetTy);7213 if (ST)7214 NumRetOutputs = ST->getNumElements();7215 else7216 NumRetOutputs = 1;7217 }7218 InlineAsm::ConstraintInfoVector Constraints = IA->ParseConstraints();7219 for (const InlineAsm::ConstraintInfo &Info : Constraints) {7220 switch (Info.Type) {7221 case InlineAsm::isOutput:7222 NumOutputs++;7223 break;7224 default:7225 break;7226 }7227 }7228 return NumOutputs - NumRetOutputs;7229 }7230 7231 void visitAsmInstruction(Instruction &I) {7232 // Conservative inline assembly handling: check for poisoned shadow of7233 // asm() arguments, then unpoison the result and all the memory locations7234 // pointed to by those arguments.7235 // An inline asm() statement in C++ contains lists of input and output7236 // arguments used by the assembly code. These are mapped to operands of the7237 // CallInst as follows:7238 // - nR register outputs ("=r) are returned by value in a single structure7239 // (SSA value of the CallInst);7240 // - nO other outputs ("=m" and others) are returned by pointer as first7241 // nO operands of the CallInst;7242 // - nI inputs ("r", "m" and others) are passed to CallInst as the7243 // remaining nI operands.7244 // The total number of asm() arguments in the source is nR+nO+nI, and the7245 // corresponding CallInst has nO+nI+1 operands (the last operand is the7246 // function to be called).7247 const DataLayout &DL = F.getDataLayout();7248 CallBase *CB = cast<CallBase>(&I);7249 IRBuilder<> IRB(&I);7250 InlineAsm *IA = cast<InlineAsm>(CB->getCalledOperand());7251 int OutputArgs = getNumOutputArgs(IA, CB);7252 // The last operand of a CallInst is the function itself.7253 int NumOperands = CB->getNumOperands() - 1;7254 7255 // Check input arguments. Doing so before unpoisoning output arguments, so7256 // that we won't overwrite uninit values before checking them.7257 for (int i = OutputArgs; i < NumOperands; i++) {7258 Value *Operand = CB->getOperand(i);7259 instrumentAsmArgument(Operand, CB->getParamElementType(i), I, IRB, DL,7260 /*isOutput*/ false);7261 }7262 // Unpoison output arguments. This must happen before the actual InlineAsm7263 // call, so that the shadow for memory published in the asm() statement7264 // remains valid.7265 for (int i = 0; i < OutputArgs; i++) {7266 Value *Operand = CB->getOperand(i);7267 instrumentAsmArgument(Operand, CB->getParamElementType(i), I, IRB, DL,7268 /*isOutput*/ true);7269 }7270 7271 setShadow(&I, getCleanShadow(&I));7272 setOrigin(&I, getCleanOrigin());7273 }7274 7275 void visitFreezeInst(FreezeInst &I) {7276 // Freeze always returns a fully defined value.7277 setShadow(&I, getCleanShadow(&I));7278 setOrigin(&I, getCleanOrigin());7279 }7280 7281 void visitInstruction(Instruction &I) {7282 // Everything else: stop propagating and check for poisoned shadow.7283 if (ClDumpStrictInstructions)7284 dumpInst(I);7285 LLVM_DEBUG(dbgs() << "DEFAULT: " << I << "\n");7286 for (size_t i = 0, n = I.getNumOperands(); i < n; i++) {7287 Value *Operand = I.getOperand(i);7288 if (Operand->getType()->isSized())7289 insertCheckShadowOf(Operand, &I);7290 }7291 setShadow(&I, getCleanShadow(&I));7292 setOrigin(&I, getCleanOrigin());7293 }7294};7295 7296struct VarArgHelperBase : public VarArgHelper {7297 Function &F;7298 MemorySanitizer &MS;7299 MemorySanitizerVisitor &MSV;7300 SmallVector<CallInst *, 16> VAStartInstrumentationList;7301 const unsigned VAListTagSize;7302 7303 VarArgHelperBase(Function &F, MemorySanitizer &MS,7304 MemorySanitizerVisitor &MSV, unsigned VAListTagSize)7305 : F(F), MS(MS), MSV(MSV), VAListTagSize(VAListTagSize) {}7306 7307 Value *getShadowAddrForVAArgument(IRBuilder<> &IRB, unsigned ArgOffset) {7308 Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy);7309 return IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset));7310 }7311 7312 /// Compute the shadow address for a given va_arg.7313 Value *getShadowPtrForVAArgument(IRBuilder<> &IRB, unsigned ArgOffset) {7314 return IRB.CreatePtrAdd(7315 MS.VAArgTLS, ConstantInt::get(MS.IntptrTy, ArgOffset), "_msarg_va_s");7316 }7317 7318 /// Compute the shadow address for a given va_arg.7319 Value *getShadowPtrForVAArgument(IRBuilder<> &IRB, unsigned ArgOffset,7320 unsigned ArgSize) {7321 // Make sure we don't overflow __msan_va_arg_tls.7322 if (ArgOffset + ArgSize > kParamTLSSize)7323 return nullptr;7324 return getShadowPtrForVAArgument(IRB, ArgOffset);7325 }7326 7327 /// Compute the origin address for a given va_arg.7328 Value *getOriginPtrForVAArgument(IRBuilder<> &IRB, int ArgOffset) {7329 // getOriginPtrForVAArgument() is always called after7330 // getShadowPtrForVAArgument(), so __msan_va_arg_origin_tls can never7331 // overflow.7332 return IRB.CreatePtrAdd(MS.VAArgOriginTLS,7333 ConstantInt::get(MS.IntptrTy, ArgOffset),7334 "_msarg_va_o");7335 }7336 7337 void CleanUnusedTLS(IRBuilder<> &IRB, Value *ShadowBase,7338 unsigned BaseOffset) {7339 // The tails of __msan_va_arg_tls is not large enough to fit full7340 // value shadow, but it will be copied to backup anyway. Make it7341 // clean.7342 if (BaseOffset >= kParamTLSSize)7343 return;7344 Value *TailSize =7345 ConstantInt::getSigned(IRB.getInt32Ty(), kParamTLSSize - BaseOffset);7346 IRB.CreateMemSet(ShadowBase, ConstantInt::getNullValue(IRB.getInt8Ty()),7347 TailSize, Align(8));7348 }7349 7350 void unpoisonVAListTagForInst(IntrinsicInst &I) {7351 IRBuilder<> IRB(&I);7352 Value *VAListTag = I.getArgOperand(0);7353 const Align Alignment = Align(8);7354 auto [ShadowPtr, OriginPtr] = MSV.getShadowOriginPtr(7355 VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true);7356 // Unpoison the whole __va_list_tag.7357 IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()),7358 VAListTagSize, Alignment, false);7359 }7360 7361 void visitVAStartInst(VAStartInst &I) override {7362 if (F.getCallingConv() == CallingConv::Win64)7363 return;7364 VAStartInstrumentationList.push_back(&I);7365 unpoisonVAListTagForInst(I);7366 }7367 7368 void visitVACopyInst(VACopyInst &I) override {7369 if (F.getCallingConv() == CallingConv::Win64)7370 return;7371 unpoisonVAListTagForInst(I);7372 }7373};7374 7375/// AMD64-specific implementation of VarArgHelper.7376struct VarArgAMD64Helper : public VarArgHelperBase {7377 // An unfortunate workaround for asymmetric lowering of va_arg stuff.7378 // See a comment in visitCallBase for more details.7379 static const unsigned AMD64GpEndOffset = 48; // AMD64 ABI Draft 0.99.6 p3.5.77380 static const unsigned AMD64FpEndOffsetSSE = 176;7381 // If SSE is disabled, fp_offset in va_list is zero.7382 static const unsigned AMD64FpEndOffsetNoSSE = AMD64GpEndOffset;7383 7384 unsigned AMD64FpEndOffset;7385 AllocaInst *VAArgTLSCopy = nullptr;7386 AllocaInst *VAArgTLSOriginCopy = nullptr;7387 Value *VAArgOverflowSize = nullptr;7388 7389 enum ArgKind { AK_GeneralPurpose, AK_FloatingPoint, AK_Memory };7390 7391 VarArgAMD64Helper(Function &F, MemorySanitizer &MS,7392 MemorySanitizerVisitor &MSV)7393 : VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/24) {7394 AMD64FpEndOffset = AMD64FpEndOffsetSSE;7395 for (const auto &Attr : F.getAttributes().getFnAttrs()) {7396 if (Attr.isStringAttribute() &&7397 (Attr.getKindAsString() == "target-features")) {7398 if (Attr.getValueAsString().contains("-sse"))7399 AMD64FpEndOffset = AMD64FpEndOffsetNoSSE;7400 break;7401 }7402 }7403 }7404 7405 ArgKind classifyArgument(Value *arg) {7406 // A very rough approximation of X86_64 argument classification rules.7407 Type *T = arg->getType();7408 if (T->isX86_FP80Ty())7409 return AK_Memory;7410 if (T->isFPOrFPVectorTy())7411 return AK_FloatingPoint;7412 if (T->isIntegerTy() && T->getPrimitiveSizeInBits() <= 64)7413 return AK_GeneralPurpose;7414 if (T->isPointerTy())7415 return AK_GeneralPurpose;7416 return AK_Memory;7417 }7418 7419 // For VarArg functions, store the argument shadow in an ABI-specific format7420 // that corresponds to va_list layout.7421 // We do this because Clang lowers va_arg in the frontend, and this pass7422 // only sees the low level code that deals with va_list internals.7423 // A much easier alternative (provided that Clang emits va_arg instructions)7424 // would have been to associate each live instance of va_list with a copy of7425 // MSanParamTLS, and extract shadow on va_arg() call in the argument list7426 // order.7427 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {7428 unsigned GpOffset = 0;7429 unsigned FpOffset = AMD64GpEndOffset;7430 unsigned OverflowOffset = AMD64FpEndOffset;7431 const DataLayout &DL = F.getDataLayout();7432 7433 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {7434 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();7435 bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);7436 if (IsByVal) {7437 // ByVal arguments always go to the overflow area.7438 // Fixed arguments passed through the overflow area will be stepped7439 // over by va_start, so don't count them towards the offset.7440 if (IsFixed)7441 continue;7442 assert(A->getType()->isPointerTy());7443 Type *RealTy = CB.getParamByValType(ArgNo);7444 uint64_t ArgSize = DL.getTypeAllocSize(RealTy);7445 uint64_t AlignedSize = alignTo(ArgSize, 8);7446 unsigned BaseOffset = OverflowOffset;7447 Value *ShadowBase = getShadowPtrForVAArgument(IRB, OverflowOffset);7448 Value *OriginBase = nullptr;7449 if (MS.TrackOrigins)7450 OriginBase = getOriginPtrForVAArgument(IRB, OverflowOffset);7451 OverflowOffset += AlignedSize;7452 7453 if (OverflowOffset > kParamTLSSize) {7454 CleanUnusedTLS(IRB, ShadowBase, BaseOffset);7455 continue; // We have no space to copy shadow there.7456 }7457 7458 Value *ShadowPtr, *OriginPtr;7459 std::tie(ShadowPtr, OriginPtr) =7460 MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(), kShadowTLSAlignment,7461 /*isStore*/ false);7462 IRB.CreateMemCpy(ShadowBase, kShadowTLSAlignment, ShadowPtr,7463 kShadowTLSAlignment, ArgSize);7464 if (MS.TrackOrigins)7465 IRB.CreateMemCpy(OriginBase, kShadowTLSAlignment, OriginPtr,7466 kShadowTLSAlignment, ArgSize);7467 } else {7468 ArgKind AK = classifyArgument(A);7469 if (AK == AK_GeneralPurpose && GpOffset >= AMD64GpEndOffset)7470 AK = AK_Memory;7471 if (AK == AK_FloatingPoint && FpOffset >= AMD64FpEndOffset)7472 AK = AK_Memory;7473 Value *ShadowBase, *OriginBase = nullptr;7474 switch (AK) {7475 case AK_GeneralPurpose:7476 ShadowBase = getShadowPtrForVAArgument(IRB, GpOffset);7477 if (MS.TrackOrigins)7478 OriginBase = getOriginPtrForVAArgument(IRB, GpOffset);7479 GpOffset += 8;7480 assert(GpOffset <= kParamTLSSize);7481 break;7482 case AK_FloatingPoint:7483 ShadowBase = getShadowPtrForVAArgument(IRB, FpOffset);7484 if (MS.TrackOrigins)7485 OriginBase = getOriginPtrForVAArgument(IRB, FpOffset);7486 FpOffset += 16;7487 assert(FpOffset <= kParamTLSSize);7488 break;7489 case AK_Memory:7490 if (IsFixed)7491 continue;7492 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());7493 uint64_t AlignedSize = alignTo(ArgSize, 8);7494 unsigned BaseOffset = OverflowOffset;7495 ShadowBase = getShadowPtrForVAArgument(IRB, OverflowOffset);7496 if (MS.TrackOrigins) {7497 OriginBase = getOriginPtrForVAArgument(IRB, OverflowOffset);7498 }7499 OverflowOffset += AlignedSize;7500 if (OverflowOffset > kParamTLSSize) {7501 // We have no space to copy shadow there.7502 CleanUnusedTLS(IRB, ShadowBase, BaseOffset);7503 continue;7504 }7505 }7506 // Take fixed arguments into account for GpOffset and FpOffset,7507 // but don't actually store shadows for them.7508 // TODO(glider): don't call get*PtrForVAArgument() for them.7509 if (IsFixed)7510 continue;7511 Value *Shadow = MSV.getShadow(A);7512 IRB.CreateAlignedStore(Shadow, ShadowBase, kShadowTLSAlignment);7513 if (MS.TrackOrigins) {7514 Value *Origin = MSV.getOrigin(A);7515 TypeSize StoreSize = DL.getTypeStoreSize(Shadow->getType());7516 MSV.paintOrigin(IRB, Origin, OriginBase, StoreSize,7517 std::max(kShadowTLSAlignment, kMinOriginAlignment));7518 }7519 }7520 }7521 Constant *OverflowSize =7522 ConstantInt::get(IRB.getInt64Ty(), OverflowOffset - AMD64FpEndOffset);7523 IRB.CreateStore(OverflowSize, MS.VAArgOverflowSizeTLS);7524 }7525 7526 void finalizeInstrumentation() override {7527 assert(!VAArgOverflowSize && !VAArgTLSCopy &&7528 "finalizeInstrumentation called twice");7529 if (!VAStartInstrumentationList.empty()) {7530 // If there is a va_start in this function, make a backup copy of7531 // va_arg_tls somewhere in the function entry block.7532 IRBuilder<> IRB(MSV.FnPrologueEnd);7533 VAArgOverflowSize =7534 IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS);7535 Value *CopySize = IRB.CreateAdd(7536 ConstantInt::get(MS.IntptrTy, AMD64FpEndOffset), VAArgOverflowSize);7537 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);7538 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);7539 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),7540 CopySize, kShadowTLSAlignment, false);7541 7542 Value *SrcSize = IRB.CreateBinaryIntrinsic(7543 Intrinsic::umin, CopySize,7544 ConstantInt::get(MS.IntptrTy, kParamTLSSize));7545 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,7546 kShadowTLSAlignment, SrcSize);7547 if (MS.TrackOrigins) {7548 VAArgTLSOriginCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);7549 VAArgTLSOriginCopy->setAlignment(kShadowTLSAlignment);7550 IRB.CreateMemCpy(VAArgTLSOriginCopy, kShadowTLSAlignment,7551 MS.VAArgOriginTLS, kShadowTLSAlignment, SrcSize);7552 }7553 }7554 7555 // Instrument va_start.7556 // Copy va_list shadow from the backup copy of the TLS contents.7557 for (CallInst *OrigInst : VAStartInstrumentationList) {7558 NextNodeIRBuilder IRB(OrigInst);7559 Value *VAListTag = OrigInst->getArgOperand(0);7560 7561 Value *RegSaveAreaPtrPtr =7562 IRB.CreatePtrAdd(VAListTag, ConstantInt::get(MS.IntptrTy, 16));7563 Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);7564 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;7565 const Align Alignment = Align(16);7566 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =7567 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),7568 Alignment, /*isStore*/ true);7569 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,7570 AMD64FpEndOffset);7571 if (MS.TrackOrigins)7572 IRB.CreateMemCpy(RegSaveAreaOriginPtr, Alignment, VAArgTLSOriginCopy,7573 Alignment, AMD64FpEndOffset);7574 Value *OverflowArgAreaPtrPtr =7575 IRB.CreatePtrAdd(VAListTag, ConstantInt::get(MS.IntptrTy, 8));7576 Value *OverflowArgAreaPtr =7577 IRB.CreateLoad(MS.PtrTy, OverflowArgAreaPtrPtr);7578 Value *OverflowArgAreaShadowPtr, *OverflowArgAreaOriginPtr;7579 std::tie(OverflowArgAreaShadowPtr, OverflowArgAreaOriginPtr) =7580 MSV.getShadowOriginPtr(OverflowArgAreaPtr, IRB, IRB.getInt8Ty(),7581 Alignment, /*isStore*/ true);7582 Value *SrcPtr = IRB.CreateConstGEP1_32(IRB.getInt8Ty(), VAArgTLSCopy,7583 AMD64FpEndOffset);7584 IRB.CreateMemCpy(OverflowArgAreaShadowPtr, Alignment, SrcPtr, Alignment,7585 VAArgOverflowSize);7586 if (MS.TrackOrigins) {7587 SrcPtr = IRB.CreateConstGEP1_32(IRB.getInt8Ty(), VAArgTLSOriginCopy,7588 AMD64FpEndOffset);7589 IRB.CreateMemCpy(OverflowArgAreaOriginPtr, Alignment, SrcPtr, Alignment,7590 VAArgOverflowSize);7591 }7592 }7593 }7594};7595 7596/// AArch64-specific implementation of VarArgHelper.7597struct VarArgAArch64Helper : public VarArgHelperBase {7598 static const unsigned kAArch64GrArgSize = 64;7599 static const unsigned kAArch64VrArgSize = 128;7600 7601 static const unsigned AArch64GrBegOffset = 0;7602 static const unsigned AArch64GrEndOffset = kAArch64GrArgSize;7603 // Make VR space aligned to 16 bytes.7604 static const unsigned AArch64VrBegOffset = AArch64GrEndOffset;7605 static const unsigned AArch64VrEndOffset =7606 AArch64VrBegOffset + kAArch64VrArgSize;7607 static const unsigned AArch64VAEndOffset = AArch64VrEndOffset;7608 7609 AllocaInst *VAArgTLSCopy = nullptr;7610 Value *VAArgOverflowSize = nullptr;7611 7612 enum ArgKind { AK_GeneralPurpose, AK_FloatingPoint, AK_Memory };7613 7614 VarArgAArch64Helper(Function &F, MemorySanitizer &MS,7615 MemorySanitizerVisitor &MSV)7616 : VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/32) {}7617 7618 // A very rough approximation of aarch64 argument classification rules.7619 std::pair<ArgKind, uint64_t> classifyArgument(Type *T) {7620 if (T->isIntOrPtrTy() && T->getPrimitiveSizeInBits() <= 64)7621 return {AK_GeneralPurpose, 1};7622 if (T->isFloatingPointTy() && T->getPrimitiveSizeInBits() <= 128)7623 return {AK_FloatingPoint, 1};7624 7625 if (T->isArrayTy()) {7626 auto R = classifyArgument(T->getArrayElementType());7627 R.second *= T->getScalarType()->getArrayNumElements();7628 return R;7629 }7630 7631 if (const FixedVectorType *FV = dyn_cast<FixedVectorType>(T)) {7632 auto R = classifyArgument(FV->getScalarType());7633 R.second *= FV->getNumElements();7634 return R;7635 }7636 7637 LLVM_DEBUG(errs() << "Unknown vararg type: " << *T << "\n");7638 return {AK_Memory, 0};7639 }7640 7641 // The instrumentation stores the argument shadow in a non ABI-specific7642 // format because it does not know which argument is named (since Clang,7643 // like x86_64 case, lowers the va_args in the frontend and this pass only7644 // sees the low level code that deals with va_list internals).7645 // The first seven GR registers are saved in the first 56 bytes of the7646 // va_arg tls arra, followed by the first 8 FP/SIMD registers, and then7647 // the remaining arguments.7648 // Using constant offset within the va_arg TLS array allows fast copy7649 // in the finalize instrumentation.7650 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {7651 unsigned GrOffset = AArch64GrBegOffset;7652 unsigned VrOffset = AArch64VrBegOffset;7653 unsigned OverflowOffset = AArch64VAEndOffset;7654 7655 const DataLayout &DL = F.getDataLayout();7656 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {7657 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();7658 auto [AK, RegNum] = classifyArgument(A->getType());7659 if (AK == AK_GeneralPurpose &&7660 (GrOffset + RegNum * 8) > AArch64GrEndOffset)7661 AK = AK_Memory;7662 if (AK == AK_FloatingPoint &&7663 (VrOffset + RegNum * 16) > AArch64VrEndOffset)7664 AK = AK_Memory;7665 Value *Base;7666 switch (AK) {7667 case AK_GeneralPurpose:7668 Base = getShadowPtrForVAArgument(IRB, GrOffset);7669 GrOffset += 8 * RegNum;7670 break;7671 case AK_FloatingPoint:7672 Base = getShadowPtrForVAArgument(IRB, VrOffset);7673 VrOffset += 16 * RegNum;7674 break;7675 case AK_Memory:7676 // Don't count fixed arguments in the overflow area - va_start will7677 // skip right over them.7678 if (IsFixed)7679 continue;7680 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());7681 uint64_t AlignedSize = alignTo(ArgSize, 8);7682 unsigned BaseOffset = OverflowOffset;7683 Base = getShadowPtrForVAArgument(IRB, BaseOffset);7684 OverflowOffset += AlignedSize;7685 if (OverflowOffset > kParamTLSSize) {7686 // We have no space to copy shadow there.7687 CleanUnusedTLS(IRB, Base, BaseOffset);7688 continue;7689 }7690 break;7691 }7692 // Count Gp/Vr fixed arguments to their respective offsets, but don't7693 // bother to actually store a shadow.7694 if (IsFixed)7695 continue;7696 IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);7697 }7698 Constant *OverflowSize =7699 ConstantInt::get(IRB.getInt64Ty(), OverflowOffset - AArch64VAEndOffset);7700 IRB.CreateStore(OverflowSize, MS.VAArgOverflowSizeTLS);7701 }7702 7703 // Retrieve a va_list field of 'void*' size.7704 Value *getVAField64(IRBuilder<> &IRB, Value *VAListTag, int offset) {7705 Value *SaveAreaPtrPtr =7706 IRB.CreatePtrAdd(VAListTag, ConstantInt::get(MS.IntptrTy, offset));7707 return IRB.CreateLoad(Type::getInt64Ty(*MS.C), SaveAreaPtrPtr);7708 }7709 7710 // Retrieve a va_list field of 'int' size.7711 Value *getVAField32(IRBuilder<> &IRB, Value *VAListTag, int offset) {7712 Value *SaveAreaPtr =7713 IRB.CreatePtrAdd(VAListTag, ConstantInt::get(MS.IntptrTy, offset));7714 Value *SaveArea32 = IRB.CreateLoad(IRB.getInt32Ty(), SaveAreaPtr);7715 return IRB.CreateSExt(SaveArea32, MS.IntptrTy);7716 }7717 7718 void finalizeInstrumentation() override {7719 assert(!VAArgOverflowSize && !VAArgTLSCopy &&7720 "finalizeInstrumentation called twice");7721 if (!VAStartInstrumentationList.empty()) {7722 // If there is a va_start in this function, make a backup copy of7723 // va_arg_tls somewhere in the function entry block.7724 IRBuilder<> IRB(MSV.FnPrologueEnd);7725 VAArgOverflowSize =7726 IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS);7727 Value *CopySize = IRB.CreateAdd(7728 ConstantInt::get(MS.IntptrTy, AArch64VAEndOffset), VAArgOverflowSize);7729 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);7730 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);7731 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),7732 CopySize, kShadowTLSAlignment, false);7733 7734 Value *SrcSize = IRB.CreateBinaryIntrinsic(7735 Intrinsic::umin, CopySize,7736 ConstantInt::get(MS.IntptrTy, kParamTLSSize));7737 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,7738 kShadowTLSAlignment, SrcSize);7739 }7740 7741 Value *GrArgSize = ConstantInt::get(MS.IntptrTy, kAArch64GrArgSize);7742 Value *VrArgSize = ConstantInt::get(MS.IntptrTy, kAArch64VrArgSize);7743 7744 // Instrument va_start, copy va_list shadow from the backup copy of7745 // the TLS contents.7746 for (CallInst *OrigInst : VAStartInstrumentationList) {7747 NextNodeIRBuilder IRB(OrigInst);7748 7749 Value *VAListTag = OrigInst->getArgOperand(0);7750 7751 // The variadic ABI for AArch64 creates two areas to save the incoming7752 // argument registers (one for 64-bit general register xn-x7 and another7753 // for 128-bit FP/SIMD vn-v7).7754 // We need then to propagate the shadow arguments on both regions7755 // 'va::__gr_top + va::__gr_offs' and 'va::__vr_top + va::__vr_offs'.7756 // The remaining arguments are saved on shadow for 'va::stack'.7757 // One caveat is it requires only to propagate the non-named arguments,7758 // however on the call site instrumentation 'all' the arguments are7759 // saved. So to copy the shadow values from the va_arg TLS array7760 // we need to adjust the offset for both GR and VR fields based on7761 // the __{gr,vr}_offs value (since they are stores based on incoming7762 // named arguments).7763 Type *RegSaveAreaPtrTy = IRB.getPtrTy();7764 7765 // Read the stack pointer from the va_list.7766 Value *StackSaveAreaPtr =7767 IRB.CreateIntToPtr(getVAField64(IRB, VAListTag, 0), RegSaveAreaPtrTy);7768 7769 // Read both the __gr_top and __gr_off and add them up.7770 Value *GrTopSaveAreaPtr = getVAField64(IRB, VAListTag, 8);7771 Value *GrOffSaveArea = getVAField32(IRB, VAListTag, 24);7772 7773 Value *GrRegSaveAreaPtr = IRB.CreateIntToPtr(7774 IRB.CreateAdd(GrTopSaveAreaPtr, GrOffSaveArea), RegSaveAreaPtrTy);7775 7776 // Read both the __vr_top and __vr_off and add them up.7777 Value *VrTopSaveAreaPtr = getVAField64(IRB, VAListTag, 16);7778 Value *VrOffSaveArea = getVAField32(IRB, VAListTag, 28);7779 7780 Value *VrRegSaveAreaPtr = IRB.CreateIntToPtr(7781 IRB.CreateAdd(VrTopSaveAreaPtr, VrOffSaveArea), RegSaveAreaPtrTy);7782 7783 // It does not know how many named arguments is being used and, on the7784 // callsite all the arguments were saved. Since __gr_off is defined as7785 // '0 - ((8 - named_gr) * 8)', the idea is to just propagate the variadic7786 // argument by ignoring the bytes of shadow from named arguments.7787 Value *GrRegSaveAreaShadowPtrOff =7788 IRB.CreateAdd(GrArgSize, GrOffSaveArea);7789 7790 Value *GrRegSaveAreaShadowPtr =7791 MSV.getShadowOriginPtr(GrRegSaveAreaPtr, IRB, IRB.getInt8Ty(),7792 Align(8), /*isStore*/ true)7793 .first;7794 7795 Value *GrSrcPtr =7796 IRB.CreateInBoundsPtrAdd(VAArgTLSCopy, GrRegSaveAreaShadowPtrOff);7797 Value *GrCopySize = IRB.CreateSub(GrArgSize, GrRegSaveAreaShadowPtrOff);7798 7799 IRB.CreateMemCpy(GrRegSaveAreaShadowPtr, Align(8), GrSrcPtr, Align(8),7800 GrCopySize);7801 7802 // Again, but for FP/SIMD values.7803 Value *VrRegSaveAreaShadowPtrOff =7804 IRB.CreateAdd(VrArgSize, VrOffSaveArea);7805 7806 Value *VrRegSaveAreaShadowPtr =7807 MSV.getShadowOriginPtr(VrRegSaveAreaPtr, IRB, IRB.getInt8Ty(),7808 Align(8), /*isStore*/ true)7809 .first;7810 7811 Value *VrSrcPtr = IRB.CreateInBoundsPtrAdd(7812 IRB.CreateInBoundsPtrAdd(VAArgTLSCopy,7813 IRB.getInt32(AArch64VrBegOffset)),7814 VrRegSaveAreaShadowPtrOff);7815 Value *VrCopySize = IRB.CreateSub(VrArgSize, VrRegSaveAreaShadowPtrOff);7816 7817 IRB.CreateMemCpy(VrRegSaveAreaShadowPtr, Align(8), VrSrcPtr, Align(8),7818 VrCopySize);7819 7820 // And finally for remaining arguments.7821 Value *StackSaveAreaShadowPtr =7822 MSV.getShadowOriginPtr(StackSaveAreaPtr, IRB, IRB.getInt8Ty(),7823 Align(16), /*isStore*/ true)7824 .first;7825 7826 Value *StackSrcPtr = IRB.CreateInBoundsPtrAdd(7827 VAArgTLSCopy, IRB.getInt32(AArch64VAEndOffset));7828 7829 IRB.CreateMemCpy(StackSaveAreaShadowPtr, Align(16), StackSrcPtr,7830 Align(16), VAArgOverflowSize);7831 }7832 }7833};7834 7835/// PowerPC64-specific implementation of VarArgHelper.7836struct VarArgPowerPC64Helper : public VarArgHelperBase {7837 AllocaInst *VAArgTLSCopy = nullptr;7838 Value *VAArgSize = nullptr;7839 7840 VarArgPowerPC64Helper(Function &F, MemorySanitizer &MS,7841 MemorySanitizerVisitor &MSV)7842 : VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/8) {}7843 7844 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {7845 // For PowerPC, we need to deal with alignment of stack arguments -7846 // they are mostly aligned to 8 bytes, but vectors and i128 arrays7847 // are aligned to 16 bytes, byvals can be aligned to 8 or 16 bytes,7848 // For that reason, we compute current offset from stack pointer (which is7849 // always properly aligned), and offset for the first vararg, then subtract7850 // them.7851 unsigned VAArgBase;7852 Triple TargetTriple(F.getParent()->getTargetTriple());7853 // Parameter save area starts at 48 bytes from frame pointer for ABIv1,7854 // and 32 bytes for ABIv2. This is usually determined by target7855 // endianness, but in theory could be overridden by function attribute.7856 if (TargetTriple.isPPC64ELFv2ABI())7857 VAArgBase = 32;7858 else7859 VAArgBase = 48;7860 unsigned VAArgOffset = VAArgBase;7861 const DataLayout &DL = F.getDataLayout();7862 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {7863 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();7864 bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);7865 if (IsByVal) {7866 assert(A->getType()->isPointerTy());7867 Type *RealTy = CB.getParamByValType(ArgNo);7868 uint64_t ArgSize = DL.getTypeAllocSize(RealTy);7869 Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(8));7870 if (ArgAlign < 8)7871 ArgAlign = Align(8);7872 VAArgOffset = alignTo(VAArgOffset, ArgAlign);7873 if (!IsFixed) {7874 Value *Base =7875 getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase, ArgSize);7876 if (Base) {7877 Value *AShadowPtr, *AOriginPtr;7878 std::tie(AShadowPtr, AOriginPtr) =7879 MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(),7880 kShadowTLSAlignment, /*isStore*/ false);7881 7882 IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr,7883 kShadowTLSAlignment, ArgSize);7884 }7885 }7886 VAArgOffset += alignTo(ArgSize, Align(8));7887 } else {7888 Value *Base;7889 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());7890 Align ArgAlign = Align(8);7891 if (A->getType()->isArrayTy()) {7892 // Arrays are aligned to element size, except for long double7893 // arrays, which are aligned to 8 bytes.7894 Type *ElementTy = A->getType()->getArrayElementType();7895 if (!ElementTy->isPPC_FP128Ty())7896 ArgAlign = Align(DL.getTypeAllocSize(ElementTy));7897 } else if (A->getType()->isVectorTy()) {7898 // Vectors are naturally aligned.7899 ArgAlign = Align(ArgSize);7900 }7901 if (ArgAlign < 8)7902 ArgAlign = Align(8);7903 VAArgOffset = alignTo(VAArgOffset, ArgAlign);7904 if (DL.isBigEndian()) {7905 // Adjusting the shadow for argument with size < 8 to match the7906 // placement of bits in big endian system7907 if (ArgSize < 8)7908 VAArgOffset += (8 - ArgSize);7909 }7910 if (!IsFixed) {7911 Base =7912 getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase, ArgSize);7913 if (Base)7914 IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);7915 }7916 VAArgOffset += ArgSize;7917 VAArgOffset = alignTo(VAArgOffset, Align(8));7918 }7919 if (IsFixed)7920 VAArgBase = VAArgOffset;7921 }7922 7923 Constant *TotalVAArgSize =7924 ConstantInt::get(MS.IntptrTy, VAArgOffset - VAArgBase);7925 // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of7926 // a new class member i.e. it is the total size of all VarArgs.7927 IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);7928 }7929 7930 void finalizeInstrumentation() override {7931 assert(!VAArgSize && !VAArgTLSCopy &&7932 "finalizeInstrumentation called twice");7933 IRBuilder<> IRB(MSV.FnPrologueEnd);7934 VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS);7935 Value *CopySize = VAArgSize;7936 7937 if (!VAStartInstrumentationList.empty()) {7938 // If there is a va_start in this function, make a backup copy of7939 // va_arg_tls somewhere in the function entry block.7940 7941 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);7942 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);7943 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),7944 CopySize, kShadowTLSAlignment, false);7945 7946 Value *SrcSize = IRB.CreateBinaryIntrinsic(7947 Intrinsic::umin, CopySize,7948 ConstantInt::get(IRB.getInt64Ty(), kParamTLSSize));7949 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,7950 kShadowTLSAlignment, SrcSize);7951 }7952 7953 // Instrument va_start.7954 // Copy va_list shadow from the backup copy of the TLS contents.7955 for (CallInst *OrigInst : VAStartInstrumentationList) {7956 NextNodeIRBuilder IRB(OrigInst);7957 Value *VAListTag = OrigInst->getArgOperand(0);7958 Value *RegSaveAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);7959 7960 RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);7961 7962 Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);7963 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;7964 const DataLayout &DL = F.getDataLayout();7965 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);7966 const Align Alignment = Align(IntptrSize);7967 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =7968 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),7969 Alignment, /*isStore*/ true);7970 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,7971 CopySize);7972 }7973 }7974};7975 7976/// PowerPC32-specific implementation of VarArgHelper.7977struct VarArgPowerPC32Helper : public VarArgHelperBase {7978 AllocaInst *VAArgTLSCopy = nullptr;7979 Value *VAArgSize = nullptr;7980 7981 VarArgPowerPC32Helper(Function &F, MemorySanitizer &MS,7982 MemorySanitizerVisitor &MSV)7983 : VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/12) {}7984 7985 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {7986 unsigned VAArgBase;7987 // Parameter save area is 8 bytes from frame pointer in PPC327988 VAArgBase = 8;7989 unsigned VAArgOffset = VAArgBase;7990 const DataLayout &DL = F.getDataLayout();7991 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);7992 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {7993 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();7994 bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);7995 if (IsByVal) {7996 assert(A->getType()->isPointerTy());7997 Type *RealTy = CB.getParamByValType(ArgNo);7998 uint64_t ArgSize = DL.getTypeAllocSize(RealTy);7999 Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(IntptrSize));8000 if (ArgAlign < IntptrSize)8001 ArgAlign = Align(IntptrSize);8002 VAArgOffset = alignTo(VAArgOffset, ArgAlign);8003 if (!IsFixed) {8004 Value *Base =8005 getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase, ArgSize);8006 if (Base) {8007 Value *AShadowPtr, *AOriginPtr;8008 std::tie(AShadowPtr, AOriginPtr) =8009 MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(),8010 kShadowTLSAlignment, /*isStore*/ false);8011 8012 IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr,8013 kShadowTLSAlignment, ArgSize);8014 }8015 }8016 VAArgOffset += alignTo(ArgSize, Align(IntptrSize));8017 } else {8018 Value *Base;8019 Type *ArgTy = A->getType();8020 8021 // On PPC 32 floating point variable arguments are stored in separate8022 // area: fp_save_area = reg_save_area + 4*8. We do not copy shaodow for8023 // them as they will be found when checking call arguments.8024 if (!ArgTy->isFloatingPointTy()) {8025 uint64_t ArgSize = DL.getTypeAllocSize(ArgTy);8026 Align ArgAlign = Align(IntptrSize);8027 if (ArgTy->isArrayTy()) {8028 // Arrays are aligned to element size, except for long double8029 // arrays, which are aligned to 8 bytes.8030 Type *ElementTy = ArgTy->getArrayElementType();8031 if (!ElementTy->isPPC_FP128Ty())8032 ArgAlign = Align(DL.getTypeAllocSize(ElementTy));8033 } else if (ArgTy->isVectorTy()) {8034 // Vectors are naturally aligned.8035 ArgAlign = Align(ArgSize);8036 }8037 if (ArgAlign < IntptrSize)8038 ArgAlign = Align(IntptrSize);8039 VAArgOffset = alignTo(VAArgOffset, ArgAlign);8040 if (DL.isBigEndian()) {8041 // Adjusting the shadow for argument with size < IntptrSize to match8042 // the placement of bits in big endian system8043 if (ArgSize < IntptrSize)8044 VAArgOffset += (IntptrSize - ArgSize);8045 }8046 if (!IsFixed) {8047 Base = getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase,8048 ArgSize);8049 if (Base)8050 IRB.CreateAlignedStore(MSV.getShadow(A), Base,8051 kShadowTLSAlignment);8052 }8053 VAArgOffset += ArgSize;8054 VAArgOffset = alignTo(VAArgOffset, Align(IntptrSize));8055 }8056 }8057 }8058 8059 Constant *TotalVAArgSize =8060 ConstantInt::get(MS.IntptrTy, VAArgOffset - VAArgBase);8061 // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of8062 // a new class member i.e. it is the total size of all VarArgs.8063 IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);8064 }8065 8066 void finalizeInstrumentation() override {8067 assert(!VAArgSize && !VAArgTLSCopy &&8068 "finalizeInstrumentation called twice");8069 IRBuilder<> IRB(MSV.FnPrologueEnd);8070 VAArgSize = IRB.CreateLoad(MS.IntptrTy, MS.VAArgOverflowSizeTLS);8071 Value *CopySize = VAArgSize;8072 8073 if (!VAStartInstrumentationList.empty()) {8074 // If there is a va_start in this function, make a backup copy of8075 // va_arg_tls somewhere in the function entry block.8076 8077 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);8078 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);8079 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),8080 CopySize, kShadowTLSAlignment, false);8081 8082 Value *SrcSize = IRB.CreateBinaryIntrinsic(8083 Intrinsic::umin, CopySize,8084 ConstantInt::get(MS.IntptrTy, kParamTLSSize));8085 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,8086 kShadowTLSAlignment, SrcSize);8087 }8088 8089 // Instrument va_start.8090 // Copy va_list shadow from the backup copy of the TLS contents.8091 for (CallInst *OrigInst : VAStartInstrumentationList) {8092 NextNodeIRBuilder IRB(OrigInst);8093 Value *VAListTag = OrigInst->getArgOperand(0);8094 Value *RegSaveAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);8095 Value *RegSaveAreaSize = CopySize;8096 8097 // In PPC32 va_list_tag is a struct8098 RegSaveAreaPtrPtr =8099 IRB.CreateAdd(RegSaveAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 8));8100 8101 // On PPC 32 reg_save_area can only hold 32 bytes of data8102 RegSaveAreaSize = IRB.CreateBinaryIntrinsic(8103 Intrinsic::umin, CopySize, ConstantInt::get(MS.IntptrTy, 32));8104 8105 RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);8106 Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);8107 8108 const DataLayout &DL = F.getDataLayout();8109 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);8110 const Align Alignment = Align(IntptrSize);8111 8112 { // Copy reg save area8113 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;8114 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =8115 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),8116 Alignment, /*isStore*/ true);8117 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy,8118 Alignment, RegSaveAreaSize);8119 8120 RegSaveAreaShadowPtr =8121 IRB.CreatePtrToInt(RegSaveAreaShadowPtr, MS.IntptrTy);8122 Value *FPSaveArea = IRB.CreateAdd(RegSaveAreaShadowPtr,8123 ConstantInt::get(MS.IntptrTy, 32));8124 FPSaveArea = IRB.CreateIntToPtr(FPSaveArea, MS.PtrTy);8125 // We fill fp shadow with zeroes as uninitialized fp args should have8126 // been found during call base check8127 IRB.CreateMemSet(FPSaveArea, ConstantInt::getNullValue(IRB.getInt8Ty()),8128 ConstantInt::get(MS.IntptrTy, 32), Alignment);8129 }8130 8131 { // Copy overflow area8132 // RegSaveAreaSize is min(CopySize, 32) -> no overflow can occur8133 Value *OverflowAreaSize = IRB.CreateSub(CopySize, RegSaveAreaSize);8134 8135 Value *OverflowAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);8136 OverflowAreaPtrPtr =8137 IRB.CreateAdd(OverflowAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 4));8138 OverflowAreaPtrPtr = IRB.CreateIntToPtr(OverflowAreaPtrPtr, MS.PtrTy);8139 8140 Value *OverflowAreaPtr = IRB.CreateLoad(MS.PtrTy, OverflowAreaPtrPtr);8141 8142 Value *OverflowAreaShadowPtr, *OverflowAreaOriginPtr;8143 std::tie(OverflowAreaShadowPtr, OverflowAreaOriginPtr) =8144 MSV.getShadowOriginPtr(OverflowAreaPtr, IRB, IRB.getInt8Ty(),8145 Alignment, /*isStore*/ true);8146 8147 Value *OverflowVAArgTLSCopyPtr =8148 IRB.CreatePtrToInt(VAArgTLSCopy, MS.IntptrTy);8149 OverflowVAArgTLSCopyPtr =8150 IRB.CreateAdd(OverflowVAArgTLSCopyPtr, RegSaveAreaSize);8151 8152 OverflowVAArgTLSCopyPtr =8153 IRB.CreateIntToPtr(OverflowVAArgTLSCopyPtr, MS.PtrTy);8154 IRB.CreateMemCpy(OverflowAreaShadowPtr, Alignment,8155 OverflowVAArgTLSCopyPtr, Alignment, OverflowAreaSize);8156 }8157 }8158 }8159};8160 8161/// SystemZ-specific implementation of VarArgHelper.8162struct VarArgSystemZHelper : public VarArgHelperBase {8163 static const unsigned SystemZGpOffset = 16;8164 static const unsigned SystemZGpEndOffset = 56;8165 static const unsigned SystemZFpOffset = 128;8166 static const unsigned SystemZFpEndOffset = 160;8167 static const unsigned SystemZMaxVrArgs = 8;8168 static const unsigned SystemZRegSaveAreaSize = 160;8169 static const unsigned SystemZOverflowOffset = 160;8170 static const unsigned SystemZVAListTagSize = 32;8171 static const unsigned SystemZOverflowArgAreaPtrOffset = 16;8172 static const unsigned SystemZRegSaveAreaPtrOffset = 24;8173 8174 bool IsSoftFloatABI;8175 AllocaInst *VAArgTLSCopy = nullptr;8176 AllocaInst *VAArgTLSOriginCopy = nullptr;8177 Value *VAArgOverflowSize = nullptr;8178 8179 enum class ArgKind {8180 GeneralPurpose,8181 FloatingPoint,8182 Vector,8183 Memory,8184 Indirect,8185 };8186 8187 enum class ShadowExtension { None, Zero, Sign };8188 8189 VarArgSystemZHelper(Function &F, MemorySanitizer &MS,8190 MemorySanitizerVisitor &MSV)8191 : VarArgHelperBase(F, MS, MSV, SystemZVAListTagSize),8192 IsSoftFloatABI(F.getFnAttribute("use-soft-float").getValueAsBool()) {}8193 8194 ArgKind classifyArgument(Type *T) {8195 // T is a SystemZABIInfo::classifyArgumentType() output, and there are8196 // only a few possibilities of what it can be. In particular, enums, single8197 // element structs and large types have already been taken care of.8198 8199 // Some i128 and fp128 arguments are converted to pointers only in the8200 // back end.8201 if (T->isIntegerTy(128) || T->isFP128Ty())8202 return ArgKind::Indirect;8203 if (T->isFloatingPointTy())8204 return IsSoftFloatABI ? ArgKind::GeneralPurpose : ArgKind::FloatingPoint;8205 if (T->isIntegerTy() || T->isPointerTy())8206 return ArgKind::GeneralPurpose;8207 if (T->isVectorTy())8208 return ArgKind::Vector;8209 return ArgKind::Memory;8210 }8211 8212 ShadowExtension getShadowExtension(const CallBase &CB, unsigned ArgNo) {8213 // ABI says: "One of the simple integer types no more than 64 bits wide.8214 // ... If such an argument is shorter than 64 bits, replace it by a full8215 // 64-bit integer representing the same number, using sign or zero8216 // extension". Shadow for an integer argument has the same type as the8217 // argument itself, so it can be sign or zero extended as well.8218 bool ZExt = CB.paramHasAttr(ArgNo, Attribute::ZExt);8219 bool SExt = CB.paramHasAttr(ArgNo, Attribute::SExt);8220 if (ZExt) {8221 assert(!SExt);8222 return ShadowExtension::Zero;8223 }8224 if (SExt) {8225 assert(!ZExt);8226 return ShadowExtension::Sign;8227 }8228 return ShadowExtension::None;8229 }8230 8231 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {8232 unsigned GpOffset = SystemZGpOffset;8233 unsigned FpOffset = SystemZFpOffset;8234 unsigned VrIndex = 0;8235 unsigned OverflowOffset = SystemZOverflowOffset;8236 const DataLayout &DL = F.getDataLayout();8237 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {8238 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();8239 // SystemZABIInfo does not produce ByVal parameters.8240 assert(!CB.paramHasAttr(ArgNo, Attribute::ByVal));8241 Type *T = A->getType();8242 ArgKind AK = classifyArgument(T);8243 if (AK == ArgKind::Indirect) {8244 T = MS.PtrTy;8245 AK = ArgKind::GeneralPurpose;8246 }8247 if (AK == ArgKind::GeneralPurpose && GpOffset >= SystemZGpEndOffset)8248 AK = ArgKind::Memory;8249 if (AK == ArgKind::FloatingPoint && FpOffset >= SystemZFpEndOffset)8250 AK = ArgKind::Memory;8251 if (AK == ArgKind::Vector && (VrIndex >= SystemZMaxVrArgs || !IsFixed))8252 AK = ArgKind::Memory;8253 Value *ShadowBase = nullptr;8254 Value *OriginBase = nullptr;8255 ShadowExtension SE = ShadowExtension::None;8256 switch (AK) {8257 case ArgKind::GeneralPurpose: {8258 // Always keep track of GpOffset, but store shadow only for varargs.8259 uint64_t ArgSize = 8;8260 if (GpOffset + ArgSize <= kParamTLSSize) {8261 if (!IsFixed) {8262 SE = getShadowExtension(CB, ArgNo);8263 uint64_t GapSize = 0;8264 if (SE == ShadowExtension::None) {8265 uint64_t ArgAllocSize = DL.getTypeAllocSize(T);8266 assert(ArgAllocSize <= ArgSize);8267 GapSize = ArgSize - ArgAllocSize;8268 }8269 ShadowBase = getShadowAddrForVAArgument(IRB, GpOffset + GapSize);8270 if (MS.TrackOrigins)8271 OriginBase = getOriginPtrForVAArgument(IRB, GpOffset + GapSize);8272 }8273 GpOffset += ArgSize;8274 } else {8275 GpOffset = kParamTLSSize;8276 }8277 break;8278 }8279 case ArgKind::FloatingPoint: {8280 // Always keep track of FpOffset, but store shadow only for varargs.8281 uint64_t ArgSize = 8;8282 if (FpOffset + ArgSize <= kParamTLSSize) {8283 if (!IsFixed) {8284 // PoP says: "A short floating-point datum requires only the8285 // left-most 32 bit positions of a floating-point register".8286 // Therefore, in contrast to AK_GeneralPurpose and AK_Memory,8287 // don't extend shadow and don't mind the gap.8288 ShadowBase = getShadowAddrForVAArgument(IRB, FpOffset);8289 if (MS.TrackOrigins)8290 OriginBase = getOriginPtrForVAArgument(IRB, FpOffset);8291 }8292 FpOffset += ArgSize;8293 } else {8294 FpOffset = kParamTLSSize;8295 }8296 break;8297 }8298 case ArgKind::Vector: {8299 // Keep track of VrIndex. No need to store shadow, since vector varargs8300 // go through AK_Memory.8301 assert(IsFixed);8302 VrIndex++;8303 break;8304 }8305 case ArgKind::Memory: {8306 // Keep track of OverflowOffset and store shadow only for varargs.8307 // Ignore fixed args, since we need to copy only the vararg portion of8308 // the overflow area shadow.8309 if (!IsFixed) {8310 uint64_t ArgAllocSize = DL.getTypeAllocSize(T);8311 uint64_t ArgSize = alignTo(ArgAllocSize, 8);8312 if (OverflowOffset + ArgSize <= kParamTLSSize) {8313 SE = getShadowExtension(CB, ArgNo);8314 uint64_t GapSize =8315 SE == ShadowExtension::None ? ArgSize - ArgAllocSize : 0;8316 ShadowBase =8317 getShadowAddrForVAArgument(IRB, OverflowOffset + GapSize);8318 if (MS.TrackOrigins)8319 OriginBase =8320 getOriginPtrForVAArgument(IRB, OverflowOffset + GapSize);8321 OverflowOffset += ArgSize;8322 } else {8323 OverflowOffset = kParamTLSSize;8324 }8325 }8326 break;8327 }8328 case ArgKind::Indirect:8329 llvm_unreachable("Indirect must be converted to GeneralPurpose");8330 }8331 if (ShadowBase == nullptr)8332 continue;8333 Value *Shadow = MSV.getShadow(A);8334 if (SE != ShadowExtension::None)8335 Shadow = MSV.CreateShadowCast(IRB, Shadow, IRB.getInt64Ty(),8336 /*Signed*/ SE == ShadowExtension::Sign);8337 ShadowBase = IRB.CreateIntToPtr(ShadowBase, MS.PtrTy, "_msarg_va_s");8338 IRB.CreateStore(Shadow, ShadowBase);8339 if (MS.TrackOrigins) {8340 Value *Origin = MSV.getOrigin(A);8341 TypeSize StoreSize = DL.getTypeStoreSize(Shadow->getType());8342 MSV.paintOrigin(IRB, Origin, OriginBase, StoreSize,8343 kMinOriginAlignment);8344 }8345 }8346 Constant *OverflowSize = ConstantInt::get(8347 IRB.getInt64Ty(), OverflowOffset - SystemZOverflowOffset);8348 IRB.CreateStore(OverflowSize, MS.VAArgOverflowSizeTLS);8349 }8350 8351 void copyRegSaveArea(IRBuilder<> &IRB, Value *VAListTag) {8352 Value *RegSaveAreaPtrPtr = IRB.CreateIntToPtr(8353 IRB.CreateAdd(8354 IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),8355 ConstantInt::get(MS.IntptrTy, SystemZRegSaveAreaPtrOffset)),8356 MS.PtrTy);8357 Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);8358 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;8359 const Align Alignment = Align(8);8360 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =8361 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(), Alignment,8362 /*isStore*/ true);8363 // TODO(iii): copy only fragments filled by visitCallBase()8364 // TODO(iii): support packed-stack && !use-soft-float8365 // For use-soft-float functions, it is enough to copy just the GPRs.8366 unsigned RegSaveAreaSize =8367 IsSoftFloatABI ? SystemZGpEndOffset : SystemZRegSaveAreaSize;8368 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,8369 RegSaveAreaSize);8370 if (MS.TrackOrigins)8371 IRB.CreateMemCpy(RegSaveAreaOriginPtr, Alignment, VAArgTLSOriginCopy,8372 Alignment, RegSaveAreaSize);8373 }8374 8375 // FIXME: This implementation limits OverflowOffset to kParamTLSSize, so we8376 // don't know real overflow size and can't clear shadow beyond kParamTLSSize.8377 void copyOverflowArea(IRBuilder<> &IRB, Value *VAListTag) {8378 Value *OverflowArgAreaPtrPtr = IRB.CreateIntToPtr(8379 IRB.CreateAdd(8380 IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),8381 ConstantInt::get(MS.IntptrTy, SystemZOverflowArgAreaPtrOffset)),8382 MS.PtrTy);8383 Value *OverflowArgAreaPtr = IRB.CreateLoad(MS.PtrTy, OverflowArgAreaPtrPtr);8384 Value *OverflowArgAreaShadowPtr, *OverflowArgAreaOriginPtr;8385 const Align Alignment = Align(8);8386 std::tie(OverflowArgAreaShadowPtr, OverflowArgAreaOriginPtr) =8387 MSV.getShadowOriginPtr(OverflowArgAreaPtr, IRB, IRB.getInt8Ty(),8388 Alignment, /*isStore*/ true);8389 Value *SrcPtr = IRB.CreateConstGEP1_32(IRB.getInt8Ty(), VAArgTLSCopy,8390 SystemZOverflowOffset);8391 IRB.CreateMemCpy(OverflowArgAreaShadowPtr, Alignment, SrcPtr, Alignment,8392 VAArgOverflowSize);8393 if (MS.TrackOrigins) {8394 SrcPtr = IRB.CreateConstGEP1_32(IRB.getInt8Ty(), VAArgTLSOriginCopy,8395 SystemZOverflowOffset);8396 IRB.CreateMemCpy(OverflowArgAreaOriginPtr, Alignment, SrcPtr, Alignment,8397 VAArgOverflowSize);8398 }8399 }8400 8401 void finalizeInstrumentation() override {8402 assert(!VAArgOverflowSize && !VAArgTLSCopy &&8403 "finalizeInstrumentation called twice");8404 if (!VAStartInstrumentationList.empty()) {8405 // If there is a va_start in this function, make a backup copy of8406 // va_arg_tls somewhere in the function entry block.8407 IRBuilder<> IRB(MSV.FnPrologueEnd);8408 VAArgOverflowSize =8409 IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS);8410 Value *CopySize =8411 IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, SystemZOverflowOffset),8412 VAArgOverflowSize);8413 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);8414 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);8415 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),8416 CopySize, kShadowTLSAlignment, false);8417 8418 Value *SrcSize = IRB.CreateBinaryIntrinsic(8419 Intrinsic::umin, CopySize,8420 ConstantInt::get(MS.IntptrTy, kParamTLSSize));8421 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,8422 kShadowTLSAlignment, SrcSize);8423 if (MS.TrackOrigins) {8424 VAArgTLSOriginCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);8425 VAArgTLSOriginCopy->setAlignment(kShadowTLSAlignment);8426 IRB.CreateMemCpy(VAArgTLSOriginCopy, kShadowTLSAlignment,8427 MS.VAArgOriginTLS, kShadowTLSAlignment, SrcSize);8428 }8429 }8430 8431 // Instrument va_start.8432 // Copy va_list shadow from the backup copy of the TLS contents.8433 for (CallInst *OrigInst : VAStartInstrumentationList) {8434 NextNodeIRBuilder IRB(OrigInst);8435 Value *VAListTag = OrigInst->getArgOperand(0);8436 copyRegSaveArea(IRB, VAListTag);8437 copyOverflowArea(IRB, VAListTag);8438 }8439 }8440};8441 8442/// i386-specific implementation of VarArgHelper.8443struct VarArgI386Helper : public VarArgHelperBase {8444 AllocaInst *VAArgTLSCopy = nullptr;8445 Value *VAArgSize = nullptr;8446 8447 VarArgI386Helper(Function &F, MemorySanitizer &MS,8448 MemorySanitizerVisitor &MSV)8449 : VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/4) {}8450 8451 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {8452 const DataLayout &DL = F.getDataLayout();8453 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);8454 unsigned VAArgOffset = 0;8455 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {8456 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();8457 bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);8458 if (IsByVal) {8459 assert(A->getType()->isPointerTy());8460 Type *RealTy = CB.getParamByValType(ArgNo);8461 uint64_t ArgSize = DL.getTypeAllocSize(RealTy);8462 Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(IntptrSize));8463 if (ArgAlign < IntptrSize)8464 ArgAlign = Align(IntptrSize);8465 VAArgOffset = alignTo(VAArgOffset, ArgAlign);8466 if (!IsFixed) {8467 Value *Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);8468 if (Base) {8469 Value *AShadowPtr, *AOriginPtr;8470 std::tie(AShadowPtr, AOriginPtr) =8471 MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(),8472 kShadowTLSAlignment, /*isStore*/ false);8473 8474 IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr,8475 kShadowTLSAlignment, ArgSize);8476 }8477 VAArgOffset += alignTo(ArgSize, Align(IntptrSize));8478 }8479 } else {8480 Value *Base;8481 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());8482 Align ArgAlign = Align(IntptrSize);8483 VAArgOffset = alignTo(VAArgOffset, ArgAlign);8484 if (DL.isBigEndian()) {8485 // Adjusting the shadow for argument with size < IntptrSize to match8486 // the placement of bits in big endian system8487 if (ArgSize < IntptrSize)8488 VAArgOffset += (IntptrSize - ArgSize);8489 }8490 if (!IsFixed) {8491 Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);8492 if (Base)8493 IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);8494 VAArgOffset += ArgSize;8495 VAArgOffset = alignTo(VAArgOffset, Align(IntptrSize));8496 }8497 }8498 }8499 8500 Constant *TotalVAArgSize = ConstantInt::get(MS.IntptrTy, VAArgOffset);8501 // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of8502 // a new class member i.e. it is the total size of all VarArgs.8503 IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);8504 }8505 8506 void finalizeInstrumentation() override {8507 assert(!VAArgSize && !VAArgTLSCopy &&8508 "finalizeInstrumentation called twice");8509 IRBuilder<> IRB(MSV.FnPrologueEnd);8510 VAArgSize = IRB.CreateLoad(MS.IntptrTy, MS.VAArgOverflowSizeTLS);8511 Value *CopySize = VAArgSize;8512 8513 if (!VAStartInstrumentationList.empty()) {8514 // If there is a va_start in this function, make a backup copy of8515 // va_arg_tls somewhere in the function entry block.8516 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);8517 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);8518 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),8519 CopySize, kShadowTLSAlignment, false);8520 8521 Value *SrcSize = IRB.CreateBinaryIntrinsic(8522 Intrinsic::umin, CopySize,8523 ConstantInt::get(MS.IntptrTy, kParamTLSSize));8524 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,8525 kShadowTLSAlignment, SrcSize);8526 }8527 8528 // Instrument va_start.8529 // Copy va_list shadow from the backup copy of the TLS contents.8530 for (CallInst *OrigInst : VAStartInstrumentationList) {8531 NextNodeIRBuilder IRB(OrigInst);8532 Value *VAListTag = OrigInst->getArgOperand(0);8533 Type *RegSaveAreaPtrTy = PointerType::getUnqual(*MS.C);8534 Value *RegSaveAreaPtrPtr =8535 IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),8536 PointerType::get(*MS.C, 0));8537 Value *RegSaveAreaPtr =8538 IRB.CreateLoad(RegSaveAreaPtrTy, RegSaveAreaPtrPtr);8539 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;8540 const DataLayout &DL = F.getDataLayout();8541 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);8542 const Align Alignment = Align(IntptrSize);8543 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =8544 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),8545 Alignment, /*isStore*/ true);8546 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,8547 CopySize);8548 }8549 }8550};8551 8552/// Implementation of VarArgHelper that is used for ARM32, MIPS, RISCV,8553/// LoongArch64.8554struct VarArgGenericHelper : public VarArgHelperBase {8555 AllocaInst *VAArgTLSCopy = nullptr;8556 Value *VAArgSize = nullptr;8557 8558 VarArgGenericHelper(Function &F, MemorySanitizer &MS,8559 MemorySanitizerVisitor &MSV, const unsigned VAListTagSize)8560 : VarArgHelperBase(F, MS, MSV, VAListTagSize) {}8561 8562 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {8563 unsigned VAArgOffset = 0;8564 const DataLayout &DL = F.getDataLayout();8565 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);8566 for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {8567 bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();8568 if (IsFixed)8569 continue;8570 uint64_t ArgSize = DL.getTypeAllocSize(A->getType());8571 if (DL.isBigEndian()) {8572 // Adjusting the shadow for argument with size < IntptrSize to match the8573 // placement of bits in big endian system8574 if (ArgSize < IntptrSize)8575 VAArgOffset += (IntptrSize - ArgSize);8576 }8577 Value *Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);8578 VAArgOffset += ArgSize;8579 VAArgOffset = alignTo(VAArgOffset, IntptrSize);8580 if (!Base)8581 continue;8582 IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);8583 }8584 8585 Constant *TotalVAArgSize = ConstantInt::get(MS.IntptrTy, VAArgOffset);8586 // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of8587 // a new class member i.e. it is the total size of all VarArgs.8588 IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);8589 }8590 8591 void finalizeInstrumentation() override {8592 assert(!VAArgSize && !VAArgTLSCopy &&8593 "finalizeInstrumentation called twice");8594 IRBuilder<> IRB(MSV.FnPrologueEnd);8595 VAArgSize = IRB.CreateLoad(MS.IntptrTy, MS.VAArgOverflowSizeTLS);8596 Value *CopySize = VAArgSize;8597 8598 if (!VAStartInstrumentationList.empty()) {8599 // If there is a va_start in this function, make a backup copy of8600 // va_arg_tls somewhere in the function entry block.8601 VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);8602 VAArgTLSCopy->setAlignment(kShadowTLSAlignment);8603 IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),8604 CopySize, kShadowTLSAlignment, false);8605 8606 Value *SrcSize = IRB.CreateBinaryIntrinsic(8607 Intrinsic::umin, CopySize,8608 ConstantInt::get(MS.IntptrTy, kParamTLSSize));8609 IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,8610 kShadowTLSAlignment, SrcSize);8611 }8612 8613 // Instrument va_start.8614 // Copy va_list shadow from the backup copy of the TLS contents.8615 for (CallInst *OrigInst : VAStartInstrumentationList) {8616 NextNodeIRBuilder IRB(OrigInst);8617 Value *VAListTag = OrigInst->getArgOperand(0);8618 Type *RegSaveAreaPtrTy = PointerType::getUnqual(*MS.C);8619 Value *RegSaveAreaPtrPtr =8620 IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),8621 PointerType::get(*MS.C, 0));8622 Value *RegSaveAreaPtr =8623 IRB.CreateLoad(RegSaveAreaPtrTy, RegSaveAreaPtrPtr);8624 Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;8625 const DataLayout &DL = F.getDataLayout();8626 unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);8627 const Align Alignment = Align(IntptrSize);8628 std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =8629 MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),8630 Alignment, /*isStore*/ true);8631 IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,8632 CopySize);8633 }8634 }8635};8636 8637// ARM32, Loongarch64, MIPS and RISCV share the same calling conventions8638// regarding VAArgs.8639using VarArgARM32Helper = VarArgGenericHelper;8640using VarArgRISCVHelper = VarArgGenericHelper;8641using VarArgMIPSHelper = VarArgGenericHelper;8642using VarArgLoongArch64Helper = VarArgGenericHelper;8643 8644/// A no-op implementation of VarArgHelper.8645struct VarArgNoOpHelper : public VarArgHelper {8646 VarArgNoOpHelper(Function &F, MemorySanitizer &MS,8647 MemorySanitizerVisitor &MSV) {}8648 8649 void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {}8650 8651 void visitVAStartInst(VAStartInst &I) override {}8652 8653 void visitVACopyInst(VACopyInst &I) override {}8654 8655 void finalizeInstrumentation() override {}8656};8657 8658} // end anonymous namespace8659 8660static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan,8661 MemorySanitizerVisitor &Visitor) {8662 // VarArg handling is only implemented on AMD64. False positives are possible8663 // on other platforms.8664 Triple TargetTriple(Func.getParent()->getTargetTriple());8665 8666 if (TargetTriple.getArch() == Triple::x86)8667 return new VarArgI386Helper(Func, Msan, Visitor);8668 8669 if (TargetTriple.getArch() == Triple::x86_64)8670 return new VarArgAMD64Helper(Func, Msan, Visitor);8671 8672 if (TargetTriple.isARM())8673 return new VarArgARM32Helper(Func, Msan, Visitor, /*VAListTagSize=*/4);8674 8675 if (TargetTriple.isAArch64())8676 return new VarArgAArch64Helper(Func, Msan, Visitor);8677 8678 if (TargetTriple.isSystemZ())8679 return new VarArgSystemZHelper(Func, Msan, Visitor);8680 8681 // On PowerPC32 VAListTag is a struct8682 // {char, char, i16 padding, char *, char *}8683 if (TargetTriple.isPPC32())8684 return new VarArgPowerPC32Helper(Func, Msan, Visitor);8685 8686 if (TargetTriple.isPPC64())8687 return new VarArgPowerPC64Helper(Func, Msan, Visitor);8688 8689 if (TargetTriple.isRISCV32())8690 return new VarArgRISCVHelper(Func, Msan, Visitor, /*VAListTagSize=*/4);8691 8692 if (TargetTriple.isRISCV64())8693 return new VarArgRISCVHelper(Func, Msan, Visitor, /*VAListTagSize=*/8);8694 8695 if (TargetTriple.isMIPS32())8696 return new VarArgMIPSHelper(Func, Msan, Visitor, /*VAListTagSize=*/4);8697 8698 if (TargetTriple.isMIPS64())8699 return new VarArgMIPSHelper(Func, Msan, Visitor, /*VAListTagSize=*/8);8700 8701 if (TargetTriple.isLoongArch64())8702 return new VarArgLoongArch64Helper(Func, Msan, Visitor,8703 /*VAListTagSize=*/8);8704 8705 return new VarArgNoOpHelper(Func, Msan, Visitor);8706}8707 8708bool MemorySanitizer::sanitizeFunction(Function &F, TargetLibraryInfo &TLI) {8709 if (!CompileKernel && F.getName() == kMsanModuleCtorName)8710 return false;8711 8712 if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))8713 return false;8714 8715 MemorySanitizerVisitor Visitor(F, *this, TLI);8716 8717 // Clear out memory attributes.8718 AttributeMask B;8719 B.addAttribute(Attribute::Memory).addAttribute(Attribute::Speculatable);8720 F.removeFnAttrs(B);8721 8722 return Visitor.runOnFunction();8723}8724