10 changes: 7 additions & 3 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Clang-Tidy Checks
:doc:`bugprone-not-null-terminated-result <bugprone/not-null-terminated-result>`, "Yes"
:doc:`bugprone-optional-value-conversion <bugprone/optional-value-conversion>`, "Yes"
:doc:`bugprone-parent-virtual-call <bugprone/parent-virtual-call>`, "Yes"
:doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`bugprone-posix-return <bugprone/posix-return>`, "Yes"
:doc:`bugprone-redundant-branch-condition <bugprone/redundant-branch-condition>`, "Yes"
:doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
Expand Down Expand Up @@ -158,7 +159,6 @@ Clang-Tidy Checks
:doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes"
:doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
:doc:`bugprone-use-after-move <bugprone/use-after-move>`,
:doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
:doc:`cert-dcl50-cpp <cert/dcl50-cpp>`,
:doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
Expand Down Expand Up @@ -269,7 +269,7 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`,
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`, "Yes"
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
:doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
Expand Down Expand Up @@ -409,6 +409,7 @@ Check aliases
:doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`, :doc:`cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions>`,
:doc:`cert-con36-c <cert/con36-c>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
:doc:`cert-con54-cpp <cert/con54-cpp>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
:doc:`cert-ctr56-cpp <cert/ctr56-cpp>`, :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
:doc:`cert-dcl03-c <cert/dcl03-c>`, :doc:`misc-static-assert <misc/static-assert>`, "Yes"
:doc:`cert-dcl16-c <cert/dcl16-c>`, :doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
:doc:`cert-dcl37-c <cert/dcl37-c>`, :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
Expand Down Expand Up @@ -448,7 +449,7 @@ Check aliases
:doc:`clang-analyzer-core.uninitialized.UndefReturn <clang-analyzer/core.uninitialized.UndefReturn>`, `Clang Static Analyzer core.uninitialized.UndefReturn <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-undefreturn>`_,
:doc:`clang-analyzer-cplusplus.ArrayDelete <clang-analyzer/cplusplus.ArrayDelete>`, `Clang Static Analyzer cplusplus.ArrayDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete>`_,
:doc:`clang-analyzer-cplusplus.InnerPointer <clang-analyzer/cplusplus.InnerPointer>`, `Clang Static Analyzer cplusplus.InnerPointer <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-innerpointer>`_,
:doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, Clang Static Analyzer cplusplus.Move,
:doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, `Clang Static Analyzer cplusplus.Move <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-move>`_,
:doc:`clang-analyzer-cplusplus.NewDelete <clang-analyzer/cplusplus.NewDelete>`, `Clang Static Analyzer cplusplus.NewDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdelete>`_,
:doc:`clang-analyzer-cplusplus.NewDeleteLeaks <clang-analyzer/cplusplus.NewDeleteLeaks>`, `Clang Static Analyzer cplusplus.NewDeleteLeaks <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdeleteleaks>`_,
:doc:`clang-analyzer-cplusplus.PlacementNew <clang-analyzer/cplusplus.PlacementNew>`, `Clang Static Analyzer cplusplus.PlacementNew <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-placementnew>`_,
Expand All @@ -471,6 +472,7 @@ Check aliases
:doc:`clang-analyzer-optin.performance.GCDAntipattern <clang-analyzer/optin.performance.GCDAntipattern>`, `Clang Static Analyzer optin.performance.GCDAntipattern <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-gcdantipattern>`_,
:doc:`clang-analyzer-optin.performance.Padding <clang-analyzer/optin.performance.Padding>`, `Clang Static Analyzer optin.performance.Padding <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-padding>`_,
:doc:`clang-analyzer-optin.portability.UnixAPI <clang-analyzer/optin.portability.UnixAPI>`, `Clang Static Analyzer optin.portability.UnixAPI <https://clang.llvm.org/docs/analyzer/checkers.html#optin-portability-unixapi>`_,
:doc:`clang-analyzer-optin.taint.TaintedAlloc <clang-analyzer/optin.taint.TaintedAlloc>`, `Clang Static Analyzer optin.taint.TaintedAlloc <https://clang.llvm.org/docs/analyzer/checkers.html#optin-taint-taintedalloc>`_,
:doc:`clang-analyzer-osx.API <clang-analyzer/osx.API>`, `Clang Static Analyzer osx.API <https://clang.llvm.org/docs/analyzer/checkers.html#osx-api>`_,
:doc:`clang-analyzer-osx.MIG <clang-analyzer/osx.MIG>`, Clang Static Analyzer osx.MIG,
:doc:`clang-analyzer-osx.NumberObjectConversion <clang-analyzer/osx.NumberObjectConversion>`, `Clang Static Analyzer osx.NumberObjectConversion <https://clang.llvm.org/docs/analyzer/checkers.html#osx-numberobjectconversion>`_,
Expand Down Expand Up @@ -501,6 +503,7 @@ Check aliases
:doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds <clang-analyzer/osx.coreFoundation.containers.OutOfBounds>`, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-outofbounds>`_,
:doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues <clang-analyzer/osx.coreFoundation.containers.PointerSizedValues>`, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-pointersizedvalues>`_,
:doc:`clang-analyzer-security.FloatLoopCounter <clang-analyzer/security.FloatLoopCounter>`, `Clang Static Analyzer security.FloatLoopCounter <https://clang.llvm.org/docs/analyzer/checkers.html#security-floatloopcounter>`_,
:doc:`clang-analyzer-security.PutenvStackArray <clang-analyzer/security.PutenvStackArray>`, Clang Static Analyzer security.PutenvStackArray,
:doc:`clang-analyzer-security.SetgidSetuidOrder <clang-analyzer/security.SetgidSetuidOrder>`, Clang Static Analyzer security.SetgidSetuidOrder,
:doc:`clang-analyzer-security.cert.env.InvalidPtr <clang-analyzer/security.cert.env.InvalidPtr>`, `Clang Static Analyzer security.cert.env.InvalidPtr <https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_,
:doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling <clang-analyzer/security.insecureAPI.DeprecatedOrUnsafeBufferHandling>`, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling>`_,
Expand All @@ -517,6 +520,7 @@ Check aliases
:doc:`clang-analyzer-security.insecureAPI.strcpy <clang-analyzer/security.insecureAPI.strcpy>`, `Clang Static Analyzer security.insecureAPI.strcpy <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-strcpy>`_,
:doc:`clang-analyzer-security.insecureAPI.vfork <clang-analyzer/security.insecureAPI.vfork>`, `Clang Static Analyzer security.insecureAPI.vfork <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-vfork>`_,
:doc:`clang-analyzer-unix.API <clang-analyzer/unix.API>`, `Clang Static Analyzer unix.API <https://clang.llvm.org/docs/analyzer/checkers.html#unix-api>`_,
:doc:`clang-analyzer-unix.BlockInCriticalSection <clang-analyzer/unix.BlockInCriticalSection>`, `Clang Static Analyzer unix.BlockInCriticalSection <https://clang.llvm.org/docs/analyzer/checkers.html#unix-blockincriticalsection>`_,
:doc:`clang-analyzer-unix.Errno <clang-analyzer/unix.Errno>`, `Clang Static Analyzer unix.Errno <https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno>`_,
:doc:`clang-analyzer-unix.Malloc <clang-analyzer/unix.Malloc>`, `Clang Static Analyzer unix.Malloc <https://clang.llvm.org/docs/analyzer/checkers.html#unix-malloc>`_,
:doc:`clang-analyzer-unix.MallocSizeof <clang-analyzer/unix.MallocSizeof>`, `Clang Static Analyzer unix.MallocSizeof <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mallocsizeof>`_,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ void some_function(double np_arg0, wchar_t np_arg1) {
np_local6--;
}

int function_try_block() try {
int p_local0 = 0;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
// CHECK-FIXES: int const p_local0
return p_local0;
} catch (...) {
return 0;
}

