LLVM 22.0.0git
XtensaFrameLowering.cpp
Go to the documentation of this file.
1//===- XtensaFrameLowering.cpp - Xtensa Frame Information -----------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains the Xtensa implementation of TargetFrameLowering class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "XtensaFrameLowering.h"
14#include "XtensaInstrInfo.h"
16#include "XtensaSubtarget.h"
22#include "llvm/IR/Function.h"
23
24using namespace llvm;
25
26// Minimum frame = reg save area (4 words) plus static chain (1 word)
27// and the total number of words must be a multiple of 128 bits.
28// Width of a word, in units (bytes).
29#define UNITS_PER_WORD 4
30#define MIN_FRAME_SIZE (8 * UNITS_PER_WORD)
31
33 : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0,
34 Align(4)),
35 STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
36
38 const MachineFrameInfo &MFI = MF.getFrameInfo();
41}
42
44 MachineBasicBlock &MBB) const {
45 assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
48 DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
49 MCRegister SP = Xtensa::SP;
53
54 // First, compute final stack size.
55 uint64_t StackSize = MFI.getStackSize();
56 uint64_t PrevStackSize = StackSize;
57
58 // Round up StackSize to 16*N
59 StackSize += (16 - StackSize) & 0xf;
60
61 if (STI.isWindowedABI()) {
62 StackSize += 32;
63 uint64_t MaxAlignment = MFI.getMaxAlign().value();
64 if (MaxAlignment > 32)
65 StackSize += MaxAlignment;
66
67 if (StackSize <= 32760) {
68 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
69 .addReg(SP)
70 .addImm(StackSize);
71 } else {
72 // Use a8 as a temporary since a0-a7 may be live.
73 MCRegister TmpReg = Xtensa::A8;
74
75 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ENTRY))
76 .addReg(SP)
78 TII.loadImmediate(MBB, MBBI, &TmpReg, StackSize - MIN_FRAME_SIZE);
79 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), TmpReg)
80 .addReg(SP)
81 .addReg(TmpReg);
82 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::MOVSP), SP).addReg(TmpReg);
83 }
84
85 // Calculate how much is needed to have the correct alignment.
86 // Change offset to: alignment + difference.
87 // For example, in case of alignment of 128:
88 // diff_to_128_aligned_address = (128 - (SP & 127))
89 // new_offset = SP + diff_to_128_aligned_address
90 // This is safe to do because we increased the stack size by MaxAlignment.
91 MCRegister Reg, RegMisAlign;
92 if (MaxAlignment > 32) {
93 TII.loadImmediate(MBB, MBBI, &RegMisAlign, MaxAlignment - 1);
94 TII.loadImmediate(MBB, MBBI, &Reg, MaxAlignment);
95 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::AND))
96 .addReg(RegMisAlign, RegState::Define)
97 .addReg(FP)
98 .addReg(RegMisAlign);
99 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::SUB), RegMisAlign)
100 .addReg(Reg)
101 .addReg(RegMisAlign);
102 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::ADD), SP)
103 .addReg(SP)
104 .addReg(RegMisAlign, RegState::Kill);
105 }
106
107 // Store FP register in A8, because FP may be used to pass function
108 // arguments
109 if (XtensaFI->isSaveFrameRegister()) {
110 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), Xtensa::A8)
111 .addReg(FP)
112 .addReg(FP);
113 }
114
115 // if framepointer enabled, set it to point to the stack pointer.
116 if (hasFP(MF)) {
117 // Insert instruction "move $fp, $sp" at this location.
118 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
119 .addReg(SP)
120 .addReg(SP)
122
124 nullptr, MRI->getDwarfRegNum(FP, true), StackSize);
125 unsigned CFIIndex = MF.addFrameInst(Inst);
126 BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
127 .addCFIIndex(CFIIndex);
128 } else {
129 // emit ".cfi_def_cfa_offset StackSize"
130 unsigned CFIIndex = MF.addFrameInst(
131 MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
132 BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
133 .addCFIIndex(CFIIndex);
134 }
135 } else {
136 // No need to allocate space on the stack.
137 if (StackSize == 0 && !MFI.adjustsStack())
138 return;
139
140 // Adjust stack.
141 TII.adjustStackPtr(SP, -StackSize, MBB, MBBI);
142
143 // emit ".cfi_def_cfa_offset StackSize"
144 unsigned CFIIndex =
145 MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
146 BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
147 .addCFIIndex(CFIIndex);
148
149 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
150
151 if (!CSI.empty()) {
152 // Find the instruction past the last instruction that saves a
153 // callee-saved register to the stack. The callee-saved store
154 // instructions are placed at the begin of basic block, so
155 // iterate over instruction sequence and check that
156 // save instructions are placed correctly.
157 for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
158#ifndef NDEBUG
159 const CalleeSavedInfo &Info = CSI[i];
160 int FI = Info.getFrameIdx();
161 int StoreFI = 0;
162
163 // Checking that the instruction is exactly as expected
164 bool IsStoreInst = false;
165 if (MBBI->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
166 Register DstReg = MBBI->getOperand(0).getReg();
167 Register Reg = MBBI->getOperand(1).getReg();
168 IsStoreInst = Info.getDstReg() == DstReg.asMCReg() &&
169 Info.getReg() == Reg.asMCReg();
170 } else {
171 Register Reg = TII.isStoreToStackSlot(*MBBI, StoreFI);
172 IsStoreInst = Reg.asMCReg() == Info.getReg() && StoreFI == FI;
173 }
174 assert(IsStoreInst &&
175 "Unexpected callee-saved register store instruction");
176#endif
177 ++MBBI;
178 }
179
180 // Iterate over list of callee-saved registers and emit .cfi_offset
181 // directives.
182 for (const auto &I : CSI) {
183 int64_t Offset = MFI.getObjectOffset(I.getFrameIdx());
184 MCRegister Reg = I.getReg();
185
186 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
187 nullptr, MRI->getDwarfRegNum(Reg, 1), Offset));
188 BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
189 .addCFIIndex(CFIIndex);
190 }
191 }
192
193 // if framepointer enabled, set it to point to the stack pointer.
194 if (hasFP(MF)) {
195 // Insert instruction "move $fp, $sp" at this location.
196 BuildMI(MBB, MBBI, DL, TII.get(Xtensa::OR), FP)
197 .addReg(SP)
198 .addReg(SP)
200
201 // emit ".cfi_def_cfa_register $fp"
202 unsigned CFIIndex =
204 nullptr, MRI->getDwarfRegNum(FP, true)));
205 BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
206 .addCFIIndex(CFIIndex);
207 }
208 }
209
210 if (StackSize != PrevStackSize) {
211 MFI.setStackSize(StackSize);
212
213 for (int i = MFI.getObjectIndexBegin(); i < MFI.getObjectIndexEnd(); i++) {
214 if (!MFI.isDeadObjectIndex(i)) {
215 int64_t SPOffset = MFI.getObjectOffset(i);
216
217 if (SPOffset < 0)
218 MFI.setObjectOffset(i, SPOffset - StackSize + PrevStackSize);
219 }
220 }
221 }
222}
223
225 MachineBasicBlock &MBB) const {
227 MachineFrameInfo &MFI = MF.getFrameInfo();
228 DebugLoc DL = MBBI->getDebugLoc();
229 MCRegister SP = Xtensa::SP;
230 MCRegister FP = TRI->getFrameRegister(MF);
231
232 // if framepointer enabled, restore the stack pointer.
233 if (hasFP(MF)) {
234 // We should place restore stack pointer instruction just before
235 // sequence of instructions which restores callee-saved registers.
236 // This sequence is placed at the end of the basic block,
237 // so we should find first instruction of the sequence.
239
240 const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
241
242 // Find the first instruction at the end that restores a callee-saved
243 // register.
244 for (unsigned i = 0, e = CSI.size(); i < e; ++i) {
245 --I;
246#ifndef NDEBUG
247 const CalleeSavedInfo &Info = CSI[i];
248 int FI = Info.getFrameIdx();
249 int LoadFI = 0;
250
251 // Checking that the instruction is exactly as expected
252 bool IsRestoreInst = false;
253 if (I->getOpcode() == TargetOpcode::COPY && Info.isSpilledToReg()) {
254 Register Reg = I->getOperand(0).getReg();
255 Register DstReg = I->getOperand(1).getReg();
256 IsRestoreInst = Info.getDstReg() == DstReg.asMCReg() &&
257 Info.getReg() == Reg.asMCReg();
258 } else {
259 Register Reg = TII.isLoadFromStackSlot(*I, LoadFI);
260 IsRestoreInst = Info.getReg() == Reg.asMCReg() && LoadFI == FI;
261 }
262 assert(IsRestoreInst &&
263 "Unexpected callee-saved register restore instruction");
264#endif
265 }
266 if (STI.isWindowedABI()) {
267 // In most architectures, we need to explicitly restore the stack pointer
268 // before returning.
269 //
270 // For Xtensa Windowed Register option, it is not needed to explicitly
271 // restore the stack pointer. Reason being is that on function return,
272 // the window of the caller (including the old stack pointer) gets
273 // restored anyways.
274 } else {
275 BuildMI(MBB, I, DL, TII.get(Xtensa::OR), SP).addReg(FP).addReg(FP);
276 }
277 }
278
279 if (STI.isWindowedABI())
280 return;
281
282 // Get the number of bytes from FrameInfo
283 uint64_t StackSize = MFI.getStackSize();
284
285 if (!StackSize)
286 return;
287
288 // Adjust stack.
289 TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
290}
291
296 MachineBasicBlock &EntryBlock = *(MF->begin());
297
298 if (STI.isWindowedABI())
299 return true;
300
301 for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
302 // Add the callee-saved register as live-in. Do not add if the register is
303 // A0 and return address is taken, because it will be implemented in
304 // method XtensaTargetLowering::LowerRETURNADDR.
305 // It's killed at the spill, unless the register is RA and return address
306 // is taken.
307 MCRegister Reg = CSI[i].getReg();
308 bool IsA0AndRetAddrIsTaken =
309 (Reg == Xtensa::A0) && MF->getFrameInfo().isReturnAddressTaken();
310 if (!IsA0AndRetAddrIsTaken)
311 EntryBlock.addLiveIn(Reg);
312
313 // Insert the spill to the stack frame.
314 bool IsKill = !IsA0AndRetAddrIsTaken;
315 const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
316 TII.storeRegToStackSlot(EntryBlock, MI, Reg, IsKill, CSI[i].getFrameIdx(),
317 RC, TRI, Register());
318 }
319
320 return true;
321}
322
326 if (STI.isWindowedABI())
327 return true;
329}
330
331// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
335 if (!hasReservedCallFrame(MF)) {
336 int64_t Amount = I->getOperand(0).getImm();
337
338 if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN)
339 Amount = -Amount;
340
341 TII.adjustStackPtr(Xtensa::SP, Amount, MBB, I);
342 }
343
344 return MBB.erase(I);
345}
346
348 BitVector &SavedRegs,
349 RegScavenger *RS) const {
350 MCRegister FP = TRI->getFrameRegister(MF);
351
352 if (STI.isWindowedABI()) {
353 return;
354 }
355
357
358 // Mark $fp as used if function has dedicated frame pointer.
359 if (hasFP(MF))
360 SavedRegs.set(FP);
361}
362
364 MachineFunction &MF, RegScavenger *RS) const {
365 // Set scavenging frame index if necessary.
366 MachineFrameInfo &MFI = MF.getFrameInfo();
367 uint64_t MaxSPOffset = MFI.estimateStackSize(MF);
368 auto *XtensaFI = MF.getInfo<XtensaMachineFunctionInfo>();
369 unsigned ScavSlotsNum = 0;
370
371 if (!isInt<12>(MaxSPOffset))
372 ScavSlotsNum = 1;
373
374 // Far branches over 18-bit offset require a spill slot for scratch register.
375 bool IsLargeFunction = !isInt<18>(MF.estimateFunctionSizeInBytes());
376 if (IsLargeFunction)
377 ScavSlotsNum = std::max(ScavSlotsNum, 1u);
378
379 const TargetRegisterClass &RC = Xtensa::ARRegClass;
380 unsigned Size = TRI->getSpillSize(RC);
381 Align Alignment = TRI->getSpillAlign(RC);
382 for (unsigned I = 0; I < ScavSlotsNum; I++) {
383 int FI = MFI.CreateSpillStackObject(Size, Alignment);
385
386 if (IsLargeFunction &&
387 XtensaFI->getBranchRelaxationScratchFrameIndex() == -1)
388 XtensaFI->setBranchRelaxationScratchFrameIndex(FI);
389 }
390}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
uint64_t Size
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
Register const TargetRegisterInfo * TRI
This file declares the machine register scavenger class.
#define MIN_FRAME_SIZE
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:147
BitVector & set()
Definition: BitVector.h:351
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
A debug info location.
Definition: DebugLoc.h:124
static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_def_cfa_register modifies a rule for computing CFA.
Definition: MCDwarf.h:592
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa defines a rule for computing CFA as: take address from Register and add Offset to it.
Definition: MCDwarf.h:585
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_offset Previous value of Register is saved at offset Offset from CFA.
Definition: MCDwarf.h:627
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa_offset modifies a rule for computing CFA.
Definition: MCDwarf.h:600
const MCRegisterInfo * getRegisterInfo() const
Definition: MCContext.h:414
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Wrapper class representing physical registers. Should be passed by value.
Definition: MCRegister.h:33
LLVM_ABI iterator getLastNonDebugInstr(bool SkipPseudoOp=true)
Returns an iterator to the last non-debug instruction in the basic block, or end().
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
bool adjustsStack() const
Return true if this function adjusts the stack – e.g., when calling another function.
bool isReturnAddressTaken() const
This method may be called any time after instruction selection is complete to determine if there is a...
Align getMaxAlign() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
void setObjectOffset(int ObjectIdx, int64_t SPOffset)
Set the stack frame offset of the specified object.
LLVM_ABI int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
LLVM_ABI uint64_t estimateStackSize(const MachineFunction &MF) const
Estimate and return the size of the stack frame.
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
void setStackSize(uint64_t Size)
Set the size of the stack.
int getObjectIndexBegin() const
Return the minimum frame object index.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
unsigned addFrameInst(const MCCFIInstruction &Inst)
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MCContext & getContext() const
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineBasicBlock & front() const
int64_t estimateFunctionSizeInBytes()
Return an estimate of the function's code size, taking into account block and function alignment.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:303
void addScavengingFrameIndex(int FI)
Add a scavenging frame index.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
Definition: Register.h:102
Information about stack frame layout on the target.
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
virtual bool hasReservedCallFrame(const MachineFunction &MF) const
hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...
virtual void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS=nullptr) const
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
TargetOptions Options
LLVM_ABI bool DisableFramePointerElim(const MachineFunction &MF) const
DisableFramePointerElim - This returns true if frame pointer elimination optimization should be disab...
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
void processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const override
processFunctionBeforeFrameFinalized - This method is called immediately before the specified function...
bool hasFPImpl(const MachineFunction &MF) const override
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
void emitPrologue(MachineFunction &, MachineBasicBlock &) const override
emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.
XtensaFrameLowering(const XtensaSubtarget &STI)
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const override
This method determines which of the registers reported by TargetRegisterInfo::getCalleeSavedRegs() sh...
Register isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const override
void adjustStackPtr(MCRegister SP, int64_t Amount, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const
Adjust SP by Amount bytes.
Register isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const override
void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MCRegister *Reg, int64_t Value) const
void storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, bool isKill, int FrameIndex, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, Register VReg, MachineInstr::MIFlag Flags=MachineInstr::NoFlags) const override
Register getFrameRegister(const MachineFunction &MF) const override
bool isWindowedABI() const
@ Define
Register definition.
@ Kill
The last use of a register.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
uint64_t value() const
This is a hole in the type system and should not be abused.
Definition: Alignment.h:85