30 changes: 15 additions & 15 deletions clang/bindings/python/tests/cindex/test_translation_unit.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import os
from clang.cindex import Config

from clang.cindex import (
Config,
Cursor,
CursorKind,
File,
Index,
SourceLocation,
SourceRange,
TranslationUnit,
TranslationUnitLoadError,
TranslationUnitSaveError,
)

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from contextlib import contextmanager
import gc
import os
import tempfile
import unittest
from contextlib import contextmanager
from pathlib import Path

from clang.cindex import CursorKind
from clang.cindex import Cursor
from clang.cindex import File
from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TranslationUnitSaveError
from clang.cindex import TranslationUnitLoadError
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu

from .util import get_cursor, get_tu

kInputsDir = os.path.join(os.path.dirname(__file__), "INPUTS")

Expand Down
12 changes: 3 additions & 9 deletions clang/bindings/python/tests/cindex/test_type.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import os
from clang.cindex import Config

from clang.cindex import Config, CursorKind, RefQualifierKind, TranslationUnit, TypeKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

import gc
import unittest

from clang.cindex import CursorKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from clang.cindex import RefQualifierKind
from .util import get_cursor
from .util import get_cursors
from .util import get_tu

from .util import get_cursor, get_cursors, get_tu

kInput = """\
Expand Down
3 changes: 1 addition & 2 deletions clang/bindings/python/tests/cindex/util.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# This file provides common utility functions for the test suite.

from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from clang.cindex import Cursor, TranslationUnit


def get_tu(source, lang="c", all_warnings=False, flags=[]):
Expand Down
44 changes: 42 additions & 2 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Bitstream/BitstreamReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/VersionTuple.h"
#include <cassert>
Expand Down Expand Up @@ -1341,9 +1342,48 @@ class ASTReader
serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
bool Complain = true);

/// The buffer used as the temporary backing storage for resolved paths.
SmallString<0> PathBuf;

/// A wrapper around StringRef that temporarily borrows the underlying buffer.
class TemporarilyOwnedStringRef {
StringRef String;
llvm::SaveAndRestore<SmallString<0>> UnderlyingBuffer;

public:
TemporarilyOwnedStringRef(StringRef S, SmallString<0> &UnderlyingBuffer)
: String(S), UnderlyingBuffer(UnderlyingBuffer, {}) {}

/// Return the wrapped \c StringRef that must be outlived by \c this.
const StringRef *operator->() const & { return &String; }
const StringRef &operator*() const & { return String; }

/// Make it harder to get a \c StringRef that outlives \c this.
const StringRef *operator->() && = delete;
const StringRef &operator*() && = delete;
};

public:
void ResolveImportedPath(ModuleFile &M, std::string &Filename);
static void ResolveImportedPath(std::string &Filename, StringRef Prefix);
/// Get the buffer for resolving paths.
SmallString<0> &getPathBuf() { return PathBuf; }

/// Resolve \c Path in the context of module file \c M. The return value
/// must go out of scope before the next call to \c ResolveImportedPath.
static TemporarilyOwnedStringRef
ResolveImportedPath(SmallString<0> &Buf, StringRef Path, ModuleFile &ModF);
/// Resolve \c Path in the context of the \c Prefix directory. The return
/// value must go out of scope before the next call to \c ResolveImportedPath.
static TemporarilyOwnedStringRef
ResolveImportedPath(SmallString<0> &Buf, StringRef Path, StringRef Prefix);

/// Resolve \c Path in the context of module file \c M.
static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef Path,
ModuleFile &ModF);
/// Resolve \c Path in the context of the \c Prefix directory.
static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef Path,
StringRef Prefix);

/// Returns the first key declaration for the given declaration. This
/// is one that is formerly-canonical (or still canonical) and whose module
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/ByteCode/Boolean.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ class Boolean final {

Boolean truncate(unsigned TruncBits) const { return *this; }

static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
// Boolean width is currently always 8 for all supported targets. If this
// changes we need to get the bool width from the target info.
assert(BitWidth == 8);
bool Val = static_cast<bool>(*Buff);
return Boolean(Val);
}

void bitcastToMemory(std::byte *Buff) { std::memcpy(Buff, &V, sizeof(V)); }

void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
Expand Down
63 changes: 63 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitDecayPtr(*FromT, *ToT, CE);
}

case CK_LValueToRValueBitCast:
return this->emitBuiltinBitCast(CE);

case CK_IntegralToBoolean:
case CK_FixedPointToBoolean:
case CK_BooleanToSignedIntegral:
Expand Down Expand Up @@ -6426,6 +6429,66 @@ bool Compiler<Emitter>::emitDummyPtr(const DeclTy &D, const Expr *E) {
return this->emitDecayPtr(PT_Ptr, PT, E);
return false;
}
return true;
}

// This function is constexpr if and only if To, From, and the types of
// all subobjects of To and From are types T such that...
// (3.1) - is_union_v<T> is false;
// (3.2) - is_pointer_v<T> is false;
// (3.3) - is_member_pointer_v<T> is false;
// (3.4) - is_volatile_v<T> is false; and
// (3.5) - T has no non-static data members of reference type
template <class Emitter>
bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
const Expr *SubExpr = E->getSubExpr();
QualType FromType = SubExpr->getType();
QualType ToType = E->getType();
std::optional<PrimType> ToT = classify(ToType);

assert(!DiscardResult && "Implement DiscardResult mode for bitcasts.");

if (ToType->isNullPtrType()) {
if (!this->discard(SubExpr))
return false;

return this->emitNullPtr(nullptr, E);
}

if (FromType->isNullPtrType() && ToT) {
if (!this->discard(SubExpr))
return false;

return visitZeroInitializer(*ToT, ToType, E);
}
assert(!ToType->isReferenceType());

// Get a pointer to the value-to-cast on the stack.
if (!this->visit(SubExpr))
return false;

if (!ToT || ToT == PT_Ptr) {
// Conversion to an array or record type.
assert(false && "Implement bitcast to pointers.");
}
assert(ToT);

const llvm::fltSemantics *TargetSemantics = nullptr;
if (ToT == PT_Float)
TargetSemantics = &Ctx.getFloatSemantics(ToType);

// Conversion to a primitive type. FromType can be another
// primitive type, or a record/array.
bool ToTypeIsUChar = (ToType->isSpecificBuiltinType(BuiltinType::UChar) ||
ToType->isSpecificBuiltinType(BuiltinType::Char_U));
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);

if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
ResultBitWidth, TargetSemantics, E))
return false;

if (DiscardResult)
return this->emitPop(*ToT, E);

return true;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
unsigned collectBaseOffset(const QualType BaseType,
const QualType DerivedType);
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
bool emitBuiltinBitCast(const CastExpr *E);
bool compileConstructor(const CXXConstructorDecl *Ctor);
bool compileDestructor(const CXXDestructorDecl *Dtor);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ByteCode/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ class Floating final {
return Floating(APFloat(Sem, API));
}

void bitcastToMemory(std::byte *Buff) {
llvm::APInt API = F.bitcastToAPInt();
llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
}

// === Serialization support ===
size_t bytesToSerialize() const {
return sizeof(llvm::fltSemantics *) +
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ template <unsigned Bits, bool Signed> class Integral final {
// The primitive representing the integral.
using ReprT = typename Repr<Bits, Signed>::Type;
ReprT V;
static_assert(std::is_trivially_copyable_v<ReprT>);

/// Primitive representing limits.
static const auto Min = std::numeric_limits<ReprT>::min();
Expand Down Expand Up @@ -154,6 +155,18 @@ template <unsigned Bits, bool Signed> class Integral final {
return Compare(V, RHS.V);
}

void bitcastToMemory(std::byte *Dest) const {
std::memcpy(Dest, &V, sizeof(V));
}

static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
assert(BitWidth == sizeof(ReprT) * 8);
ReprT V;

std::memcpy(&V, Src, sizeof(ReprT));
return Integral(V);
}

std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ template <bool Signed> class IntegralAP final {
return IntegralAP<false>(Copy);
}

void bitcastToMemory(std::byte *Dest) const { assert(false); }

static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
return IntegralAP();
}

ComparisonCategoryResult compare(const IntegralAP &RHS) const {
assert(Signed == RHS.isSigned());
assert(bitWidth() == RHS.bitWidth());
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,23 @@ bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
return true;
}

bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool TargetIsUCharOrByte) {
// This is always fine.
if (!HasIndeterminateBits)
return true;

// Indeterminate bits can only be bitcast to unsigned char or std::byte.
if (TargetIsUCharOrByte)
return true;

const Expr *E = S.Current->getExpr(OpPC);
QualType ExprType = E->getType();
S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
<< ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();
return false;
}

// https://github.com/llvm/llvm-project/issues/102513
#if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "Floating.h"
#include "Function.h"
#include "FunctionPointer.h"
#include "InterpBuiltinBitCast.h"
#include "InterpFrame.h"
#include "InterpStack.h"
#include "InterpState.h"
Expand Down Expand Up @@ -162,6 +163,8 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
const CallExpr *CE);
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool TargetIsUCharOrByte);

template <typename T>
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
Expand Down Expand Up @@ -3039,6 +3042,34 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
}
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) {
const Pointer &FromPtr = S.Stk.pop<Pointer>();

if (!CheckLoad(S, OpPC, FromPtr))
return false;

size_t BuffSize = ResultBitWidth / 8;
llvm::SmallVector<std::byte> Buff(BuffSize);
bool HasIndeterminateBits = false;

if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BuffSize, HasIndeterminateBits))
return false;

if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
return false;

if constexpr (std::is_same_v<T, Floating>) {
assert(false && "Implement bitcasting to a floating type");
} else {
assert(!Sem);
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
}
return true;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Compiler.h"
#include "EvalEmitter.h"
#include "Interp.h"
#include "InterpBuiltinBitCast.h"
#include "PrimType.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
Expand Down
367 changes: 367 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,367 @@
//===-------------------- InterpBuiltinBitCast.cpp --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "InterpBuiltinBitCast.h"
#include "Boolean.h"
#include "Context.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Integral.h"
#include "IntegralAP.h"
#include "InterpState.h"
#include "MemberPointer.h"
#include "Pointer.h"
#include "Record.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/BitVector.h"
#include <bitset>

using namespace clang;
using namespace clang::interp;

/// Used to iterate over pointer fields.
using DataFunc =
llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>;

#define BITCAST_TYPE_SWITCH(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
default: \
llvm_unreachable("Unhandled bitcast type"); \
} \
} while (0)

/// Float is a special case that sometimes needs the floating point semantics
/// to be available.
#define BITCAST_TYPE_SWITCH_WITH_FLOAT(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
TYPE_SWITCH_CASE(PT_Float, B) \
default: \
llvm_unreachable("Unhandled bitcast type"); \
} \
} while (0)

static bool bitof(std::byte B, unsigned BitIndex) {
return (B & (std::byte{1} << BitIndex)) != std::byte{0};
}

static void swapBytes(std::byte *M, size_t N) {
for (size_t I = 0; I != (N / 2); ++I)
std::swap(M[I], M[N - 1 - I]);
}

/// Track what bits have been initialized to known values and which ones
/// have indeterminate value.
/// All offsets are in bits.
struct BitcastBuffer {
llvm::BitVector Data;

BitcastBuffer() = default;

size_t size() const { return Data.size(); }

const std::byte *data() const {
unsigned NBytes = Data.size() / 8;
unsigned BitVectorWordSize = sizeof(uintptr_t);
bool FullWord = (NBytes % BitVectorWordSize == 0);

// llvm::BitVector uses 64-bit fields internally, so when we have
// fewer bytes than that, we need to compensate for that on
// big endian hosts.
unsigned DataPlus;
if (llvm::sys::IsBigEndianHost)
DataPlus = BitVectorWordSize - (NBytes % BitVectorWordSize);
else
DataPlus = 0;

return reinterpret_cast<const std::byte *>(Data.getData().data()) +
(FullWord ? 0 : DataPlus);
}

bool allInitialized() const {
// FIXME: Implement.
return true;
}

void pushData(const std::byte *data, size_t BitOffset, size_t BitWidth,
bool BigEndianTarget) {
Data.reserve(BitOffset + BitWidth);

bool OnlyFullBytes = BitWidth % 8 == 0;
unsigned NBytes = BitWidth / 8;

size_t BitsHandled = 0;
// Read all full bytes first
for (size_t I = 0; I != NBytes; ++I) {
std::byte B =
BigEndianTarget ? data[NBytes - OnlyFullBytes - I] : data[I];
for (unsigned X = 0; X != 8; ++X) {
Data.push_back(bitof(B, X));
++BitsHandled;
}
}

if (BitsHandled == BitWidth)
return;

// Rest of the bits.
assert((BitWidth - BitsHandled) < 8);
std::byte B = BigEndianTarget ? data[0] : data[NBytes];
for (size_t I = 0, E = (BitWidth - BitsHandled); I != E; ++I) {
Data.push_back(bitof(B, I));
++BitsHandled;
}

assert(BitsHandled == BitWidth);
}
};

/// We use this to recursively iterate over all fields and elemends of a pointer
/// and extract relevant data for a bitcast.
static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
DataFunc F) {
const Descriptor *FieldDesc = P.getFieldDesc();
assert(FieldDesc);

// Primitives.
if (FieldDesc->isPrimitive())
return F(P, FieldDesc->getPrimType(), Offset);

// Primitive arrays.
if (FieldDesc->isPrimitiveArray()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
QualType ElemType = FieldDesc->getElemQualType();
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
PrimType ElemT = *Ctx.classify(ElemType);
bool Ok = true;
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
Ok = Ok && F(P.atIndex(Index), ElemT, Offset);
Offset += ElemSizeInBits;
}
return Ok;
}

// Composite arrays.
if (FieldDesc->isCompositeArray()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
QualType ElemType = FieldDesc->getElemQualType();
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
enumerateData(P.atIndex(Index).narrow(), Ctx, Offset, F);
Offset += ElemSizeInBits;
}
return true;
}

// Records.
if (FieldDesc->isRecord()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
const Record *R = FieldDesc->ElemRecord;
const ASTRecordLayout &Layout =
Ctx.getASTContext().getASTRecordLayout(R->getDecl());
bool Ok = true;

auto enumerateFields = [&]() -> void {
for (unsigned I = 0, N = R->getNumFields(); I != N; ++I) {
const Record::Field *Fi =
R->getField(BigEndianTarget ? (N - 1 - I) : I);
Pointer Elem = P.atField(Fi->Offset);
size_t BitOffset =
Offset + Layout.getFieldOffset(Fi->Decl->getFieldIndex());
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
}
};
auto enumerateBases = [&]() -> void {
for (unsigned I = 0, N = R->getNumBases(); I != N; ++I) {
const Record::Base *B = R->getBase(BigEndianTarget ? (N - 1 - I) : I);
Pointer Elem = P.atField(B->Offset);
CharUnits ByteOffset =
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B->Decl));
size_t BitOffset = Offset + Ctx.getASTContext().toBits(ByteOffset);
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
}
};

if (BigEndianTarget) {
enumerateFields();
enumerateBases();
} else {
enumerateBases();
enumerateFields();
}

return Ok;
}

llvm_unreachable("Unhandled data type");
}

static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
DataFunc F) {
return enumerateData(P, Ctx, 0, F);
}

// This function is constexpr if and only if To, From, and the types of
// all subobjects of To and From are types T such that...
// (3.1) - is_union_v<T> is false;
// (3.2) - is_pointer_v<T> is false;
// (3.3) - is_member_pointer_v<T> is false;
// (3.4) - is_volatile_v<T> is false; and
// (3.5) - T has no non-static data members of reference type
//
// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
// ExprConstant.cpp.
static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T,
bool IsToType) {
enum {
E_Union = 0,
E_Pointer,
E_MemberPointer,
E_Volatile,
E_Reference,
};
enum { C_Member, C_Base };

auto diag = [&](int Reason) -> bool {
const Expr *E = S.Current->getExpr(OpPC);
S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
<< static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
<< E->getSourceRange();
return false;
};
auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) {
S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
<< NoteType << Construct << T << NoteRange;
return false;
};

T = T.getCanonicalType();

if (T->isUnionType())
return diag(E_Union);
if (T->isPointerType())
return diag(E_Pointer);
if (T->isMemberPointerType())
return diag(E_MemberPointer);
if (T.isVolatileQualified())
return diag(E_Volatile);

if (const RecordDecl *RD = T->getAsRecordDecl()) {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
return note(C_Base, BS.getType(), BS.getBeginLoc());
}
}
for (const FieldDecl *FD : RD->fields()) {
if (FD->getType()->isReferenceType())
return diag(E_Reference);
if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType))
return note(C_Member, FD->getType(), FD->getSourceRange());
}
}

if (T->isArrayType() &&
!CheckBitcastType(S, OpPC, S.getASTContext().getBaseElementType(T),
IsToType))
return false;

return true;
}

static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
BitcastBuffer &Buffer, bool ReturnOnUninit) {
const ASTContext &ASTCtx = Ctx.getASTContext();
bool SwapData = (ASTCtx.getTargetInfo().isLittleEndian() !=
llvm::sys::IsLittleEndianHost);
bool BigEndianTarget = ASTCtx.getTargetInfo().isBigEndian();

return enumeratePointerFields(
FromPtr, Ctx,
[&](const Pointer &P, PrimType T, size_t BitOffset) -> bool {
if (!P.isInitialized()) {
assert(false && "Implement uninitialized value tracking");
return ReturnOnUninit;
}

assert(P.isInitialized());
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
if (T == PT_Ptr)
assert(false && "Implement casting to pointer types");

CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
unsigned BitWidth;
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
BitWidth = FD->getBitWidthValue(ASTCtx);
else
BitWidth = ASTCtx.toBits(ObjectReprChars);

llvm::SmallVector<std::byte> Buff(ObjectReprChars.getQuantity());
BITCAST_TYPE_SWITCH_WITH_FLOAT(T, {
T Val = P.deref<T>();
Val.bitcastToMemory(Buff.data());
});
if (SwapData)
swapBytes(Buff.data(), ObjectReprChars.getQuantity());

if (BitWidth != (Buff.size() * 8) && BigEndianTarget) {
Buffer.pushData(Buff.data() + (Buff.size() - 1 - (BitWidth / 8)),
BitOffset, BitWidth, BigEndianTarget);
} else {
Buffer.pushData(Buff.data(), BitOffset, BitWidth, BigEndianTarget);
}
return true;
});
}

bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize,
bool &HasIndeterminateBits) {
assert(Ptr.isLive());
assert(Ptr.isBlockPointer());
assert(Buff);

BitcastBuffer Buffer;
if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false))
return false;

bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
/*ReturnOnUninit=*/false);
assert(Buffer.size() == BuffSize * 8);

HasIndeterminateBits = !Buffer.allInitialized();
std::memcpy(Buff, Buffer.data(), BuffSize);

return Success;
}
26 changes: 26 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===------------------ InterpBuiltinBitCast.h ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H
#define LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H

#include <cstddef>

namespace clang {
namespace interp {
class Pointer;
class InterpState;
class CodePtr;

bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize, bool &HasIndeterminateBits);

} // namespace interp
} // namespace clang

#endif
10 changes: 10 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -837,3 +837,13 @@ def CheckNewTypeMismatchArray : Opcode {

def IsConstantContext: Opcode;
def CheckAllocations : Opcode;

def BitCastTypeClass : TypeClass {
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float];
}

def BitCast : Opcode {
let Types = [BitCastTypeClass];
let Args = [ArgBool, ArgUint32, ArgFltSemantics];
let HasGroup = 1;
}
4 changes: 2 additions & 2 deletions clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,10 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
}

// Arrays.
if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
QualType ElemTy = ArrayType->getElementType();
// Array of well-known bounds.
if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
size_t NumElems = CAT->getZExtSize();
if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
// Arrays of primitives.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ add_clang_library(clangAST
ByteCode/Function.cpp
ByteCode/FunctionPointer.cpp
ByteCode/InterpBuiltin.cpp
ByteCode/InterpBuiltinBitCast.cpp
ByteCode/Floating.cpp
ByteCode/EvaluationResult.cpp
ByteCode/DynamicAllocator.cpp
Expand Down
41 changes: 19 additions & 22 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22398,10 +22398,6 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
default: llvm_unreachable("unexpected builtin ID");
case RISCV::BI__builtin_riscv_orc_b_32:
case RISCV::BI__builtin_riscv_orc_b_64:
case RISCV::BI__builtin_riscv_clz_32:
case RISCV::BI__builtin_riscv_clz_64:
case RISCV::BI__builtin_riscv_ctz_32:
case RISCV::BI__builtin_riscv_ctz_64:
case RISCV::BI__builtin_riscv_clmul_32:
case RISCV::BI__builtin_riscv_clmul_64:
case RISCV::BI__builtin_riscv_clmulh_32:
Expand All @@ -22423,24 +22419,6 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_orc_b_64:
ID = Intrinsic::riscv_orc_b;
break;
case RISCV::BI__builtin_riscv_clz_32:
case RISCV::BI__builtin_riscv_clz_64: {
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
return Result;
}
case RISCV::BI__builtin_riscv_ctz_32:
case RISCV::BI__builtin_riscv_ctz_64: {
Function *F = CGM.getIntrinsic(Intrinsic::cttz, Ops[0]->getType());
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
"cast");
return Result;
}

// Zbc
case RISCV::BI__builtin_riscv_clmul_32:
Expand Down Expand Up @@ -22515,6 +22493,25 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::riscv_sm3p1;
break;

case RISCV::BI__builtin_riscv_clz_32:
case RISCV::BI__builtin_riscv_clz_64: {
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
if (Result->getType() != ResultType)
Result =
Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
return Result;
}
case RISCV::BI__builtin_riscv_ctz_32:
case RISCV::BI__builtin_riscv_ctz_64: {
Function *F = CGM.getIntrinsic(Intrinsic::cttz, Ops[0]->getType());
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
if (Result->getType() != ResultType)
Result =
Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
return Result;
}

// Zihintntl
case RISCV::BI__builtin_riscv_ntl_load: {
llvm::Type *ResTy = ConvertType(E->getType());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);

CmdArgs.push_back("-m");
CmdArgs.push_back("elf_x86_64_fbsd");

CmdArgs.push_back(
Args.MakeArgString("--sysroot=" + TC.getSDKLibraryRootDir()));

Expand Down
133 changes: 69 additions & 64 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2042,19 +2042,15 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M,
return LocalID + I->second;
}

const FileEntry *HeaderFileInfoTrait::getFile(const internal_key_type &Key) {
OptionalFileEntryRef
HeaderFileInfoTrait::getFile(const internal_key_type &Key) {
FileManager &FileMgr = Reader.getFileManager();
if (!Key.Imported) {
if (auto File = FileMgr.getOptionalFileRef(Key.Filename))
return *File;
return nullptr;
}
if (!Key.Imported)
return FileMgr.getOptionalFileRef(Key.Filename);

std::string Resolved = std::string(Key.Filename);
Reader.ResolveImportedPath(M, Resolved);
if (auto File = FileMgr.getOptionalFileRef(Resolved))
return *File;
return nullptr;
auto Resolved =
ASTReader::ResolveImportedPath(Reader.getPathBuf(), Key.Filename, M);
return FileMgr.getOptionalFileRef(*Resolved);
}

unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
Expand All @@ -2080,8 +2076,8 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
return true;

// Determine whether the actual files are equivalent.
const FileEntry *FEA = getFile(a);
const FileEntry *FEB = getFile(b);
OptionalFileEntryRef FEA = getFile(a);
OptionalFileEntryRef FEB = getFile(b);
return FEA && FEA == FEB;
}

Expand Down Expand Up @@ -2112,12 +2108,13 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HeaderFileInfo HFI;
unsigned Flags = *d++;

OptionalFileEntryRef FE;
bool Included = (Flags >> 6) & 0x01;
if (Included)
if (const FileEntry *FE = getFile(key))
if ((FE = getFile(key)))
// Not using \c Preprocessor::markIncluded(), since that would attempt to
// deserialize this header file info again.
Reader.getPreprocessor().getIncludedFiles().insert(FE);
Reader.getPreprocessor().getIncludedFiles().insert(*FE);

// FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp.
HFI.isImport |= (Flags >> 5) & 0x01;
Expand Down Expand Up @@ -2146,14 +2143,10 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
// implicit module import.
SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
Module *Mod = Reader.getSubmodule(GlobalSMID);
FileManager &FileMgr = Reader.getFileManager();
ModuleMap &ModMap =
Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();

std::string Filename = std::string(key.Filename);
if (key.Imported)
Reader.ResolveImportedPath(M, Filename);
if (auto FE = FileMgr.getOptionalFileRef(Filename)) {
if (FE || (FE = getFile(key))) {
// FIXME: NameAsWritten
Module::Header H = {std::string(key.Filename), "", *FE};
ModMap.addHeader(Mod, H, HeaderRole, /*Imported=*/true);
Expand Down Expand Up @@ -2520,11 +2513,12 @@ InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) {
std::tie(R.FilenameAsRequested, R.Filename) = [&]() {
uint16_t AsRequestedLength = Record[7];

std::string NameAsRequested = Blob.substr(0, AsRequestedLength).str();
std::string Name = Blob.substr(AsRequestedLength).str();
StringRef NameAsRequestedRef = Blob.substr(0, AsRequestedLength);
StringRef NameRef = Blob.substr(AsRequestedLength);

ResolveImportedPath(F, NameAsRequested);
ResolveImportedPath(F, Name);
std::string NameAsRequested =
ResolveImportedPathAndAllocate(PathBuf, NameAsRequestedRef, F);
std::string Name = ResolveImportedPathAndAllocate(PathBuf, NameRef, F);

if (Name.empty())
Name = NameAsRequested;
Expand Down Expand Up @@ -2750,23 +2744,38 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
return IF;
}

/// If we are loading a relocatable PCH or module file, and the filename
/// is not an absolute path, add the system or module root to the beginning of
/// the file name.
void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) {
// Resolve relative to the base directory, if we have one.
if (!M.BaseDirectory.empty())
return ResolveImportedPath(Filename, M.BaseDirectory);
ASTReader::TemporarilyOwnedStringRef
ASTReader::ResolveImportedPath(SmallString<0> &Buf, StringRef Path,
ModuleFile &ModF) {
return ResolveImportedPath(Buf, Path, ModF.BaseDirectory);
}

void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) {
if (Filename.empty() || llvm::sys::path::is_absolute(Filename) ||
Filename == "<built-in>" || Filename == "<command line>")
return;
ASTReader::TemporarilyOwnedStringRef
ASTReader::ResolveImportedPath(SmallString<0> &Buf, StringRef Path,
StringRef Prefix) {
assert(Buf.capacity() != 0 && "Overlapping ResolveImportedPath calls");

if (Prefix.empty() || Path.empty() || llvm::sys::path::is_absolute(Path) ||
Path == "<built-in>" || Path == "<command line>")
return {Path, Buf};

Buf.clear();
llvm::sys::path::append(Buf, Prefix, Path);
StringRef ResolvedPath{Buf.data(), Buf.size()};
return {ResolvedPath, Buf};
}

std::string ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef P,
ModuleFile &ModF) {
return ResolveImportedPathAndAllocate(Buf, P, ModF.BaseDirectory);
}

SmallString<128> Buffer;
llvm::sys::path::append(Buffer, Prefix, Filename);
Filename.assign(Buffer.begin(), Buffer.end());
std::string ASTReader::ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef P,
StringRef Prefix) {
auto ResolvedPath = ResolveImportedPath(Buf, P, Prefix);
return ResolvedPath->str();
}

static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) {
Expand Down Expand Up @@ -3194,8 +3203,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case ORIGINAL_FILE:
F.OriginalSourceFileID = FileID::get(Record[0]);
F.ActualOriginalSourceFileName = std::string(Blob);
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
ResolveImportedPath(F, F.OriginalSourceFileName);
F.OriginalSourceFileName = ResolveImportedPathAndAllocate(
PathBuf, F.ActualOriginalSourceFileName, F);
break;

case ORIGINAL_FILE_ID:
Expand Down Expand Up @@ -5484,6 +5493,8 @@ bool ASTReader::readASTFileControlBlock(
RecordData Record;
std::string ModuleDir;
bool DoneWithControlBlock = false;
SmallString<0> PathBuf;
PathBuf.reserve(256);
while (!DoneWithControlBlock) {
Expected<llvm::BitstreamEntry> MaybeEntry = Stream.advance();
if (!MaybeEntry) {
Expand Down Expand Up @@ -5566,9 +5577,9 @@ bool ASTReader::readASTFileControlBlock(
break;
case MODULE_MAP_FILE: {
unsigned Idx = 0;
auto Path = ReadString(Record, Idx);
ResolveImportedPath(Path, ModuleDir);
Listener.ReadModuleMapFile(Path);
std::string PathStr = ReadString(Record, Idx);
auto Path = ResolveImportedPath(PathBuf, PathStr, ModuleDir);
Listener.ReadModuleMapFile(*Path);
break;
}
case INPUT_FILE_OFFSETS: {
Expand Down Expand Up @@ -5615,10 +5626,9 @@ bool ASTReader::readASTFileControlBlock(
break;
case INPUT_FILE:
bool Overridden = static_cast<bool>(Record[3]);
std::string Filename = std::string(Blob);
ResolveImportedPath(Filename, ModuleDir);
auto Filename = ResolveImportedPath(PathBuf, Blob, ModuleDir);
shouldContinue = Listener.visitInputFile(
Filename, isSystemFile, Overridden, /*IsExplicitModule*/false);
*Filename, isSystemFile, Overridden, /*IsExplicitModule=*/false);
break;
}
if (!shouldContinue)
Expand Down Expand Up @@ -5653,9 +5663,9 @@ bool ASTReader::readASTFileControlBlock(
// Skip Size, ModTime and Signature
Idx += 1 + 1 + ASTFileSignature::size;
std::string ModuleName = ReadString(Record, Idx);
std::string Filename = ReadString(Record, Idx);
ResolveImportedPath(Filename, ModuleDir);
Listener.visitImport(ModuleName, Filename);
std::string FilenameStr = ReadString(Record, Idx);
auto Filename = ResolveImportedPath(PathBuf, FilenameStr, ModuleDir);
Listener.visitImport(ModuleName, *Filename);
}
break;
}
Expand Down Expand Up @@ -5908,9 +5918,8 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
// FIXME: This doesn't work for framework modules as `Filename` is the
// name as written in the module file and does not include
// `Headers/`, so this path will never exist.
std::string Filename = std::string(Blob);
ResolveImportedPath(F, Filename);
if (auto Umbrella = PP.getFileManager().getOptionalFileRef(Filename)) {
auto Filename = ResolveImportedPath(PathBuf, Blob, F);
if (auto Umbrella = PP.getFileManager().getOptionalFileRef(*Filename)) {
if (!CurrentModule->getUmbrellaHeaderAsWritten()) {
// FIXME: NameAsWritten
ModMap.setUmbrellaHeaderAsWritten(CurrentModule, *Umbrella, Blob, "");
Expand Down Expand Up @@ -5938,18 +5947,16 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
break;

case SUBMODULE_TOPHEADER: {
std::string HeaderName(Blob);
ResolveImportedPath(F, HeaderName);
CurrentModule->addTopHeaderFilename(HeaderName);
auto HeaderName = ResolveImportedPath(PathBuf, Blob, F);
CurrentModule->addTopHeaderFilename(*HeaderName);
break;
}

case SUBMODULE_UMBRELLA_DIR: {
// See comments in SUBMODULE_UMBRELLA_HEADER
std::string Dirname = std::string(Blob);
ResolveImportedPath(F, Dirname);
auto Dirname = ResolveImportedPath(PathBuf, Blob, F);
if (auto Umbrella =
PP.getFileManager().getOptionalDirectoryRef(Dirname)) {
PP.getFileManager().getOptionalDirectoryRef(*Dirname)) {
if (!CurrentModule->getUmbrellaDirAsWritten()) {
// FIXME: NameAsWritten
ModMap.setUmbrellaDirAsWritten(CurrentModule, *Umbrella, Blob, "");
Expand Down Expand Up @@ -9604,17 +9611,13 @@ std::string ASTReader::ReadString(const RecordDataImpl &Record, unsigned &Idx) {

std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
std::string Filename = ReadString(Record, Idx);
ResolveImportedPath(F, Filename);
return Filename;
return ReadPath(F.BaseDirectory, Record, Idx);
}

std::string ASTReader::ReadPath(StringRef BaseDirectory,
const RecordData &Record, unsigned &Idx) {
std::string Filename = ReadString(Record, Idx);
if (!BaseDirectory.empty())
ResolveImportedPath(Filename, BaseDirectory);
return Filename;
return ResolveImportedPathAndAllocate(PathBuf, Filename, BaseDirectory);
}

VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record,
Expand Down Expand Up @@ -10519,6 +10522,8 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) {
SourceMgr.setExternalSLocEntrySource(this);

PathBuf.reserve(256);

for (const auto &Ext : Extensions) {
auto BlockName = Ext->getExtensionMetadata().BlockName;
auto Known = ModuleFileExtensions.find(BlockName);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTReaderInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ class HeaderFileInfoTrait {
data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);

private:
const FileEntry *getFile(const internal_key_type &Key);
OptionalFileEntryRef getFile(const internal_key_type &Key);
};

/// The on-disk hash table used for known header files.
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,12 +1091,15 @@ static bool isStandardDelete(const FunctionDecl *FD) {
if (Kind != OO_Delete && Kind != OO_Array_Delete)
return false;

bool HasBody = FD->hasBody(); // Prefer using the definition.

// This is standard if and only if it's not defined in a user file.
SourceLocation L = FD->getLocation();

// If the header for operator delete is not included, it's still defined
// in an invalid source location. Check to make sure we don't crash.
return !L.isValid() ||
FD->getASTContext().getSourceManager().isInSystemHeader(L);
const auto &SM = FD->getASTContext().getSourceManager();
return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));
}

//===----------------------------------------------------------------------===//
Expand Down
451 changes: 451 additions & 0 deletions clang/test/AST/ByteCode/builtin-bit-cast.cpp

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions clang/test/Analysis/Inputs/overloaded-delete-in-header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef OVERLOADED_DELETE_IN_HEADER
#define OVERLOADED_DELETE_IN_HEADER

struct DeleteInHeader {
int data;
static void operator delete(void *ptr);
};

void DeleteInHeader::operator delete(void *ptr) {
DeleteInHeader *self = (DeleteInHeader *)ptr;
self->data = 1; // no-warning: Still alive.

::operator delete(ptr);

self->data = 2; // expected-warning {{Use of memory after it is freed [cplusplus.NewDelete]}}
}

#endif // OVERLOADED_DELETE_IN_SYSTEM_HEADER
9 changes: 9 additions & 0 deletions clang/test/Analysis/overloaded-delete-in-system-header.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_analyze_cc1 -isystem %S/Inputs/ -verify %s \
// RUN: -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete

// RUN: %clang_analyze_cc1 -I %S/Inputs/ -verify %s \
// RUN: -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete

#include "overloaded-delete-in-header.h"

void deleteInHeader(DeleteInHeader *p) { delete p; }
3 changes: 3 additions & 0 deletions clang/test/CodeGen/2004-02-20-Builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ double sqrt(double x);

// CHECK-LABEL: @zsqrtxxx
// CHECK-NOT: builtin
// Don't search into metadata definitions. !llvm.ident can contain the
// substring "builtin" if it's in the source tree path.
// CHECK-LABEL: !llvm.ident
void zsqrtxxx(float num) {
num = sqrt(num);
}
7 changes: 7 additions & 0 deletions clang/test/Driver/ps5-linker.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// Test that a target emulation is supplied to the linker

// RUN: %clang --target=x86_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-EMU %s

// CHECK-EMU: {{ld(\.exe)?}}"
// CHECK-EMU-SAME: "-m" "elf_x86_64_fbsd"

// Test that PIE is the default for main components

// RUN: %clang --target=x86_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-PIE %s
Expand Down
4 changes: 4 additions & 0 deletions clang/tools/clang-sycl-linker/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BinaryFormat
Option
Object
TargetParser
Support
)

set(LLVM_TARGET_DEFINITIONS SYCLLinkOpts.td)
Expand Down
36 changes: 24 additions & 12 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,33 +164,45 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
}

// Deletes the specified signal from newset, if it is not present in oldset
// Equivalently: newset[signum] = newset[signum] & oldset[signum]
static void KeepUnblocked(__sanitizer_sigset_t &newset,
__sanitizer_sigset_t &oldset, int signum) {
if (!internal_sigismember(&oldset, signum))
internal_sigdelset(&newset, signum);
}

// Block asynchronous signals
void BlockSignals(__sanitizer_sigset_t *oldset) {
__sanitizer_sigset_t set;
internal_sigfillset(&set);
__sanitizer_sigset_t currentset;
SetSigProcMask(NULL, &currentset);

__sanitizer_sigset_t newset;
internal_sigfillset(&newset);
# if SANITIZER_LINUX && !SANITIZER_ANDROID
// Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
// on any thread, setuid call hangs.
// See test/sanitizer_common/TestCases/Linux/setuid.c.
internal_sigdelset(&set, 33);
KeepUnblocked(newset, currentset, 33);
# endif
# if SANITIZER_LINUX
// Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
// If this signal is blocked, such calls cannot be handled and the process may
// hang.
internal_sigdelset(&set, 31);
KeepUnblocked(newset, currentset, 31);

// Don't block synchronous signals
internal_sigdelset(&set, SIGSEGV);
internal_sigdelset(&set, SIGBUS);
internal_sigdelset(&set, SIGILL);
internal_sigdelset(&set, SIGTRAP);
internal_sigdelset(&set, SIGABRT);
internal_sigdelset(&set, SIGFPE);
internal_sigdelset(&set, SIGPIPE);
// but also don't unblock signals that the user had deliberately blocked.
KeepUnblocked(newset, currentset, SIGSEGV);
KeepUnblocked(newset, currentset, SIGBUS);
KeepUnblocked(newset, currentset, SIGILL);
KeepUnblocked(newset, currentset, SIGTRAP);
KeepUnblocked(newset, currentset, SIGABRT);
KeepUnblocked(newset, currentset, SIGFPE);
KeepUnblocked(newset, currentset, SIGPIPE);
# endif

SetSigProcMask(&set, oldset);
SetSigProcMask(&newset, oldset);
}

ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(SANITIZER_UNITTESTS
sanitizer_array_ref_test.cpp
sanitizer_atomic_test.cpp
sanitizer_bitvector_test.cpp
sanitizer_block_signals.cpp
sanitizer_bvgraph_test.cpp
sanitizer_chained_origin_depot_test.cpp
sanitizer_common_test.cpp
Expand Down
76 changes: 76 additions & 0 deletions compiler-rt/lib/sanitizer_common/tests/sanitizer_block_signals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===-- sanitizer_block_signals.cpp ---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of sanitizer_common unit tests.
//
//===----------------------------------------------------------------------===//
#include <signal.h>
#include <stdio.h>

#include "gtest/gtest.h"
#include "sanitizer_common/sanitizer_linux.h"

namespace __sanitizer {

#if SANITIZER_LINUX
volatile int received_sig = -1;

void signal_handler(int signum) { received_sig = signum; }

TEST(SanitizerCommon, NoBlockSignals) {
// No signals blocked
signal(SIGUSR1, signal_handler);
raise(SIGUSR1);
EXPECT_EQ(received_sig, SIGUSR1);

received_sig = -1;
signal(SIGPIPE, signal_handler);
raise(SIGPIPE);
EXPECT_EQ(received_sig, SIGPIPE);
}

TEST(SanitizerCommon, BlockSignalsPlain) {
// ScopedBlockSignals; SIGUSR1 should be blocked but not SIGPIPE
{
__sanitizer_sigset_t sigset = {};
ScopedBlockSignals block(&sigset);

received_sig = -1;
signal(SIGUSR1, signal_handler);
raise(SIGUSR1);
EXPECT_EQ(received_sig, -1);

received_sig = -1;
signal(SIGPIPE, signal_handler);
raise(SIGPIPE);
EXPECT_EQ(received_sig, SIGPIPE);
}
EXPECT_EQ(received_sig, SIGUSR1);
}

TEST(SanitizerCommon, BlockSignalsExceptPipe) {
// Manually block SIGPIPE; ScopedBlockSignals should not unblock this
sigset_t block_sigset;
sigemptyset(&block_sigset);
sigaddset(&block_sigset, SIGPIPE);
sigprocmask(SIG_BLOCK, &block_sigset, NULL);
{
__sanitizer_sigset_t sigset = {};
ScopedBlockSignals block(&sigset);

received_sig = -1;
signal(SIGPIPE, signal_handler);
raise(SIGPIPE);
EXPECT_EQ(received_sig, -1);
}
sigprocmask(SIG_UNBLOCK, &block_sigset, NULL);
EXPECT_EQ(received_sig, SIGPIPE);
}
#endif // SANITIZER_LINUX

} // namespace __sanitizer
2 changes: 1 addition & 1 deletion flang/include/flang/Runtime/CUDA/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void RTDECL(CUFMemFree)(void *devicePtr, unsigned type,
/// Set value to the data hold by a descriptor. The \p value pointer must be
/// addressable to the same amount of bytes specified by the element size of
/// the descriptor \p desc.
void RTDECL(CUFMemsetDescriptor)(const Descriptor &desc, void *value,
void RTDECL(CUFMemsetDescriptor)(Descriptor *desc, void *value,
const char *sourceFile = nullptr, int sourceLine = 0);

/// Data transfer from a pointer to a pointer.
Expand Down
21 changes: 19 additions & 2 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,27 @@ static void genLoopVars(
llvm::SmallVector<mlir::Location> locs(args.size(), loc);
firOpBuilder.createBlock(&region, {}, tiv, locs);

// Update nested wrapper operands if parent wrappers have mapped these values
// to block arguments.
//
// Binding these values earlier would take care of this, but we cannot rely on
// that approach because binding in between the creation of a wrapper and the
// next one would result in 'hlfir.declare' operations being introduced inside
// of a wrapper, which is illegal.
mlir::IRMapping mapper;
for (auto [argGeneratingOp, blockArgs] : wrapperArgs) {
for (mlir::OpOperand &operand : argGeneratingOp->getOpOperands())
operand.set(mapper.lookupOrDefault(operand.get()));

for (const auto [arg, var] : llvm::zip_equal(
argGeneratingOp->getRegion(0).getArguments(), blockArgs.getVars()))
mapper.map(var, arg);
}

// Bind the entry block arguments of parent wrappers to the corresponding
// symbols.
for (auto [argGeneratingOp, args] : wrapperArgs)
bindEntryBlockArgs(converter, argGeneratingOp, args);
for (auto [argGeneratingOp, blockArgs] : wrapperArgs)
bindEntryBlockArgs(converter, argGeneratingOp, blockArgs);

// The argument is not currently in memory, so make a temporary for the
// argument, and store it there, then bind that location to the argument.
Expand Down
22 changes: 17 additions & 5 deletions flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/CodeGen/Target.h"
#include "flang/Optimizer/CodeGen/TypeConverter.h"
#include "flang/Optimizer/Dialect/CUF/CUFOps.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Support/DataLayout.h"
#include "flang/Optimizer/Transforms/CUFCommon.h"
#include "flang/Runtime/CUDA/registration.h"
Expand Down Expand Up @@ -84,6 +86,8 @@ struct CUFAddConstructor
auto registeredMod = builder.create<cuf::RegisterModuleOp>(
loc, llvmPtrTy, mlir::SymbolRefAttr::get(ctx, gpuMod.getName()));

fir::LLVMTypeConverter typeConverter(mod, /*applyTBAA=*/false,
/*forceUnifiedTBAATree=*/false, *dl);
// Register kernels
for (auto func : gpuMod.getOps<mlir::gpu::GPUFuncOp>()) {
if (func.isKernel()) {
Expand Down Expand Up @@ -115,17 +119,25 @@ struct CUFAddConstructor
fir::factory::createStringLiteral(builder, loc, gblNameStr));

// Global variable size
auto sizeAndAlign = fir::getTypeSizeAndAlignmentOrCrash(
loc, globalOp.getType(), *dl, kindMap);
auto size =
builder.createIntegerConstant(loc, idxTy, sizeAndAlign.first);
std::optional<uint64_t> size;
if (auto boxTy =
mlir::dyn_cast<fir::BaseBoxType>(globalOp.getType())) {
mlir::Type structTy = typeConverter.convertBoxTypeAsStruct(boxTy);
size = dl->getTypeSizeInBits(structTy) / 8;
}
if (!size) {
size = fir::getTypeSizeAndAlignmentOrCrash(loc, globalOp.getType(),
*dl, kindMap)
.first;
}
auto sizeVal = builder.createIntegerConstant(loc, idxTy, *size);

// Global variable address
mlir::Value addr = builder.create<fir::AddrOfOp>(
loc, globalOp.resultType(), globalOp.getSymbol());

llvm::SmallVector<mlir::Value> args{fir::runtime::createArguments(
builder, loc, fTy, registeredMod, addr, gblName, size)};
builder, loc, fTy, registeredMod, addr, gblName, sizeVal)};
builder.create<fir::CallOp>(loc, func, args);
} break;
case cuf::DataAttribute::Managed:
Expand Down
3 changes: 1 addition & 2 deletions flang/lib/Optimizer/Transforms/CUFOpConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,9 +552,8 @@ struct CUFDataTransferOpConversion
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
mlir::Value sourceLine =
fir::factory::locationToLineNo(builder, loc, fTy.getInput(3));
mlir::Value dst = builder.loadIfRef(loc, op.getDst());
llvm::SmallVector<mlir::Value> args{fir::runtime::createArguments(
builder, loc, fTy, dst, val, sourceFile, sourceLine)};
builder, loc, fTy, op.getDst(), val, sourceFile, sourceLine)};
builder.create<fir::CallOp>(loc, func, args);
rewriter.eraseOp(op);
} else {
Expand Down
4 changes: 2 additions & 2 deletions flang/runtime/CUDA/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ void RTDEF(CUFMemFree)(
}
}

void RTDEF(CUFMemsetDescriptor)(const Descriptor &desc, void *value,
const char *sourceFile, int sourceLine) {
void RTDEF(CUFMemsetDescriptor)(
Descriptor *desc, void *value, const char *sourceFile, int sourceLine) {
Terminator terminator{sourceFile, sourceLine};
terminator.Crash("not yet implemented: CUDA data transfer from a scalar "
"value to a descriptor");
Expand Down
14 changes: 12 additions & 2 deletions flang/test/Fir/CUDA/cuda-constructor-2.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.ident = "flang version 20.0.0 (https://github.com/llvm/llvm-project.git cae351f3453a0a26ec8eb2ddaf773c24a29d929e)", llvm.target_triple = "x86_64-unknown-linux-gnu"} {

fir.global @_QMmtestsEn(dense<[3, 4, 5, 6, 7]> : tensor<5xi32>) {data_attr = #cuf.cuda<device>} : !fir.array<5xi32>
fir.global @_QMmtestsEndev {data_attr = #cuf.cuda<device>} : !fir.box<!fir.heap<!fir.array<?xi32>>> {
%c0 = arith.constant 0 : index
%0 = fir.zero_bits !fir.heap<!fir.array<?xi32>>
%1 = fircg.ext_embox %0(%c0) {allocator_idx = 2 : i32} : (!fir.heap<!fir.array<?xi32>>, index) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
fir.has_value %1 : !fir.box<!fir.heap<!fir.array<?xi32>>>
}

gpu.module @cuda_device_mod [#nvvm.target] {
}
Expand All @@ -18,5 +24,9 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<
// CHECK-DAG: %[[VAR_ADDR2:.*]] = fir.convert %[[VAR_ADDR]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.ref<i8>
// CHECK-DAG: %[[VAR_NAME2:.*]] = fir.convert %[[VAR_NAME]] : (!fir.ref<!fir.char<1,12>>) -> !fir.ref<i8>
// CHECK-DAG: %[[CST:.*]] = arith.constant 20 : index
// CHECK-DAG %[[CST2:.*]] = fir.convert %[[CST]] : (index) -> i64
// CHECK fir.call @_FortranACUFRegisterVariable(%[[MODULE2]], %[[VAR_ADDR2]], %[[VAR_NAME2]], %[[CST2]]) : (!fir.ref<!fir.llvm_ptr<i8>>, !fir.ref<i8>, !fir.ref<i8>, i64) -> none
// CHECK-DAG: %[[CST2:.*]] = fir.convert %[[CST]] : (index) -> i64
// CHECK-DAG: fir.call @_FortranACUFRegisterVariable(%[[MODULE2]], %[[VAR_ADDR2]], %[[VAR_NAME2]], %[[CST2]]) : (!fir.ref<!fir.llvm_ptr<i8>>, !fir.ref<i8>, !fir.ref<i8>, i64) -> none
// CHECK-DAG: %[[BOX:.*]] = fir.address_of(@_QMmtestsEndev) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
// CHECK-DAG: %[[BOXREF:.*]] = fir.convert %[[BOX]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<i8>
// CHECK-DAG: fir.call @_FortranACUFRegisterVariable(%[[MODULE:.*]], %[[BOXREF]], %{{.*}}, %{{.*}})
//
10 changes: 4 additions & 6 deletions flang/test/Fir/CUDA/cuda-data-transfer.fir
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ func.func @_QPsub2() {
// CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub2Eadev"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
// CHECK: %[[C2:.*]] = arith.constant 2 : i32
// CHECK: fir.store %[[C2]] to %[[TEMP]] : !fir.ref<i32>
// CHECK: %[[ADEV_LOAD:.*]] = fir.load %[[ADEV]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV_LOAD]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.box<none>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[TEMP_CONV:.*]] = fir.convert %[[TEMP]] : (!fir.ref<i32>) -> !fir.llvm_ptr<i8>
// CHECK: fir.call @_FortranACUFMemsetDescriptor(%[[ADEV_BOX]], %[[TEMP_CONV]], %{{.*}}, %{{.*}}) : (!fir.box<none>, !fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> none
// CHECK: fir.call @_FortranACUFMemsetDescriptor(%[[ADEV_BOX]], %[[TEMP_CONV]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> none

func.func @_QPsub3() {
%0 = cuf.alloc !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "adev", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub3Eadev"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
Expand All @@ -51,10 +50,9 @@ func.func @_QPsub3() {
// CHECK-LABEL: func.func @_QPsub3()
// CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub3Eadev"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
// CHECK: %[[V:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub3Ev"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
// CHECK: %[[ADEV_LOAD:.*]] = fir.load %[[ADEV]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV_LOAD]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.box<none>
// CHECK: %[[ADEV_BOX:.*]] = fir.convert %[[ADEV]]#0 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
// CHECK: %[[V_CONV:.*]] = fir.convert %[[V]]#0 : (!fir.ref<i32>) -> !fir.llvm_ptr<i8>
// CHECK: fir.call @_FortranACUFMemsetDescriptor(%[[ADEV_BOX]], %[[V_CONV]], %{{.*}}, %{{.*}}) : (!fir.box<none>, !fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> none
// CHECK: fir.call @_FortranACUFMemsetDescriptor(%[[ADEV_BOX]], %[[V_CONV]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> none

func.func @_QPsub4() {
%0 = cuf.alloc !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "adev", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub4Eadev"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Fir/CUDA/cuda-register-func.fir
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: fir-opt --cuf-add-constructor %s | FileCheck %s

module attributes {gpu.container_module} {
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.ident = "flang version 20.0.0 (https://github.com/llvm/llvm-project.git cae351f3453a0a26ec8eb2ddaf773c24a29d929e)", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
gpu.module @cuda_device_mod {
gpu.func @_QPsub_device1() kernel {
gpu.return
Expand Down
1 change: 1 addition & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class MPFRNumber {

int d = mpz_tstbit(integer, 0);
mpfr_set_si(result.value, d ? -1 : 1, mpfr_rounding);
mpz_clear(integer);
return result;
}

Expand Down
15 changes: 12 additions & 3 deletions libclc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,21 +321,30 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )
message( STATUS " device: ${d} ( ${${d}_aliases} )" )

if ( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
set( build_flags -O0 -finline-hint-functions )
set( build_flags -O0 -finline-hint-functions -DCLC_SPIRV )
set( opt_flags )
set( spvflags --spirv-max-version=1.1 )
set( MACRO_ARCH SPIRV32 )
if( ARCH STREQUAL spirv64 )
set( MACRO_ARCH SPIRV64 )
endif()
elseif( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 )
set( build_flags "-Wno-unknown-assumption")
set( build_flags "-Wno-unknown-assumption" -DCLC_CLSPV )
set( opt_flags -O3 )
set( MACRO_ARCH CLSPV32 )
if( ARCH STREQUAL clspv64 )
set( MACRO_ARCH CLSPV64 )
endif()
else()
set( build_flags )
set( opt_flags -O3 )
set( MACRO_ARCH ${ARCH} )
endif()

set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )

string( TOUPPER "CLC_${ARCH}" CLC_TARGET_DEFINE )
string( TOUPPER "CLC_${MACRO_ARCH}" CLC_TARGET_DEFINE )

list( APPEND build_flags
-D__CLC_INTERNAL
Expand Down
4 changes: 2 additions & 2 deletions libclc/clc/include/clc/clcfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

// avoid inlines for SPIR-V related targets since we'll optimise later in the
// chain
#if defined(CLC_SPIRV) || defined(CLC_SPIRV64)
#if defined(CLC_SPIRV)
#define _CLC_DEF
#elif defined(CLC_CLSPV) || defined(CLC_CLSPV64)
#elif defined(CLC_CLSPV)
#define _CLC_DEF __attribute__((noinline)) __attribute__((clspv_libclc_builtin))
#else
#define _CLC_DEF __attribute__((always_inline))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//These 2 defines only change when switching between data sizes or base types to
//keep this file manageable.
// These 2 defines only change when switching between data sizes or base types
// to keep this file manageable.
#define __CLC_GENSIZE 8
#define __CLC_SCALAR_GENTYPE char

Expand Down
File renamed without changes.
15 changes: 15 additions & 0 deletions libclc/clc/include/clc/shared/clc_clamp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#if defined(CLC_CLSPV) || defined(CLC_SPIRV)
// clspv and spir-v targets provide their own OpenCL-compatible clamp
#define __clc_clamp clamp
#else

#include <clc/clcfunc.h>
#include <clc/clctypes.h>

#define __CLC_BODY <clc/shared/clc_clamp.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc/shared/clc_clamp.inc>
#include <clc/math/gentype.inc>

#endif
9 changes: 9 additions & 0 deletions libclc/clc/include/clc/shared/clc_clamp.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_clamp(__CLC_GENTYPE x,
__CLC_GENTYPE y,
__CLC_GENTYPE z);

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_clamp(__CLC_GENTYPE x,
__CLC_SCALAR_GENTYPE y,
__CLC_SCALAR_GENTYPE z);
#endif
12 changes: 12 additions & 0 deletions libclc/clc/include/clc/shared/clc_max.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#if defined(CLC_CLSPV) || defined(CLC_SPIRV)
// clspv and spir-v targets provide their own OpenCL-compatible max
#define __clc_max max
#else

#define __CLC_BODY <clc/shared/clc_max.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc/shared/clc_max.inc>
#include <clc/math/gentype.inc>

#endif
7 changes: 7 additions & 0 deletions libclc/clc/include/clc/shared/clc_max.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_max(__CLC_GENTYPE a,
__CLC_GENTYPE b);

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_max(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b);
#endif
12 changes: 12 additions & 0 deletions libclc/clc/include/clc/shared/clc_min.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#if defined(CLC_CLSPV) || defined(CLC_SPIRV)
// clspv and spir-v targets provide their own OpenCL-compatible min
#define __clc_min min
#else

#define __CLC_BODY <clc/shared/clc_min.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc/shared/clc_min.inc>
#include <clc/math/gentype.inc>

#endif
7 changes: 7 additions & 0 deletions libclc/clc/include/clc/shared/clc_min.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_min(__CLC_GENTYPE a,
__CLC_GENTYPE b);

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_min(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b);
#endif
3 changes: 3 additions & 0 deletions libclc/clc/lib/generic/SOURCES
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
geometric/clc_dot.cl
shared/clc_clamp.cl
shared/clc_max.cl
shared/clc_min.cl
7 changes: 7 additions & 0 deletions libclc/clc/lib/generic/shared/clc_clamp.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <clc/internal/clc.h>

#define __CLC_BODY <clc_clamp.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc_clamp.inc>
#include <clc/math/gentype.inc>
14 changes: 14 additions & 0 deletions libclc/clc/lib/generic/shared/clc_clamp.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_clamp(__CLC_GENTYPE x,
__CLC_GENTYPE y,
__CLC_GENTYPE z) {
return (x > z ? z : (x < y ? y : x));
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_clamp(__CLC_GENTYPE x,
__CLC_SCALAR_GENTYPE y,
__CLC_SCALAR_GENTYPE z) {
return (x > (__CLC_GENTYPE)z ? (__CLC_GENTYPE)z
: (x < (__CLC_GENTYPE)y ? (__CLC_GENTYPE)y : x));
}
#endif
7 changes: 7 additions & 0 deletions libclc/clc/lib/generic/shared/clc_max.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <clc/internal/clc.h>

#define __CLC_BODY <clc_max.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc_max.inc>
#include <clc/math/gentype.inc>
11 changes: 11 additions & 0 deletions libclc/clc/lib/generic/shared/clc_max.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_max(__CLC_GENTYPE a,
__CLC_GENTYPE b) {
return (a > b ? a : b);
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_max(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b) {
return (a > (__CLC_GENTYPE)b ? a : (__CLC_GENTYPE)b);
}
#endif
7 changes: 7 additions & 0 deletions libclc/clc/lib/generic/shared/clc_min.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <clc/internal/clc.h>

#define __CLC_BODY <clc_min.inc>
#include <clc/integer/gentype.inc>

#define __CLC_BODY <clc_min.inc>
#include <clc/math/gentype.inc>
11 changes: 11 additions & 0 deletions libclc/clc/lib/generic/shared/clc_min.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_min(__CLC_GENTYPE a,
__CLC_GENTYPE b) {
return (b < a ? b : a);
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_min(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b) {
return (b < (__CLC_GENTYPE)a ? (__CLC_GENTYPE)b : a);
}
#endif
2 changes: 2 additions & 0 deletions libclc/generic/include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* THE SOFTWARE.
*/

#include <clc/clcfunc.h>

_CLC_DECL bool __clc_subnormals_disabled();
_CLC_DECL bool __clc_fp16_subnormals_supported();
_CLC_DECL bool __clc_fp32_subnormals_supported();
Expand Down
2 changes: 1 addition & 1 deletion libclc/generic/lib/common/smoothstep.cl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ SMOOTH_STEP_DEF(double, double, SMOOTH_STEP_IMPL_D);

_CLC_TERNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, smoothstep, double, double, double);

#if !defined(CLC_SPIRV) && !defined(CLC_SPIRV64)
#if !defined(CLC_SPIRV)
SMOOTH_STEP_DEF(float, double, SMOOTH_STEP_IMPL_D);
SMOOTH_STEP_DEF(double, float, SMOOTH_STEP_IMPL_D);

Expand Down
2 changes: 1 addition & 1 deletion libclc/generic/lib/common/step.cl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ STEP_DEF(double, double);
_CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, step, double, double);
_CLC_V_S_V_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, step, double, double);

#if !defined(CLC_SPIRV) && !defined(CLC_SPIRV64)
#if !defined(CLC_SPIRV)
STEP_DEF(float, double);
STEP_DEF(double, float);

Expand Down
4 changes: 3 additions & 1 deletion libclc/generic/lib/math/clc_hypot.cl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

#include <clc/clc.h>
#include <clc/shared/clc_clamp.h>
#include <math/clc_hypot.h>

#include "config.h"
Expand All @@ -39,7 +40,8 @@ _CLC_DEF _CLC_OVERLOAD float __clc_hypot(float x, float y) {
ux = c ? aux : auy;
uy = c ? auy : aux;

int xexp = clamp((int)(ux >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32, -126, 126);
int xexp =
__clc_clamp((int)(ux >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32, -126, 126);
float fx_exp = as_float((xexp + EXPBIAS_SP32) << EXPSHIFTBITS_SP32);
float fi_exp = as_float((-xexp + EXPBIAS_SP32) << EXPSHIFTBITS_SP32);
float fx = as_float(ux) * fi_exp;
Expand Down
9 changes: 5 additions & 4 deletions libclc/generic/lib/math/clc_ldexp.cl
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
* THE SOFTWARE.
*/

#include <clc/clc.h>
#include "config.h"
#include "../clcmacro.h"
#include "config.h"
#include "math.h"
#include <clc/clc.h>
#include <clc/shared/clc_clamp.h>

_CLC_DEF _CLC_OVERLOAD float __clc_ldexp(float x, int n) {

Expand All @@ -35,7 +36,7 @@ _CLC_DEF _CLC_OVERLOAD float __clc_ldexp(float x, int n) {
int m = i & 0x007fffff;
int s = i & 0x80000000;
int v = add_sat(e, n);
v = clamp(v, 0, 0xff);
v = __clc_clamp(v, 0, 0xff);
int mr = e == 0 | v == 0 | v == 0xff ? 0 : m;
int c = e == 0xff;
mr = c ? m : mr;
Expand Down Expand Up @@ -110,7 +111,7 @@ _CLC_DEF _CLC_OVERLOAD double __clc_ldexp(double x, int n) {
ux = c ? ux : l;

int v = e + n;
v = clamp(v, -0x7ff, 0x7ff);
v = __clc_clamp(v, -0x7ff, 0x7ff);

ux &= ~EXPBITS_DP64;

Expand Down
2 changes: 1 addition & 1 deletion libclc/generic/lib/math/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

#if (defined __AMDGCN__ || defined __R600__) && !defined __HAS_FMAF__
#define HAVE_HW_FMA32() (0)
#elif defined CLC_SPIRV || defined CLC_SPIRV64
#elif defined(CLC_SPIRV)
bool __attribute__((noinline)) __clc_runtime_has_hw_fma32(void);
#define HAVE_HW_FMA32() __clc_runtime_has_hw_fma32()
#else
Expand Down
1 change: 1 addition & 0 deletions libclc/generic/lib/shared/clamp.cl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <clc/clc.h>
#include <clc/shared/clc_clamp.h>

#define __CLC_BODY <clamp.inc>
#include <clc/integer/gentype.inc>
Expand Down
4 changes: 2 additions & 2 deletions libclc/generic/lib/shared/clamp.inc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE clamp(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_GENTYPE z) {
return (x > z ? z : (x < y ? y : x));
return __clc_clamp(x, y, z);
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE clamp(__CLC_GENTYPE x, __CLC_SCALAR_GENTYPE y, __CLC_SCALAR_GENTYPE z) {
return (x > (__CLC_GENTYPE)z ? (__CLC_GENTYPE)z : (x < (__CLC_GENTYPE)y ? (__CLC_GENTYPE)y : x));
return __clc_clamp(x, y, z);
}
#endif
1 change: 1 addition & 0 deletions libclc/generic/lib/shared/max.cl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <clc/clc.h>
#include <clc/shared/clc_max.h>

#define __CLC_BODY <max.inc>
#include <clc/integer/gentype.inc>
Expand Down
7 changes: 4 additions & 3 deletions libclc/generic/lib/shared/max.inc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE max(__CLC_GENTYPE a, __CLC_GENTYPE b) {
return (a > b ? a : b);
return __clc_max(a, b);
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE max(__CLC_GENTYPE a, __CLC_SCALAR_GENTYPE b) {
return (a > (__CLC_GENTYPE)b ? a : (__CLC_GENTYPE)b);
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE max(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b) {
return __clc_max(a, b);
}
#endif
1 change: 1 addition & 0 deletions libclc/generic/lib/shared/min.cl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <clc/clc.h>
#include <clc/shared/clc_min.h>

#define __CLC_BODY <min.inc>
#include <clc/integer/gentype.inc>
Expand Down
7 changes: 4 additions & 3 deletions libclc/generic/lib/shared/min.inc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE min(__CLC_GENTYPE a, __CLC_GENTYPE b) {
return (b < a ? b : a);
return __clc_min(a, b);
}

#ifndef __CLC_SCALAR
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE min(__CLC_GENTYPE a, __CLC_SCALAR_GENTYPE b) {
return (b < (__CLC_GENTYPE)a ? (__CLC_GENTYPE)b : a);
_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE min(__CLC_GENTYPE a,
__CLC_SCALAR_GENTYPE b) {
return __clc_min(a, b);
}
#endif
1 change: 1 addition & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <__configuration/abi.h>
#include <__configuration/availability.h>
#include <__configuration/compiler.h>
#include <__configuration/language.h>
#include <__configuration/platform.h>

#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
Expand Down
2 changes: 1 addition & 1 deletion libcxxabi/src/demangle/cp-to-llvm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
exit 1
fi

read -p "This will overwrite the copies of $FILES in $LLVM_DEMANGLE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
echo

if [[ $ANSWER =~ ^[Yy]$ ]]; then
Expand Down
37 changes: 29 additions & 8 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
case OPT_entry:
if (!arg->getValue()[0])
fatal("missing entry point symbol name");
ctx.config.entry = addUndefined(mangle(arg->getValue()));
ctx.config.entry = addUndefined(mangle(arg->getValue()), true);
break;
case OPT_failifmismatch:
checkFailIfMismatch(arg->getValue(), file);
Expand Down Expand Up @@ -696,12 +696,33 @@ void LinkerDriver::addLibSearchPaths() {
}
}

Symbol *LinkerDriver::addUndefined(StringRef name) {
Symbol *LinkerDriver::addUndefined(StringRef name, bool aliasEC) {
Symbol *b = ctx.symtab.addUndefined(name);
if (!b->isGCRoot) {
b->isGCRoot = true;
ctx.config.gcroot.push_back(b);
}

// On ARM64EC, a symbol may be defined in either its mangled or demangled form
// (or both). Define an anti-dependency symbol that binds both forms, similar
// to how compiler-generated code references external functions.
if (aliasEC && isArm64EC(ctx.config.machine)) {
if (std::optional<std::string> mangledName =
getArm64ECMangledFunctionName(name)) {
auto u = dyn_cast<Undefined>(b);
if (u && !u->weakAlias) {
Symbol *t = ctx.symtab.addUndefined(saver().save(*mangledName));
u->setWeakAlias(t, true);
}
} else {
std::optional<std::string> demangledName =
getArm64ECDemangledFunctionName(name);
Symbol *us = ctx.symtab.addUndefined(saver().save(*demangledName));
auto u = dyn_cast<Undefined>(us);
if (u && !u->weakAlias)
u->setWeakAlias(b, true);
}
}
return b;
}

Expand Down Expand Up @@ -2342,22 +2363,22 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (auto *arg = args.getLastArg(OPT_entry)) {
if (!arg->getValue()[0])
fatal("missing entry point symbol name");
config->entry = addUndefined(mangle(arg->getValue()));
config->entry = addUndefined(mangle(arg->getValue()), true);
} else if (!config->entry && !config->noEntry) {
if (args.hasArg(OPT_dll)) {
StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
config->entry = addUndefined(s);
config->entry = addUndefined(s, true);
} else if (config->driverWdm) {
// /driver:wdm implies /entry:_NtProcessStartup
config->entry = addUndefined(mangle("_NtProcessStartup"));
config->entry = addUndefined(mangle("_NtProcessStartup"), true);
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
StringRef s = findDefaultEntry();
if (s.empty())
fatal("entry point must be defined");
config->entry = addUndefined(s);
config->entry = addUndefined(s, true);
log("Entry name inferred: " + s);
}
}
Expand All @@ -2371,7 +2392,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
if (config->machine == I386) {
config->delayLoadHelper = addUndefined("___delayLoadHelper2@8");
} else {
config->delayLoadHelper = addUndefined("__delayLoadHelper2");
config->delayLoadHelper = addUndefined("__delayLoadHelper2", true);
}
}
}
Expand Down Expand Up @@ -2505,7 +2526,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (Export &e : config->exports) {
if (!e.forwardTo.empty())
continue;
e.sym = addUndefined(e.name);
e.sym = addUndefined(e.name, !e.data);
if (e.source != ExportSource::Directives)
e.symbolName = mangleMaybe(e.sym);
}
Expand Down
2 changes: 1 addition & 1 deletion lld/COFF/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class LinkerDriver {

std::set<std::string> visitedLibs;

Symbol *addUndefined(StringRef sym);
Symbol *addUndefined(StringRef sym, bool aliasEC = false);

void addUndefinedGlob(StringRef arg);

Expand Down
50 changes: 38 additions & 12 deletions lld/test/COFF/arm64ec-delayimport.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ REQUIRES: aarch64, x86
RUN: split-file %s %t.dir && cd %t.dir

RUN: llvm-mc -filetype=obj -triple=arm64ec-windows test.s -o test.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows helper-mangled.s -o helper-mangled.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows helper-demangled.s -o helper-demangled.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj
RUN: llvm-lib -machine:arm64ec -def:test.def -out:test-arm64ec.lib
RUN: llvm-lib -machine:arm64ec -def:test2.def -out:test2-arm64ec.lib

RUN: lld-link -machine:arm64ec -dll -noentry -out:out.dll loadconfig-arm64ec.obj test.obj \
RUN: test-arm64ec.lib test2-arm64ec.lib -delayload:test.dll -map
RUN: helper-mangled.obj test-arm64ec.lib test2-arm64ec.lib -delayload:test.dll -map

RUN: llvm-readobj --hex-dump=.test out.dll | FileCheck --check-prefix=TESTSEC %s
TESTSEC: 0x180008000 00600000 88700000 00200000 10100000
Expand Down Expand Up @@ -97,7 +99,7 @@ IMPORTS-NEXT: }
IMPORTS-NEXT: }

RUN: FileCheck --check-prefix=MAP %s < out.map
MAP: 0001:00000008 #__delayLoadHelper2 0000000180001008 test.obj
MAP: 0001:00000008 #__delayLoadHelper2 0000000180001008 helper-mangled.obj
MAP: 0001:00000010 #func 0000000180001010 test-arm64ec:test.dll
MAP-NEXT: 0001:0000001c __impchk_func 000000018000101c test-arm64ec:test.dll
MAP-NEXT: 0001:00000030 #func2 0000000180001030 test-arm64ec:test.dll
Expand Down Expand Up @@ -138,6 +140,21 @@ RELOC-NEXT: Type: DIR64
RELOC-NEXT: Address: 0x6008
RELOC-NEXT: }

Verify that a demangled version of __delayLoadHelper2 can be used.

RUN: lld-link -machine:arm64ec -dll -noentry -out:out2.dll loadconfig-arm64ec.obj test.obj \
RUN: helper-demangled.obj test-arm64ec.lib test2-arm64ec.lib -delayload:test.dll
RUN: llvm-objdump -d out2.dll | FileCheck --check-prefix=DISASM %s

Verify that the mangled version of __delayLoadHelper2 can be used from a library.
Even if an anti-dependency alias is defined by the helper, it won't appear in
the archive index, so we need to locate it by its mangled name.

RUN: llvm-lib -machine:arm64ec -out:helper.lib helper-mangled.obj
RUN: lld-link -machine:arm64ec -dll -noentry -out:out3.dll loadconfig-arm64ec.obj test.obj \
RUN: helper.lib test-arm64ec.lib test2-arm64ec.lib -delayload:test.dll
RUN: llvm-objdump -d out3.dll | FileCheck --check-prefix=DISASM %s

#--- test.s
.section .test,"r"
.rva __imp_func
Expand All @@ -159,16 +176,6 @@ __icall_helper_arm64ec:
mov w0, #0
ret

.section .text,"xr",discard,"#__delayLoadHelper2"
.globl "#__delayLoadHelper2"
.p2align 2, 0x0
"#__delayLoadHelper2":
mov w0, #1
ret

.weak_anti_dep __delayLoadHelper2
.set __delayLoadHelper2,"#__delayLoadHelper2"

.section .hybmp$x, "yi"
.symidx __imp_func
.symidx func_exit_thunk
Expand All @@ -189,6 +196,25 @@ func2_exit_thunk:
mov w0, #3
ret

#--- helper-mangled.s
.section .text,"xr",discard,"#__delayLoadHelper2"
.globl "#__delayLoadHelper2"
.p2align 2, 0x0
"#__delayLoadHelper2":
mov w0, #1
ret

.weak_anti_dep __delayLoadHelper2
.set __delayLoadHelper2,"#__delayLoadHelper2"

#--- helper-demangled.s
.section .text,"xr",discard,__delayLoadHelper2
.globl __delayLoadHelper2
.p2align 2, 0x0
__delayLoadHelper2:
mov w0, #1
ret

#--- test.def
NAME test.dll
EXPORTS
Expand Down
129 changes: 129 additions & 0 deletions lld/test/COFF/arm64ec-entry-mangle.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
REQUIRES: aarch64, x86
RUN: split-file %s %t.dir && cd %t.dir

RUN: llvm-mc -filetype=obj -triple=arm64ec-windows demangled-dll-main.s -o demangled-dll-main.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows mangled-dll-main.s -o mangled-dll-main.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows demangled-func.s -o demangled-func.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows mangled-func.s -o mangled-func.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ref-demangled.s -o ref-demangled.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows demangled-entry-drectve.s -o demangled-entry-drectve.obj
RUN: llvm-mc -filetype=obj -triple=x86_64-windows demangled-dll-main.s -o x64-dll-main.obj
RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj

RUN: llvm-lib -machine:arm64ec -out:func.lib mangled-func.obj
RUN: llvm-lib -machine:arm64ec -out:dllmain.lib mangled-dll-main.obj

Ensure that the linker recognizes the demangled version of _DllMainCRTStartup.
RUN: lld-link -machine:arm64ec -dll -out:demangled-main.dll demangled-dll-main.obj loadconfig-arm64ec.obj
RUN: llvm-objdump -d demangled-main.dll | FileCheck -check-prefix=DISASM %s

DISASM: 0000000180001000 <.text>:
DISASM-NEXT: 180001000: d65f03c0 ret
DISASM-EMPTY:
DISASM-NEXT: Disassembly of section .hexpthk:
DISASM-EMPTY:
DISASM: 180002000: 48 8b c4 movq %rsp, %rax
DISASM-NEXT: 180002003: 48 89 58 20 movq %rbx, 0x20(%rax)
DISASM-NEXT: 180002007: 55 pushq %rbp
DISASM-NEXT: 180002008: 5d popq %rbp
DISASM-NEXT: 180002009: e9 f2 ef ff ff jmp 0x180001000 <.text>
DISASM-NEXT: 18000200e: cc int3
DISASM-NEXT: 18000200f: cc int3

Ensure that the linker recognizes the mangled version of #_DllMainCRTStartup.
RUN: lld-link -machine:arm64ec -dll -out:mangled-dllmain.dll mangled-dll-main.obj loadconfig-arm64ec.obj
RUN: llvm-objdump -d mangled-dllmain.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled version of _DllMainCRTStartup from an archive.
RUN: lld-link -machine:arm64ec -dll -out:mangled-lib-dllmain.dll dllmain.lib loadconfig-arm64ec.obj
RUN: llvm-objdump -d mangled-lib-dllmain.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the demangled entry function.
RUN: lld-link -machine:arm64ec -dll -out:demangled-entry.dll demangled-func.obj loadconfig-arm64ec.obj -entry:func
RUN: llvm-objdump -d demangled-entry.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled entry function when it is referenced by its demangled name.
RUN: lld-link -machine:arm64ec -dll -out:mangled-entry.dll mangled-func.obj loadconfig-arm64ec.obj -entry:func
RUN: llvm-objdump -d mangled-entry.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled entry function when it is referenced by its demangled
name in drectve section.
RUN: lld-link -machine:arm64ec -dll -out:mangled-entry.dll mangled-func.obj loadconfig-arm64ec.obj demangled-entry-drectve.obj
RUN: llvm-objdump -d mangled-entry.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled entry function from an archive.
RUN: lld-link -machine:arm64ec -dll -out:mangled-lib-entry.dll func.lib loadconfig-arm64ec.obj -entry:func
RUN: llvm-objdump -d mangled-lib-entry.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the entry function when referenced by its mangled name.
RUN: lld-link -machine:arm64ec -dll -out:mangled-entry2.dll mangled-func.obj loadconfig-arm64ec.obj "-entry:#func"
RUN: llvm-objdump -d mangled-entry2.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the demangled exported function.
RUN: lld-link -machine:arm64ec -dll -out:demangled-export.dll demangled-func.obj \
RUN: loadconfig-arm64ec.obj -noentry -export:func
RUN: llvm-objdump -d demangled-export.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled exported function when referenced by its demangled name.
RUN: lld-link -machine:arm64ec -dll -out:mangled-export.dll mangled-func.obj \
RUN: loadconfig-arm64ec.obj -noentry -export:func
RUN: llvm-objdump -d mangled-export.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled exported function when referenced by its mangled name.
RUN: lld-link -machine:arm64ec -dll -out:mangled-export2.dll mangled-func.obj \
RUN: loadconfig-arm64ec.obj -noentry "-export:#func"
RUN: llvm-objdump -d mangled-export2.dll | FileCheck -check-prefix=DISASM %s

Verify that the linker recognizes the mangled exported function when referenced
by its mangled name and creates a demangled alias for it.
RUN: lld-link -machine:arm64ec -dll -noentry -out:demangled-export-ref.dll mangled-func.obj \
RUN: ref-demangled.obj loadconfig-arm64ec.obj "-export:#func"
RUN: llvm-objdump -d demangled-export-ref.dll | FileCheck -check-prefix=DISASM %s

DISASM2: 0000000180001000 <.text>:
DISASM2-NEXT: 180001000: d65f03c0 ret

Verify that the linker emits appropriate errors for mismatched mangling.
RUN: not lld-link -machine:arm64ec -dll -out:test.dll demangled-func.obj loadconfig-arm64ec.obj \
RUN: "-entry:#func" 2>&1 | FileCheck -check-prefix=FUNC-NOT-FOUND %s
RUN: not lld-link -machine:arm64ec -dll -out:test.dll demangled-func.obj loadconfig-arm64ec.obj \
RUN: -noentry "-export:#func" 2>&1 | FileCheck -check-prefix=FUNC-NOT-FOUND %s
FUNC-NOT-FOUND: undefined symbol: #func

Verify that the linker recognizes the demangled x86_64 _DllMainCRTStartup.
RUN: lld-link -machine:arm64ec -dll -out:test.dll x64-dll-main.obj loadconfig-arm64ec.obj
RUN: llvm-objdump -d test.dll | FileCheck -check-prefix=DISASM-X64 %s
DISASM-X64: 0000000180001000 <.text>:
DISASM-X64-NEXT: 180001000: c3 retq

#--- demangled-dll-main.s
.text
.globl _DllMainCRTStartup
_DllMainCRTStartup:
ret

#--- mangled-dll-main.s
.text
.globl "#_DllMainCRTStartup"
"#_DllMainCRTStartup":
ret

#--- demangled-func.s
.text
.globl func
func:
ret

#--- mangled-func.s
.text
.globl "#func"
"#func":
ret

#--- ref-demangled.s
.data
.rva func

#--- demangled-entry-drectve.s
.section .drectve,"rd"
.ascii " -entry:func"
16 changes: 16 additions & 0 deletions lldb/include/lldb/Symbol/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ FLAGS_ENUM(TypeQueryOptions){
/// matching type is found. When false, the type query should find all
/// matching types.
e_find_one = (1u << 4),
// If set, treat TypeQuery::m_name as a mangled name that should be
// searched.
e_search_by_mangled_name = (1u << 5),
};
LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions)

Expand Down Expand Up @@ -300,6 +303,19 @@ class TypeQuery {
m_options &= ~e_find_one;
}

/// Returns true if the type query is supposed to treat the name to be
/// searched as a mangled name.
bool GetSearchByMangledName() const {
return (m_options & e_search_by_mangled_name) != 0;
}

void SetSearchByMangledName(bool b) {
if (b)
m_options |= e_search_by_mangled_name;
else
m_options &= ~e_search_by_mangled_name;
}

/// Access the internal compiler context array.
///
/// Clients can use this to populate the context manually.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {
}

static bool python_is_finalizing() {
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 13) || (PY_MAJOR_VERSION > 3)
#if PY_VERSION_HEX >= 0x030d0000
return Py_IsFinalizing();
#elif PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7
return _Py_Finalizing != nullptr;
#else
#elif PY_VERSION_HEX >= 0x03070000
return _Py_IsFinalizing();
#else
return _Py_Finalizing != nullptr;
#endif
}

Expand Down Expand Up @@ -810,7 +810,7 @@ bool PythonCallable::Check(PyObject *py_obj) {
return PyCallable_Check(py_obj);
}

#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
#if PY_VERSION_HEX >= 0x03030000
static const char get_arg_info_script[] = R"(
from inspect import signature, Parameter, ismethod
from collections import namedtuple
Expand Down Expand Up @@ -839,7 +839,7 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
if (!IsValid())
return nullDeref();

#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
#if PY_VERSION_HEX >= 0x03030000

// no need to synchronize access to this global, we already have the GIL
static PythonScript get_arg_info(get_arg_info_script);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ extern "C" PyObject *PyInit__lldb(void);
#define LLDB_USE_PYTHON_SET_INTERRUPT 0
#else
// PyErr_SetInterrupt was introduced in 3.2.
#define LLDB_USE_PYTHON_SET_INTERRUPT \
(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2) || (PY_MAJOR_VERSION > 3)
#define LLDB_USE_PYTHON_SET_INTERRUPT PY_VERSION_HEX >= 0x03020000
#endif

static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) {
Expand All @@ -92,7 +91,7 @@ namespace {
struct InitializePythonRAII {
public:
InitializePythonRAII() {
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8) || (PY_MAJOR_VERSION > 3)
#if PY_VERSION_HEX >= 0x03080000
PyConfig config;
PyConfig_InitPythonConfig(&config);
#endif
Expand All @@ -109,7 +108,7 @@ struct InitializePythonRAII {
return spec.GetPath();
}();
if (!g_python_home.empty()) {
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8) || (PY_MAJOR_VERSION > 3)
#if PY_VERSION_HEX >= 0x03080000
PyConfig_SetBytesString(&config, &config.home, g_python_home.c_str());
#else
size_t size = 0;
Expand Down Expand Up @@ -143,7 +142,7 @@ struct InitializePythonRAII {
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
}

#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8) || (PY_MAJOR_VERSION > 3)
#if PY_VERSION_HEX >= 0x03080000
config.install_signal_handlers = 0;
Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
Expand All @@ -152,7 +151,7 @@ struct InitializePythonRAII {
// Python < 3.2 and Python >= 3.2 reversed the ordering requirements for
// calling `Py_Initialize` and `PyEval_InitThreads`. < 3.2 requires that you
// call `PyEval_InitThreads` first, and >= 3.2 requires that you call it last.
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2)
#if PY_VERSION_HEX >= 0x03020000
Py_InitializeEx(0);
InitializeThreadsPrivate();
#else
Expand Down Expand Up @@ -182,15 +181,15 @@ struct InitializePythonRAII {
// would always return `true` and `PyGILState_Ensure/Release` flow would be
// executed instead of unlocking GIL with `PyEval_SaveThread`. When
// an another thread calls `PyGILState_Ensure` it would get stuck in deadlock.
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 7) || (PY_MAJOR_VERSION > 3)
#if PY_VERSION_HEX >= 0x03070000
// The only case we should go further and acquire the GIL: it is unlocked.
if (PyGILState_Check())
return;
#endif

// `PyEval_ThreadsInitialized` was deprecated in Python 3.9 and removed in
// Python 3.13. It has been returning `true` always since Python 3.7.
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9) || (PY_MAJOR_VERSION < 3)
#if PY_VERSION_HEX < 0x03090000
if (PyEval_ThreadsInitialized()) {
#else
if (true) {
Expand All @@ -204,7 +203,7 @@ struct InitializePythonRAII {

// `PyEval_InitThreads` was deprecated in Python 3.9 and removed in
// Python 3.13.
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9) || (PY_MAJOR_VERSION < 3)
#if PY_VERSION_HEX < 0x03090000
return;
}

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ static llvm::Expected<bool> *g_fcxx_modules_workaround [[maybe_unused]];

// Include python for non windows machines
#include <Python.h>

// Provide a meaningful diagnostic error if someone tries to compile this file
// with a version of Python we don't support.
static_assert(PY_VERSION_HEX >= 0x03000000,
"LLDB requires at least Python 3.0");
#endif

#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H
4 changes: 2 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const {
return result;
}

const char *DWARFDIE::GetMangledName() const {
const char *DWARFDIE::GetMangledName(bool substitute_name_allowed) const {
if (IsValid())
return m_die->GetMangledName(m_cu);
return m_die->GetMangledName(m_cu, substitute_name_allowed);
else
return nullptr;
}
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class DWARFDIE : public DWARFBaseDIE {
// Accessors

// Accessing information about a DIE
const char *GetMangledName() const;
const char *GetMangledName(bool substitute_name_allowed = true) const;

const char *GetPubname() const;

Expand Down
14 changes: 14 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2758,6 +2758,20 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
return true; // Keep iterating over index types, language mismatch.
}

// Since mangled names are unique, we only need to check if the names are
// the same.
if (query.GetSearchByMangledName()) {
if (die.GetMangledName(/*substitute_name_allowed=*/false) !=
query.GetTypeBasename().GetStringRef())
return true; // Keep iterating over index types, mangled name mismatch.
if (Type *matching_type = ResolveType(die, true, true)) {
results.InsertUnique(matching_type->shared_from_this());
return !results.Done(query); // Keep iterating if we aren't done.
}
return true; // Keep iterating over index types, weren't able to resolve
// this type
}

// Check the context matches
std::vector<lldb_private::CompilerContext> die_context;
if (query.GetModuleSearch())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

import re

class LibCxxInternalsRecognizerTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True

@add_test_categories(["libc++"])
@skipIf(compiler="clang", compiler_version=["<", "16.0"])
def test_frame_recognizer(self):
"""Test that implementation details of libc++ are hidden"""
self.build()
Expand All @@ -21,7 +23,7 @@ def test_frame_recognizer(self):
# We never hide the frame of the entry-point into the standard library, even
# if the name starts with `__` which usually indicates an internal function.
"ranges_sort_less(int, int)": [
"ranges::__sort::operator()",
re.compile("ranges::__sort::(__fn::)?operator\(\)"),
"test_algorithms",
],
# `ranges::views::transform` internally uses `std::invoke`, and that
Expand Down Expand Up @@ -57,9 +59,14 @@ def test_frame_recognizer(self):
):
frame_id = frame_id + 1
# Expect the correct parent frame
self.assertIn(
expected_parent, thread.GetFrameAtIndex(frame_id).GetFunctionName()
)
func_name = thread.GetFrameAtIndex(frame_id).GetFunctionName()
if isinstance(expected_parent, re.Pattern):
self.assertTrue(
expected_parent.search(func_name) is not None,
f"'{expected_parent}' not found in '{func_name}'"
)
else:
self.assertIn(expected_parent, func_name)
frame_id = frame_id + 1
process.Continue()

Expand Down
6 changes: 0 additions & 6 deletions lldb/test/API/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,6 @@ def delete_module_cache(path):
if is_configured("lldb_framework_dir"):
dotest_cmd += ["--framework", config.lldb_framework_dir]

if (
"lldb-repro-capture" in config.available_features
or "lldb-repro-replay" in config.available_features
):
dotest_cmd += ["--skip-category=lldb-dap", "--skip-category=std-module"]

if "lldb-simulator-ios" in config.available_features:
dotest_cmd += ["--apple-sdk", "iphonesimulator", "--platform-name", "ios-simulator"]
elif "lldb-simulator-watchos" in config.available_features:
Expand Down
1 change: 0 additions & 1 deletion lldb/test/Shell/Driver/LocalLLDBInit.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# REQUIRES: python
# UNSUPPORTED: lldb-repro
#
# RUN: mkdir -p %t.root
# RUN: mkdir -p %t.home
Expand Down
2 changes: 0 additions & 2 deletions lldb/test/Shell/Driver/TestCore.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
# UNSUPPORTED: lldb-repro
#
# RUN: not %lldb -c /bogus/path 2>&1 | FileCheck %s
# CHECK: error: file specified in --core (-c) option doesn't exist
1 change: 0 additions & 1 deletion lldb/test/Shell/Driver/TestError.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
UNSUPPORTED: lldb-repro
RUN: not %lldb --arch 2>&1 | FileCheck %s
CHECK: error: argument to '--arch' is missing
2 changes: 0 additions & 2 deletions lldb/test/Shell/Driver/TestFile.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
# UNSUPPORTED: lldb-repro
#
# RUN: not %lldb -f /bogus/path 2>&1 | FileCheck %s
# CHECK: error: file specified in --file (-f) option doesn't exist
2 changes: 0 additions & 2 deletions lldb/test/Shell/Driver/TestHelp.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
UNSUPPORTED: lldb-repro

RUN: %lldb --help | FileCheck %s
RUN: cat %S/../../../docs/man/lldb.rst | FileCheck %s

Expand Down
2 changes: 0 additions & 2 deletions lldb/test/Shell/Driver/TestPositionalArgs.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
UNSUPPORTED: lldb-repro

RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t.foo

RUN: %lldb -x -b %t.foo bar baz quux | FileCheck %s
Expand Down
2 changes: 0 additions & 2 deletions lldb/test/Shell/Driver/TestRepl.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# UNSUPPORTED: lldb-repro
#
# RUN: echo ':quit' | %lldb -x --repl -O 'expr 42' -S %S/Inputs/Print2.in -o 'expr 999999' -s %s 2>&1 | FileCheck %s
# CHECK: {{w}}arning: commands specified to run after file load (via -o or -s) are ignored in REPL mode
# CHECK: (int) $0 = 42
Expand Down
1 change: 0 additions & 1 deletion lldb/test/Shell/Process/TestEnvironment.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
UNSUPPORTED: system-windows
UNSUPPORTED: lldb-repro

The double quotes around "BAR" ensure we don't match the command.

Expand Down
1 change: 0 additions & 1 deletion lldb/test/Shell/Quit/TestQuitExitCode-30.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# UNSUPPORTED: system-windows
# UNSUPPORTED: lldb-repro
# RUN: %python %S/expect_exit_code.py 226 %lldb -b -s %s
q -30
1 change: 0 additions & 1 deletion lldb/test/Shell/Quit/TestQuitExitCode30.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# UNSUPPORTED: system-windows
# UNSUPPORTED: lldb-repro
# RUN: %python %S/expect_exit_code.py 30 %lldb -b -s %s
q 30
1 change: 0 additions & 1 deletion lldb/test/Shell/Quit/TestQuitExitCodeHexA.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# UNSUPPORTED: system-windows
# UNSUPPORTED: lldb-repro
# RUN: %python %S/expect_exit_code.py 10 %lldb -b -s %s
q 0xA
1 change: 0 additions & 1 deletion lldb/test/Shell/Register/x86-64-read.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# UNSUPPORTED: lldb-repro
# XFAIL: system-windows
# REQUIRES: native && target-x86_64
# RUN: %clangxx_host %p/Inputs/x86-64-read.cpp -o %t
Expand Down
1 change: 0 additions & 1 deletion lldb/test/Shell/Register/x86-64-ymm-read.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# UNSUPPORTED: lldb-repro
# XFAIL: system-windows
# REQUIRES: native && target-x86_64 && native-cpu-avx
# RUN: %clangxx_host %p/Inputs/x86-ymm-read.cpp -o %t
Expand Down
1 change: 0 additions & 1 deletion lldb/test/Shell/Register/x86-multithread-write.test
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# XFAIL: system-windows
# REQUIRES: native && (target-x86 || target-x86_64)
# UNSUPPORTED: system-debugserver
# UNSUPPORTED: lldb-repro
# RUN: %clangxx_host %p/Inputs/x86-multithread-write.cpp -o %t -pthread
# RUN: %lldb -b -s %s %t | FileCheck %s

Expand Down
2 changes: 0 additions & 2 deletions lldb/test/Shell/ScriptInterpreter/Lua/bindings.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# UNSUPPORTED: lldb-repro
#
# RUN: cat %s | %lldb --script-language lua 2>&1 | FileCheck %s
script
debugger = lldb.SBDebugger.Create()
Expand Down
Loading