void nested_scopes() {
int p_local0 = 2;
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: variable 'p_local0' of type 'int' can be declared 'const'
Expand Down
2 changes: 2 additions & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_USE_NEW_HEADER_GEN OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
Expand Down Expand Up @@ -385,6 +386,7 @@ foreach(target riscv32-unknown-elf)
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_USE_NEW_HEADER_GEN OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
Expand Down
74 changes: 74 additions & 0 deletions clang/docs/ClangNVLinkWrapper.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
====================
Clang nvlink Wrapper
====================

.. contents::
:local:

.. _clang-nvlink-wrapper:

Introduction
============

This tools works as a wrapper around the NVIDIA ``nvlink`` linker. The purpose
of this wrapper is to provide an interface similar to the ``ld.lld`` linker
while still relying on NVIDIA's proprietary linker to produce the final output.

``nvlink`` has a number of known quirks that make it difficult to use in a
unified offloading setting. For example, it does not accept ``.o`` files as they
must be named ``.cubin``. Static archives do not work, so passing a ``.a`` will
provide a linker error. ``nvlink`` also does not support link time optimization
and ignores many standard linker arguments. This tool works around these issues.

Usage
=====

This tool can be used with the following options. Any arguments not intended
only for the linker wrapper will be forwarded to ``nvlink``.

.. code-block:: console
OVERVIEW: A utility that wraps around the NVIDIA 'nvlink' linker.
This enables static linking and LTO handling for NVPTX targets.
USAGE: clang-nvlink-wrapper [options] <options to passed to nvlink>
OPTIONS:
--arch <value> Specify the 'sm_' name of the target architecture.
--cuda-path=<dir> Set the system CUDA path
--dry-run Print generated commands without running.
--feature <value> Specify the '+ptx' freature to use for LTO.
-g Specify that this was a debug compile.
-help-hidden Display all available options
-help Display available options (--help-hidden for more)
-L <dir> Add <dir> to the library search path
-l <libname> Search for library <libname>
-mllvm <arg> Arguments passed to LLVM, including Clang invocations,
for which the '-mllvm' prefix is preserved. Use '-mllvm
--help' for a list of options.
-o <path> Path to file to write output
--plugin-opt=jobs=<value>
Number of LTO codegen partitions
--plugin-opt=lto-partitions=<value>
Number of LTO codegen partitions
--plugin-opt=O<O0, O1, O2, or O3>
Optimization level for LTO
--plugin-opt=thinlto<value>
Enable the thin-lto backend
--plugin-opt=<value> Arguments passed to LLVM, including Clang invocations,
for which the '-mllvm' prefix is preserved. Use '-mllvm
--help' for a list of options.
--save-temps Save intermediate results
--version Display the version number and exit
-v Print verbose information
Example
=======

This tool is intended to be invoked when targeting the NVPTX toolchain directly
as a cross-compiling target. This can be used to create standalone GPU
executables with normal linking semantics similar to standard compilation.

.. code-block:: console
clang --target=nvptx64-nvidia-cuda -march=native -flto=full input.c
5 changes: 2 additions & 3 deletions clang/docs/HLSL/AvailabilityDiagnostics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ If the compilation target is a shader library, only availability based on shader

As a result, availability based on specific shader stage will only be diagnosed in code that is reachable from a shader entry point or library export function. It also means that function bodies might be scanned multiple time. When that happens, care should be taken not to produce duplicated diagnostics.

========
Examples
========

Expand All @@ -62,7 +61,7 @@ For the example below, the ``WaveActiveCountBits`` API function became available
The availability of ``ddx`` function depends on a shader stage. It is available for pixel shaders in shader model 2.1 and higher, for compute, mesh and amplification shaders in shader model 6.6 and higher. For any other shader stages it is not available.

Compute shader example
======================
----------------------

.. code-block:: c++

Expand Down Expand Up @@ -94,7 +93,7 @@ With strict diagnostic mode, in addition to the 2 errors above Clang will also e
<>:7:13: error: 'WaveActiveCountBits' is only available on Shader Model 6.5 or newer
Shader library example
======================
----------------------

.. code-block:: c++

Expand Down
2 changes: 1 addition & 1 deletion clang/docs/HLSL/ExpectedDifferences.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

===================================
Expected Differences vs DXC and FXC
===================================

Expand Down
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,11 @@ AIX Support
This access sequence is not used for TLS variables larger than 32KB, and is
currently only supported on 64-bit mode.

NetBSD Support
^^^^^^^^^^^^^^

- Removed support for building NetBSD/i386 6.x or older binaries.

WebAssembly Support
^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Using Clang Tools
ClangFormatStyleOptions
ClangFormattedStatus
ClangLinkerWrapper
ClangNVLinkWrapper
ClangOffloadBundler
ClangOffloadPackager
ClangRepl
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);

/// Return the "other" type-specific discriminator for the given type.
uint16_t getPointerAuthTypeDiscriminator(QualType T) const;
uint16_t getPointerAuthTypeDiscriminator(QualType T);

/// Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,9 @@ def warn_pragma_intrinsic_builtin : Warning<
def warn_pragma_unused_expected_var : Warning<
"expected '#pragma unused' argument to be a variable name">,
InGroup<IgnoredPragmas>;
// - #pragma mc_func
def err_pragma_mc_func_not_supported :
Error<"#pragma mc_func is not supported">;
// - #pragma init_seg
def warn_pragma_init_seg_unsupported_target : Warning<
"'#pragma init_seg' is only supported when targeting a "
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,9 @@ def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
def note_ptrauth_virtual_function_incomplete_arg_ret_type :
Note<"%0 is incomplete">;

def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
"%select{subtraction|addition}0 of address-of-label expressions is not "
"supported with ptrauth indirect gotos">;

/// main()
// static main() is not an error in C, just in C++.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,11 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,11 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication")
LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
LANGOPT(PointerAuthIndirectGotos, 1, 0, "indirect gotos pointer authentication")
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
"Use type discrimination when signing function pointers")
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ namespace clang {

constexpr unsigned PointerAuthKeyNone = -1;

/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
/// The value is ptrauth_string_discriminator("_ZTVSt9type_info"), i.e.,
/// the vtable type discriminator for classes derived from std::type_info.
constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA;

class PointerAuthSchema {
public:
enum class Kind : unsigned {
Expand Down Expand Up @@ -154,6 +159,9 @@ class PointerAuthSchema {
};

struct PointerAuthOptions {
/// Do indirect goto label addresses need to be authenticated?
bool IndirectGotos = false;

/// The ABI for C function pointers.
PointerAuthSchema FunctionPointers;

Expand All @@ -175,6 +183,9 @@ struct PointerAuthOptions {

/// The ABI for variadic C++ virtual function pointers.
PointerAuthSchema CXXVirtualVariadicFunctionPointers;

/// The ABI for C++ member function pointers.
PointerAuthSchema CXXMemberFunctionPointers;
};

} // end namespace clang
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4249,9 +4249,13 @@ defm ptrauth_vtable_pointer_address_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">;
defm ptrauth_vtable_pointer_type_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
defm ptrauth_type_info_vtable_pointer_discrimination :
OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
"Enable type discrimination on C function pointers">;
defm ptrauth_indirect_gotos : OptInCC1FFlag<"ptrauth-indirect-gotos",
"Enable signing and authentication of indirect goto targets">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down Expand Up @@ -8082,6 +8086,13 @@ def source_date_epoch : Separate<["-"], "source-date-epoch">,

} // let Visibility = [CC1Option]

defm err_pragma_mc_func_aix : BoolFOption<"err-pragma-mc-func-aix",
PreprocessorOpts<"ErrorOnPragmaMcfuncOnAIX">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Treat uses of #pragma mc_func as errors">,
NegFlag<SetFalse,[], [ClangOption, CC1Option],
"Ignore uses of #pragma mc_func">>;

//===----------------------------------------------------------------------===//
// CUDA Options
//===----------------------------------------------------------------------===//
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Lex/PreprocessorOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ class PreprocessorOptions {
/// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
std::optional<uint64_t> SourceDateEpoch;

/// If set, the preprocessor reports an error when processing #pragma mc_func
/// on AIX.
bool ErrorOnPragmaMcfuncOnAIX = false;

public:
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}

Expand Down Expand Up @@ -248,6 +252,7 @@ class PreprocessorOptions {
PrecompiledPreambleBytes.first = 0;
PrecompiledPreambleBytes.second = false;
RetainExcludedConditionalBlocks = false;
ErrorOnPragmaMcfuncOnAIX = false;
}
};

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
std::unique_ptr<PragmaHandler> MCFuncPragmaHandler;

std::unique_ptr<CommentHandler> CommentSemaHandler;

Expand Down
12 changes: 7 additions & 5 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3407,7 +3407,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
}
}

uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) const {
uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) {
assert(!T->isDependentType() &&
"cannot compute type discriminator of a dependent type");

Expand All @@ -3417,11 +3417,13 @@ uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) const {
if (T->isFunctionPointerType() || T->isFunctionReferenceType())
T = T->getPointeeType();

if (T->isFunctionType())
if (T->isFunctionType()) {
encodeTypeForFunctionPointerAuth(*this, Out, T);
else
llvm_unreachable(
"type discrimination of non-function type not implemented yet");
} else {
T = T.getUnqualifiedType();
std::unique_ptr<MangleContext> MC(createMangleContext());
MC->mangleCanonicalTypeName(T, Out);
}

return llvm::getPointerAuthStableSipHash(Str);
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ using namespace clang::interp;
/// Similar information is available via ASTContext::BuiltinInfo,
/// but that is not correct for our use cases.
static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
return BuiltinID == Builtin::BI__builtin_classify_type;
return BuiltinID == Builtin::BI__builtin_classify_type ||
BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size;
}

Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
}

static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D, unsigned FieldOffset) {
bool IsActive, const Descriptor *D, unsigned FieldOffset,
bool IsVirtualBase) {
assert(D);
assert(D->ElemRecord);

Expand All @@ -172,13 +173,14 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
Desc->Desc = D;
Desc->IsInitialized = D->IsArray;
Desc->IsBase = true;
Desc->IsVirtualBase = IsVirtualBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || D->IsConst;
Desc->IsFieldMutable = IsMutable || D->IsMutable;

for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
V.Offset);
V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion,
F.Desc, F.Offset);
Expand All @@ -187,11 +189,11 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D) {
for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset);
for (const auto &V : D->ElemRecord->virtual_bases())
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);
}

static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ struct InlineDescriptor {
/// Flag indicating if the field is an embedded base class.
LLVM_PREFERRED_TYPE(bool)
unsigned IsBase : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsVirtualBase : 1;
/// Flag indicating if the field is the active member of a union.
LLVM_PREFERRED_TYPE(bool)
unsigned IsActive : 1;
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ template <typename T>
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
if (RHS.isZero()) {
const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
if constexpr (std::is_same_v<T, Floating>) {
S.CCEDiag(Op, diag::note_expr_divide_by_zero)
<< Op->getRHS()->getSourceRange();
return true;
}

S.FFDiag(Op, diag::note_expr_divide_by_zero)
<< Op->getRHS()->getSourceRange();
if constexpr (!std::is_same_v<T, Floating>)
return false;
return false;
}

if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
Expand Down
22 changes: 17 additions & 5 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,18 +180,30 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
// TODO: figure out if base is virtual
bool IsVirtual = false;

// Create a path entry for the field.
const Descriptor *Desc = Ptr.getFieldDesc();
if (const auto *BaseOrMember = Desc->asDecl()) {
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
Ptr = Ptr.getBase();

if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
Ptr = Ptr.getBase();
Offset += getFieldOffset(FD);
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
IsVirtual = Ptr.isVirtualBaseClass();
Ptr = Ptr.getBase();
const Record *BaseRecord = Ptr.getRecord();

const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
cast<CXXRecordDecl>(BaseRecord->getDecl()));
if (IsVirtual)
Offset += Layout.getVBaseClassOffset(RD);
else
Offset += Layout.getBaseClassOffset(RD);

} else {
Ptr = Ptr.getBase();
}
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
continue;
}
llvm_unreachable("Invalid field type");
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ class Pointer {
}
/// Checks if a structure is a base class.
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
bool isVirtualBaseClass() const {
return isField() && getInlineDesc()->IsVirtualBase;
}
/// Checks if the pointer points to a dummy value.
bool isDummy() const {
if (!isBlockPointer())
Expand Down
23 changes: 22 additions & 1 deletion clang/lib/Basic/Targets/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,24 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,

// Define __loongarch_arch.
StringRef ArchName = getCPU();
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
if (ArchName == "loongarch64") {
if (HasFeatureLSX) {
// TODO: As more features of the V1.1 ISA are supported, a unified "v1.1"
// arch feature set will be used to include all sub-features belonging to
// the V1.1 ISA version.
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.1" + Twine('"'));
else
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.0" + Twine('"'));
} else {
Builder.defineMacro("__loongarch_arch",
Twine('"') + ArchName + Twine('"'));
}
} else {
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
}

// Define __loongarch_tune.
StringRef TuneCPU = getTargetOpts().TuneCPU;
Expand All @@ -216,6 +233,8 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__loongarch_simd_width", "128");
Builder.defineMacro("__loongarch_sx", Twine(1));
}
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_frecipe", Twine(1));

StringRef ABI = getABI();
if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
Expand Down Expand Up @@ -291,6 +310,8 @@ bool LoongArchTargetInfo::handleTargetFeatures(
HasFeatureLASX = true;
else if (Feature == "-ual")
HasUnalignedAccess = false;
else if (Feature == "+frecipe")
HasFeatureFrecipe = true;
}
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/LoongArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool HasFeatureF;
bool HasFeatureLSX;
bool HasFeatureLASX;
bool HasFeatureFrecipe;

public:
LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
Expand All @@ -37,6 +38,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
HasFeatureF = false;
HasFeatureLSX = false;
HasFeatureLASX = false;
HasFeatureFrecipe = false;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,15 +513,6 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
public:
NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}

LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
VersionTuple OsVersion = getTriple().getOSVersion();
// New NetBSD uses the default rounding mode.
if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0)
return X86_32TargetInfo::getFPEvalMethod();
// NetBSD before 6.99.26 defaults to "double" rounding.
return LangOptions::FPEvalMethodKind::FEM_Double;
}
};

class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo
Expand Down
213 changes: 115 additions & 98 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5034,7 +5034,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc) {
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.

assert(Callee.isOrdinary() || Callee.isVirtual());
Expand Down Expand Up @@ -5098,7 +5099,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
RawAddress SRetAlloca = RawAddress::invalid();
llvm::Value *UnusedReturnSizePtr = nullptr;
if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
if (!ReturnValue.isNull()) {
if (IsVirtualFunctionPointerThunk && RetAI.isIndirect()) {
SRetPtr = makeNaturalAddressForPointer(CurFn->arg_begin() +
IRFunctionArgs.getSRetArgNo(),
RetTy, CharUnits::fromQuantity(1));
} else if (!ReturnValue.isNull()) {
SRetPtr = ReturnValue.getAddress();
} else {
SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca);
Expand Down Expand Up @@ -5877,119 +5882,131 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CallArgs.freeArgumentMemory(*this);

// Extract the return value.
RValue Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());
RValue Ret;

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
// If the current function is a virtual function pointer thunk, avoid copying
// the return value of the musttail call to a temporary.
if (IsVirtualFunctionPointerThunk) {
Ret = RValue::get(CI);
} else {
Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
}
[[fallthrough]];
}
[[fallthrough]];
}

case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);
case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy &&
RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it.
// This can happen due to trivial type mismatches.
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
llvm_unreachable("bad evaluation kind");
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it. This
// can happen due to trivial type mismatches.

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() ==
ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero,
"cast.fixed");
return RValue::get(V);
}
}
}
llvm_unreachable("bad evaluation kind");
}

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() == ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero, "cast.fixed");
return RValue::get(V);
}
Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
}
}

Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
}

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

llvm_unreachable("Unhandled ABIArgInfo::Kind");
} ();
llvm_unreachable("Unhandled ABIArgInfo::Kind");
}();
}

// Emit the assume_aligned check on the return value.
if (Ret.isScalar() && TargetDecl) {
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/CodeGen/CGPointerAuth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,40 @@ llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
}

CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (!Schema)
return CGPointerAuthInfo();

assert(!Schema.isAddressDiscriminated() &&
"function pointers cannot use address-specific discrimination");

llvm::ConstantInt *Discriminator =
getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);
return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
/* IsIsaPointer */ false,
/* AuthenticatesNullValues */ false, Discriminator);
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT) {
if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
return getConstantSignedPointer(
Pointer, PointerAuth.getKey(), nullptr,
cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));

