//===------------------------- LSUnit.h --------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file /// /// A Load/Store unit class that models load/store queues and that implements /// a simple weak memory consistency model. /// //===----------------------------------------------------------------------===// #ifndef LLVM_MCA_HARDWAREUNITS_LSUNIT_H #define LLVM_MCA_HARDWAREUNITS_LSUNIT_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCSchedule.h" #include "llvm/MCA/HardwareUnits/HardwareUnit.h" #include "llvm/MCA/Instruction.h" namespace llvm { namespace mca { /// A node of a memory dependency graph. A MemoryGroup describes a set of /// instructions with same memory dependencies. /// /// By construction, instructions of a MemoryGroup don't depend on each other. /// At dispatch stage, instructions are mapped by the LSUnit to MemoryGroups. /// A Memory group identifier is then stored as a "token" in field /// Instruction::LSUTokenID of each dispatched instructions. That token is used /// internally by the LSUnit to track memory dependencies. class MemoryGroup { … }; /// Abstract base interface for LS (load/store) units in llvm-mca. class LSUnitBase : public HardwareUnit { … }; /// Default Load/Store Unit (LS Unit) for simulated processors. /// /// Each load (or store) consumes one entry in the load (or store) queue. /// /// Rules are: /// 1) A younger load is allowed to pass an older load only if there are no /// stores nor barriers in between the two loads. /// 2) An younger store is not allowed to pass an older store. /// 3) A younger store is not allowed to pass an older load. /// 4) A younger load is allowed to pass an older store only if the load does /// not alias with the store. /// /// This class optimistically assumes that loads don't alias store operations. /// Under this assumption, younger loads are always allowed to pass older /// stores (this would only affects rule 4). /// Essentially, this class doesn't perform any sort alias analysis to /// identify aliasing loads and stores. /// /// To enforce aliasing between loads and stores, flag `AssumeNoAlias` must be /// set to `false` by the constructor of LSUnit. /// /// Note that this class doesn't know about the existence of different memory /// types for memory operations (example: write-through, write-combining, etc.). /// Derived classes are responsible for implementing that extra knowledge, and /// provide different sets of rules for loads and stores by overriding method /// `isReady()`. /// To emulate a write-combining memory type, rule 2. must be relaxed in a /// derived class to enable the reordering of non-aliasing store operations. /// /// No assumptions are made by this class on the size of the store buffer. This /// class doesn't know how to identify cases where store-to-load forwarding may /// occur. /// /// LSUnit doesn't attempt to predict whether a load or store hits or misses /// the L1 cache. To be more specific, LSUnit doesn't know anything about /// cache hierarchy and memory types. /// It only knows if an instruction "mayLoad" and/or "mayStore". For loads, the /// scheduling model provides an "optimistic" load-to-use latency (which usually /// matches the load-to-use latency for when there is a hit in the L1D). /// Derived classes may expand this knowledge. /// /// Class MCInstrDesc in LLVM doesn't know about serializing operations, nor /// memory-barrier like instructions. /// LSUnit conservatively assumes that an instruction which `mayLoad` and has /// `unmodeled side effects` behave like a "soft" load-barrier. That means, it /// serializes loads without forcing a flush of the load queue. /// Similarly, instructions that both `mayStore` and have `unmodeled side /// effects` are treated like store barriers. A full memory /// barrier is a 'mayLoad' and 'mayStore' instruction with unmodeled side /// effects. This is obviously inaccurate, but this is the best that we can do /// at the moment. /// /// Each load/store barrier consumes one entry in the load/store queue. A /// load/store barrier enforces ordering of loads/stores: /// - A younger load cannot pass a load barrier. /// - A younger store cannot pass a store barrier. /// /// A younger load has to wait for the memory load barrier to execute. /// A load/store barrier is "executed" when it becomes the oldest entry in /// the load/store queue(s). That also means, all the older loads/stores have /// already been executed. class LSUnit : public LSUnitBase { … }; } // namespace mca } // namespace llvm #endif // LLVM_MCA_HARDWAREUNITS_LSUNIT_H