File indexing completed on 2026-05-10 08:43:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_BITSTREAM_BITSTREAMWRITER_H
0015 #define LLVM_BITSTREAM_BITSTREAMWRITER_H
0016
0017 #include "llvm/ADT/ArrayRef.h"
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/ADT/StringRef.h"
0020 #include "llvm/Bitstream/BitCodes.h"
0021 #include "llvm/Support/Casting.h"
0022 #include "llvm/Support/Endian.h"
0023 #include "llvm/Support/MathExtras.h"
0024 #include "llvm/Support/raw_ostream.h"
0025 #include <algorithm>
0026 #include <optional>
0027 #include <vector>
0028
0029 namespace llvm {
0030
0031 class BitstreamWriter {
0032
0033
0034 SmallVector<char, 0> OwnBuffer;
0035
0036
0037
0038 SmallVectorImpl<char> &Buffer;
0039
0040
0041
0042
0043 raw_ostream *const FS;
0044
0045
0046
0047 const uint64_t FlushThreshold;
0048
0049
0050 unsigned CurBit = 0;
0051
0052
0053 uint32_t CurValue = 0;
0054
0055
0056
0057 unsigned CurCodeSize = 2;
0058
0059
0060
0061 unsigned BlockInfoCurBID = 0;
0062
0063
0064 std::vector<std::shared_ptr<BitCodeAbbrev>> CurAbbrevs;
0065
0066
0067
0068 std::optional<size_t> BlockFlushingStartPos;
0069
0070 struct Block {
0071 unsigned PrevCodeSize;
0072 size_t StartSizeWord;
0073 std::vector<std::shared_ptr<BitCodeAbbrev>> PrevAbbrevs;
0074 Block(unsigned PCS, size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {}
0075 };
0076
0077
0078 std::vector<Block> BlockScope;
0079
0080
0081
0082 struct BlockInfo {
0083 unsigned BlockID;
0084 std::vector<std::shared_ptr<BitCodeAbbrev>> Abbrevs;
0085 };
0086 std::vector<BlockInfo> BlockInfoRecords;
0087
0088 void WriteWord(unsigned Value) {
0089 Value =
0090 support::endian::byte_swap<uint32_t, llvm::endianness::little>(Value);
0091 Buffer.append(reinterpret_cast<const char *>(&Value),
0092 reinterpret_cast<const char *>(&Value + 1));
0093 }
0094
0095 uint64_t GetNumOfFlushedBytes() const {
0096 return fdStream() ? fdStream()->tell() : 0;
0097 }
0098
0099 size_t GetBufferOffset() const {
0100 return Buffer.size() + GetNumOfFlushedBytes();
0101 }
0102
0103 size_t GetWordIndex() const {
0104 size_t Offset = GetBufferOffset();
0105 assert((Offset & 3) == 0 && "Not 32-bit aligned");
0106 return Offset / 4;
0107 }
0108
0109 void flushAndClear() {
0110 assert(FS);
0111 assert(!Buffer.empty());
0112 assert(!BlockFlushingStartPos &&
0113 "a call to markAndBlockFlushing should have been paired with a "
0114 "call to getMarkedBufferAndResumeFlushing");
0115 FS->write(Buffer.data(), Buffer.size());
0116 Buffer.clear();
0117 }
0118
0119
0120
0121
0122 void FlushToFile(bool OnClosing = false) {
0123 if (!FS || Buffer.empty())
0124 return;
0125 if (OnClosing)
0126 return flushAndClear();
0127 if (BlockFlushingStartPos)
0128 return;
0129 if (fdStream() && Buffer.size() > FlushThreshold)
0130 flushAndClear();
0131 }
0132
0133 raw_fd_stream *fdStream() { return dyn_cast_or_null<raw_fd_stream>(FS); }
0134
0135 const raw_fd_stream *fdStream() const {
0136 return dyn_cast_or_null<raw_fd_stream>(FS);
0137 }
0138
0139 SmallVectorImpl<char> &getInternalBufferFromStream(raw_ostream &OutStream) {
0140 if (auto *SV = dyn_cast<raw_svector_ostream>(&OutStream))
0141 return SV->buffer();
0142 return OwnBuffer;
0143 }
0144
0145 public:
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 BitstreamWriter(raw_ostream &OutStream, uint32_t FlushThreshold = 512)
0157 : Buffer(getInternalBufferFromStream(OutStream)),
0158 FS(!isa<raw_svector_ostream>(OutStream) ? &OutStream : nullptr),
0159 FlushThreshold(uint64_t(FlushThreshold) << 20) {}
0160
0161
0162
0163 BitstreamWriter(SmallVectorImpl<char> &Buff)
0164 : Buffer(Buff), FS(nullptr), FlushThreshold(0) {}
0165
0166 ~BitstreamWriter() {
0167 FlushToWord();
0168 assert(BlockScope.empty() && CurAbbrevs.empty() && "Block imbalance");
0169 FlushToFile(true);
0170 }
0171
0172
0173
0174
0175
0176 void markAndBlockFlushing() {
0177 assert(!BlockFlushingStartPos);
0178 BlockFlushingStartPos = Buffer.size();
0179 }
0180
0181
0182
0183
0184
0185
0186 StringRef getMarkedBufferAndResumeFlushing() {
0187 assert(BlockFlushingStartPos);
0188 size_t Start = *BlockFlushingStartPos;
0189 BlockFlushingStartPos.reset();
0190 return {&Buffer[Start], Buffer.size() - Start};
0191 }
0192
0193
0194 uint64_t GetCurrentBitNo() const { return GetBufferOffset() * 8 + CurBit; }
0195
0196
0197 unsigned GetAbbrevIDWidth() const { return CurCodeSize; }
0198
0199
0200
0201
0202
0203
0204
0205 void BackpatchByte(uint64_t BitNo, uint8_t NewByte) {
0206 using namespace llvm::support;
0207 uint64_t ByteNo = BitNo / 8;
0208 uint64_t StartBit = BitNo & 7;
0209 uint64_t NumOfFlushedBytes = GetNumOfFlushedBytes();
0210
0211 if (ByteNo >= NumOfFlushedBytes) {
0212 assert((!endian::readAtBitAlignment<uint8_t, llvm::endianness::little,
0213 unaligned>(
0214 &Buffer[ByteNo - NumOfFlushedBytes], StartBit)) &&
0215 "Expected to be patching over 0-value placeholders");
0216 endian::writeAtBitAlignment<uint8_t, llvm::endianness::little, unaligned>(
0217 &Buffer[ByteNo - NumOfFlushedBytes], NewByte, StartBit);
0218 return;
0219 }
0220
0221
0222
0223 assert(fdStream() != nullptr);
0224
0225
0226 uint64_t CurPos = fdStream()->tell();
0227
0228
0229 char Bytes[3];
0230 size_t BytesNum = StartBit ? 2 : 1;
0231 size_t BytesFromDisk = std::min(static_cast<uint64_t>(BytesNum), NumOfFlushedBytes - ByteNo);
0232 size_t BytesFromBuffer = BytesNum - BytesFromDisk;
0233
0234
0235
0236
0237
0238 #ifdef NDEBUG
0239 if (StartBit)
0240 #endif
0241 {
0242 fdStream()->seek(ByteNo);
0243 ssize_t BytesRead = fdStream()->read(Bytes, BytesFromDisk);
0244 (void)BytesRead;
0245 assert(BytesRead >= 0 && static_cast<size_t>(BytesRead) == BytesFromDisk);
0246 for (size_t i = 0; i < BytesFromBuffer; ++i)
0247 Bytes[BytesFromDisk + i] = Buffer[i];
0248 assert((!endian::readAtBitAlignment<uint8_t, llvm::endianness::little,
0249 unaligned>(Bytes, StartBit)) &&
0250 "Expected to be patching over 0-value placeholders");
0251 }
0252
0253
0254 endian::writeAtBitAlignment<uint8_t, llvm::endianness::little, unaligned>(
0255 Bytes, NewByte, StartBit);
0256
0257
0258 fdStream()->seek(ByteNo);
0259 fdStream()->write(Bytes, BytesFromDisk);
0260 for (size_t i = 0; i < BytesFromBuffer; ++i)
0261 Buffer[i] = Bytes[BytesFromDisk + i];
0262
0263
0264 fdStream()->seek(CurPos);
0265 }
0266
0267 void BackpatchHalfWord(uint64_t BitNo, uint16_t Val) {
0268 BackpatchByte(BitNo, (uint8_t)Val);
0269 BackpatchByte(BitNo + 8, (uint8_t)(Val >> 8));
0270 }
0271
0272 void BackpatchWord(uint64_t BitNo, unsigned Val) {
0273 BackpatchHalfWord(BitNo, (uint16_t)Val);
0274 BackpatchHalfWord(BitNo + 16, (uint16_t)(Val >> 16));
0275 }
0276
0277 void BackpatchWord64(uint64_t BitNo, uint64_t Val) {
0278 BackpatchWord(BitNo, (uint32_t)Val);
0279 BackpatchWord(BitNo + 32, (uint32_t)(Val >> 32));
0280 }
0281
0282 void Emit(uint32_t Val, unsigned NumBits) {
0283 assert(NumBits && NumBits <= 32 && "Invalid value size!");
0284 assert((Val & ~(~0U >> (32-NumBits))) == 0 && "High bits set!");
0285 CurValue |= Val << CurBit;
0286 if (CurBit + NumBits < 32) {
0287 CurBit += NumBits;
0288 return;
0289 }
0290
0291
0292 WriteWord(CurValue);
0293
0294 if (CurBit)
0295 CurValue = Val >> (32-CurBit);
0296 else
0297 CurValue = 0;
0298 CurBit = (CurBit+NumBits) & 31;
0299 }
0300
0301 void FlushToWord() {
0302 if (CurBit) {
0303 WriteWord(CurValue);
0304 CurBit = 0;
0305 CurValue = 0;
0306 }
0307 }
0308
0309 void EmitVBR(uint32_t Val, unsigned NumBits) {
0310 assert(NumBits <= 32 && "Too many bits to emit!");
0311 uint32_t Threshold = 1U << (NumBits-1);
0312
0313
0314 while (Val >= Threshold) {
0315 Emit((Val & ((1U << (NumBits - 1)) - 1)) | (1U << (NumBits - 1)),
0316 NumBits);
0317 Val >>= NumBits-1;
0318 }
0319
0320 Emit(Val, NumBits);
0321 }
0322
0323 void EmitVBR64(uint64_t Val, unsigned NumBits) {
0324 assert(NumBits <= 32 && "Too many bits to emit!");
0325 if ((uint32_t)Val == Val)
0326 return EmitVBR((uint32_t)Val, NumBits);
0327
0328 uint32_t Threshold = 1U << (NumBits-1);
0329
0330
0331 while (Val >= Threshold) {
0332 Emit(((uint32_t)Val & ((1U << (NumBits - 1)) - 1)) |
0333 (1U << (NumBits - 1)),
0334 NumBits);
0335 Val >>= NumBits-1;
0336 }
0337
0338 Emit((uint32_t)Val, NumBits);
0339 }
0340
0341
0342 void EmitCode(unsigned Val) {
0343 Emit(Val, CurCodeSize);
0344 }
0345
0346
0347
0348
0349
0350
0351
0352 BlockInfo *getBlockInfo(unsigned BlockID) {
0353
0354 if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID)
0355 return &BlockInfoRecords.back();
0356
0357 for (BlockInfo &BI : BlockInfoRecords)
0358 if (BI.BlockID == BlockID)
0359 return &BI;
0360 return nullptr;
0361 }
0362
0363 void EnterSubblock(unsigned BlockID, unsigned CodeLen) {
0364
0365
0366 EmitCode(bitc::ENTER_SUBBLOCK);
0367 EmitVBR(BlockID, bitc::BlockIDWidth);
0368 EmitVBR(CodeLen, bitc::CodeLenWidth);
0369 FlushToWord();
0370
0371 size_t BlockSizeWordIndex = GetWordIndex();
0372 unsigned OldCodeSize = CurCodeSize;
0373
0374
0375 Emit(0, bitc::BlockSizeWidth);
0376
0377 CurCodeSize = CodeLen;
0378
0379
0380
0381 BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex);
0382 BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
0383
0384
0385
0386 if (BlockInfo *Info = getBlockInfo(BlockID))
0387 append_range(CurAbbrevs, Info->Abbrevs);
0388 }
0389
0390 void ExitBlock() {
0391 assert(!BlockScope.empty() && "Block scope imbalance!");
0392 const Block &B = BlockScope.back();
0393
0394
0395
0396 EmitCode(bitc::END_BLOCK);
0397 FlushToWord();
0398
0399
0400 size_t SizeInWords = GetWordIndex() - B.StartSizeWord - 1;
0401 uint64_t BitNo = uint64_t(B.StartSizeWord) * 32;
0402
0403
0404 BackpatchWord(BitNo, SizeInWords);
0405
0406
0407 CurCodeSize = B.PrevCodeSize;
0408 CurAbbrevs = std::move(B.PrevAbbrevs);
0409 BlockScope.pop_back();
0410 FlushToFile();
0411 }
0412
0413
0414
0415
0416
0417 private:
0418
0419
0420 template<typename uintty>
0421 void EmitAbbreviatedLiteral(const BitCodeAbbrevOp &Op, uintty V) {
0422 assert(Op.isLiteral() && "Not a literal");
0423
0424
0425 assert(V == Op.getLiteralValue() &&
0426 "Invalid abbrev for record!");
0427 }
0428
0429
0430
0431 template<typename uintty>
0432 void EmitAbbreviatedField(const BitCodeAbbrevOp &Op, uintty V) {
0433 assert(!Op.isLiteral() && "Literals should use EmitAbbreviatedLiteral!");
0434
0435
0436 switch (Op.getEncoding()) {
0437 default: llvm_unreachable("Unknown encoding!");
0438 case BitCodeAbbrevOp::Fixed:
0439 if (Op.getEncodingData())
0440 Emit((unsigned)V, (unsigned)Op.getEncodingData());
0441 break;
0442 case BitCodeAbbrevOp::VBR:
0443 if (Op.getEncodingData())
0444 EmitVBR64(V, (unsigned)Op.getEncodingData());
0445 break;
0446 case BitCodeAbbrevOp::Char6:
0447 Emit(BitCodeAbbrevOp::EncodeChar6((char)V), 6);
0448 break;
0449 }
0450 }
0451
0452
0453
0454
0455
0456
0457
0458 template <typename uintty>
0459 void EmitRecordWithAbbrevImpl(unsigned Abbrev, ArrayRef<uintty> Vals,
0460 StringRef Blob, std::optional<unsigned> Code) {
0461 const char *BlobData = Blob.data();
0462 unsigned BlobLen = (unsigned) Blob.size();
0463 unsigned AbbrevNo = Abbrev-bitc::FIRST_APPLICATION_ABBREV;
0464 assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
0465 const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get();
0466
0467 EmitCode(Abbrev);
0468
0469 unsigned i = 0, e = static_cast<unsigned>(Abbv->getNumOperandInfos());
0470 if (Code) {
0471 assert(e && "Expected non-empty abbreviation");
0472 const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i++);
0473
0474 if (Op.isLiteral())
0475 EmitAbbreviatedLiteral(Op, *Code);
0476 else {
0477 assert(Op.getEncoding() != BitCodeAbbrevOp::Array &&
0478 Op.getEncoding() != BitCodeAbbrevOp::Blob &&
0479 "Expected literal or scalar");
0480 EmitAbbreviatedField(Op, *Code);
0481 }
0482 }
0483
0484 unsigned RecordIdx = 0;
0485 for (; i != e; ++i) {
0486 const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
0487 if (Op.isLiteral()) {
0488 assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
0489 EmitAbbreviatedLiteral(Op, Vals[RecordIdx]);
0490 ++RecordIdx;
0491 } else if (Op.getEncoding() == BitCodeAbbrevOp::Array) {
0492
0493 assert(i + 2 == e && "array op not second to last?");
0494 const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i);
0495
0496
0497
0498 if (BlobData) {
0499 assert(RecordIdx == Vals.size() &&
0500 "Blob data and record entries specified for array!");
0501
0502 EmitVBR(static_cast<uint32_t>(BlobLen), 6);
0503
0504
0505 for (unsigned i = 0; i != BlobLen; ++i)
0506 EmitAbbreviatedField(EltEnc, (unsigned char)BlobData[i]);
0507
0508
0509 BlobData = nullptr;
0510 } else {
0511
0512 EmitVBR(static_cast<uint32_t>(Vals.size()-RecordIdx), 6);
0513
0514
0515 for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx)
0516 EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
0517 }
0518 } else if (Op.getEncoding() == BitCodeAbbrevOp::Blob) {
0519
0520
0521
0522 if (BlobData) {
0523 assert(RecordIdx == Vals.size() &&
0524 "Blob data and record entries specified for blob operand!");
0525
0526 assert(Blob.data() == BlobData && "BlobData got moved");
0527 assert(Blob.size() == BlobLen && "BlobLen got changed");
0528 emitBlob(Blob);
0529 BlobData = nullptr;
0530 } else {
0531 emitBlob(Vals.slice(RecordIdx));
0532 }
0533 } else {
0534 assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
0535 EmitAbbreviatedField(Op, Vals[RecordIdx]);
0536 ++RecordIdx;
0537 }
0538 }
0539 assert(RecordIdx == Vals.size() && "Not all record operands emitted!");
0540 assert(BlobData == nullptr &&
0541 "Blob data specified for record that doesn't use it!");
0542 }
0543
0544 public:
0545
0546 template <class UIntTy>
0547 void emitBlob(ArrayRef<UIntTy> Bytes, bool ShouldEmitSize = true) {
0548
0549 if (ShouldEmitSize)
0550 EmitVBR(static_cast<uint32_t>(Bytes.size()), 6);
0551
0552
0553 FlushToWord();
0554
0555
0556 assert(llvm::all_of(Bytes, [](UIntTy B) { return isUInt<8>(B); }));
0557 Buffer.append(Bytes.begin(), Bytes.end());
0558
0559
0560 while (GetBufferOffset() & 3)
0561 Buffer.push_back(0);
0562 }
0563 void emitBlob(StringRef Bytes, bool ShouldEmitSize = true) {
0564 emitBlob(ArrayRef((const uint8_t *)Bytes.data(), Bytes.size()),
0565 ShouldEmitSize);
0566 }
0567
0568
0569
0570 template <typename Container>
0571 void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev = 0) {
0572 if (!Abbrev) {
0573
0574
0575 auto Count = static_cast<uint32_t>(std::size(Vals));
0576 EmitCode(bitc::UNABBREV_RECORD);
0577 EmitVBR(Code, 6);
0578 EmitVBR(Count, 6);
0579 for (unsigned i = 0, e = Count; i != e; ++i)
0580 EmitVBR64(Vals[i], 6);
0581 return;
0582 }
0583
0584 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), StringRef(), Code);
0585 }
0586
0587
0588
0589
0590 template <typename Container>
0591 void EmitRecordWithAbbrev(unsigned Abbrev, const Container &Vals) {
0592 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), StringRef(), std::nullopt);
0593 }
0594
0595
0596
0597
0598
0599
0600 template <typename Container>
0601 void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals,
0602 StringRef Blob) {
0603 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), Blob, std::nullopt);
0604 }
0605 template <typename Container>
0606 void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals,
0607 const char *BlobData, unsigned BlobLen) {
0608 return EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals),
0609 StringRef(BlobData, BlobLen), std::nullopt);
0610 }
0611
0612
0613
0614 template <typename Container>
0615 void EmitRecordWithArray(unsigned Abbrev, const Container &Vals,
0616 StringRef Array) {
0617 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), Array, std::nullopt);
0618 }
0619 template <typename Container>
0620 void EmitRecordWithArray(unsigned Abbrev, const Container &Vals,
0621 const char *ArrayData, unsigned ArrayLen) {
0622 return EmitRecordWithAbbrevImpl(
0623 Abbrev, ArrayRef(Vals), StringRef(ArrayData, ArrayLen), std::nullopt);
0624 }
0625
0626
0627
0628
0629
0630 private:
0631
0632 void EncodeAbbrev(const BitCodeAbbrev &Abbv) {
0633 EmitCode(bitc::DEFINE_ABBREV);
0634 EmitVBR(Abbv.getNumOperandInfos(), 5);
0635 for (unsigned i = 0, e = static_cast<unsigned>(Abbv.getNumOperandInfos());
0636 i != e; ++i) {
0637 const BitCodeAbbrevOp &Op = Abbv.getOperandInfo(i);
0638 Emit(Op.isLiteral(), 1);
0639 if (Op.isLiteral()) {
0640 EmitVBR64(Op.getLiteralValue(), 8);
0641 } else {
0642 Emit(Op.getEncoding(), 3);
0643 if (Op.hasEncodingData())
0644 EmitVBR64(Op.getEncodingData(), 5);
0645 }
0646 }
0647 }
0648 public:
0649
0650
0651 unsigned EmitAbbrev(std::shared_ptr<BitCodeAbbrev> Abbv) {
0652 EncodeAbbrev(*Abbv);
0653 CurAbbrevs.push_back(std::move(Abbv));
0654 return static_cast<unsigned>(CurAbbrevs.size())-1 +
0655 bitc::FIRST_APPLICATION_ABBREV;
0656 }
0657
0658
0659
0660
0661
0662
0663 void EnterBlockInfoBlock() {
0664 EnterSubblock(bitc::BLOCKINFO_BLOCK_ID, 2);
0665 BlockInfoCurBID = ~0U;
0666 BlockInfoRecords.clear();
0667 }
0668 private:
0669
0670
0671 void SwitchToBlockID(unsigned BlockID) {
0672 if (BlockInfoCurBID == BlockID) return;
0673 SmallVector<unsigned, 2> V;
0674 V.push_back(BlockID);
0675 EmitRecord(bitc::BLOCKINFO_CODE_SETBID, V);
0676 BlockInfoCurBID = BlockID;
0677 }
0678
0679 BlockInfo &getOrCreateBlockInfo(unsigned BlockID) {
0680 if (BlockInfo *BI = getBlockInfo(BlockID))
0681 return *BI;
0682
0683
0684 BlockInfoRecords.emplace_back();
0685 BlockInfoRecords.back().BlockID = BlockID;
0686 return BlockInfoRecords.back();
0687 }
0688
0689 public:
0690
0691
0692
0693 unsigned EmitBlockInfoAbbrev(unsigned BlockID, std::shared_ptr<BitCodeAbbrev> Abbv) {
0694 SwitchToBlockID(BlockID);
0695 EncodeAbbrev(*Abbv);
0696
0697
0698 BlockInfo &Info = getOrCreateBlockInfo(BlockID);
0699 Info.Abbrevs.push_back(std::move(Abbv));
0700
0701 return Info.Abbrevs.size()-1+bitc::FIRST_APPLICATION_ABBREV;
0702 }
0703 };
0704
0705
0706 }
0707
0708 #endif