[llvm-branch-commits] Add pointer field protection feature. (PR #133538)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Mar 28 15:35:14 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: Peter Collingbourne (pcc)
<details>
<summary>Changes</summary>
Pointer field protection is a use-after-free vulnerability
mitigation that works by changing how data structures' pointer
fields are stored in memory. For more information, see the RFC:
https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555
TODO:
- Fix test failure.
- Add more tests.
- Add documentation.
---
Patch is 82.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/133538.diff
52 Files Affected:
- (modified) clang/include/clang/AST/ASTContext.h (+22)
- (modified) clang/include/clang/Basic/Attr.td (+6)
- (modified) clang/include/clang/Basic/Features.def (+3)
- (modified) clang/include/clang/Basic/LangOptions.def (+3)
- (modified) clang/include/clang/Basic/LangOptions.h (+11)
- (modified) clang/include/clang/Basic/TokenKinds.def (+1)
- (modified) clang/include/clang/Driver/Options.td (+6)
- (modified) clang/lib/AST/ASTContext.cpp (+95)
- (modified) clang/lib/AST/ExprConstant.cpp (+1)
- (modified) clang/lib/AST/Type.cpp (+3-1)
- (modified) clang/lib/AST/TypePrinter.cpp (+3)
- (modified) clang/lib/CodeGen/CGCall.cpp (+108-6)
- (modified) clang/lib/CodeGen/CGClass.cpp (+45-7)
- (modified) clang/lib/CodeGen/CGExpr.cpp (+7-1)
- (modified) clang/lib/CodeGen/CGExprAgg.cpp (+1-1)
- (modified) clang/lib/CodeGen/CGExprCXX.cpp (+10)
- (modified) clang/lib/CodeGen/CGExprConstant.cpp (+38-1)
- (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+38-5)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+6-2)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+39)
- (modified) clang/lib/CodeGen/CodeGenModule.h (+7)
- (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+1)
- (modified) clang/lib/CodeGen/MicrosoftCXXABI.cpp (+1)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+4)
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+8)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+5)
- (added) clang/test/CodeGen/pfp-attribute-disable.cpp (+33)
- (added) clang/test/CodeGen/pfp-load-store.cpp (+40)
- (added) clang/test/CodeGen/pfp-memcpy.cpp (+19)
- (added) clang/test/CodeGen/pfp-null-init.cpp (+16)
- (added) clang/test/CodeGen/pfp-struct-gep.cpp (+25)
- (modified) clang/test/CodeGenCXX/trivial_abi.cpp (+1-3)
- (modified) libcxx/include/__config (+23)
- (modified) libcxx/include/__functional/function.h (+1-1)
- (modified) libcxx/include/__memory/shared_ptr.h (+2-2)
- (modified) libcxx/include/__memory/unique_ptr.h (+2-2)
- (modified) libcxx/include/__tree (+1-1)
- (modified) libcxx/include/__type_traits/is_trivially_relocatable.h (+6-2)
- (modified) libcxx/include/__vector/vector.h (+1-1)
- (modified) libcxx/include/typeinfo (+1-1)
- (modified) libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp (+9)
- (modified) libcxxabi/include/__cxxabi_config.h (+10)
- (modified) libcxxabi/src/private_typeinfo.h (+3-3)
- (modified) llvm/include/llvm/Analysis/PtrUseVisitor.h (+15)
- (modified) llvm/include/llvm/IR/Intrinsics.td (+23)
- (modified) llvm/include/llvm/Transforms/Utils/Local.h (+2)
- (modified) llvm/lib/Analysis/PtrUseVisitor.cpp (+2-1)
- (modified) llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp (+246)
- (modified) llvm/lib/Target/AArch64/AArch64InstrFormats.td (+3)
- (modified) llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp (+2-4)
- (modified) llvm/lib/Transforms/Scalar/SROA.cpp (+35-5)
- (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+20-5)
``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index af8c49e99a7ce..abba83e1ff9c4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -183,6 +183,12 @@ struct TypeInfoChars {
}
};
+struct PFPField {
+ CharUnits structOffset;
+ CharUnits offset;
+ FieldDecl *field;
+};
+
/// Holds long-lived AST nodes (such as types and decls) that can be
/// referred to throughout the semantic analysis of a file.
class ASTContext : public RefCountedBase<ASTContext> {
@@ -3618,6 +3624,22 @@ OPT_LIST(V)
StringRef getCUIDHash() const;
+ bool isPFPStruct(const RecordDecl *rec) const;
+ void findPFPFields(QualType Ty, CharUnits Offset,
+ std::vector<PFPField> &Fields, bool IncludeVBases) const;
+ bool hasPFPFields(QualType ty) const;
+ bool isPFPField(const FieldDecl *field) const;
+
+ /// Returns whether this record's PFP fields (if any) are trivially
+ /// relocatable (i.e. may be memcpy'd). This may also return true if the
+ /// record does not have any PFP fields, so it may be necessary for the caller
+ /// to check for PFP fields, e.g. by calling hasPFPFields().
+ bool arePFPFieldsTriviallyRelocatable(const RecordDecl *RD) const;
+
+ llvm::SetVector<const FieldDecl *> PFPFieldsWithEvaluatedOffset;
+ void recordMemberDataPointerEvaluation(const ValueDecl *VD);
+ void recordOffsetOfEvaluation(const OffsetOfExpr *E);
+
private:
/// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive.
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 0999d8065e9f5..3d26c2f001812 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2460,6 +2460,12 @@ def CountedByOrNull : DeclOrTypeAttr {
let LangOpts = [COnly];
}
+def NoPointerFieldProtection : DeclOrTypeAttr {
+ let Spellings = [Clang<"no_field_protection">];
+ let Subjects = SubjectList<[Field], ErrorDiag>;
+ let Documentation = [Undocumented];
+}
+
def SizedBy : DeclOrTypeAttr {
let Spellings = [Clang<"sized_by">];
let Subjects = SubjectList<[Field], ErrorDiag>;
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 05ce214935fad..d4ded24c5a87e 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -262,6 +262,9 @@ FEATURE(shadow_call_stack,
FEATURE(tls, PP.getTargetInfo().isTLSSupported())
FEATURE(underlying_type, LangOpts.CPlusPlus)
FEATURE(experimental_library, LangOpts.ExperimentalLibrary)
+FEATURE(pointer_field_protection,
+ LangOpts.getPointerFieldProtection() !=
+ LangOptions::PointerFieldProtectionKind::None)
// C11 features supported by other languages as extensions.
EXTENSION(c_alignas, true)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 3879cc7942877..8eacb6e066007 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -501,6 +501,9 @@ LANGOPT(RelativeCXXABIVTables, 1, 0,
LANGOPT(OmitVTableRTTI, 1, 0,
"Use an ABI-incompatible v-table layout that omits the RTTI component")
+ENUM_LANGOPT(PointerFieldProtection, PointerFieldProtectionKind, 2, PointerFieldProtectionKind::None,
+ "Encode struct pointer fields to protect against UAF vulnerabilities")
+
LANGOPT(VScaleMin, 32, 0, "Minimum vscale value")
LANGOPT(VScaleMax, 32, 0, "Maximum vscale value")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index e925e0f3b5d85..797a14038ba4b 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -365,6 +365,17 @@ class LangOptionsBase {
BKey
};
+ enum class PointerFieldProtectionKind {
+ /// Pointer field protection disabled
+ None,
+ /// Pointer field protection enabled, allocator does not tag heap
+ /// allocations.
+ Untagged,
+ /// Pointer field protection enabled, allocator is expected to tag heap
+ /// allocations.
+ Tagged,
+ };
+
enum class ThreadModelKind {
/// POSIX Threads.
POSIX,
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 1bf9f43f80986..142e13b3ee784 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -542,6 +542,7 @@ TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBas
// Clang-only C++ Type Traits
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
+TYPE_TRAIT_1(__has_non_relocatable_fields, HasNonRelocatableFields, KEYCXX)
TYPE_TRAIT_1(__is_trivially_equality_comparable, IsTriviallyEqualityComparable, KEYCXX)
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)
TYPE_TRAIT_1(__is_unbounded_array, IsUnboundedArray, KEYCXX)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index a7fcb160d3867..c903e0554319e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2957,6 +2957,12 @@ defm experimental_omit_vtable_rtti : BoolFOption<"experimental-omit-vtable-rtti"
NegFlag<SetFalse, [], [CC1Option], "Do not omit">,
BothFlags<[], [CC1Option], " the RTTI component from virtual tables">>;
+def experimental_pointer_field_protection_EQ : Joined<["-"], "fexperimental-pointer-field-protection=">, Group<f_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ Values<"none,untagged,tagged">, NormalizedValuesScope<"LangOptions::PointerFieldProtectionKind">,
+ NormalizedValues<["None", "Untagged", "Tagged"]>,
+ MarshallingInfoEnum<LangOpts<"PointerFieldProtection">, "None">;
+
def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">,
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"C++ ABI to use. This will override the target C++ ABI.">;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c9d1bea4c623a..c3cbfec2c93d3 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -79,6 +79,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
@@ -14948,3 +14949,97 @@ bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
ThunksToBeAbbreviated[VirtualMethodDecl] = std::move(SimplifiedThunkNames);
return Result;
}
+
+bool ASTContext::arePFPFieldsTriviallyRelocatable(const RecordDecl *RD) const {
+ if (getLangOpts().getPointerFieldProtection() ==
+ LangOptions::PointerFieldProtectionKind::Tagged)
+ return !isa<CXXRecordDecl>(RD) ||
+ cast<CXXRecordDecl>(RD)->hasTrivialDestructor();
+ return true;
+}
+
+bool ASTContext::isPFPStruct(const RecordDecl *rec) const {
+ if (getLangOpts().getPointerFieldProtection() !=
+ LangOptions::PointerFieldProtectionKind::None)
+ if (auto *cxxRec = dyn_cast<CXXRecordDecl>(rec))
+ return !cxxRec->isStandardLayout();
+ return false;
+}
+
+void ASTContext::findPFPFields(QualType Ty, CharUnits Offset,
+ std::vector<PFPField> &Fields,
+ bool IncludeVBases) const {
+ if (auto *AT = getAsConstantArrayType(Ty)) {
+ if (auto *ElemDecl = AT->getElementType()->getAsCXXRecordDecl()) {
+ const ASTRecordLayout &ElemRL = getASTRecordLayout(ElemDecl);
+ for (unsigned i = 0; i != AT->getSize(); ++i) {
+ findPFPFields(AT->getElementType(), Offset + i * ElemRL.getSize(),
+ Fields, true);
+ }
+ }
+ }
+ auto *Decl = Ty->getAsCXXRecordDecl();
+ if (!Decl)
+ return;
+ const ASTRecordLayout &RL = getASTRecordLayout(Decl);
+ for (FieldDecl *field : Decl->fields()) {
+ CharUnits fieldOffset =
+ Offset + toCharUnitsFromBits(RL.getFieldOffset(field->getFieldIndex()));
+ if (isPFPField(field))
+ Fields.push_back({Offset, fieldOffset, field});
+ findPFPFields(field->getType(), fieldOffset, Fields, true);
+ }
+ for (auto &Base : Decl->bases()) {
+ if (Base.isVirtual())
+ continue;
+ CharUnits BaseOffset =
+ Offset + RL.getBaseClassOffset(Base.getType()->getAsCXXRecordDecl());
+ findPFPFields(Base.getType(), BaseOffset, Fields, false);
+ }
+ if (IncludeVBases) {
+ for (auto &Base : Decl->vbases()) {
+ CharUnits BaseOffset =
+ Offset + RL.getVBaseClassOffset(Base.getType()->getAsCXXRecordDecl());
+ findPFPFields(Base.getType(), BaseOffset, Fields, false);
+ }
+ }
+}
+
+bool ASTContext::hasPFPFields(QualType ty) const {
+ std::vector<PFPField> pfpFields;
+ findPFPFields(ty, CharUnits::Zero(), pfpFields, true);
+ return !pfpFields.empty();
+}
+
+bool ASTContext::isPFPField(const FieldDecl *field) const {
+ if (!isPFPStruct(field->getParent()))
+ return false;
+ return field->getType()->isPointerType() &&
+ !field->hasAttr<NoPointerFieldProtectionAttr>();
+}
+
+void ASTContext::recordMemberDataPointerEvaluation(const ValueDecl *VD) {
+ if (getLangOpts().getPointerFieldProtection() ==
+ LangOptions::PointerFieldProtectionKind::None)
+ return;
+ auto *FD = dyn_cast<FieldDecl>(VD);
+ if (!FD)
+ FD = cast<FieldDecl>(cast<IndirectFieldDecl>(VD)->chain().back());
+ if (!isPFPField(FD))
+ return;
+ PFPFieldsWithEvaluatedOffset.insert(FD);
+}
+
+void ASTContext::recordOffsetOfEvaluation(const OffsetOfExpr *E) {
+ if (getLangOpts().getPointerFieldProtection() ==
+ LangOptions::PointerFieldProtectionKind::None ||
+ E->getNumComponents() == 0)
+ return;
+ OffsetOfNode Comp = E->getComponent(E->getNumComponents() - 1);
+ if (Comp.getKind() != OffsetOfNode::Field)
+ return;
+ FieldDecl *FD = Comp.getField();
+ if (!isPFPField(FD))
+ return;
+ PFPFieldsWithEvaluatedOffset.insert(FD);
+}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 95da7b067b459..51f319fd26f20 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14932,6 +14932,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
}
bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
+ Info.Ctx.recordOffsetOfEvaluation(OOE);
CharUnits Result;
unsigned n = OOE->getNumComponents();
if (n == 0)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 08798219c0b83..ca7ccc7f2bb5a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2852,7 +2852,9 @@ bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
} else if (!BaseElementType->isObjectType()) {
return false;
} else if (const auto *RD = BaseElementType->getAsRecordDecl()) {
- return RD->canPassInRegisters();
+ return RD->canPassInRegisters() &&
+ (Context.arePFPFieldsTriviallyRelocatable(RD) ||
+ !Context.hasPFPFields(BaseElementType));
} else if (BaseElementType.isTriviallyCopyableType(Context)) {
return true;
} else {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 3982ca3b50604..1382b4a9edfd4 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2096,6 +2096,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::ExtVectorType:
OS << "ext_vector_type";
break;
+ case attr::NoPointerFieldProtection:
+ OS << "no_field_protection";
+ break;
}
OS << "))";
}
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7aa77e55dbfcc..9d824231d02cb 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1298,7 +1298,8 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
/// This safely handles the case when the src type is smaller than the
/// destination type; in this situation the values of bits which not
/// present in the src are undefined.
-static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
+static llvm::Value *CreateCoercedLoad(Address Src, QualType SrcFETy,
+ llvm::Type *Ty,
CodeGenFunction &CGF) {
llvm::Type *SrcTy = Src.getElementType();
@@ -1306,6 +1307,57 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
if (SrcTy == Ty)
return CGF.Builder.CreateLoad(Src);
+ // Coercion directly through memory does not work if the structure has pointer
+ // field protection because the struct in registers has a different bit
+ // pattern to the struct in memory, so we must read the elements one by one
+ // and use them to form the coerced structure.
+ std::vector<PFPField> PFPFields;
+ CGF.getContext().findPFPFields(SrcFETy, CharUnits::Zero(), PFPFields, true);
+ if (!PFPFields.empty()) {
+ auto LoadCoercedField = [&](CharUnits Offset,
+ llvm::Type *FieldType) -> llvm::Value * {
+ if (!PFPFields.empty() && PFPFields[0].offset == Offset) {
+ auto fieldAddr = CGF.EmitAddressOfPFPField(Src, PFPFields[0]);
+ llvm::Value *FieldVal = CGF.Builder.CreateLoad(fieldAddr);
+ if (isa<llvm::IntegerType>(FieldType))
+ FieldVal = CGF.Builder.CreatePtrToInt(FieldVal, FieldType);
+ PFPFields.erase(PFPFields.begin());
+ return FieldVal;
+ }
+ auto FieldAddr = CGF.Builder
+ .CreateConstInBoundsByteGEP(
+ Src.withElementType(CGF.Int8Ty), Offset)
+ .withElementType(FieldType);
+ return CGF.Builder.CreateLoad(FieldAddr);
+ };
+ if (isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) {
+ auto Addr = CGF.EmitAddressOfPFPField(Src, PFPFields[0]);
+ llvm::Value *Val = CGF.Builder.CreateLoad(Addr);
+ if (isa<llvm::IntegerType>(Ty))
+ Val = CGF.Builder.CreatePtrToInt(Val, Ty);
+ return Val;
+ }
+ if (auto *AT = dyn_cast<llvm::ArrayType>(Ty)) {
+ auto *ET = AT->getElementType();
+ CharUnits wordSize = CGF.getContext().toCharUnitsFromBits(
+ CGF.CGM.getDataLayout().getTypeSizeInBits(ET));
+ CharUnits Offset = CharUnits::Zero();
+ llvm::Value *Val = llvm::UndefValue::get(AT);
+ for (unsigned i = 0; i != AT->getNumElements(); ++i, Offset += wordSize)
+ Val = CGF.Builder.CreateInsertValue(Val, LoadCoercedField(Offset, ET), i);
+ return Val;
+ }
+ auto *ST = cast<llvm::StructType>(Ty);
+ llvm::Value *Val = llvm::UndefValue::get(ST);
+ auto *SL = CGF.CGM.getDataLayout().getStructLayout(ST);
+ for (unsigned i = 0; i != ST->getNumElements(); ++i) {
+ CharUnits Offset = CharUnits::fromQuantity(SL->getElementOffset(i));
+ Val = CGF.Builder.CreateInsertValue(
+ Val, LoadCoercedField(Offset, ST->getElementType(i)), i);
+ }
+ return Val;
+ }
+
llvm::TypeSize DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
@@ -1374,7 +1426,9 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
return CGF.Builder.CreateLoad(Tmp);
}
-void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
+void CodeGenFunction::CreateCoercedStore(llvm::Value *Src,
+ QualType SrcFETy,
+ Address Dst,
llvm::TypeSize DstSize,
bool DstIsVolatile) {
if (!DstSize)
@@ -1395,6 +1449,52 @@ void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
}
}
+ // Coercion directly through memory does not work if the structure has pointer
+ // field protection because the struct passed by value has a different bit
+ // pattern to the struct in memory, so we must read the elements one by one
+ // and use them to form the coerced structure.
+ std::vector<PFPField> PFPFields;
+ getContext().findPFPFields(SrcFETy, CharUnits::Zero(), PFPFields, true);
+ if (!PFPFields.empty()) {
+ auto StoreCoercedField = [&](CharUnits Offset, llvm::Value *FieldVal) {
+ if (!PFPFields.empty() && PFPFields[0].offset == Offset) {
+ auto fieldAddr = EmitAddressOfPFPField(Dst, PFPFields[0]);
+ if (isa<llvm::IntegerType>(FieldVal->getType()))
+ FieldVal = Builder.CreateIntToPtr(FieldVal, VoidPtrTy);
+ Builder.CreateStore(FieldVal, fieldAddr);
+ PFPFields.erase(PFPFields.begin());
+ } else {
+ auto fieldAddr =
+ Builder
+ .CreateConstInBoundsByteGEP(Dst.withElementType(Int8Ty), Offset)
+ .withElementType(FieldVal->getType());
+ Builder.CreateStore(FieldVal, fieldAddr);
+ }
+ };
+
+ if (isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) {
+ if (isa<llvm::IntegerType>(SrcTy))
+ Src = Builder.CreateIntToPtr(Src, VoidPtrTy);
+ auto Addr = EmitAddressOfPFPField(Dst, PFPFields[0]);
+ Builder.CreateStore(Src, Addr);
+ } else if (auto *at = dyn_cast<llvm::ArrayType>(SrcTy)) {
+ auto *et = at->getElementType();
+ CharUnits wordSize = getContext().toCharUnitsFromBits(
+ CGM.getDataLayout().getTypeSizeInBits(et));
+ CharUnits Offset = CharUnits::Zero();
+ for (unsigned i = 0; i != at->getNumElements(); ++i, Offset += wordSize)
+ StoreCoercedField(Offset, Builder.CreateExtractValue(Src, i));
+ } else {
+ auto *ST = cast<llvm::StructType>(SrcTy);
+ auto *SL = CGM.getDataLayout().getStructLayout(ST);
+ for (unsigned i = 0; i != ST->getNumElements(); ++i) {
+ CharUnits Offset = CharUnits::fromQuantity(SL->getElementOffset(i));
+ StoreCoercedField(Offset, Builder.CreateExtractValue(Src, i));
+ }
+ }
+ return;
+ }
+
if (SrcSize.isScalable() || SrcSize <= DstSize) {
if (SrcTy->isIntegerTy() && Dst.getElementType()->isPointerTy() &&
SrcSize == CGM.getDataLayout().getTypeAllocSize(Dst.getElementType())) {
@@ -3347,7 +3447,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
auto AI = Fn->getArg(FirstIRArg);
AI->setName(Arg->getName() + ".coerce");
CreateCoercedStore(
- AI, Ptr,
+ AI, Ty, Ptr,
llvm::TypeSize::getFixed(
getContext().getTypeSizeInChars(Ty).getQuantity() -
ArgI.getDirectOffset()),
@@ -3969,7 +4069,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
// If the value is offset in memory, apply the offset now.
Address V = emitAddressAtOffset(*this, ReturnValue, RetAI);
- RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
+ RV = CreateCoercedLoad(V, RetTy, RetAI.getCoerceToType(), *this);
}
// In ARC, end functions that return a retainable type with a call
@@ -4020,6 +4120,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
auto eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CreateCoercedLoad(
eltAddr,
+ RetTy,
unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
: unpaddedCoercionType,
*this);
@@ -5550,7 +5651,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// In the simple case, just pass the coerced loaded value.
assert(NumIRArgs == 1);
llvm::Value *Load =
- CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this);
+ CreateCoercedLoad(Src, I->Ty, ArgInfo.getCoerceToType(), *this);
if (CallInfo.isCmseNSCall()) {
// For certain parameter types, clear padding bits, as they may reveal
@@ -5611,6 +5712,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CreateCoercedLoad(
eltAddr,
+ I->Ty,
unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++)
: unpaddedCoercionType,
*this);
@@ -6105,7 +6207,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/133538
More information about the llvm-branch-commits
mailing list