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