42#define DEBUG_TYPE "loadstore-opt"
46using namespace MIPatternMatch;
48STATISTIC(NumStoresMerged,
"Number of stores merged");
67 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
90 Info.IsIndexSignExt =
false;
96 Info.Offset = RHSCst->Value.getSExtValue();
100 Info.IndexReg = PtrAddRHS;
101 Info.IsIndexSignExt =
false;
109 auto *LdSt1 = dyn_cast<GLoadStore>(&MI1);
110 auto *LdSt2 = dyn_cast<GLoadStore>(&MI2);
111 if (!LdSt1 || !LdSt2)
120 int64_t Size1 = LdSt1->getMemSize();
121 int64_t Size2 = LdSt2->getMemSize();
136 IsAlias = !(Size1 <= PtrDiff);
144 IsAlias = !((PtrDiff + Size2) <= 0);
156 if (!Base0Def || !Base1Def)
160 if (Base0Def->getOpcode() != Base1Def->getOpcode())
163 if (Base0Def->getOpcode() == TargetOpcode::G_FRAME_INDEX) {
167 if (Base0Def != Base1Def &&
177 if (Base0Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
178 auto GV0 = Base0Def->getOperand(1).getGlobal();
179 auto GV1 = Base1Def->getOperand(1).getGlobal();
194 struct MemUseCharacteristics {
203 auto getCharacteristics =
205 if (
const auto *LS = dyn_cast<GLoadStore>(
MI)) {
211 BaseReg = LS->getPointerReg();
216 LS->getMMO().getMemoryType().getSizeInBytes());
217 return {LS->isVolatile(), LS->isAtomic(), BaseReg,
227 MemUseCharacteristics MUC0 = getCharacteristics(&
MI),
228 MUC1 = getCharacteristics(&
Other);
231 if (MUC0.BasePtr.isValid() && MUC0.BasePtr == MUC1.BasePtr &&
232 MUC0.Offset == MUC1.Offset)
236 if (MUC0.IsVolatile && MUC1.IsVolatile)
241 if (MUC0.IsAtomic && MUC1.IsAtomic)
246 if (MUC0.MMO && MUC1.MMO) {
247 if ((MUC0.MMO->isInvariant() && MUC1.MMO->isStore()) ||
248 (MUC1.MMO->isInvariant() && MUC0.MMO->isStore()))
259 if (!MUC0.MMO || !MUC1.MMO)
263 int64_t SrcValOffset0 = MUC0.MMO->getOffset();
264 int64_t SrcValOffset1 = MUC1.MMO->getOffset();
267 if (AA && MUC0.MMO->getValue() && MUC1.MMO->getValue() &&
271 int64_t MinOffset = std::min(SrcValOffset0, SrcValOffset1);
272 int64_t Overlap0 = Size0 + SrcValOffset0 - MinOffset;
273 int64_t Overlap1 = Size1 + SrcValOffset1 - MinOffset;
275 MUC0.MMO->getAAInfo()),
277 MUC1.MMO->getAAInfo())))
288 return MI.hasUnmodeledSideEffects() ||
MI.hasOrderedMemoryRef();
294 assert(StoresToMerge.
size() > 1 &&
"Expected multiple stores to merge");
295 LLT OrigTy = MRI->
getType(StoresToMerge[0]->getValueReg());
296 LLT PtrTy = MRI->
getType(StoresToMerge[0]->getPointerReg());
299 initializeStoreMergeTargetInfo(AS);
300 const auto &LegalSizes = LegalStoreSizes[AS];
303 for (
auto *StoreMI : StoresToMerge)
308 bool AnyMerged =
false;
313 unsigned MergeSizeBits;
314 for (MergeSizeBits = MaxSizeBits; MergeSizeBits > 1; MergeSizeBits /= 2) {
318 if (LegalSizes.size() > MergeSizeBits && LegalSizes[MergeSizeBits] &&
326 unsigned NumStoresToMerge = MergeSizeBits / OrigTy.
getSizeInBits();
329 StoresToMerge.begin(), StoresToMerge.begin() + NumStoresToMerge);
330 AnyMerged |= doSingleStoreMerge(SingleMergeStores);
331 StoresToMerge.erase(StoresToMerge.begin(),
332 StoresToMerge.begin() + NumStoresToMerge);
333 }
while (StoresToMerge.size() > 1);
337bool LoadStoreOpt::isLegalOrBeforeLegalizer(
const LegalityQuery &Query,
343 return IsPreLegalizer ||
Action == LegalizeAction::Legal;
353 GStore *FirstStore = Stores[0];
354 const unsigned NumStores = Stores.
size();
371 for (
auto *Store : Stores) {
375 ConstantVals.
clear();
384 if (ConstantVals.
empty()) {
393 if (!isLegalOrBeforeLegalizer({TargetOpcode::G_CONSTANT, {WideValueTy}}, *MF))
406 <<
" stores into merged store: " << *NewStore);
408 NumStoresMerged += Stores.size();
415 R <<
"Merged " <<
NV(
"NumMerged", Stores.size()) <<
" stores of "
417 <<
" bytes into a single store of "
422 for (
auto *
MI : Stores)
423 InstsToErase.insert(
MI);
427bool LoadStoreOpt::processMergeCandidate(StoreMergeCandidate &
C) {
428 if (
C.Stores.size() < 2) {
433 LLVM_DEBUG(
dbgs() <<
"Checking store merge candidate with " <<
C.Stores.size()
434 <<
" stores, starting with " << *
C.Stores[0]);
448 auto DoesStoreAliasWithPotential = [&](
unsigned Idx,
GStore &CheckStore) {
449 for (
auto AliasInfo :
reverse(
C.PotentialAliases)) {
451 unsigned PreCheckedIdx = AliasInfo.second;
452 if (
static_cast<unsigned>(
Idx) < PreCheckedIdx) {
470 for (
int StoreIdx =
C.Stores.size() - 1; StoreIdx >= 0; --StoreIdx) {
471 auto *CheckStore =
C.Stores[StoreIdx];
472 if (DoesStoreAliasWithPotential(StoreIdx, *CheckStore))
478 <<
" stores remaining after alias checks. Merging...\n");
482 if (StoresToMerge.
size() < 2)
484 return mergeStores(StoresToMerge);
488 StoreMergeCandidate &
C) {
489 if (
C.Stores.empty())
492 return instMayAlias(MI, *OtherMI, *MRI, AA);
496void LoadStoreOpt::StoreMergeCandidate::addPotentialAlias(
MachineInstr &
MI) {
497 PotentialAliases.emplace_back(std::make_pair(&
MI, Stores.size() - 1));
500bool LoadStoreOpt::addStoreToCandidate(
GStore &StoreMI,
501 StoreMergeCandidate &
C) {
525 if (
C.Stores.empty()) {
531 C.BasePtr = StoreBase;
532 C.CurrentLowestOffset = StoreOffCst;
533 C.Stores.emplace_back(&StoreMI);
534 LLVM_DEBUG(
dbgs() <<
"Starting a new merge candidate group with: "
550 if (
C.BasePtr != StoreBase)
557 C.Stores.emplace_back(&StoreMI);
564 bool Changed =
false;
566 StoreMergeCandidate Candidate;
568 if (InstsToErase.contains(&
MI))
571 if (
auto *StoreMI = dyn_cast<GStore>(&
MI)) {
574 if (!addStoreToCandidate(*StoreMI, Candidate)) {
577 if (operationAliasesWithCandidate(*StoreMI, Candidate)) {
578 Changed |= processMergeCandidate(Candidate);
581 Candidate.addPotentialAlias(*StoreMI);
587 if (Candidate.Stores.empty())
592 Changed |= processMergeCandidate(Candidate);
593 Candidate.Stores.clear();
597 if (!
MI.mayLoadOrStore())
600 if (operationAliasesWithCandidate(
MI, Candidate)) {
603 Changed |= processMergeCandidate(Candidate);
609 Candidate.addPotentialAlias(
MI);
613 Changed |= processMergeCandidate(Candidate);
616 for (
auto *
MI : InstsToErase)
617 MI->eraseFromParent();
618 InstsToErase.clear();
628static std::optional<int64_t>
646 if (!SrcVal.
isValid() || TruncVal == SrcVal) {
654 unsigned NarrowBits = Store.getMMO().getMemoryType().getScalarSizeInBits();
655 if (ShiftAmt % NarrowBits != 0)
657 const unsigned Offset = ShiftAmt / NarrowBits;
659 if (SrcVal.
isValid() && FoundSrcVal != SrcVal)
663 SrcVal = FoundSrcVal;
664 else if (
MRI.getType(SrcVal) !=
MRI.getType(FoundSrcVal))
691bool LoadStoreOpt::mergeTruncStore(
GStore &StoreMI,
719 auto &LastStore = StoreMI;
724 if (!
mi_match(LastStore.getPointerReg(), *MRI,
726 BaseReg = LastStore.getPointerReg();
730 GStore *LowestIdxStore = &LastStore;
731 int64_t LowestIdxOffset = LastOffset;
743 const unsigned NumStoresRequired =
747 OffsetMap[*LowestShiftAmt] = LastOffset;
750 const int MaxInstsToCheck = 10;
751 int NumInstsChecked = 0;
752 for (
auto II = ++LastStore.getReverseIterator();
753 II != LastStore.getParent()->rend() && NumInstsChecked < MaxInstsToCheck;
757 if ((NewStore = dyn_cast<GStore>(&*II))) {
760 }
else if (II->isLoadFoldBarrier() || II->mayLoad()) {
774 if (BaseReg != NewBaseReg)
778 if (!ShiftByteOffset)
780 if (MemOffset < LowestIdxOffset) {
781 LowestIdxOffset = MemOffset;
782 LowestIdxStore = NewStore;
787 if (*ShiftByteOffset < 0 || *ShiftByteOffset >= NumStoresRequired ||
788 OffsetMap[*ShiftByteOffset] !=
INT64_MAX)
790 OffsetMap[*ShiftByteOffset] = MemOffset;
795 if (FoundStores.
size() == NumStoresRequired)
799 if (FoundStores.
size() != NumStoresRequired) {
800 if (FoundStores.
size() == 1)
808 unsigned NumStoresFound = FoundStores.
size();
810 const auto &
DL = LastStore.getMF()->getDataLayout();
811 auto &
C = LastStore.getMF()->getFunction().getContext();
816 if (!Allowed || !
Fast)
822 auto checkOffsets = [&](
bool MatchLittleEndian) {
823 if (MatchLittleEndian) {
824 for (
unsigned i = 0; i != NumStoresFound; ++i)
825 if (OffsetMap[i] != i * (NarrowBits / 8) + LowestIdxOffset)
828 for (
unsigned i = 0, j = NumStoresFound - 1; i != NumStoresFound;
830 if (OffsetMap[j] != i * (NarrowBits / 8) + LowestIdxOffset)
837 bool NeedBswap =
false;
838 bool NeedRotate =
false;
839 if (!checkOffsets(
DL.isLittleEndian())) {
841 if (NarrowBits == 8 && checkOffsets(
DL.isBigEndian()))
843 else if (NumStoresFound == 2 && checkOffsets(
DL.isBigEndian()))
850 !isLegalOrBeforeLegalizer({TargetOpcode::G_BSWAP, {WideStoreTy}}, *MF))
853 !isLegalOrBeforeLegalizer(
854 {TargetOpcode::G_ROTR, {WideStoreTy, WideStoreTy}}, *MF))
859 if (WideStoreTy != MRI->
getType(WideSrcVal))
864 }
else if (NeedRotate) {
866 "Unexpected type for rotate");
878 for (
auto *ST : FoundStores) {
879 ST->eraseFromParent();
886 bool Changed =
false;
891 if (
auto *StoreMI = dyn_cast<GStore>(&
MI))
894 for (
auto *StoreMI : Stores) {
895 if (DeletedStores.
count(StoreMI))
897 if (mergeTruncStore(*StoreMI, DeletedStores))
904 bool Changed =
false;
906 Changed |= mergeBlockStores(BB);
907 Changed |= mergeTruncStoresBlock(BB);
912 for (
auto &BB : MF) {
923void LoadStoreOpt::initializeStoreMergeTargetInfo(
unsigned AddrSpace) {
928 if (LegalStoreSizes.count(AddrSpace)) {
929 assert(LegalStoreSizes[AddrSpace].
any());
935 const auto &LI = *MF->getSubtarget().getLegalizerInfo();
949 LegalSizes.set(
Size);
951 assert(LegalSizes.any() &&
"Expected some store sizes to be legal!");
952 LegalStoreSizes[AddrSpace] = LegalSizes;
965 bool Changed =
false;
966 Changed |= mergeFunctionStores(MF);
968 LegalStoreSizes.clear();
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
Analysis containing CSE Info
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Performs the initial survey of the specified function
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Generic memory optimizations
const unsigned MaxStoreSizeToForm
static std::optional< int64_t > getTruncStoreByteOffset(GStore &Store, Register &SrcVal, MachineRegisterInfo &MRI)
Check if the store Store is a truncstore that can be merged.
static bool isInstHardMergeHazard(MachineInstr &MI)
Returns true if the instruction creates an unavoidable hazard that forces a boundary between store me...
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file provides utility analysis objects describing memory locations.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
This file describes how to lower LLVM code to machine code.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
Class for arbitrary precision integers.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
static DILocation * getMergedLocation(DILocation *LocA, DILocation *LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
uint64_t getMemSizeInBits() const
Returns the size in bits of the memory access.
bool isSimple() const
Returns true if the memory operation is neither atomic or volatile.
Register getValueReg() const
Get the stored value register.
Module * getParent()
Get the module that this global value is contained inside of...
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr unsigned getAddressSpace() const
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LegalizeActionStep getAction(const LegalityQuery &Query) const
Determine what action should be taken to legalize the described instruction.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
bool isFixedObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a fixed stack object.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
bool hasProperty(Property P) const
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
MachineInstrBuilder buildRotateRight(const DstOp &Dst, const SrcOp &Src, const SrcOp &Amt)
Build and insert Dst = G_ROTR Src, Amt.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
MachineInstrBuilder buildBSwap(const DstOp &Dst, const SrcOp &Src0)
Build and insert Dst = G_BSWAP Src0.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
void setDebugLoc(const DebugLoc &DL)
Set the debug location to DL for all the next build instructions.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_TRUNC Op.
void setMF(MachineFunction &MF)
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
Representation of each machine instruction.
const MachineBasicBlock * getParent() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
A description of a memory reference used in the backend.
LLT getMemoryType() const
Return the memory type of the memory reference.
const MachinePointerInfo & getPointerInfo() const
Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Representation for a specific memory location.
static uint64_t getSizeOrUnknown(const TypeSize &T)
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
virtual bool allowsMemoryAccess(LLVMContext &Context, const DataLayout &DL, EVT VT, unsigned AddrSpace=0, Align Alignment=Align(1), MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *Fast=nullptr) const
Return true if the target supports a memory access of this type for the given address space and align...
virtual bool canMergeStoresTo(unsigned AS, EVT MemVT, const MachineFunction &MF) const
Returns if it's reasonable to merge stores to MemVT size.
virtual const LegalizerInfo * getLegalizerInfo() const
virtual const TargetLowering * getTargetLowering() const
The instances of the Type class are immutable: once they are created, they are never changed.
constexpr ScalarTy getFixedValue() const
constexpr bool any(E Val)
@ Fast
Attempts to make calls as fast as possible (e.g.
@ C
The default llvm calling convention, compatible with C.
bool aliasIsKnownForLoadStore(const MachineInstr &MI1, const MachineInstr &MI2, bool &IsAlias, MachineRegisterInfo &MRI)
Compute whether or not a memory access at MI1 aliases with an access at MI2.
BaseIndexOffset getPointerInfo(Register Ptr, MachineRegisterInfo &MRI)
Returns a BaseIndexOffset which describes the pointer in Ptr.
bool instMayAlias(const MachineInstr &MI, const MachineInstr &Other, MachineRegisterInfo &MRI, AliasAnalysis *AA)
Returns true if the instruction MI may alias Other.
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ Unsupported
This operation is completely unsupported on the target.
operand_type_match m_Reg()
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
ManagedStatic< cl::opt< FnT >, OptCreatorT > Action
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
EVT getApproximateEVTForLLT(LLT Ty, const DataLayout &DL, LLVMContext &Ctx)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
LLT getLLTForType(Type &Ty, const DataLayout &DL)
Construct a low-level type based on an LLVM type.
bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...
Implement std::hash so that hash_code can be used in STL containers.
Helper struct to store a base, index and offset that forms an address.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
LegalizeAction Action
The action to take or the final answer.