return Pointer;
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty) {
QualType FT = FD->getType();
FT = getContext().getMemberPointerType(
FT, cast<CXXMethodDecl>(FD)->getParent()->getTypeForDecl());
return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);
}

std::optional<PointerAuthQualifier>
CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
if (CodeGenOpts.PointerAuth.FunctionPointers)
Fn->addFnAttr("ptrauth-calls");
if (CodeGenOpts.PointerAuth.IndirectGotos)
Fn->addFnAttr("ptrauth-indirect-gotos");

// Apply xray attributes to the function (as a string, for now)
bool AlwaysXRayAttr = false;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4374,7 +4374,8 @@ class CodeGenFunction : public CodeGenTypeCache {
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc);
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk = false);
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke = nullptr,
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,16 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
QualType FunctionType);

llvm::Constant *getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty = nullptr);

llvm::Constant *getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT);

CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);

CGPointerAuthInfo getMemberFunctionPointerAuthInfo(QualType FT);

CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);

CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
Expand Down
254 changes: 242 additions & 12 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {

bool NeedsVTTParameter(GlobalDecl GD) override;

llvm::Constant *
getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD);

/**************************** RTTI Uniqueness ******************************/

protected:
Expand Down Expand Up @@ -426,6 +429,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
const CXXRecordDecl *RD) override;

private:
llvm::Constant *
getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD);

bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
const auto &VtableLayout =
CGM.getItaniumVTableContext().getVTableLayout(RD);
Expand Down Expand Up @@ -835,7 +841,25 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
CalleePtr->addIncoming(VirtualFn, FnVirtual);
CalleePtr->addIncoming(NonVirtualFn, FnNonVirtual);

CGCallee Callee(FPT, CalleePtr);
CGPointerAuthInfo PointerAuth;

if (const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers) {
llvm::PHINode *DiscriminatorPHI = Builder.CreatePHI(CGF.IntPtrTy, 2);
DiscriminatorPHI->addIncoming(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
FnVirtual);
const auto &AuthInfo =
CGM.getMemberFunctionPointerAuthInfo(QualType(MPT, 0));
assert(Schema.getKey() == AuthInfo.getKey() &&
"Keys for virtual and non-virtual member functions must match");
auto *NonVirtualDiscriminator = AuthInfo.getDiscriminator();
DiscriminatorPHI->addIncoming(NonVirtualDiscriminator, FnNonVirtual);
PointerAuth = CGPointerAuthInfo(
Schema.getKey(), Schema.getAuthenticationMode(), Schema.isIsaPointer(),
Schema.authenticatesNullValues(), DiscriminatorPHI);
}

CGCallee Callee(FPT, CalleePtr, PointerAuth);
return Callee;
}

Expand All @@ -853,6 +877,25 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
"memptr.offset");
}

// See if it's possible to return a constant signed pointer.
static llvm::Constant *pointerAuthResignConstant(
llvm::Value *Ptr, const CGPointerAuthInfo &CurAuthInfo,
const CGPointerAuthInfo &NewAuthInfo, CodeGenModule &CGM) {
const auto *CPA = dyn_cast<llvm::ConstantPtrAuth>(Ptr);

if (!CPA)
return nullptr;

assert(CPA->getKey()->getZExtValue() == CurAuthInfo.getKey() &&
CPA->getAddrDiscriminator()->isZeroValue() &&
CPA->getDiscriminator() == CurAuthInfo.getDiscriminator() &&
"unexpected key or discriminators");

return CGM.getConstantSignedPointer(
CPA->getPointer(), NewAuthInfo.getKey(), nullptr,
cast<llvm::ConstantInt>(NewAuthInfo.getDiscriminator()));
}

/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
/// conversion.
///
Expand Down Expand Up @@ -880,21 +923,63 @@ llvm::Value *
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *src) {
// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

CGBuilderTy &Builder = CGF.Builder;
QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType()) {
if (const auto &NewAuthInfo =
CGM.getMemberFunctionPointerAuthInfo(DstType)) {
QualType SrcType = E->getSubExpr()->getType();
assert(SrcType->isMemberFunctionPointerType());
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
llvm::Type *OrigTy = MemFnPtr->getType();

llvm::BasicBlock *StartBB = Builder.GetInsertBlock();
llvm::BasicBlock *ResignBB = CGF.createBasicBlock("resign");
llvm::BasicBlock *MergeBB = CGF.createBasicBlock("merge");

// Check whether we have a virtual offset or a pointer to a function.
assert(UseARMMethodPtrABI && "ARM ABI expected");
llvm::Value *Adj = Builder.CreateExtractValue(src, 1, "memptr.adj");
llvm::Constant *Ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
llvm::Value *AndVal = Builder.CreateAnd(Adj, Ptrdiff_1);
llvm::Value *IsVirtualOffset =
Builder.CreateIsNotNull(AndVal, "is.virtual.offset");
Builder.CreateCondBr(IsVirtualOffset, MergeBB, ResignBB);

CGF.EmitBlock(ResignBB);
llvm::Type *PtrTy = llvm::PointerType::getUnqual(CGM.Int8Ty);
MemFnPtr = Builder.CreateIntToPtr(MemFnPtr, PtrTy);
MemFnPtr =
CGF.emitPointerAuthResign(MemFnPtr, SrcType, CurAuthInfo, NewAuthInfo,
isa<llvm::Constant>(src));
MemFnPtr = Builder.CreatePtrToInt(MemFnPtr, OrigTy);
llvm::Value *ResignedVal = Builder.CreateInsertValue(src, MemFnPtr, 0);
ResignBB = Builder.GetInsertBlock();

CGF.EmitBlock(MergeBB);
llvm::PHINode *NewSrc = Builder.CreatePHI(src->getType(), 2);
NewSrc->addIncoming(src, StartBB);
NewSrc->addIncoming(ResignedVal, ResignBB);
src = NewSrc;
}
}

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

llvm::Constant *adj = getMemberPointerAdjustment(E);
if (!adj) return src;

CGBuilderTy &Builder = CGF.Builder;
bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);

const MemberPointerType *destTy =
Expand Down Expand Up @@ -932,13 +1017,47 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
return Builder.CreateInsertValue(src, dstAdj, 1);
}

static llvm::Constant *
pointerAuthResignMemberFunctionPointer(llvm::Constant *Src, QualType DestType,
QualType SrcType, CodeGenModule &CGM) {
assert(DestType->isMemberFunctionPointerType() &&
SrcType->isMemberFunctionPointerType() &&
"member function pointers expected");
if (DestType == SrcType)
return Src;

const auto &NewAuthInfo = CGM.getMemberFunctionPointerAuthInfo(DestType);
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);

if (!NewAuthInfo && !CurAuthInfo)
return Src;

llvm::Constant *MemFnPtr = Src->getAggregateElement(0u);
if (MemFnPtr->getNumOperands() == 0) {
// src must be a pair of null pointers.
assert(isa<llvm::ConstantInt>(MemFnPtr) && "constant int expected");
return Src;
}

llvm::Constant *ConstPtr = pointerAuthResignConstant(
cast<llvm::User>(MemFnPtr)->getOperand(0), CurAuthInfo, NewAuthInfo, CGM);
ConstPtr = llvm::ConstantExpr::getPtrToInt(ConstPtr, MemFnPtr->getType());
return ConstantFoldInsertValueInstruction(Src, ConstPtr, 0);
}

llvm::Constant *
ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *src) {
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType())
src = pointerAuthResignMemberFunctionPointer(
src, DstType, E->getSubExpr()->getType(), CGM);

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

Expand Down Expand Up @@ -1036,9 +1155,32 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// least significant bit of adj then makes exactly the same
// discrimination as the least significant bit of ptr does for
// Itanium.
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
2 * ThisAdjustment.getQuantity() + 1);

