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();
89 assert((Offset & 3) == 0 &&
"Not 32-bit aligned");
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 (
unsigned i = 0,
e =
static_cast<unsigned>(BlockInfoRecords.size());
272 if (BlockInfoRecords[
i].BlockID == BlockID)
273 return &BlockInfoRecords[
i];
285 size_t BlockSizeWordIndex = GetWordIndex();
286 unsigned OldCodeSize = CurCodeSize;
291 CurCodeSize = CodeLen;
295 BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex);
296 BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
305 assert(!BlockScope.empty() &&
"Block scope imbalance!");
306 const Block &
B = BlockScope.back();
314 size_t SizeInWords = GetWordIndex() -
B.StartSizeWord - 1;
321 CurCodeSize =
B.PrevCodeSize;
323 BlockScope.pop_back();
334 template<
typename u
intty>
336 assert(
Op.isLiteral() &&
"Not a literal");
340 "Invalid abbrev for record!");
345 template<
typename u
intty>
346 void EmitAbbreviatedField(
const BitCodeAbbrevOp &
Op, uintty V) {
347 assert(!
Op.isLiteral() &&
"Literals should use EmitAbbreviatedLiteral!");
350 switch (
Op.getEncoding()) {
353 if (
Op.getEncodingData())
354 Emit((
unsigned)V, (
unsigned)
Op.getEncodingData());
357 if (
Op.getEncodingData())
372 template <
typename u
intty>
373 void EmitRecordWithAbbrevImpl(
unsigned Abbrev, ArrayRef<uintty> Vals,
374 StringRef Blob, Optional<unsigned> Code) {
375 const char *BlobData = Blob.data();
376 unsigned BlobLen = (unsigned) Blob.size();
378 assert(AbbrevNo < CurAbbrevs.size() &&
"Invalid abbrev #!");
379 const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get();
383 unsigned i = 0,
e =
static_cast<unsigned>(Abbv->getNumOperandInfos());
385 assert(
e &&
"Expected non-empty abbreviation");
386 const BitCodeAbbrevOp &
Op = Abbv->getOperandInfo(
i++);
389 EmitAbbreviatedLiteral(
Op,
Code.getValue());
393 "Expected literal or scalar");
394 EmitAbbreviatedField(
Op,
Code.getValue());
398 unsigned RecordIdx = 0;
399 for (;
i !=
e; ++
i) {
400 const BitCodeAbbrevOp &
Op = Abbv->getOperandInfo(
i);
401 if (
Op.isLiteral()) {
402 assert(RecordIdx < Vals.size() &&
"Invalid abbrev/record");
403 EmitAbbreviatedLiteral(
Op, Vals[RecordIdx]);
407 assert(
i + 2 ==
e &&
"array op not second to last?");
408 const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++
i);
413 assert(RecordIdx == Vals.size() &&
414 "Blob data and record entries specified for array!");
419 for (
unsigned i = 0;
i != BlobLen; ++
i)
420 EmitAbbreviatedField(EltEnc, (
unsigned char)BlobData[
i]);
429 for (
unsigned e = Vals.size(); RecordIdx !=
e; ++RecordIdx)
430 EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
437 assert(RecordIdx == Vals.size() &&
438 "Blob data and record entries specified for blob operand!");
440 assert(Blob.data() == BlobData &&
"BlobData got moved");
441 assert(Blob.size() == BlobLen &&
"BlobLen got changed");
448 assert(RecordIdx < Vals.size() &&
"Invalid abbrev/record");
449 EmitAbbreviatedField(
Op, Vals[RecordIdx]);
453 assert(RecordIdx == Vals.size() &&
"Not all record operands emitted!");
454 assert(BlobData ==
nullptr &&
455 "Blob data specified for record that doesn't use it!");
460 template <
class UIntTy>
474 while (GetBufferOffset() & 3)
484 template <
typename Container>
485 void EmitRecord(
unsigned Code,
const Container &Vals,
unsigned Abbrev = 0) {
493 for (
unsigned i = 0,
e = Count;
i !=
e; ++
i)
504 template <
typename Container>
514 template <
typename Container>
519 template <
typename Container>
521 const char *BlobData,
unsigned BlobLen) {
522 return EmitRecordWithAbbrevImpl(Abbrev,
makeArrayRef(Vals),
528 template <
typename Container>
533 template <
typename Container>
535 const char *ArrayData,
unsigned ArrayLen) {
536 return EmitRecordWithAbbrevImpl(Abbrev,
makeArrayRef(Vals),
553 if (
Op.isLiteral()) {
556 Emit(
Op.getEncoding(), 3);
557 if (
Op.hasEncodingData())
568 return static_cast<unsigned>(CurAbbrevs.size())-1 +
579 BlockInfoCurBID = ~0U;
580 BlockInfoRecords.clear();
585 void SwitchToBlockID(
unsigned BlockID) {
586 if (BlockInfoCurBID == BlockID)
return;
588 V.push_back(BlockID);
590 BlockInfoCurBID = BlockID;
593 BlockInfo &getOrCreateBlockInfo(
unsigned BlockID) {
598 BlockInfoRecords.emplace_back();
599 BlockInfoRecords.back().BlockID = BlockID;
600 return BlockInfoRecords.back();
608 SwitchToBlockID(BlockID);
612 BlockInfo &
Info = getOrCreateBlockInfo(BlockID);