|
63 | 63 | #include "llvm/Support/ScopedPrinter.h"
|
64 | 64 | #include "llvm/TargetParser/AArch64TargetParser.h"
|
65 | 65 | #include "llvm/TargetParser/X86TargetParser.h"
|
| 66 | +#include <algorithm> |
66 | 67 | #include <optional>
|
67 | 68 | #include <sstream>
|
68 | 69 |
|
@@ -2538,6 +2539,205 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
|
2538 | 2539 | return RValue::get(CGF->Builder.CreateCall(UBF, Args));
|
2539 | 2540 | }
|
2540 | 2541 |
|
| 2542 | +template <class T> |
| 2543 | +void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, |
| 2544 | + size_t CurrentStartOffset, |
| 2545 | + size_t &RunningOffset, T &&WriteZeroAtOffset, |
| 2546 | + bool VisitVirtualBase); |
| 2547 | + |
| 2548 | +template <class T> |
| 2549 | +void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, |
| 2550 | + StructType *ST, size_t CurrentStartOffset, |
| 2551 | + size_t &RunningOffset, T &&WriteZeroAtOffset, |
| 2552 | + bool VisitVirtualBase) { |
| 2553 | + llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n'; |
| 2554 | + const auto &DL = CGF.CGM.getModule().getDataLayout(); |
| 2555 | + auto *SL = DL.getStructLayout(ST); |
| 2556 | + auto *R = dyn_cast<CXXRecordDecl>(Ty->getAsRecordDecl()); |
| 2557 | + if (!R) { |
| 2558 | + llvm::dbgs() << "Not a CXXRecordDecl\n"; |
| 2559 | + return; |
| 2560 | + } |
| 2561 | + const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R); |
| 2562 | + if (ASTLayout.hasOwnVFPtr()) { |
| 2563 | + llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from " |
| 2564 | + << RunningOffset << " to " |
| 2565 | + << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n'; |
| 2566 | + RunningOffset += DL.getPointerSizeInBits() / 8; |
| 2567 | + } |
| 2568 | + std::vector<std::pair<size_t, CXXBaseSpecifier>> Bases; |
| 2569 | + Bases.reserve(R->getNumBases()); |
| 2570 | + // todo get vbases |
| 2571 | + for (auto Base : R->bases()) { |
| 2572 | + auto *BaseRecord = cast<CXXRecordDecl>(Base.getType()->getAsRecordDecl()); |
| 2573 | + if (!Base.isVirtual()) { |
| 2574 | + auto Offset = static_cast<size_t>( |
| 2575 | + ASTLayout.getBaseClassOffset(BaseRecord).getQuantity()); |
| 2576 | + Bases.emplace_back(Offset, Base); |
| 2577 | + } |
| 2578 | + } |
| 2579 | + |
| 2580 | + auto VisitBases = |
| 2581 | + [&](std::vector<std::pair<size_t, CXXBaseSpecifier>> &BasesToVisit) { |
| 2582 | + std::sort( |
| 2583 | + BasesToVisit.begin(), BasesToVisit.end(), |
| 2584 | + [](const auto &P1, const auto &P2) { return P1.first < P2.first; }); |
| 2585 | + for (const auto &Pair : BasesToVisit) { |
| 2586 | + // is it OK to use structured binding in clang? what is the language |
| 2587 | + // version? |
| 2588 | + auto Offset = Pair.first; |
| 2589 | + auto Base = Pair.second; |
| 2590 | + |
| 2591 | + llvm::dbgs() << "visiting base at offset " << Offset << '\n'; |
| 2592 | + // Recursively zero out base classes. |
| 2593 | + auto Index = SL->getElementContainingOffset(Offset); |
| 2594 | + Value *Idx = CGF.Builder.getSize(Index); |
| 2595 | + llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType()); |
| 2596 | + Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx); |
| 2597 | + RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), |
| 2598 | + CurrentStartOffset + Offset, |
| 2599 | + RunningOffset, WriteZeroAtOffset, false); |
| 2600 | + } |
| 2601 | + }; |
| 2602 | + |
| 2603 | + VisitBases(Bases); |
| 2604 | + |
| 2605 | + size_t NumFields = std::distance(R->field_begin(), R->field_end()); |
| 2606 | + std::vector<size_t> FieldOffsets; |
| 2607 | + FieldOffsets.reserve(NumFields); |
| 2608 | + auto CurrentField = R->field_begin(); |
| 2609 | + for (size_t I = 0; I < NumFields; ++I, ++CurrentField) { |
| 2610 | + // Size needs to be in bytes so we can compare it later. |
| 2611 | + auto Offset = ASTLayout.getFieldOffset(I) / 8; |
| 2612 | + llvm::dbgs() << "visiting field at offset " << Offset << '\n'; |
| 2613 | + auto Index = SL->getElementContainingOffset(Offset); |
| 2614 | + Value *Idx = CGF.Builder.getSize(Index); |
| 2615 | + llvm::Type *CurrentFieldType = |
| 2616 | + CGF.ConvertTypeForMem(CurrentField->getType()); |
| 2617 | + Value *Element = CGF.Builder.CreateGEP(CurrentFieldType, Ptr, Idx); |
| 2618 | + RecursivelyClearPaddingImpl(CGF, Element, CurrentField->getType(), |
| 2619 | + CurrentStartOffset + Offset, RunningOffset, |
| 2620 | + WriteZeroAtOffset, true); |
| 2621 | + } |
| 2622 | + |
| 2623 | + if (VisitVirtualBase) { |
| 2624 | + |
| 2625 | + std::vector<std::pair<size_t, CXXBaseSpecifier>> VBases; |
| 2626 | + VBases.reserve(R->getNumVBases()); |
| 2627 | + for (auto VBase : R->vbases()) { |
| 2628 | + auto *BaseRecord = |
| 2629 | + cast<CXXRecordDecl>(VBase.getType()->getAsRecordDecl()); |
| 2630 | + auto Offset = static_cast<size_t>( |
| 2631 | + ASTLayout.getVBaseClassOffset(BaseRecord).getQuantity()); |
| 2632 | + VBases.emplace_back(Offset, VBase); |
| 2633 | + } |
| 2634 | + |
| 2635 | + VisitBases(VBases); |
| 2636 | + } |
| 2637 | +} |
| 2638 | + |
| 2639 | +template <class T> |
| 2640 | +void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, |
| 2641 | + llvm::Type *Type, ConstantArrayType const *AT, |
| 2642 | + size_t CurrentStartOffset, size_t &RunningOffset, |
| 2643 | + T &&WriteZeroAtOffset) { |
| 2644 | + llvm::dbgs() << "clear padding constant array\n"; |
| 2645 | + for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue(); |
| 2646 | + ++ArrIndex) { |
| 2647 | + |
| 2648 | + QualType ElementQualType = AT->getElementType(); |
| 2649 | + |
| 2650 | + auto *ElementRecord = ElementQualType->getAsRecordDecl(); |
| 2651 | + if (!ElementRecord) { |
| 2652 | + llvm::dbgs() << "null!\n"; |
| 2653 | + } |
| 2654 | + auto ElementAlign = |
| 2655 | + ElementRecord |
| 2656 | + ? CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment() |
| 2657 | + : CGF.getContext().getTypeAlignInChars(ElementQualType); |
| 2658 | + |
| 2659 | + Address FieldElementAddr{Ptr, Type, ElementAlign}; |
| 2660 | + |
| 2661 | + auto Element = CGF.Builder.CreateConstArrayGEP(FieldElementAddr, ArrIndex); |
| 2662 | + auto *ElementType = CGF.ConvertTypeForMem(ElementQualType); |
| 2663 | + auto AllocSize = |
| 2664 | + CGF.CGM.getModule().getDataLayout().getTypeAllocSize(ElementType); |
| 2665 | + llvm::dbgs() << "clearing array index! " << ArrIndex << '\n'; |
| 2666 | + RecursivelyClearPaddingImpl(CGF, Element.getBasePointer(), ElementQualType, |
| 2667 | + CurrentStartOffset + |
| 2668 | + ArrIndex * AllocSize.getKnownMinValue(), |
| 2669 | + RunningOffset, WriteZeroAtOffset, true); |
| 2670 | + } |
| 2671 | +} |
| 2672 | + |
| 2673 | +template <class T> |
| 2674 | +void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, |
| 2675 | + size_t CurrentStartOffset, |
| 2676 | + size_t &RunningOffset, T &&WriteZeroAtOffset, |
| 2677 | + bool VisitVirtualBase) { |
| 2678 | + |
| 2679 | + llvm::dbgs() << "clear padding before current [" << RunningOffset << ", " |
| 2680 | + << CurrentStartOffset << ")\n"; |
| 2681 | + for (; RunningOffset < CurrentStartOffset; ++RunningOffset) { |
| 2682 | + WriteZeroAtOffset(RunningOffset); |
| 2683 | + } |
| 2684 | + auto *Type = CGF.ConvertTypeForMem(Ty); |
| 2685 | + auto Size = CGF.CGM.getModule() |
| 2686 | + .getDataLayout() |
| 2687 | + .getTypeSizeInBits(Type) |
| 2688 | + .getKnownMinValue() / |
| 2689 | + 8; |
| 2690 | + |
| 2691 | + if (auto *AT = dyn_cast<ConstantArrayType>(Ty)) { |
| 2692 | + ClearPaddingConstantArray(CGF, Ptr, Type, AT, CurrentStartOffset, |
| 2693 | + RunningOffset, WriteZeroAtOffset); |
| 2694 | + } else if (auto *ST = dyn_cast<StructType>(Type); ST && Ty->isRecordType()) { |
| 2695 | + ClearPaddingStruct(CGF, Ptr, Ty, ST, CurrentStartOffset, RunningOffset, |
| 2696 | + WriteZeroAtOffset, VisitVirtualBase); |
| 2697 | + } else if (Ty->isAtomicType()) { |
| 2698 | + RecursivelyClearPaddingImpl(CGF, Ptr, Ty.getAtomicUnqualifiedType(), |
| 2699 | + CurrentStartOffset, RunningOffset, |
| 2700 | + WriteZeroAtOffset, true); |
| 2701 | + } else { |
| 2702 | + llvm::dbgs() << "increment running offset from: " << RunningOffset << " to " |
| 2703 | + << RunningOffset + Size << '\n'; |
| 2704 | + RunningOffset = |
| 2705 | + std::max(RunningOffset, CurrentStartOffset + static_cast<size_t>(Size)); |
| 2706 | + } |
| 2707 | +} |
| 2708 | + |
| 2709 | +static void RecursivelyClearPadding(CodeGenFunction &CGF, Value *Ptr, |
| 2710 | + QualType Ty) { |
| 2711 | + auto *I8Ptr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy); |
| 2712 | + auto *Zero = ConstantInt::get(CGF.Int8Ty, 0); |
| 2713 | + auto WriteZeroAtOffset = [&](uint64_t Offset) { |
| 2714 | + auto *Index = ConstantInt::get(CGF.IntTy, Offset); |
| 2715 | + auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index); |
| 2716 | + CGF.Builder.CreateAlignedStore( |
| 2717 | + Zero, Element, |
| 2718 | + CharUnits::One().alignmentAtOffset(CharUnits::fromQuantity(Offset))); |
| 2719 | + }; |
| 2720 | + |
| 2721 | + size_t RunningOffset = 0; |
| 2722 | + |
| 2723 | + RecursivelyClearPaddingImpl(CGF, Ptr, Ty, 0, RunningOffset, WriteZeroAtOffset, |
| 2724 | + true); |
| 2725 | + |
| 2726 | + // Clear tail padding |
| 2727 | + auto *Type = CGF.ConvertTypeForMem(Ty); |
| 2728 | + |
| 2729 | + auto Size = CGF.CGM.getModule() |
| 2730 | + .getDataLayout() |
| 2731 | + .getTypeAllocSize(Type) |
| 2732 | + .getKnownMinValue(); |
| 2733 | + |
| 2734 | + llvm::dbgs() << "clear tail padding [" << RunningOffset << ", " << Size |
| 2735 | + << ")\n"; |
| 2736 | + for (; RunningOffset < Size; ++RunningOffset) { |
| 2737 | + WriteZeroAtOffset(RunningOffset); |
| 2738 | + } |
| 2739 | +} |
| 2740 | + |
2541 | 2741 | RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
|
2542 | 2742 | const CallExpr *E,
|
2543 | 2743 | ReturnValueSlot ReturnValue) {
|
@@ -4462,6 +4662,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
|
4462 | 4662 |
|
4463 | 4663 | return RValue::get(Ptr);
|
4464 | 4664 | }
|
| 4665 | + case Builtin::BI__builtin_clear_padding: { |
| 4666 | + const Expr *Op = E->getArg(0); |
| 4667 | + Value *Address = EmitScalarExpr(Op); |
| 4668 | + auto PointeeTy = Op->getType()->getPointeeType(); |
| 4669 | + RecursivelyClearPadding(*this, Address, PointeeTy); |
| 4670 | + return RValue::get(nullptr); |
| 4671 | + } |
4465 | 4672 | case Builtin::BI__sync_fetch_and_add:
|
4466 | 4673 | case Builtin::BI__sync_fetch_and_sub:
|
4467 | 4674 | case Builtin::BI__sync_fetch_and_or:
|
|
0 commit comments