Author: Timm Bäder Date: 2024-07-20T17:29:31+02:00 New Revision: 5303ca1496fc5f604f37c071d37821597788e83e
URL: https://github.com/llvm/llvm-project/commit/5303ca1496fc5f604f37c071d37821597788e83e DIFF: https://github.com/llvm/llvm-project/commit/5303ca1496fc5f604f37c071d37821597788e83e.diff LOG: [clang][Interp] Start computing APValue offsets For array elements, arrays roots and fields. Added: clang/test/AST/Interp/codegen.cpp Modified: clang/lib/AST/Interp/Pointer.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index f7bd76b260584..229007c6d720a 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -16,6 +16,7 @@ #include "MemberPointer.h" #include "PrimType.h" #include "Record.h" +#include "clang/AST/RecordLayout.h" using namespace clang; using namespace clang::interp; @@ -141,25 +142,38 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { else llvm_unreachable("Invalid allocation type"); - if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) + if (isUnknownSizeArray() || Desc->asExpr()) return APValue(Base, CharUnits::Zero(), Path, /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); - // TODO: compute the offset into the object. CharUnits Offset = CharUnits::Zero(); + auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits { + const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent()); + unsigned FieldIndex = FD->getFieldIndex(); + return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)); + }; + // Build the path into the object. Pointer Ptr = *this; while (Ptr.isField() || Ptr.isArrayElement()) { if (Ptr.isArrayRoot()) { Path.push_back(APValue::LValuePathEntry( {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false})); + + if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl())) + Offset += getFieldOffset(FD); + Ptr = Ptr.getBase(); } else if (Ptr.isArrayElement()) { + unsigned Index; if (Ptr.isOnePastEnd()) - Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getArray().getNumElems())); + Index = Ptr.getArray().getNumElems(); else - Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); + Index = Ptr.getIndex(); + + Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType())); + Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index)); Ptr = Ptr.getArray(); } else { // TODO: figure out if base is virtual @@ -170,12 +184,21 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { if (const auto *BaseOrMember = Desc->asDecl()) { Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); Ptr = Ptr.getBase(); + + if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) + Offset += getFieldOffset(FD); + continue; } llvm_unreachable("Invalid field type"); } } + // FIXME(perf): We compute the lvalue path above, but we can't supply it + // for dummy pointers (that causes crashes later in CheckConstantExpression). + if (isDummy()) + Path.clear(); + // We assemble the LValuePath starting from the innermost pointer to the // outermost one. SO in a.b.c, the first element in Path will refer to // the field 'c', while later code expects it to refer to 'a'. diff --git a/clang/test/AST/Interp/codegen.cpp b/clang/test/AST/Interp/codegen.cpp new file mode 100644 index 0000000000000..8a0d070d19da3 --- /dev/null +++ b/clang/test/AST/Interp/codegen.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s + + +int arr[2]; +// CHECK: @pastEnd = constant ptr getelementptr (i8, ptr @arr, i64 8) +int &pastEnd = arr[2]; + +// CHECK: @F = constant ptr @arr, align 8 +int &F = arr[0]; + +struct S { + int a; + float c[3]; +}; + +// CHECK: @s = global %struct.S zeroinitializer, align 4 +S s; +// CHECK: @sp = constant ptr getelementptr (i8, ptr @s, i64 16), align 8 +float &sp = s.c[3]; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits