|
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