|
19 | 19 | #include "clang/AST/RecordLayout.h"
|
20 | 20 | #include "clang/Basic/TargetInfo.h"
|
21 | 21 |
|
| 22 | +#include <variant> |
| 23 | + |
22 | 24 | using namespace clang;
|
23 | 25 | using namespace clang::interp;
|
24 | 26 |
|
@@ -450,33 +452,48 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
|
450 | 452 | return Success;
|
451 | 453 | }
|
452 | 454 |
|
| 455 | +using PrimTypeVariant = |
| 456 | + std::variant<Pointer, FunctionPointer, MemberPointer, FixedPoint, |
| 457 | + Integral<8, false>, Integral<8, true>, Integral<16, false>, |
| 458 | + Integral<16, true>, Integral<32, false>, Integral<32, true>, |
| 459 | + Integral<64, false>, Integral<64, true>, IntegralAP<true>, |
| 460 | + IntegralAP<false>, Boolean, Floating>; |
| 461 | + |
| 462 | +// NB: This implementation isn't exactly ideal, but: |
| 463 | +// 1) We can't just do a bitcast here since we need to be able to |
| 464 | +// copy pointers. |
| 465 | +// 2) This also needs to handle overlapping regions. |
| 466 | +// 3) We currently have no way of iterating over the fields of a pointer |
| 467 | +// backwards. |
453 | 468 | bool clang::interp::DoMemcpy(InterpState &S, CodePtr OpPC,
|
454 | 469 | const Pointer &SrcPtr, const Pointer &DestPtr,
|
455 | 470 | Bits Size) {
|
456 | 471 | assert(SrcPtr.isBlockPointer());
|
457 | 472 | assert(DestPtr.isBlockPointer());
|
458 | 473 |
|
459 |
| - unsigned SrcStartOffset = SrcPtr.getByteOffset(); |
460 |
| - unsigned DestStartOffset = DestPtr.getByteOffset(); |
461 |
| - |
| 474 | + llvm::SmallVector<PrimTypeVariant> Values; |
462 | 475 | enumeratePointerFields(SrcPtr, S.getContext(), Size,
|
463 | 476 | [&](const Pointer &P, PrimType T, Bits BitOffset,
|
464 | 477 | Bits FullBitWidth, bool PackedBools) -> bool {
|
465 |
| - unsigned SrcOffsetDiff = |
466 |
| - P.getByteOffset() - SrcStartOffset; |
467 |
| - |
468 |
| - Pointer DestP = |
469 |
| - Pointer(DestPtr.asBlockPointer().Pointee, |
470 |
| - DestPtr.asBlockPointer().Base, |
471 |
| - DestStartOffset + SrcOffsetDiff); |
| 478 | + TYPE_SWITCH(T, { Values.push_back(P.deref<T>()); }); |
| 479 | + return true; |
| 480 | + }); |
472 | 481 |
|
| 482 | + unsigned ValueIndex = 0; |
| 483 | + enumeratePointerFields(DestPtr, S.getContext(), Size, |
| 484 | + [&](const Pointer &P, PrimType T, Bits BitOffset, |
| 485 | + Bits FullBitWidth, bool PackedBools) -> bool { |
473 | 486 | TYPE_SWITCH(T, {
|
474 |
| - DestP.deref<T>() = P.deref<T>(); |
475 |
| - DestP.initialize(); |
| 487 | + P.deref<T>() = std::get<T>(Values[ValueIndex]); |
| 488 | + P.initialize(); |
476 | 489 | });
|
477 | 490 |
|
| 491 | + ++ValueIndex; |
478 | 492 | return true;
|
479 | 493 | });
|
480 | 494 |
|
| 495 | + // We should've read all the values into DestPtr. |
| 496 | + assert(ValueIndex == Values.size()); |
| 497 | + |
481 | 498 | return true;
|
482 | 499 | }
|
0 commit comments