// We cannot use the Itanium ABI's representation for virtual member
// function pointers under pointer authentication because it would
// require us to store both the virtual offset and the constant
// discriminator in the pointer, which would be immediately vulnerable
// to attack. Instead we introduce a thunk that does the virtual dispatch
// and store it as if it were a non-virtual member function. This means
// that virtual function pointers may not compare equal anymore, but
// fortunately they aren't required to by the standard, and we do make
// a best-effort attempt to re-use the thunk.
//
// To support interoperation with code in which pointer authentication
// is disabled, derefencing a member function pointer must still handle
// the virtual case, but it can use a discriminator which should never
// be valid.
const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (Schema)
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(
getSignedVirtualMemberFunctionPointer(MD), CGM.PtrDiffTy);
else
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
// Don't set the LSB of adj to 1 if pointer authentication for member
// function pointers is enabled.
MemPtr[1] = llvm::ConstantInt::get(
CGM.PtrDiffTy, 2 * ThisAdjustment.getQuantity() + !Schema);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
Expand All @@ -1060,7 +1202,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// function type is incomplete.
Ty = CGM.PtrDiffTy;
}
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
llvm::Constant *addr = CGM.getMemberFunctionPointer(MD, Ty);

MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
Expand All @@ -1080,8 +1222,12 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,

CharUnits ThisAdjustment = getContext().getMemberPointerPathAdjustment(MP);

if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
return BuildMemberPointer(MD, ThisAdjustment);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
llvm::Constant *Src = BuildMemberPointer(MD, ThisAdjustment);
QualType SrcType = getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return pointerAuthResignMemberFunctionPointer(Src, MPType, SrcType, CGM);
}

CharUnits FieldOffset =
getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
Expand Down Expand Up @@ -3185,6 +3331,78 @@ bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}

llvm::Constant *
ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) {
SmallString<256> MethodName;
llvm::raw_svector_ostream Out(MethodName);
getMangleContext().mangleCXXName(MD, Out);
MethodName += "_vfpthunk_";
StringRef ThunkName = MethodName.str();
llvm::Function *ThunkFn;
if ((ThunkFn = cast_or_null<llvm::Function>(
CGM.getModule().getNamedValue(ThunkName))))
return ThunkFn;

const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeCXXMethodDeclaration(MD);
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::GlobalValue::LinkageTypes Linkage =
MD->isExternallyVisible() ? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
ThunkFn =
llvm::Function::Create(ThunkTy, Linkage, ThunkName, &CGM.getModule());
if (Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
ThunkFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
assert(ThunkFn->getName() == ThunkName && "name was uniqued!");

CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn, /*IsThunk=*/true);
CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);

// Stack protection sometimes gets inserted after the musttail call.
ThunkFn->removeFnAttr(llvm::Attribute::StackProtect);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectStrong);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectReq);

// Start codegen.
CodeGenFunction CGF(CGM);
CGF.CurGD = GlobalDecl(MD);
CGF.CurFuncIsThunk = true;

// Build FunctionArgs.
FunctionArgList FunctionArgs;
CGF.BuildFunctionArgList(CGF.CurGD, FunctionArgs);

CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
FunctionArgs, MD->getLocation(), SourceLocation());
llvm::Value *ThisVal = loadIncomingCXXThis(CGF);
setCXXABIThisValue(CGF, ThisVal);

CallArgList CallArgs;
for (const VarDecl *VD : FunctionArgs)
CGF.EmitDelegateCallArg(CallArgs, VD, SourceLocation());

const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, /*this*/ 1);
const CGFunctionInfo &CallInfo =
CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT, Required, 0);
CGCallee Callee = CGCallee::forVirtual(nullptr, GlobalDecl(MD),
getThisAddress(CGF), ThunkTy);
llvm::CallBase *CallOrInvoke;
CGF.EmitCall(CallInfo, Callee, ReturnValueSlot(), CallArgs, &CallOrInvoke,
/*IsMustTail=*/true, SourceLocation(), true);
auto *Call = cast<llvm::CallInst>(CallOrInvoke);
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
if (Call->getType()->isVoidTy())
CGF.Builder.CreateRetVoid();
else
CGF.Builder.CreateRet(Call);

// Finish the function to maintain CodeGenFunction invariants.
// FIXME: Don't emit unreachable code.
CGF.EmitBlock(CGF.createBasicBlock());
CGF.FinishFunction();
return ThunkFn;
}

namespace {
class ItaniumRTTIBuilder {
CodeGenModule &CGM; // Per-module state.
Expand Down Expand Up @@ -4875,6 +5093,18 @@ ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD};
}

llvm::Constant *
ItaniumCXXABI::getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD) {
const CXXMethodDecl *origMD =
cast<CXXMethodDecl>(CGM.getItaniumVTableContext()
.findOriginalMethod(MD->getCanonicalDecl())
.getDecl());
llvm::Constant *thunk = getOrCreateVirtualFunctionPointerThunk(origMD);
QualType funcType = CGM.getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return CGM.getMemberFunctionPointer(thunk, funcType);
}

void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
const CXXCatchStmt *C) {
if (CGF.getTarget().hasFeature("exception-handling"))
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,12 @@ void AIX::addClangTargetOptions(
if (!Args.getLastArgNoClaim(options::OPT_fsized_deallocation,
options::OPT_fno_sized_deallocation))
CC1Args.push_back("-fno-sized-deallocation");

if (Args.hasFlag(options::OPT_ferr_pragma_mc_func_aix,
options::OPT_fno_err_pragma_mc_func_aix, false))
CC1Args.push_back("-ferr-pragma-mc-func-aix");
else
CC1Args.push_back("-fno-err-pragma-mc-func-aix");
}

void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
Expand Down
86 changes: 53 additions & 33 deletions clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
// Enable the `lsx` feature on 64-bit LoongArch by default.
if (Triple.isLoongArch64() &&
(!Args.hasArgNoClaim(clang::driver::options::OPT_march_EQ)))
Features.push_back("+lsx");

std::string ArchName;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
ArchName = A->getValue();
Expand All @@ -145,9 +150,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (A->getOption().matches(options::OPT_msingle_float)) {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else /*Soft-float*/ {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
}
} else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
StringRef FPU = A->getValue();
Expand All @@ -157,9 +164,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (FPU == "32") {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else if (FPU == "0" || FPU == "none") {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
}
Expand All @@ -174,6 +183,42 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_msimd_EQ))
A->ignoreTargetSpecific();

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= precedes -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -msimd=lsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
else
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float, -mfpu=none/0/32 and -mno-lsx conflict with -msimd=lasx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);

// The command options do not contain -mno-lasx.
if (!Args.getLastArg(options::OPT_mno_lasx)) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD == "none") {
if (llvm::find(Features, "+lsx") != Features.end())
Features.push_back("-lsx");
if (llvm::find(Features, "+lasx") != Features.end())
Features.push_back("-lasx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}

// Select lsx feature determined by -m[no-]lsx.
if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
Expand All @@ -197,44 +242,13 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
if (A->getOption().matches(options::OPT_mlasx)) {
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
else { /*-mlasx*/
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else /*-mno-lasx*/
Features.push_back("-lasx");
}

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= has lower priority than -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
// The previous option does not contain feature -lsx.
else if (llvm::find(Features, "-lsx") == Features.end())
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
// The previous option does not contain feature -lasx.
else if (llvm::find(Features, "-lasx") == Features.end()) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD != "none") {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}
}

std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
Expand All @@ -253,8 +267,14 @@ std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
std::string CPU;
std::string Arch;
// If we have -march, use that.
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
CPU = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
Arch = A->getValue();
if (Arch == "la64v1.0" || Arch == "la64v1.1")
CPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
else
CPU = Arch;
}
return postProcessTargetCPUString(CPU, Triple);
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
options::OPT_fno_ptrauth_function_pointer_type_discrimination);

Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos);
}

void Clang::AddLoongArchTargetArgs(const ArgList &Args,
Expand Down
65 changes: 12 additions & 53 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,6 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--output-file");
std::string OutputFileName = TC.getInputFilename(Output);

// If we are invoking `nvlink` internally we need to output a `.cubin` file.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (!C.getInputArgs().getLastArg(options::OPT_c)) {
SmallString<256> Filename(Output.getFilename());
llvm::sys::path::replace_extension(Filename, "cubin");
OutputFileName = Filename.str();
}
if (Output.isFilename() && OutputFileName != Output.getFilename())
C.addTempFile(Args.MakeArgString(OutputFileName));

Expand Down Expand Up @@ -612,64 +605,34 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-arch");
CmdArgs.push_back(Args.MakeArgString(GPUArch));

