41 UserSGPRInfo(
F, *STI), WorkGroupIDX(
false), WorkGroupIDY(
false),
43 PrivateSegmentWaveByteOffset(
false), WorkItemIDX(
false),
45 GITPtrHigh(0xffffffff), HighBitsOf32BitAddress(0) {
47 FlatWorkGroupSizes = ST.getFlatWorkGroupSizes(
F);
48 WavesPerEU = ST.getWavesPerEU(
F);
49 MaxNumWorkGroups = ST.getMaxNumWorkGroups(
F);
55 VRegFlags.reserve(1024);
67 MayNeedAGPRs = ST.hasMAIInsts();
74 StackPtrOffsetReg = AMDGPU::SGPR32;
76 ScratchRSrcReg = AMDGPU::SGPR48_SGPR49_SGPR50_SGPR51;
81 ImplicitArgPtr =
false;
86 FrameOffsetReg = AMDGPU::SGPR33;
87 StackPtrOffsetReg = AMDGPU::SGPR32;
89 if (!ST.enableFlatScratch()) {
92 ScratchRSrcReg = AMDGPU::SGPR0_SGPR1_SGPR2_SGPR3;
98 if (!
F.hasFnAttribute(
"amdgpu-no-implicitarg-ptr"))
99 ImplicitArgPtr =
true;
101 ImplicitArgPtr =
false;
105 if (ST.hasGFX90AInsts() &&
106 ST.getMaxNumVGPRs(
F) <= AMDGPU::VGPR_32RegClass.getNumRegs() &&
108 MayNeedAGPRs =
false;
113 ST.hasArchitectedSGPRs())) {
114 if (IsKernel || !
F.hasFnAttribute(
"amdgpu-no-workgroup-id-x"))
117 if (!
F.hasFnAttribute(
"amdgpu-no-workgroup-id-y"))
120 if (!
F.hasFnAttribute(
"amdgpu-no-workgroup-id-z"))
125 if (IsKernel || !
F.hasFnAttribute(
"amdgpu-no-workitem-id-x"))
128 if (!
F.hasFnAttribute(
"amdgpu-no-workitem-id-y") &&
129 ST.getMaxWorkitemID(
F, 1) != 0)
132 if (!
F.hasFnAttribute(
"amdgpu-no-workitem-id-z") &&
133 ST.getMaxWorkitemID(
F, 2) != 0)
136 if (!IsKernel && !
F.hasFnAttribute(
"amdgpu-no-lds-kernel-id"))
146 if (!ST.flatScratchIsArchitected()) {
147 PrivateSegmentWaveByteOffset =
true;
152 ArgInfo.PrivateSegmentWaveByteOffset =
157 Attribute A =
F.getFnAttribute(
"amdgpu-git-ptr-high");
162 A =
F.getFnAttribute(
"amdgpu-32bit-address-high-bits");
163 S =
A.getValueAsString();
170 if (ST.hasMAIInsts() && !ST.hasGFX90AInsts()) {
172 AMDGPU::VGPR_32RegClass.getRegister(ST.getMaxNumVGPRs(
F) - 1);
194 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SGPR_128RegClass));
196 return ArgInfo.PrivateSegmentBuffer.getRegister();
201 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
203 return ArgInfo.DispatchPtr.getRegister();
208 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
210 return ArgInfo.QueuePtr.getRegister();
216 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
218 return ArgInfo.KernargSegmentPtr.getRegister();
223 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
225 return ArgInfo.DispatchID.getRegister();
230 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
232 return ArgInfo.FlatScratchInit.getRegister();
238 return ArgInfo.PrivateSegmentSize.getRegister();
243 getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass));
245 return ArgInfo.ImplicitBufferPtr.getRegister();
251 return ArgInfo.LDSKernelId.getRegister();
256 unsigned AllocSizeDWord,
int KernArgIdx,
int PaddingSGPRs) {
258 "Preload kernel argument allocated twice.");
259 NumUserSGPRs += PaddingSGPRs;
264 TRI.getMatchingSuperReg(getNextUserSGPR(), AMDGPU::sub0, RC);
266 (RC == &AMDGPU::SReg_32RegClass || RC == &AMDGPU::SReg_64RegClass)) {
267 ArgInfo.PreloadKernArgs[KernArgIdx].Regs.push_back(PreloadReg);
268 NumUserSGPRs += AllocSizeDWord;
270 for (
unsigned I = 0;
I < AllocSizeDWord; ++
I) {
271 ArgInfo.PreloadKernArgs[KernArgIdx].Regs.push_back(getNextUserSGPR());
278 return &
ArgInfo.PreloadKernArgs[KernArgIdx].Regs;
295 WWMSpills.
insert(std::make_pair(
305 for (
auto &Reg : WWMSpills) {
307 CalleeSavedRegs.push_back(Reg);
309 ScratchRegs.push_back(Reg);
315 for (
unsigned I = 0; CSRegs[
I]; ++
I) {
316 if (CSRegs[
I] == Reg)
327 for (
unsigned I = 0, E = SpillPhysVGPRs.size();
I < E; ++
I) {
330 TRI->findUnusedRegister(
MRI, &AMDGPU::VGPR_32RegClass, MF);
331 if (!NewReg || NewReg >= Reg)
334 MRI.replaceRegWith(Reg, NewReg);
337 SpillPhysVGPRs[
I] = NewReg;
338 WWMReservedRegs.
remove(Reg);
339 WWMReservedRegs.
insert(NewReg);
340 WWMSpills.
insert(std::make_pair(NewReg, WWMSpills[Reg]));
341 WWMSpills.
erase(Reg);
350bool SIMachineFunctionInfo::allocateVirtualVGPRForSGPRSpills(
355 LaneVGPR =
MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);
356 SpillVGPRs.push_back(LaneVGPR);
358 LaneVGPR = SpillVGPRs.back();
361 SGPRSpillsToVirtualVGPRLanes[FI].push_back(
366bool SIMachineFunctionInfo::allocatePhysicalVGPRForSGPRSpills(
367 MachineFunction &MF,
int FI,
unsigned LaneIndex,
bool IsPrologEpilog) {
376 LaneVGPR =
TRI->findUnusedRegister(
MRI, &AMDGPU::VGPR_32RegClass, MF,
378 if (LaneVGPR == AMDGPU::NoRegister) {
381 SGPRSpillsToPhysicalVGPRLanes.erase(FI);
391 SpillPhysVGPRs.push_back(LaneVGPR);
393 LaneVGPR = SpillPhysVGPRs.back();
396 SGPRSpillsToPhysicalVGPRLanes[FI].push_back(
403 bool IsPrologEpilog) {
404 std::vector<SIRegisterInfo::SpilledReg> &SpillLanes =
405 SpillToPhysVGPRLane ? SGPRSpillsToPhysicalVGPRLanes[FI]
406 : SGPRSpillsToVirtualVGPRLanes[FI];
409 if (!SpillLanes.empty())
414 unsigned WaveSize = ST.getWavefrontSize();
416 unsigned Size = FrameInfo.getObjectSize(FI);
417 unsigned NumLanes =
Size / 4;
419 if (NumLanes > WaveSize)
422 assert(
Size >= 4 &&
"invalid sgpr spill size");
423 assert(ST.getRegisterInfo()->spillSGPRToVGPR() &&
424 "not spilling SGPRs to VGPRs");
426 unsigned &NumSpillLanes = SpillToPhysVGPRLane ? NumPhysicalVGPRSpillLanes
427 : NumVirtualVGPRSpillLanes;
429 for (
unsigned I = 0;
I < NumLanes; ++
I, ++NumSpillLanes) {
430 unsigned LaneIndex = (NumSpillLanes % WaveSize);
432 bool Allocated = SpillToPhysVGPRLane
433 ? allocatePhysicalVGPRForSGPRSpills(MF, FI, LaneIndex,
435 : allocateVirtualVGPRForSGPRSpills(MF, FI, LaneIndex);
457 auto &Spill = VGPRToAGPRSpills[FI];
460 if (!Spill.Lanes.empty())
461 return Spill.FullyAllocated;
464 unsigned NumLanes =
Size / 4;
465 Spill.Lanes.resize(NumLanes, AMDGPU::NoRegister);
468 isAGPRtoVGPR ? AMDGPU::VGPR_32RegClass : AMDGPU::AGPR_32RegClass;
471 auto &SpillRegs = isAGPRtoVGPR ? SpillAGPR : SpillVGPR;
473 Spill.FullyAllocated =
true;
488 OtherUsedRegs.
set(Reg);
490 OtherUsedRegs.
set(Reg);
493 for (
int I = NumLanes - 1;
I >= 0; --
I) {
494 NextSpillReg = std::find_if(
496 return MRI.isAllocatable(Reg) && !MRI.isPhysRegUsed(Reg) &&
500 if (NextSpillReg == Regs.
end()) {
501 Spill.FullyAllocated =
false;
505 OtherUsedRegs.
set(*NextSpillReg);
507 MRI.reserveReg(*NextSpillReg,
TRI);
508 Spill.Lanes[
I] = *NextSpillReg++;
511 return Spill.FullyAllocated;
524 SGPRSpillsToVirtualVGPRLanes.erase(R.first);
529 if (!ResetSGPRSpillStackIDs) {
532 SGPRSpillsToPhysicalVGPRLanes.erase(R.first);
535 bool HaveSGPRToMemory =
false;
537 if (ResetSGPRSpillStackIDs) {
545 HaveSGPRToMemory =
true;
551 for (
auto &R : VGPRToAGPRSpills) {
556 return HaveSGPRToMemory;
566 TRI.getSpillAlign(AMDGPU::SGPR_32RegClass),
false);
570MCPhysReg SIMachineFunctionInfo::getNextUserSGPR()
const {
571 assert(NumSystemSGPRs == 0 &&
"System SGPRs must be added after user SGPRs");
572 return AMDGPU::SGPR0 + NumUserSGPRs;
575MCPhysReg SIMachineFunctionInfo::getNextSystemSGPR()
const {
576 return AMDGPU::SGPR0 + NumUserSGPRs + NumSystemSGPRs;
579void SIMachineFunctionInfo::MRI_NoteNewVirtualRegister(
Register Reg) {
583void SIMachineFunctionInfo::MRI_NoteCloneVirtualRegister(
Register NewReg,
585 VRegFlags.grow(NewReg);
586 VRegFlags[NewReg] = VRegFlags[SrcReg];
592 if (!ST.isAmdPalOS())
595 if (ST.hasMergedShaders()) {
601 GitPtrLo = AMDGPU::SGPR8;
620static std::optional<yaml::SIArgumentInfo>
625 auto convertArg = [&](std::optional<yaml::SIArgument> &
A,
632 if (Arg.isRegister()) {
639 SA.
Mask = Arg.getMask();
660 ArgInfo.PrivateSegmentWaveByteOffset);
676 : ExplicitKernArgSize(MFI.getExplicitKernArgSize()),
677 MaxKernArgAlign(MFI.getMaxKernArgAlign()), LDSSize(MFI.getLDSSize()),
678 GDSSize(MFI.getGDSSize()),
679 DynLDSAlign(MFI.getDynLDSAlign()), IsEntryFunction(MFI.isEntryFunction()),
680 NoSignedZerosFPMath(MFI.hasNoSignedZerosFPMath()),
681 MemoryBound(MFI.isMemoryBound()), WaveLimiter(MFI.needsWaveLimiter()),
682 HasSpilledSGPRs(MFI.hasSpilledSGPRs()),
683 HasSpilledVGPRs(MFI.hasSpilledVGPRs()),
684 HighBitsOf32BitAddress(MFI.get32BitAddressHighBits()),
685 Occupancy(MFI.getOccupancy()),
689 BytesInStackArgArea(MFI.getBytesInStackArgArea()),
690 ReturnsVoid(MFI.returnsVoid()),
692 PSInputAddr(MFI.getPSInputAddr()),
693 PSInputEnable(MFI.getPSInputEnable()),
694 Mode(MFI.getMode()) {
745 "", std::nullopt, std::nullopt);
746 SourceRange = YamlMFI.
ScavengeFI->SourceRange;
757 return !
F.hasFnAttribute(
"amdgpu-no-agpr");
764 if (!mayNeedAGPRs()) {
777 for (
unsigned I = 0, E =
MRI.getNumVirtRegs();
I != E; ++
I) {
783 }
else if (!RC && !
MRI.use_empty(Reg) &&
MRI.getType(Reg).isValid()) {
789 for (
MCRegister Reg : AMDGPU::AGPR_32RegClass) {
790 if (
MRI.isPhysRegUsed(Reg)) {
unsigned const MachineRegisterInfo * MRI
Provides AMDGPU specific target descriptions.
Base class for AMDGPU specific classes of TargetSubtarget.
The AMDGPU TargetMachine interface definition for hw codegen targets.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
AMD GCN specific subclass of TargetSubtarget.
unsigned const TargetRegisterInfo * TRI
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const GCNTargetMachine & getTM(const GCNSubtarget *STI)
static std::optional< yaml::SIArgumentInfo > convertArgumentInfo(const AMDGPUFunctionArgInfo &ArgInfo, const TargetRegisterInfo &TRI)
static yaml::StringValue regToString(Register Reg, const TargetRegisterInfo &TRI)
Interface definition for SIRegisterInfo.
static const AMDGPUFunctionArgInfo FixedABIFunctionInfo
uint32_t getLDSSize() const
bool isChainFunction() const
bool isEntryFunction() const
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
void setBitsInMask(const uint32_t *Mask, unsigned MaskWords=~0u)
setBitsInMask - Add '1' bits from Mask to this vector.
Allocate memory in an ever growing pool, as if by bump-pointer.
Lightweight error class with error context and mandatory checking.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
const SITargetLowering * getTargetLowering() const override
void allocKernargPreloadSGPRs(unsigned NumSGPRs)
Wrapper class representing physical registers. Should be passed by value.
void sortUniqueLiveIns()
Sorts and uniques the LiveIns vector.
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
void removeLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll())
Remove the specified register from the live in set.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
bool hasCalls() const
Return true if the current function has any function calls.
int CreateSpillStackObject(uint64_t Size, Align Alignment)
Create a new statically sized stack object that represents a spill slot, returning a nonnegative iden...
void setStackID(int ObjectIdx, uint8_t ID)
bool isSpillSlotObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a spill slot.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
void RemoveStackObject(int ObjectIdx)
Remove or mark dead a statically sized stack object.
int getObjectIndexEnd() const
Return one past the maximum frame object index.
uint8_t getStackID(int ObjectIdx) const
int getObjectIndexBegin() const
Return the minimum frame object index.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * cloneInfo(const Ty &Old)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const MCPhysReg * getCalleeSavedRegs() const
Returns list of callee saved registers.
size_type count(const KeyT &Key) const
VectorType::iterator erase(typename VectorType::iterator Iterator)
Remove the element given by Iterator.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
This interface provides simple read-only access to a block of memory, and provides simple methods for...
virtual StringRef getBufferIdentifier() const
Return an identifier for this buffer, typically the filename it was read from.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
bool usesAGPRs(const MachineFunction &MF) const
bool initializeBaseYamlFields(const yaml::SIMachineFunctionInfo &YamlMFI, const MachineFunction &MF, PerFunctionMIParsingState &PFS, SMDiagnostic &Error, SMRange &SourceRange)
Register addPrivateSegmentSize(const SIRegisterInfo &TRI)
void allocateWWMSpill(MachineFunction &MF, Register VGPR, uint64_t Size=4, Align Alignment=Align(4))
Register addDispatchPtr(const SIRegisterInfo &TRI)
Register getLongBranchReservedReg() const
Register addFlatScratchInit(const SIRegisterInfo &TRI)
unsigned getMaxWavesPerEU() const
int getScavengeFI(MachineFrameInfo &MFI, const SIRegisterInfo &TRI)
Register addQueuePtr(const SIRegisterInfo &TRI)
SIMachineFunctionInfo(const SIMachineFunctionInfo &MFI)=default
Register getGITPtrLoReg(const MachineFunction &MF) const
bool allocateVGPRSpillToAGPR(MachineFunction &MF, int FI, bool isAGPRtoVGPR)
Reserve AGPRs or VGPRs to support spilling for FrameIndex FI.
void splitWWMSpillRegisters(MachineFunction &MF, SmallVectorImpl< std::pair< Register, int > > &CalleeSavedRegs, SmallVectorImpl< std::pair< Register, int > > &ScratchRegs) const
Register getSGPRForEXECCopy() const
bool mayUseAGPRs(const Function &F) const
bool isCalleeSavedReg(const MCPhysReg *CSRegs, MCPhysReg Reg) const
void shiftSpillPhysVGPRsToLowestRange(MachineFunction &MF)
Register addLDSKernelId()
Register getVGPRForAGPRCopy() const
bool allocateSGPRSpillToVGPRLane(MachineFunction &MF, int FI, bool SpillToPhysVGPRLane=false, bool IsPrologEpilog=false)
Register addKernargSegmentPtr(const SIRegisterInfo &TRI)
Register addDispatchID(const SIRegisterInfo &TRI)
bool removeDeadFrameIndices(MachineFrameInfo &MFI, bool ResetSGPRSpillStackIDs)
If ResetSGPRSpillStackIDs is true, reset the stack ID from sgpr-spill to the default stack.
MachineFunctionInfo * clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, const DenseMap< MachineBasicBlock *, MachineBasicBlock * > &Src2DstMBB) const override
Make a functionally equivalent copy of this MachineFunctionInfo in MF.
bool checkIndexInPrologEpilogSGPRSpills(int FI) const
Register addPrivateSegmentBuffer(const SIRegisterInfo &TRI)
const ReservedRegSet & getWWMReservedRegs() const
std::optional< int > getOptionalScavengeFI() const
Register addImplicitBufferPtr(const SIRegisterInfo &TRI)
void limitOccupancy(const MachineFunction &MF)
SmallVectorImpl< MCRegister > * addPreloadedKernArg(const SIRegisterInfo &TRI, const TargetRegisterClass *RC, unsigned AllocSizeDWord, int KernArgIdx, int PaddingSGPRs)
void reserveWWMRegister(Register Reg)
static bool isChainScratchRegister(Register VGPR)
static bool isAGPRClass(const TargetRegisterClass *RC)
Instances of this class encapsulate one diagnostic report, allowing printing to a raw_ostream as a ca...
Represents a location in source code.
Represents a range in source code.
bool remove(const value_type &X)
Remove an item from the set vector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
typename SuperClass::const_iterator const_iterator
unsigned getMainFileID() const
const MemoryBuffer * getMemoryBuffer(unsigned i) const
StringRef - Represent a constant reference to a string, i.e.
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
constexpr bool empty() const
empty - Check if the string is empty.
const TargetMachine & getTargetMachine() const
ArrayRef< MCPhysReg > getRegisters() const
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
A raw_ostream that writes to an std::string.
bool isEntryFunctionCC(CallingConv::ID CC)
bool isChainCC(CallingConv::ID CC)
unsigned getInitialPSInputAddr(const Function &F)
bool isGraphics(CallingConv::ID cc)
@ AMDGPU_CS
Used for Mesa/AMDPAL compute shaders.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ AMDGPU_Gfx
Used for AMD graphics targets.
@ AMDGPU_HS
Used for Mesa/AMDPAL hull shaders (= tessellation control shaders).
@ AMDGPU_GS
Used for Mesa/AMDPAL geometry shaders.
@ AMDGPU_PS
Used for Mesa/AMDPAL pixel shaders.
@ SPIR_KERNEL
Used for SPIR kernel functions.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
This is an optimization pass for GlobalISel generic memory operations.
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
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...
Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
This struct is a compact representation of a valid (non-zero power of two) alignment.
static ArgDescriptor createRegister(Register Reg, unsigned Mask=~0u)
Helper struct shared between Function Specialization and SCCP Solver.
MachineFunctionInfo - This class can be derived from and used by targets to hold private target-speci...
A serializaable representation of a reference to a stack object or fixed stack object.
std::optional< SIArgument > PrivateSegmentWaveByteOffset
std::optional< SIArgument > WorkGroupIDY
std::optional< SIArgument > FlatScratchInit
std::optional< SIArgument > DispatchPtr
std::optional< SIArgument > DispatchID
std::optional< SIArgument > WorkItemIDY
std::optional< SIArgument > WorkGroupIDX
std::optional< SIArgument > ImplicitArgPtr
std::optional< SIArgument > QueuePtr
std::optional< SIArgument > WorkGroupInfo
std::optional< SIArgument > LDSKernelId
std::optional< SIArgument > ImplicitBufferPtr
std::optional< SIArgument > WorkItemIDX
std::optional< SIArgument > KernargSegmentPtr
std::optional< SIArgument > WorkItemIDZ
std::optional< SIArgument > PrivateSegmentSize
std::optional< SIArgument > PrivateSegmentBuffer
std::optional< SIArgument > WorkGroupIDZ
std::optional< unsigned > Mask
static SIArgument createArgument(bool IsReg)
StringValue SGPRForEXECCopy
SmallVector< StringValue > WWMReservedRegs
uint32_t HighBitsOf32BitAddress
SIMachineFunctionInfo()=default
StringValue LongBranchReservedReg
uint64_t ExplicitKernArgSize
void mappingImpl(yaml::IO &YamlIO) override
StringValue VGPRForAGPRCopy
std::optional< FrameIndex > ScavengeFI
unsigned BytesInStackArgArea
A wrapper around std::string which contains a source range that's being set during parsing.