| 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; | ||
| } |
| 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 |
| 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 |
| 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; } |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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> |
| 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 |
| 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> |
| 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 |
| 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> |
| 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 |
| 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 __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 __clc_clamp(x, y, z); | ||
| } | ||
| #endif |
| 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 __clc_max(a, b); | ||
| } | ||
|
|
||
| #ifndef __CLC_SCALAR | ||
| _CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE max(__CLC_GENTYPE a, | ||
| __CLC_SCALAR_GENTYPE b) { | ||
| return __clc_max(a, b); | ||
| } | ||
| #endif |
| 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 __clc_min(a, b); | ||
| } | ||
|
|
||
| #ifndef __CLC_SCALAR | ||
| _CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE min(__CLC_GENTYPE a, | ||
| __CLC_SCALAR_GENTYPE b) { | ||
| return __clc_min(a, b); | ||
| } | ||
| #endif |
| 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" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| # REQUIRES: python | ||
| # | ||
| # RUN: mkdir -p %t.root | ||
| # RUN: mkdir -p %t.home | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,2 @@ | ||
| # RUN: not %lldb -c /bogus/path 2>&1 | FileCheck %s | ||
| # CHECK: error: file specified in --core (-c) option doesn't exist |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,2 @@ | ||
| RUN: not %lldb --arch 2>&1 | FileCheck %s | ||
| CHECK: error: argument to '--arch' is missing |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,2 @@ | ||
| # RUN: not %lldb -f /bogus/path 2>&1 | FileCheck %s | ||
| # CHECK: error: file specified in --file (-f) option doesn't exist |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,3 @@ | ||
| RUN: %lldb --help | FileCheck %s | ||
| RUN: cat %S/../../../docs/man/lldb.rst | FileCheck %s | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| UNSUPPORTED: system-windows | ||
|
|
||
| The double quotes around "BAR" ensure we don't match the command. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| # UNSUPPORTED: system-windows | ||
| # RUN: %python %S/expect_exit_code.py 226 %lldb -b -s %s | ||
| q -30 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| # UNSUPPORTED: system-windows | ||
| # RUN: %python %S/expect_exit_code.py 30 %lldb -b -s %s | ||
| q 30 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| # UNSUPPORTED: system-windows | ||
| # RUN: %python %S/expect_exit_code.py 10 %lldb -b -s %s | ||
| q 0xA |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,3 @@ | ||
| # RUN: cat %s | %lldb --script-language lua 2>&1 | FileCheck %s | ||
| script | ||
| debugger = lldb.SBDebugger.Create() | ||
|
|
||