if (Args.hasArg(options::OPT_ptxas_path_EQ))
CmdArgs.push_back(Args.MakeArgString(
"--pxtas-path=" + Args.getLastArgValue(options::OPT_ptxas_path_EQ)));

// Add paths specified in LIBRARY_PATH environment variable as -L options.
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

// Add standard library search paths passed on the command line.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);

if (C.getDriver().isUsingLTO())
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
C.getDriver().getLTOMode() == LTOK_Thin);

// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));

for (const auto &II : Inputs) {
if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) {
C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
continue;
}

// The 'nvlink' application performs RDC-mode linking when given a '.o'
// file and device linking when given a '.cubin' file. We always want to
// perform device linking, so just rename any '.o' files.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (II.isFilename()) {
auto InputFile = getToolChain().getInputFilename(II);
if (llvm::sys::path::extension(InputFile) != ".cubin") {
// If there are no actions above this one then this is direct input and
// we can copy it. Otherwise the input is internal so a `.cubin` file
// should exist.
if (II.getAction() && II.getAction()->getInputs().size() == 0) {
const char *CubinF =
Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
llvm::sys::path::stem(InputFile), "cubin"));
if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
continue;

CmdArgs.push_back(CubinF);
} else {
SmallString<256> Filename(InputFile);
llvm::sys::path::replace_extension(Filename, "cubin");
CmdArgs.push_back(Args.MakeArgString(Filename));
}
} else {
CmdArgs.push_back(Args.MakeArgString(InputFile));
}
} else if (!II.isNothing()) {
II.getInputArg().renderAsInput(Args, CmdArgs);
}
}

C.addCommand(std::make_unique<Command>(
JA, *this,
ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8,
"--options-file"},
Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs,
Inputs, Output));
Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")),
CmdArgs, Inputs, Output));
}

void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Expand Down Expand Up @@ -949,11 +912,7 @@ std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly())
return ToolChain::getInputFilename(Input);

// Replace extension for object files with cubin because nvlink relies on
// these particular file names.
SmallString<256> Filename(ToolChain::getInputFilename(Input));
llvm::sys::path::replace_extension(Filename, "cubin");
return std::string(Filename);
return ToolChain::getInputFilename(Input);
}

llvm::opt::DerivedArgList *
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain {
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool HasNativeLLVMSupport() const override { return true; }
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }

Expand Down Expand Up @@ -192,6 +193,8 @@ class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain {
return &HostTC.getTriple();
}

bool HasNativeLLVMSupport() const override { return false; }

std::string getInputFilename(const InputInfo &Input) const override;

llvm::opt::DerivedArgList *
Expand Down
25 changes: 22 additions & 3 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,20 +1488,30 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination,
LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type
: Discrimination::None);
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);

if (LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
StdTypeInfoVTablePointerConstantDiscrimination);
else
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);

Opts.CXXVTTVTablePointers =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::Decl);
Opts.CXXMemberFunctionPointers =
PointerAuthSchema(Key::ASIA, false, Discrimination::Type);
}
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
}

static void parsePointerAuthOptions(PointerAuthOptions &Opts,
const LangOptions &LangOpts,
const llvm::Triple &Triple,
DiagnosticsEngine &Diags) {
if (!LangOpts.PointerAuthCalls)
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIndirectGotos)
return;

CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
Expand Down Expand Up @@ -3405,12 +3415,17 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fptrauth_calls);
if (Opts.PointerAuthReturns)
GenerateArg(Consumer, OPT_fptrauth_returns);
if (Opts.PointerAuthIndirectGotos)
GenerateArg(Consumer, OPT_fptrauth_indirect_gotos);
if (Opts.PointerAuthAuthTraps)
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
if (Opts.PointerAuthVTPtrAddressDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
if (Opts.PointerAuthVTPtrTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);

if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthFunctionTypeDiscrimination)
Expand All @@ -3422,11 +3437,15 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
Opts.PointerAuthIndirectGotos = Args.hasArg(OPT_fptrauth_indirect_gotos);
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
Opts.PointerAuthVTPtrAddressDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
Opts.PointerAuthVTPtrTypeDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
Opts.PointerAuthTypeInfoVTPtrDiscrimination =
Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);

Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthFunctionTypeDiscrimination =
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Lex/DependencyDirectivesScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ struct Scanner {
[[nodiscard]] dependency_directives_scan::Token &
lexToken(const char *&First, const char *const End);

dependency_directives_scan::Token &lexIncludeFilename(const char *&First,
const char *const End);
[[nodiscard]] dependency_directives_scan::Token &
lexIncludeFilename(const char *&First, const char *const End);

void skipLine(const char *&First, const char *const End);
void skipDirective(StringRef Name, const char *&First, const char *const End);
Expand Down Expand Up @@ -544,7 +544,7 @@ Scanner::lexIncludeFilename(const char *&First, const char *const End) {
void Scanner::lexPPDirectiveBody(const char *&First, const char *const End) {
while (true) {
const dependency_directives_scan::Token &Tok = lexToken(First, End);
if (Tok.is(tok::eod))
if (Tok.is(tok::eod) || Tok.is(tok::eof))
break;
}
}
Expand Down Expand Up @@ -912,7 +912,11 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
case pp___include_macros:
case pp_include_next:
case pp_import:
lexIncludeFilename(First, End);
// Ignore missing filenames in include or import directives.
if (lexIncludeFilename(First, End).is(tok::eod)) {
skipDirective(Id, First, End);
return true;
}
break;
default:
break;
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/Token.h"
#include "clang/Parse/LoopHint.h"
#include "clang/Parse/ParseDiagnostic.h"
Expand Down Expand Up @@ -411,6 +412,19 @@ struct PragmaRISCVHandler : public PragmaHandler {
Sema &Actions;
};

struct PragmaMCFuncHandler : public PragmaHandler {
PragmaMCFuncHandler(bool ReportError)
: PragmaHandler("mc_func"), ReportError(ReportError) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &Tok) override {
if (ReportError)
PP.Diag(Tok, diag::err_pragma_mc_func_not_supported);
}

private:
bool ReportError = false;
};

void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
for (auto &T : Toks)
T.setFlag(clang::Token::IsReinjected);
Expand Down Expand Up @@ -568,6 +582,12 @@ void Parser::initializePragmaHandlers() {
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
}

if (getTargetInfo().getTriple().isOSAIX()) {
MCFuncPragmaHandler = std::make_unique<PragmaMCFuncHandler>(
PP.getPreprocessorOpts().ErrorOnPragmaMcfuncOnAIX);
PP.AddPragmaHandler(MCFuncPragmaHandler.get());
}
}

void Parser::resetPragmaHandlers() {
Expand Down Expand Up @@ -702,6 +722,11 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
RISCVPragmaHandler.reset();
}

if (getTargetInfo().getTriple().isOSAIX()) {
PP.RemovePragmaHandler(MCFuncPragmaHandler.get());
MCFuncPragmaHandler.reset();
}
}

/// Handle the annotation token produced for #pragma unused(...)
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10909,6 +10909,14 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp))
return QualType();

// Arithmetic on label addresses is normally allowed, except when we add
// a ptrauth signature to the addresses.
if (isa<AddrLabelExpr>(PExp) && getLangOpts().PointerAuthIndirectGotos) {
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
<< /*addition*/ 1;
return QualType();
}

// Check array bounds for pointer arithemtic
CheckArrayAccess(PExp, IExp);

Expand Down Expand Up @@ -10983,6 +10991,15 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
checkArithmeticOnObjCPointer(*this, Loc, LHS.get()))
return QualType();

// Arithmetic on label addresses is normally allowed, except when we add
// a ptrauth signature to the addresses.
if (isa<AddrLabelExpr>(LHS.get()) &&
getLangOpts().PointerAuthIndirectGotos) {
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
<< /*subtraction*/ 0;
return QualType();
}

