LLVM: include/llvm/Bitstream/BitstreamWriter.h Source File (original) (raw)
32
33
35
36
37
39
40
41
42
44
45
46
47 const uint64_t FlushThreshold;
48
49
50 unsigned CurBit = 0;
51
52
54
55
56
57 unsigned CurCodeSize = 2;
58
59
60
61 unsigned BlockInfoCurBID = 0;
62
63
64 std::vector<std::shared_ptr> CurAbbrevs;
65
66
67
68 std::optional<size_t> BlockFlushingStartPos;
69
70 struct Block {
71 unsigned PrevCodeSize;
72 size_t StartSizeWord;
73 std::vector<std::shared_ptr> PrevAbbrevs;
74 Block(unsigned PCS, size_t SSW) : PrevCodeSize(PCS), StartSizeWord(SSW) {}
75 };
76
77
78 std::vector BlockScope;
79
80
81
82 struct BlockInfo {
83 unsigned BlockID;
84 std::vector<std::shared_ptr> Abbrevs;
85 };
86 std::vector BlockInfoRecords;
87
88 void WriteWord(unsigned Value) {
91 Buffer.append(reinterpret_cast<const char *>(&Value),
92 reinterpret_cast<const char *>(&Value + 1));
93 }
94
95 uint64_t GetNumOfFlushedBytes() const {
96 return fdStream() ? fdStream()->tell() : 0;
97 }
98
99 size_t GetBufferOffset() const {
100 return Buffer.size() + GetNumOfFlushedBytes();
101 }
102
103 size_t GetWordIndex() const {
104 size_t Offset = GetBufferOffset();
105 assert((Offset & 3) == 0 && "Not 32-bit aligned");
107 }
108
109 void flushAndClear() {
111 assert(!Buffer.empty());
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());
116 Buffer.clear();
117 }
118
119
120
121
122 void FlushToFile(bool OnClosing = false) {
123 if (!FS || Buffer.empty())
124 return;
125 if (OnClosing)
126 return flushAndClear();
127 if (BlockFlushingStartPos)
128 return;
129 if (fdStream() && Buffer.size() > FlushThreshold)
130 flushAndClear();
131 }
132
134
137 }
138
141 return SV->buffer();
142 return OwnBuffer;
143 }
144
145public:
146
147
148
149
150
151
152
153
154
155
157 : Buffer(getInternalBufferFromStream(OutStream)),
159 FlushThreshold(uint64_t(FlushThreshold) << 20) {}
160
161
162
164 : Buffer(Buff), FS(nullptr), FlushThreshold(0) {}
165
168 assert(BlockScope.empty() && CurAbbrevs.empty() && "Block imbalance");
169 FlushToFile(true);
170 }
171
172
173
174
175
177 assert(!BlockFlushingStartPos);
178 BlockFlushingStartPos = Buffer.size();
179 }
180
181
182
183
184
185
187 assert(BlockFlushingStartPos);
188 size_t Start = *BlockFlushingStartPos;
189 BlockFlushingStartPos.reset();
190 return {&Buffer[Start], Buffer.size() - Start};
191 }
192
193
195
196
198
199
200
201
202
203
204
208 uint64_t StartBit = BitNo & 7;
209 uint64_t NumOfFlushedBytes = GetNumOfFlushedBytes();
210
211 if (ByteNo >= NumOfFlushedBytes) {
214 &Buffer[ByteNo - NumOfFlushedBytes], StartBit)) &&
215 "Expected to be patching over 0-value placeholders");
217 &Buffer[ByteNo - NumOfFlushedBytes], NewByte, StartBit);
218 return;
219 }
220
221
222
223 assert(fdStream() != nullptr);
224
225
226 uint64_t CurPos = fdStream()->tell();
227
228
229 char Bytes[3];
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;
233
234
235
236
237
238#ifdef NDEBUG
239 if (StartBit)
240#endif
241 {
242 fdStream()->seek(ByteNo);
243 ssize_t BytesRead = fdStream()->read(Bytes, BytesFromDisk);
244 (void)BytesRead;
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];
250 "Expected to be patching over 0-value placeholders");
251 }
252
253
255 Bytes, NewByte, StartBit);
256
257
258 fdStream()->seek(ByteNo);
259 fdStream()->write(Bytes, BytesFromDisk);
260 for (size_t i = 0; i < BytesFromBuffer; ++i)
261 Buffer[i] = Bytes[BytesFromDisk + i];
262
263
264 fdStream()->seek(CurPos);
265 }
266
271
276
281
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) {
287 CurBit += NumBits;
288 return;
289 }
290
291
292 WriteWord(CurValue);
293
294 if (CurBit)
295 CurValue = Val >> (32-CurBit);
296 else
297 CurValue = 0;
298 CurBit = (CurBit+NumBits) & 31;
299 }
300
302 if (CurBit) {
303 WriteWord(CurValue);
304 CurBit = 0;
305 CurValue = 0;
306 }
307 }
308
310 assert(NumBits <= 32 && "Too many bits to emit!");
311 uint32_t Threshold = 1U << (NumBits-1);
312
313
314 while (Val >= Threshold) {
315 Emit((Val & ((1U << (NumBits - 1)) - 1)) | (1U << (NumBits - 1)),
316 NumBits);
317 Val >>= NumBits-1;
318 }
319
320 Emit(Val, NumBits);
321 }
322
324 assert(NumBits <= 32 && "Too many bits to emit!");
327
328 uint32_t Threshold = 1U << (NumBits-1);
329
330
331 while (Val >= Threshold) {
332 Emit(((uint32_t)Val & ((1U << (NumBits - 1)) - 1)) |
333 (1U << (NumBits - 1)),
334 NumBits);
335 Val >>= NumBits-1;
336 }
337
339 }
340
341
343 Emit(Val, CurCodeSize);
344 }
345
346
347
348
349
350
351
353
354 if (!BlockInfoRecords.empty() && BlockInfoRecords.back().BlockID == BlockID)
355 return &BlockInfoRecords.back();
356
357 for (BlockInfo &BI : BlockInfoRecords)
358 if (BI.BlockID == BlockID)
359 return &BI;
360 return nullptr;
361 }
362
364
365
370
371 size_t BlockSizeWordIndex = GetWordIndex();
372 unsigned OldCodeSize = CurCodeSize;
373
374
376
377 CurCodeSize = CodeLen;
378
379
380
381 BlockScope.emplace_back(OldCodeSize, BlockSizeWordIndex);
382 BlockScope.back().PrevAbbrevs.swap(CurAbbrevs);
383
384
385
388 }
389
391 assert(!BlockScope.empty() && "Block scope imbalance!");
392 const Block &B = BlockScope.back();
393
394
395
398
399
400 size_t SizeInWords = GetWordIndex() - B.StartSizeWord - 1;
402
403
405
406
407 CurCodeSize = B.PrevCodeSize;
408 CurAbbrevs = std::move(B.PrevAbbrevs);
409 BlockScope.pop_back();
410 FlushToFile();
411 }
412
413
414
415
416
417private:
418
419
420 template
421 void EmitAbbreviatedLiteral(const BitCodeAbbrevOp &Op, uintty V) {
422 assert(Op.isLiteral() && "Not a literal");
423
424
425 assert(V == Op.getLiteralValue() &&
426 "Invalid abbrev for record!");
427 }
428
429
430
431 template
433 assert(.isLiteral() && "Literals should use EmitAbbreviatedLiteral!");
434
435
436 switch (Op.getEncoding()) {
439 if (Op.getEncodingData())
440 Emit((unsigned)V, (unsigned)Op.getEncodingData());
441 break;
443 if (Op.getEncodingData())
444 EmitVBR64(V, (unsigned)Op.getEncodingData());
445 break;
448 break;
449 }
450 }
451
452
453
454
455
456
457
458 template
459 void EmitRecordWithAbbrevImpl(unsigned Abbrev, ArrayRef Vals,
460 StringRef Blob, std::optional Code) {
461 const char *BlobData = Blob.data();
462 unsigned BlobLen = (unsigned) Blob.size();
464 assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
465 const BitCodeAbbrev *Abbv = CurAbbrevs[AbbrevNo].get();
466
468
470 if (Code) {
471 assert(e && "Expected non-empty abbreviation");
473
474 if (Op.isLiteral())
475 EmitAbbreviatedLiteral(Op, *Code);
476 else {
479 "Expected literal or scalar");
480 EmitAbbreviatedField(Op, *Code);
481 }
482 }
483
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]);
490 ++RecordIdx;
492
493 assert(i + 2 == e && "array op not second to last?");
494 const BitCodeAbbrevOp &EltEnc = Abbv->getOperandInfo(++i);
495
496
497
498 if (BlobData) {
500 "Blob data and record entries specified for array!");
501
502 EmitVBR(static_cast<uint32_t>(BlobLen), 6);
503
504
505 for (unsigned i = 0; i != BlobLen; ++i)
506 EmitAbbreviatedField(EltEnc, (unsigned char)BlobData[i]);
507
508
509 BlobData = nullptr;
510 } else {
511
512 EmitVBR(static_cast<uint32_t>(Vals.size()-RecordIdx), 6);
513
514
515 for (unsigned e = Vals.size(); RecordIdx != e; ++RecordIdx)
516 EmitAbbreviatedField(EltEnc, Vals[RecordIdx]);
517 }
519
520
521
522 if (BlobData) {
524 "Blob data and record entries specified for blob operand!");
525
526 assert(Blob.data() == BlobData && "BlobData got moved");
527 assert(Blob.size() == BlobLen && "BlobLen got changed");
529 BlobData = nullptr;
530 } else {
532 }
533 } else {
534 assert(RecordIdx < Vals.size() && "Invalid abbrev/record");
535 EmitAbbreviatedField(Op, Vals[RecordIdx]);
536 ++RecordIdx;
537 }
538 }
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!");
542 }
543
544public:
545
546 template
548
549 if (ShouldEmitSize)
551
552
554
555
557 Buffer.append(Bytes.begin(), Bytes.end());
558
559
560 while (GetBufferOffset() & 3)
561 Buffer.push_back(0);
562 }
565 ShouldEmitSize);
566 }
567
568
569
570 template
571 void EmitRecord(unsigned Code, const Container &Vals, unsigned Abbrev = 0) {
572 if (!Abbrev) {
573
574
575 auto Count = static_cast<uint32_t>(std::size(Vals));
579 for (unsigned i = 0, e = Count; i != e; ++i)
581 return;
582 }
583
584 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), StringRef(), Code);
585 }
586
587
588
589
590 template
592 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), StringRef(), std::nullopt);
593 }
594
595
596
597
598
599
600 template
603 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), Blob, std::nullopt);
604 }
605 template
607 const char *BlobData, unsigned BlobLen) {
608 return EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals),
609 StringRef(BlobData, BlobLen), std::nullopt);
610 }
611
612
613
614 template
617 EmitRecordWithAbbrevImpl(Abbrev, ArrayRef(Vals), Array, std::nullopt);
618 }
619 template
621 const char *ArrayData, unsigned ArrayLen) {
622 return EmitRecordWithAbbrevImpl(
623 Abbrev, ArrayRef(Vals), StringRef(ArrayData, ArrayLen), std::nullopt);
624 }
625
626
627
628
629
630private:
631
638 if (Op.isLiteral()) {
640 } else {
641 Emit(Op.getEncoding(), 3);
642 if (Op.hasEncodingData())
644 }
645 }
646 }
647public:
648
649
650 unsigned EmitAbbrev(std::shared_ptr Abbv) {
651 EncodeAbbrev(*Abbv);
652 CurAbbrevs.push_back(std::move(Abbv));
653 return static_cast<unsigned>(CurAbbrevs.size())-1 +
655 }
656
657
658
659
660
661
664 BlockInfoCurBID = ~0U;
665 BlockInfoRecords.clear();
666 }
667private:
668
669
670 void SwitchToBlockID(unsigned BlockID) {
671 if (BlockInfoCurBID == BlockID) return;
675 BlockInfoCurBID = BlockID;
676 }
677
678 BlockInfo &getOrCreateBlockInfo(unsigned BlockID) {
680 return *BI;
681
682
683 BlockInfoRecords.emplace_back();
684 BlockInfoRecords.back().BlockID = BlockID;
685 return BlockInfoRecords.back();
686 }
687
688public:
689
690
691
692 unsigned EmitBlockInfoAbbrev(unsigned BlockID, std::shared_ptr Abbv) {
693 SwitchToBlockID(BlockID);
694 EncodeAbbrev(*Abbv);
695
696
697 BlockInfo &Info = getOrCreateBlockInfo(BlockID);
698 Info.Abbrevs.push_back(std::move(Abbv));
699
701 }
702};