14#ifndef LLVM_BITSTREAM_BITSTREAMWRITER_H
15#define LLVM_BITSTREAM_BITSTREAMWRITER_H
57 unsigned CurCodeSize = 2;
61 unsigned BlockInfoCurBID = 0;
64 std::vector<std::shared_ptr<BitCodeAbbrev>> CurAbbrevs;
68 std::optional<size_t> BlockFlushingStartPos;
71 unsigned PrevCodeSize;
73 std::vector<std::shared_ptr<BitCodeAbbrev>> PrevAbbrevs;
74 Block(
unsigned PCS,
size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {}
78 std::vector<Block> BlockScope;
84 std::vector<std::shared_ptr<BitCodeAbbrev>> Abbrevs;
86 std::vector<BlockInfo> BlockInfoRecords;
88 void WriteWord(
unsigned Value) {
90 support::endian::byte_swap<uint32_t, llvm::endianness::little>(
Value);
91 Buffer.
append(
reinterpret_cast<const char *
>(&
Value),
92 reinterpret_cast<const char *
>(&
Value + 1));
95 uint64_t GetNumOfFlushedBytes()
const {
96 return fdStream() ? fdStream()->
tell() : 0;
99 size_t GetBufferOffset()
const {
100 return Buffer.
size() + GetNumOfFlushedBytes();
103 size_t GetWordIndex()
const {
104 size_t Offset = GetBufferOffset();
109 void flushAndClear() {
112 assert(!BlockFlushingStartPos &&
113 "a call to markAndBlockFlushing should have been paired with a "
114 "call to getMarkedBufferAndResumeFlushing");
115 FS->write(Buffer.
data(), Buffer.
size());
122 void FlushToFile(
bool OnClosing =
false) {
123 if (!FS || Buffer.
empty())
126 return flushAndClear();
127 if (BlockFlushingStartPos)
129 if (fdStream() && Buffer.
size() > FlushThreshold)
133 raw_fd_stream *fdStream() {
return dyn_cast_or_null<raw_fd_stream>(FS); }
136 return dyn_cast_or_null<raw_fd_stream>(FS);
140 if (
auto *SV = dyn_cast<raw_svector_ostream>(&OutStream))
157 : Buffer(getInternalBufferFromStream(OutStream)),
159 FlushThreshold(
uint64_t(FlushThreshold) << 20) {}
164 : Buffer(Buff), FS(nullptr), FlushThreshold(0) {}
168 assert(BlockScope.empty() && CurAbbrevs.empty() &&
"Block imbalance");
177 assert(!BlockFlushingStartPos);
178 BlockFlushingStartPos = Buffer.
size();
187 assert(BlockFlushingStartPos);
188 size_t Start = *BlockFlushingStartPos;
189 BlockFlushingStartPos.reset();
190 return {&Buffer[Start], Buffer.
size() - Start};
209 uint64_t NumOfFlushedBytes = GetNumOfFlushedBytes();
211 if (ByteNo >= NumOfFlushedBytes) {
214 &Buffer[ByteNo - NumOfFlushedBytes], StartBit)) &&
215 "Expected to be patching over 0-value placeholders");
216 endian::writeAtBitAlignment<uint8_t, llvm::endianness::little, unaligned>(
217 &Buffer[ByteNo - NumOfFlushedBytes], NewByte, StartBit);
223 assert(fdStream() !=
nullptr);
230 size_t BytesNum = StartBit ? 2 : 1;
231 size_t BytesFromDisk = std::min(
static_cast<uint64_t>(BytesNum), NumOfFlushedBytes - ByteNo);
232 size_t BytesFromBuffer = BytesNum - BytesFromDisk;
242 fdStream()->
seek(ByteNo);
243 ssize_t BytesRead = fdStream()->
read(Bytes, BytesFromDisk);
245 assert(BytesRead >= 0 &&
static_cast<size_t>(BytesRead) == BytesFromDisk);
246 for (
size_t i = 0; i < BytesFromBuffer; ++i)
247 Bytes[BytesFromDisk + i] = Buffer[i];
249 unaligned>(Bytes, StartBit)) &&
250 "Expected to be patching over 0-value placeholders");
254 endian::writeAtBitAlignment<uint8_t, llvm::endianness::little, unaligned>(
255 Bytes, NewByte, StartBit);
258 fdStream()->
seek(ByteNo);
259 fdStream()->
write(Bytes, BytesFromDisk);
260 for (
size_t i = 0; i < BytesFromBuffer; ++i)
261 Buffer[i] = Bytes[BytesFromDisk + i];
264 fdStream()->
seek(CurPos);
283 assert(NumBits && NumBits <= 32 &&
"Invalid value size!");
284 assert((Val & ~(~0U >> (32-NumBits))) == 0 &&
"High bits set!");
285 CurValue |= Val << CurBit;
286 if (CurBit + NumBits < 32) {
295 CurValue = Val >> (32-CurBit);
298 CurBit = (CurBit+NumBits) & 31;
310 assert(NumBits <= 32 &&
"Too many bits to emit!");
311 uint32_t Threshold = 1U << (NumBits-1);
314 while (Val >= Threshold) {
315 Emit((Val & ((1U << (NumBits - 1)) - 1)) | (1U << (NumBits - 1)),
324 assert(NumBits <= 32 &&
"Too many bits to emit!");
328 uint32_t Threshold = 1U << (NumBits-1);
331 while (Val >= Threshold) {
333 (1U << (NumBits - 1)),
343 Emit(Val, CurCodeSize);
354 if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID)
355 return &BlockInfoRecords.back();
357 for (BlockInfo &BI : BlockInfoRecords)
358 if (BI.BlockID == BlockID)
371 size_t BlockSizeWordIndex = GetWordIndex();
372 unsigned OldCodeSize = CurCodeSize;
377 CurCodeSize = CodeLen;
381 BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex);
382 BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
391 assert(!BlockScope.empty() &&
"Block scope imbalance!");
392 const Block &
B = BlockScope.back();
400 size_t SizeInWords = GetWordIndex() -
B.StartSizeWord - 1;
407 CurCodeSize =
B.PrevCodeSize;
408 CurAbbrevs = std::move(
B.PrevAbbrevs);
409 BlockScope.pop_back();
420 template<
typename u
intty>
422 assert(
Op.isLiteral() &&
"Not a literal");
426 "Invalid abbrev for record!");
431 template<
typename u
intty>
433 assert(!
Op.isLiteral() &&
"Literals should use EmitAbbreviatedLiteral!");
436 switch (
Op.getEncoding()) {
439 if (
Op.getEncodingData())
440 Emit((
unsigned)V, (
unsigned)
Op.getEncodingData());
443 if (
Op.getEncodingData())
458 template <
typename u
intty>
460 StringRef Blob, std::optional<unsigned> Code) {
461 const char *BlobData = Blob.
data();
464 assert(AbbrevNo < CurAbbrevs.size() &&
"Invalid abbrev #!");
471 assert(e &&
"Expected non-empty abbreviation");
475 EmitAbbreviatedLiteral(
Op, *Code);
479 "Expected literal or scalar");
480 EmitAbbreviatedField(
Op, *Code);
484 unsigned RecordIdx = 0;
485 for (; i !=
e; ++i) {
487 if (
Op.isLiteral()) {
488 assert(RecordIdx < Vals.
size() &&
"Invalid abbrev/record");
489 EmitAbbreviatedLiteral(
Op, Vals[RecordIdx]);
493 assert(i + 2 == e &&
"array op not second to last?");
500 "Blob data and record entries specified for array!");
505 for (
unsigned i = 0; i != BlobLen; ++i)
506 EmitAbbreviatedField(EltEnc, (
unsigned char)BlobData[i]);
515 for (
unsigned e = Vals.
size(); RecordIdx != e; ++RecordIdx)
516 EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
524 "Blob data and record entries specified for blob operand!");
526 assert(Blob.
data() == BlobData &&
"BlobData got moved");
527 assert(Blob.
size() == BlobLen &&
"BlobLen got changed");
534 assert(RecordIdx < Vals.
size() &&
"Invalid abbrev/record");
535 EmitAbbreviatedField(
Op, Vals[RecordIdx]);
539 assert(RecordIdx == Vals.
size() &&
"Not all record operands emitted!");
540 assert(BlobData ==
nullptr &&
541 "Blob data specified for record that doesn't use it!");
546 template <
class UIntTy>
560 while (GetBufferOffset() & 3)
570 template <
typename Container>
571 void EmitRecord(
unsigned Code,
const Container &Vals,
unsigned Abbrev = 0) {
575 auto Count =
static_cast<uint32_t>(std::size(Vals));
579 for (
unsigned i = 0, e = Count; i != e; ++i)
590 template <
typename Container>
600 template <
typename Container>
603 EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals), Blob, std::nullopt);
605 template <
typename Container>
607 const char *BlobData,
unsigned BlobLen) {
608 return EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals),
609 StringRef(BlobData, BlobLen), std::nullopt);
614 template <
typename Container>
617 EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals), Array, std::nullopt);
619 template <
typename Container>
621 const char *ArrayData,
unsigned ArrayLen) {
622 return EmitRecordWithAbbrevImpl(
639 if (
Op.isLiteral()) {
642 Emit(
Op.getEncoding(), 3);
643 if (
Op.hasEncodingData())
653 CurAbbrevs.push_back(std::move(Abbv));
654 return static_cast<unsigned>(CurAbbrevs.size())-1 +
665 BlockInfoCurBID = ~0U;
666 BlockInfoRecords.clear();
671 void SwitchToBlockID(
unsigned BlockID) {
672 if (BlockInfoCurBID == BlockID)
return;
674 V.push_back(BlockID);
676 BlockInfoCurBID = BlockID;
679 BlockInfo &getOrCreateBlockInfo(
unsigned BlockID) {
684 BlockInfoRecords.emplace_back();
685 BlockInfoRecords.back().BlockID = BlockID;
686 return BlockInfoRecords.back();
694 SwitchToBlockID(BlockID);
698 BlockInfo &
Info = getOrCreateBlockInfo(BlockID);
699 Info.Abbrevs.push_back(std::move(Abbv));
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
BitCodeAbbrevOp - This describes one or more operands in an abbreviation.
static unsigned EncodeChar6(char C)
BitCodeAbbrev - This class represents an abbreviation record.
unsigned getNumOperandInfos() const
const BitCodeAbbrevOp & getOperandInfo(unsigned N) const
unsigned EmitAbbrev(std::shared_ptr< BitCodeAbbrev > Abbv)
Emits the abbreviation Abbv to the stream.
void markAndBlockFlushing()
For scenarios where the user wants to access a section of the stream to (for example) compute some ch...
StringRef getMarkedBufferAndResumeFlushing()
resumes flushing, but does not flush, and returns the section in the internal buffer starting from th...
void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev=0)
EmitRecord - Emit the specified record to the stream, using an abbrev if we have one to compress the ...
BitstreamWriter(SmallVectorImpl< char > &Buff)
Convenience constructor for users that start with a vector - avoids needing to wrap it in a raw_svect...
void Emit(uint32_t Val, unsigned NumBits)
void emitBlob(ArrayRef< UIntTy > Bytes, bool ShouldEmitSize=true)
Emit a blob, including flushing before and tail-padding.
void EmitCode(unsigned Val)
EmitCode - Emit the specified code.
void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, const char *BlobData, unsigned BlobLen)
void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, const char *ArrayData, unsigned ArrayLen)
void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, StringRef Blob)
EmitRecordWithBlob - Emit the specified record to the stream, using an abbrev that includes a blob at...
BitstreamWriter(raw_ostream &OutStream, uint32_t FlushThreshold=512)
Create a BitstreamWriter over a raw_ostream OutStream.
void BackpatchByte(uint64_t BitNo, uint8_t NewByte)
Backpatch a byte in the output at the given bit offset with the specified value.
unsigned EmitBlockInfoAbbrev(unsigned BlockID, std::shared_ptr< BitCodeAbbrev > Abbv)
EmitBlockInfoAbbrev - Emit a DEFINE_ABBREV record for the specified BlockID.
BlockInfo * getBlockInfo(unsigned BlockID)
getBlockInfo - If there is block info for the specified ID, return it, otherwise return null.
void EmitVBR64(uint64_t Val, unsigned NumBits)
void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, StringRef Array)
EmitRecordWithArray - Just like EmitRecordWithBlob, works with records that end with an array.
void EnterBlockInfoBlock()
EnterBlockInfoBlock - Start emitting the BLOCKINFO_BLOCK.
void EmitVBR(uint32_t Val, unsigned NumBits)
void BackpatchWord(uint64_t BitNo, unsigned Val)
void BackpatchWord64(uint64_t BitNo, uint64_t Val)
void emitBlob(StringRef Bytes, bool ShouldEmitSize=true)
void BackpatchHalfWord(uint64_t BitNo, uint16_t Val)
void EnterSubblock(unsigned BlockID, unsigned CodeLen)
unsigned GetAbbrevIDWidth() const
Retrieve the number of bits currently used to encode an abbrev ID.
uint64_t GetCurrentBitNo() const
Retrieve the current position in the stream, in bits.
void EmitRecordWithAbbrev(unsigned Abbrev, const Container &Vals)
EmitRecordWithAbbrev - Emit a record with the specified abbreviation.
This class represents an Operation in the Expression.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr size_t size() const
size - Get the string size.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
LLVM Value Representation.
uint64_t seek(uint64_t off)
Flushes the stream and repositions the underlying file descriptor position to the offset specified fr...
A raw_ostream of a file for reading/writing/seeking.
ssize_t read(char *Ptr, size_t Size)
This reads the Size bytes into a buffer pointed by Ptr.
This class implements an extremely fast bulk output stream that can only output to a stream.
uint64_t tell() const
tell - Return the current offset with the file.
raw_ostream & write(unsigned char C)
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BLOCKINFO_BLOCK_ID
BLOCKINFO_BLOCK is used to define metadata about blocks, for example, standard abbrevs that should be...
@ DEFINE_ABBREV
DEFINE_ABBREV - Defines an abbrev for the current block.
@ FIRST_APPLICATION_ABBREV
value_type readAtBitAlignment(const void *memory, uint64_t startBit)
Read a value of a particular endianness from memory, for a location that starts at the given bit offs...
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...