// The result type of a pointer-int computation is the pointer type.
if (RHS.get()->getType()->isIntegerType()) {
// Subtracting from a null pointer should produce a warning.
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/Interp/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,16 @@ struct S {
S s;
// CHECK: @sp = constant ptr getelementptr (i8, ptr @s, i64 16), align 8
float &sp = s.c[3];


namespace BaseClassOffsets {
struct A { int a; };
struct B { int b; };
struct C : A, B { int c; };

extern C c;
// CHECK: @_ZN16BaseClassOffsets1aE = global ptr @_ZN16BaseClassOffsets1cE, align 8
A* a = &c;
// CHECK: @_ZN16BaseClassOffsets1bE = global ptr getelementptr (i8, ptr @_ZN16BaseClassOffsets1cE, i64 4), align 8
B* b = &c;
}
1 change: 1 addition & 0 deletions clang/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ list(APPEND CLANG_TEST_DEPS
clang-installapi
clang-scan-deps
clang-linker-wrapper
clang-nvlink-wrapper
clang-offload-bundler
clang-offload-packager
diagtool
Expand Down
1 change: 1 addition & 0 deletions clang/test/CodeGen/builtins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -o %t %s
// RUN: not grep __builtin %t
// RUN: %clang_cc1 -emit-llvm -triple x86_64-darwin-apple -o - %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -triple x86_64-darwin-apple -fexperimental-new-constant-interpreter -o - %s | FileCheck %s

int printf(const char *, ...);

Expand Down
5 changes: 5 additions & 0 deletions clang/test/CodeGen/ptrauth-function-attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS

// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-indirect-gotos -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,GOTOS
// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-indirect-gotos -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,GOTOS

// ALL: define {{(dso_local )?}}void @test() #0
void test() {
}

// CALLS: attributes #0 = {{{.*}} "ptrauth-calls" {{.*}}}

// GOTOS: attributes #0 = {{{.*}} "ptrauth-indirect-gotos" {{.*}}}

// OFF-NOT: attributes {{.*}} "ptrauth-
433 changes: 433 additions & 0 deletions clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// RUN: %clang_cc1 -DENABLE_TID=0 -I%S -std=c++11 -triple=arm64e-apple-darwin \
// RUN: -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NODISC

// RUN: %clang_cc1 -DENABLE_TID=1 -I%S -std=c++11 -triple=arm64e-apple-darwin \
// RUN: -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-type-info-vtable-pointer-discrimination \
// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DISC

// copied from typeinfo
namespace std {

#if __has_cpp_attribute(clang::ptrauth_vtable_pointer)
# if __has_feature(ptrauth_type_info_vtable_pointer_discrimination)
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
[[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]]
# else
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
[[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
# endif
#else
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH
#endif

class _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info
{
type_info& operator=(const type_info&);
type_info(const type_info&);

protected:
explicit type_info(const char* __n);

public:
virtual ~type_info();

virtual void test_method();
};
} // namespace std

static_assert(__has_feature(ptrauth_type_info_vtable_pointer_discrimination) == ENABLE_TID, "incorrect feature state");

// CHECK: @disc_std_type_info = global i32 [[STDTYPEINFO_DISC:45546]]
extern "C" int disc_std_type_info = __builtin_ptrauth_string_discriminator("_ZTVSt9type_info");

// CHECK: @_ZTV10TestStruct = unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI10TestStruct, ptr ptrauth (ptr @_ZN10TestStructD1Ev, i32 0, i64 52216, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN10TestStructD0Ev, i32 0, i64 39671, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 3))] }, align 8
// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
// CHECK: @_ZTS10TestStruct = constant [13 x i8] c"10TestStruct\00", align 1

// NODISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS10TestStruct }, align 8

// DISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2, i64 [[STDTYPEINFO_DISC]]), ptr @_ZTS10TestStruct }, align 8

struct TestStruct {
virtual ~TestStruct();
int a;
};

TestStruct::~TestStruct(){}

extern "C" void test_vtable(std::type_info* t) {
t->test_method();
}
// NODISC: define void @test_vtable(ptr noundef %t)
// NODISC: [[T_ADDR:%.*]] = alloca ptr, align 8
// NODISC: store ptr %t, ptr [[T_ADDR]], align 8
// NODISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
// NODISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
// NODISC: [[CAST_VPTR:%.*]] = ptrtoint ptr [[VPTR]] to i64
// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VPTR]], i32 2, i64 0)

// DISC: define void @test_vtable(ptr noundef %t)
// DISC: [[T_ADDR:%.*]] = alloca ptr, align 8
// DISC: store ptr %t, ptr [[T_ADDR]], align 8
// DISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
// DISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
// DISC: [[ADDR:%.*]] = ptrtoint ptr [[T]] to i64
// DISC: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 [[STDTYPEINFO_DISC]])
// DISC: [[VPTRI:%.*]] = ptrtoint ptr [[VPTR]] to i64
// DISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VPTRI]], i32 2, i64 [[DISCRIMINATOR]])

extern "C" const void *ensure_typeinfo() {
return new TestStruct;
}
8 changes: 4 additions & 4 deletions clang/test/Driver/cuda-cross-compiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
// RUN: | FileCheck -check-prefix=ARGS %s

// ARGS: -cc1" "-triple" "nvptx64-nvidia-cuda" "-S" {{.*}} "-target-cpu" "sm_61" "-target-feature" "+ptx{{[0-9]+}}" {{.*}} "-o" "[[PTX:.+]].s"
// ARGS-NEXT: ptxas{{.*}}"-m64" "-O0" "--gpu-name" "sm_61" "--output-file" "[[CUBIN:.+]].cubin" "[[PTX]].s" "-c"
// ARGS-NEXT: nvlink{{.*}}"-o" "a.out" "-arch" "sm_61" {{.*}} "[[CUBIN]].cubin"
// ARGS-NEXT: ptxas{{.*}}"-m64" "-O0" "--gpu-name" "sm_61" "--output-file" "[[CUBIN:.+]].o" "[[PTX]].s" "-c"
// ARGS-NEXT: clang-nvlink-wrapper{{.*}}"-o" "a.out" "-arch" "sm_61"{{.*}}"[[CUBIN]].o"

//
// Test the generated arguments to the CUDA binary utils when targeting NVPTX.
Expand All @@ -55,7 +55,7 @@
// RUN: %clang -target nvptx64-nvidia-cuda -march=sm_61 -### %t.o 2>&1 \
// RUN: | FileCheck -check-prefix=LINK %s

// LINK: nvlink{{.*}}"-o" "a.out" "-arch" "sm_61" {{.*}} "{{.*}}.cubin"
// LINK: clang-nvlink-wrapper{{.*}}"-o" "a.out" "-arch" "sm_61"{{.*}}[[CUBIN:.+]].o

//
// Test to ensure that we enable handling global constructors in a freestanding
Expand All @@ -72,7 +72,7 @@
// RUN: %clang -target nvptx64-nvidia-cuda -Wl,-v -Wl,a,b -march=sm_52 -### %s 2>&1 \
// RUN: | FileCheck -check-prefix=LINKER-ARGS %s

// LINKER-ARGS: nvlink{{.*}}"-v"{{.*}}"a" "b"
// LINKER-ARGS: clang-nvlink-wrapper{{.*}}"-v"{{.*}}"a" "b"

// Tests for handling a missing architecture.
//
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/loongarch-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// RUN: %clang --target=loongarch64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=LA64

// LA32: "target-features"="+32bit"
// LA64: "target-features"="+64bit,+d,+f,+ual"
// LA64: "target-features"="+64bit,+d,+f,+lsx,+ual"

int foo(void) {
return 3;
Expand Down
22 changes: 22 additions & 0 deletions clang/test/Driver/loongarch-march.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@
// RUN: FileCheck %s --check-prefix=CC1-LOONGARCH64
// RUN: %clang --target=loongarch64 -march=la464 -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-LA464
// RUN: %clang --target=loongarch64 -march=la64v1.0 -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-LA64V1P0
// RUN: %clang --target=loongarch64 -march=la64v1.1 -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-LA64V1P1
// RUN: %clang --target=loongarch64 -march=loongarch64 -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LOONGARCH64
// RUN: %clang --target=loongarch64 -march=la464 -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LA464
// RUN: %clang --target=loongarch64 -march=la64v1.0 -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LA64V1P0
// RUN: %clang --target=loongarch64 -march=la64v1.1 -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LA64V1P1

// CC1-LOONGARCH64: "-target-cpu" "loongarch64"
// CC1-LOONGARCH64-NOT: "-target-feature"
Expand All @@ -19,8 +27,22 @@
// CC1-LA464-NOT: "-target-feature"
// CC1-LA464: "-target-abi" "lp64d"

// CC1-LA64V1P0: "-target-cpu" "loongarch64"
// CC1-LA64V1P0-NOT: "-target-feature"
// CC1-LA64V1P0: "-target-feature" "+64bit" "-target-feature" "+d" "-target-feature" "+lsx" "-target-feature" "+ual"
// CC1-LA64V1P0-NOT: "-target-feature"
// CC1-LA64V1P0: "-target-abi" "lp64d"

// CC1-LA64V1P1: "-target-cpu" "loongarch64"
// CC1-LA64V1P1-NOT: "-target-feature"
// CC1-LA64V1P1: "-target-feature" "+64bit" "-target-feature" "+d" "-target-feature" "+lsx" "-target-feature" "+ual" "-target-feature" "+frecipe"
// CC1-LA64V1P1-NOT: "-target-feature"
// CC1-LA64V1P1: "-target-abi" "lp64d"

// IR-LOONGARCH64: attributes #[[#]] ={{.*}}"target-cpu"="loongarch64" {{.*}}"target-features"="+64bit,+d,+f,+ual"
// IR-LA464: attributes #[[#]] ={{.*}}"target-cpu"="la464" {{.*}}"target-features"="+64bit,+d,+f,+lasx,+lsx,+ual"
// IR-LA64V1P0: attributes #[[#]] ={{.*}}"target-cpu"="loongarch64" {{.*}}"target-features"="+64bit,+d,+lsx,+ual"
// IR-LA64V1P1: attributes #[[#]] ={{.*}}"target-cpu"="loongarch64" {{.*}}"target-features"="+64bit,+d,+frecipe,+lsx,+ual"

int foo(void) {
return 3;
Expand Down
6 changes: 4 additions & 2 deletions clang/test/Driver/loongarch-mlasx.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// RUN: %clang --target=loongarch64 -mno-lasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NOLASX
// RUN: %clang --target=loongarch64 -mlasx -mno-lasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NOLASX
// RUN: FileCheck %s --check-prefix=CC1-LSX
// RUN: %clang --target=loongarch64 -mno-lasx -mlasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-LASX
// RUN: %clang --target=loongarch64 -mlsx -mlasx -fsyntax-only %s -### 2>&1 | \
Expand All @@ -18,17 +18,19 @@
// RUN: %clang --target=loongarch64 -mno-lasx -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NOLASX
// RUN: %clang --target=loongarch64 -mlasx -mno-lasx -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NOLASX
// RUN: FileCheck %s --check-prefix=IR-LSX
// RUN: %clang --target=loongarch64 -mno-lasx -mlasx -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LASX
// RUN: %clang --target=loongarch64 -mlsx -mlasx -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LASX
// RUN: %clang --target=loongarch64 -mlasx -mlsx -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-LASX

// CC1-LSX: "-target-feature" "+lsx"
// CC1-LASX: "-target-feature" "+lsx" "-target-feature" "+lasx"
// CC1-NOLASX: "-target-feature" "-lasx"

// IR-LSX: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}+lsx{{(,.*)?}}"
// IR-LASX: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}+lasx{{(,.*)?}}"
// IR-NOLASX: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}-lasx{{(,.*)?}}"

Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/loongarch-msimd.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@
// RUN: FileCheck %s --check-prefixes=LSX,LASX

// RUN: %clang --target=loongarch64 -mlasx -mno-lasx -msimd=lasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefixes=NOLSX,NOLASX
// RUN: FileCheck %s --check-prefixes=LSX,NOLASX
// RUN: %clang --target=loongarch64 -mno-lasx -msimd=lasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefixes=NOLSX,NOLASX
// RUN: FileCheck %s --check-prefixes=LSX,NOLASX

// RUN: %clang --target=loongarch64 -mlasx -mno-lasx -mlsx -msimd=lasx -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefixes=LSX,NOLASX
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/loongarch-msingle-float.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
// WARN: warning: ignoring '-mabi=lp64s' as it conflicts with that implied by '-msingle-float' (lp64f)
// WARN: warning: ignoring '-mfpu=64' as it conflicts with that implied by '-msingle-float' (32)

// CC1: "-target-feature" "+f"{{.*}} "-target-feature" "-d"
// CC1: "-target-feature" "+f"{{.*}} "-target-feature" "-d" "-target-feature" "-lsx"
// CC1: "-target-abi" "lp64f"

// IR: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}+f,{{(.*,)?}}-d"
// IR: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}+f,{{(.*,)?}}-d,-lsx"

int foo(void) {
return 3;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/loongarch-msoft-float.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
// WARN: warning: ignoring '-mabi=lp64d' as it conflicts with that implied by '-msoft-float' (lp64s)
// WARN: warning: ignoring '-mfpu=64' as it conflicts with that implied by '-msoft-float' (0)

// CC1: "-target-feature" "-f"{{.*}} "-target-feature" "-d"
// CC1: "-target-feature" "-f"{{.*}} "-target-feature" "-d" "-target-feature" "-lsx"
// CC1: "-target-abi" "lp64s"

// IR: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}-d,{{(.*,)?}}-f{{(,.*)?}}"
// IR: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}-d,{{(.*,)?}}-f,-lsx"

int foo(void) {
return 3;
Expand Down
65 changes: 65 additions & 0 deletions clang/test/Driver/nvlink-wrapper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// REQUIRES: x86-registered-target
// REQUIRES: nvptx-registered-target

#if defined(X)
extern int y;
int foo() { return y; }

int x = 0;
#elif defined(Y)
int y = 42;
#elif defined(Z)
int z = 42;
#elif defined(W)
int w = 42;
#elif defined(U)
extern int x;
extern int __attribute__((weak)) w;

int bar() {
return x + w;
}
#else
extern int y;
int __attribute__((visibility("hidden"))) x = 999;
int baz() { return y + x; }
#endif

// Create various inputs to test basic linking and LTO capabilities. Creating a
// CUDA binary requires access to the `ptxas` executable, so we just use x64.
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -DX -o %t-x.o
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -DY -o %t-y.o
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -DZ -o %t-z.o
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -DW -o %t-w.o
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -DU -o %t-u.o
// RUN: llvm-ar rcs %t-x.a %t-x.o
// RUN: llvm-ar rcs %t-y.a %t-y.o
// RUN: llvm-ar rcs %t-z.a %t-z.o
// RUN: llvm-ar rcs %t-w.a %t-w.o

//
// Check that we forward any unrecognized argument to 'nvlink'.
//
// RUN: clang-nvlink-wrapper --dry-run -arch sm_52 %t-u.o -foo -o a.out 2>&1 \
// RUN: | FileCheck %s --check-prefix=ARGS
// ARGS: nvlink{{.*}} -arch sm_52 -foo -o a.out [[INPUT:.+]].cubin

//
// Check the symbol resolution for static archives. We expect to only link
// `libx.a` and `liby.a` because extern weak symbols do not extract and `libz.a`
// is not used at all.
//
// RUN: clang-nvlink-wrapper --dry-run %t-x.a %t-u.o %t-y.a %t-z.a %t-w.a \
// RUN: -arch sm_52 -o a.out 2>&1 | FileCheck %s --check-prefix=LINK
// LINK: nvlink{{.*}} -arch sm_52 -o a.out [[INPUT:.+]].cubin {{.*}}-x-{{.*}}.cubin{{.*}}-y-{{.*}}.cubin

// RUN: %clang -cc1 %s -triple nvptx64-nvidia-cuda -emit-llvm-bc -o %t.o

//
// Check that the LTO interface works and properly preserves symbols used in a
// regular object file.
//
// RUN: clang-nvlink-wrapper --dry-run %t.o %t-u.o %t-y.a \
// RUN: -arch sm_52 -o a.out 2>&1 | FileCheck %s --check-prefix=LTO
// LTO: ptxas{{.*}} -m64 -c [[PTX:.+]].s -O3 -arch sm_52 -o [[CUBIN:.+]].cubin
// LTO: nvlink{{.*}} -arch sm_52 -o a.out [[CUBIN]].cubin {{.*}}-u-{{.*}}.cubin {{.*}}-y-{{.*}}.cubin
Loading