14#ifndef LLVM_BITSTREAM_BITSTREAMWRITER_H
15#define LLVM_BITSTREAM_BITSTREAMWRITER_H
54 unsigned BlockInfoCurBID;
57 std::vector<std::shared_ptr<BitCodeAbbrev>> CurAbbrevs;
60 unsigned PrevCodeSize;
62 std::vector<std::shared_ptr<BitCodeAbbrev>> PrevAbbrevs;
63 Block(
unsigned PCS,
size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {}
67 std::vector<Block> BlockScope;
73 std::vector<std::shared_ptr<BitCodeAbbrev>> Abbrevs;
75 std::vector<BlockInfo> BlockInfoRecords;
77 void WriteWord(
unsigned Value) {
78 Value = support::endian::byte_swap<uint32_t, support::little>(
Value);
80 reinterpret_cast<const char *
>(&
Value + 1));
83 uint64_t GetNumOfFlushedBytes()
const {
return FS ? FS->tell() : 0; }
85 size_t GetBufferOffset()
const {
return Out.
size() + GetNumOfFlushedBytes(); }
87 size_t GetWordIndex()
const {
88 size_t Offset = GetBufferOffset();
98 if (Out.
size() < FlushThreshold)
100 FS->write((
char *)&Out.
front(), Out.
size());
114 : Out(O), FS(FS), FlushThreshold(FlushThreshold << 20), CurBit(0),
115 CurValue(0), CurCodeSize(2) {}
118 assert(CurBit == 0 &&
"Unflushed data remaining");
119 assert(BlockScope.empty() && CurAbbrevs.empty() &&
"Block imbalance");
138 uint64_t NumOfFlushedBytes = GetNumOfFlushedBytes();
140 if (ByteNo >= NumOfFlushedBytes) {
141 assert((!endian::readAtBitAlignment<uint32_t, little, unaligned>(
142 &Out[ByteNo - NumOfFlushedBytes], StartBit)) &&
143 "Expected to be patching over 0-value placeholders");
144 endian::writeAtBitAlignment<uint32_t, little, unaligned>(
145 &Out[ByteNo - NumOfFlushedBytes], NewWord, StartBit);
155 size_t BytesNum = StartBit ? 8 : 4;
156 size_t BytesFromDisk = std::min(
static_cast<uint64_t>(BytesNum), NumOfFlushedBytes - ByteNo);
157 size_t BytesFromBuffer = BytesNum - BytesFromDisk;
168 ssize_t BytesRead = FS->read(Bytes, BytesFromDisk);
170 assert(BytesRead >= 0 &&
static_cast<size_t>(BytesRead) == BytesFromDisk);
171 for (
size_t i = 0; i < BytesFromBuffer; ++i)
172 Bytes[BytesFromDisk + i] = Out[i];
173 assert((!endian::readAtBitAlignment<uint32_t, little, unaligned>(
175 "Expected to be patching over 0-value placeholders");
179 endian::writeAtBitAlignment<uint32_t, little, unaligned>(Bytes, NewWord,
184 FS->write(Bytes, BytesFromDisk);
185 for (
size_t i = 0; i < BytesFromBuffer; ++i)
186 Out[i] = Bytes[BytesFromDisk + i];
198 assert(NumBits && NumBits <= 32 &&
"Invalid value size!");
199 assert((Val & ~(~0U >> (32-NumBits))) == 0 &&
"High bits set!");
200 CurValue |= Val << CurBit;
201 if (CurBit + NumBits < 32) {
210 CurValue = Val >> (32-CurBit);
213 CurBit = (CurBit+NumBits) & 31;
225 assert(NumBits <= 32 &&
"Too many bits to emit!");
226 uint32_t Threshold = 1U << (NumBits-1);
229 while (Val >= Threshold) {
230 Emit((Val & ((1 << (NumBits-1))-1)) | (1 << (NumBits-1)), NumBits);
238 assert(NumBits <= 32 &&
"Too many bits to emit!");
242 uint32_t Threshold = 1U << (NumBits-1);
245 while (Val >= Threshold) {
246 Emit(((
uint32_t)Val & ((1 << (NumBits - 1)) - 1)) | (1 << (NumBits - 1)),
256 Emit(Val, CurCodeSize);
267 if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID)
268 return &BlockInfoRecords.back();
270 for (BlockInfo &BI : BlockInfoRecords)
271 if (BI.BlockID == BlockID)
284 size_t BlockSizeWordIndex = GetWordIndex();
285 unsigned OldCodeSize = CurCodeSize;
290 CurCodeSize = CodeLen;
294 BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex);
295 BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
304 assert(!BlockScope.empty() &&
"Block scope imbalance!");
305 const Block &
B = BlockScope.back();
313 size_t SizeInWords = GetWordIndex() -
B.StartSizeWord - 1;
320 CurCodeSize =
B.PrevCodeSize;
321 CurAbbrevs = std::move(
B.PrevAbbrevs);
322 BlockScope.pop_back();
333 template<
typename u
intty>
335 assert(Op.isLiteral() &&
"Not a literal");
338 assert(V == Op.getLiteralValue() &&
339 "Invalid abbrev for record!");
344 template<
typename u
intty>
346 assert(!Op.isLiteral() &&
"Literals should use EmitAbbreviatedLiteral!");
349 switch (Op.getEncoding()) {
352 if (Op.getEncodingData())
353 Emit((
unsigned)V, (
unsigned)Op.getEncodingData());
356 if (Op.getEncodingData())
357 EmitVBR64(V, (
unsigned)Op.getEncodingData());
371 template <
typename u
intty>
373 StringRef Blob, std::optional<unsigned> Code) {
374 const char *BlobData = Blob.
data();
377 assert(AbbrevNo < CurAbbrevs.size() &&
"Invalid abbrev #!");
384 assert(e &&
"Expected non-empty abbreviation");
388 EmitAbbreviatedLiteral(Op, *Code);
392 "Expected literal or scalar");
393 EmitAbbreviatedField(Op, *Code);
397 unsigned RecordIdx = 0;
398 for (; i !=
e; ++i) {
400 if (
Op.isLiteral()) {
401 assert(RecordIdx < Vals.
size() &&
"Invalid abbrev/record");
402 EmitAbbreviatedLiteral(Op, Vals[RecordIdx]);
406 assert(i + 2 == e &&
"array op not second to last?");
413 "Blob data and record entries specified for array!");
418 for (
unsigned i = 0; i != BlobLen; ++i)
419 EmitAbbreviatedField(EltEnc, (
unsigned char)BlobData[i]);
428 for (
unsigned e = Vals.
size(); RecordIdx != e; ++RecordIdx)
429 EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
437 "Blob data and record entries specified for blob operand!");
439 assert(Blob.
data() == BlobData &&
"BlobData got moved");
440 assert(Blob.
size() == BlobLen &&
"BlobLen got changed");
447 assert(RecordIdx < Vals.
size() &&
"Invalid abbrev/record");
448 EmitAbbreviatedField(Op, Vals[RecordIdx]);
452 assert(RecordIdx == Vals.
size() &&
"Not all record operands emitted!");
453 assert(BlobData ==
nullptr &&
454 "Blob data specified for record that doesn't use it!");
459 template <
class UIntTy>
473 while (GetBufferOffset() & 3)
483 template <
typename Container>
484 void EmitRecord(
unsigned Code,
const Container &Vals,
unsigned Abbrev = 0) {
488 auto Count =
static_cast<uint32_t>(std::size(Vals));
492 for (
unsigned i = 0, e = Count; i != e; ++i)
503 template <
typename Container>
513 template <
typename Container>
516 EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals), Blob, std::nullopt);
518 template <
typename Container>
520 const char *BlobData,
unsigned BlobLen) {
521 return EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals),
522 StringRef(BlobData, BlobLen), std::nullopt);
527 template <
typename Container>
530 EmitRecordWithAbbrevImpl(Abbrev,
ArrayRef(Vals), Array, std::nullopt);
532 template <
typename Container>
534 const char *ArrayData,
unsigned ArrayLen) {
535 return EmitRecordWithAbbrevImpl(
551 Emit(Op.isLiteral(), 1);
552 if (Op.isLiteral()) {
555 Emit(Op.getEncoding(), 3);
556 if (Op.hasEncodingData())
566 CurAbbrevs.push_back(std::move(Abbv));
567 return static_cast<unsigned>(CurAbbrevs.size())-1 +
578 BlockInfoCurBID = ~0U;
579 BlockInfoRecords.clear();
584 void SwitchToBlockID(
unsigned BlockID) {
585 if (BlockInfoCurBID == BlockID)
return;
587 V.push_back(BlockID);
589 BlockInfoCurBID = BlockID;
592 BlockInfo &getOrCreateBlockInfo(
unsigned BlockID) {
597 BlockInfoRecords.emplace_back();
598 BlockInfoRecords.back().BlockID = BlockID;
599 return BlockInfoRecords.back();
607 SwitchToBlockID(BlockID);
611 BlockInfo &
Info = getOrCreateBlockInfo(BlockID);
612 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 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 ...
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...
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 BackpatchWord(uint64_t BitNo, unsigned NewWord)
Backpatch a 32-bit word in the output at the given bit offset with the specified value.
void EmitVBR(uint32_t Val, unsigned NumBits)
void BackpatchWord64(uint64_t BitNo, uint64_t Val)
BitstreamWriter(SmallVectorImpl< char > &O, raw_fd_stream *FS=nullptr, uint32_t FlushThreshold=512)
Create a BitstreamWriter that writes to Buffer O.
void emitBlob(StringRef Bytes, bool ShouldEmitSize=true)
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 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)
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.
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
LLVM Value Representation.
A raw_ostream of a file for reading/writing/seeking.
#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
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 a range to a container.