diff --git a/.ci/monolithic-linux.sh b/.ci/monolithic-linux.sh index 9e670c447fbaddc82106905b60927fc2c5c883db..b347c443da677fd530afb91936a9605ec1218b2b 100755 --- a/.ci/monolithic-linux.sh +++ b/.ci/monolithic-linux.sh @@ -18,7 +18,7 @@ set -o pipefail MONOREPO_ROOT="${MONOREPO_ROOT:="$(git rev-parse --show-toplevel)"}" BUILD_DIR="${BUILD_DIR:=${MONOREPO_ROOT}/build}" -rm -rf ${BUILD_DIR} +rm -rf "${BUILD_DIR}" ccache --zero-stats @@ -37,8 +37,8 @@ projects="${1}" targets="${2}" echo "--- cmake" -pip install -q -r ${MONOREPO_ROOT}/mlir/python/requirements.txt -cmake -S ${MONOREPO_ROOT}/llvm -B ${BUILD_DIR} \ +pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt +cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_ENABLE_PROJECTS="${projects}" \ -G Ninja \ -D CMAKE_BUILD_TYPE=Release \ diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index 52ba13036f915983e97ad1149ffc40ee51a4c24e..4fd88ea81c84a8e2c2e1201b5593e4305ed28b09 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -19,7 +19,7 @@ set -o pipefail MONOREPO_ROOT="${MONOREPO_ROOT:="$(git rev-parse --show-toplevel)"}" BUILD_DIR="${BUILD_DIR:=${MONOREPO_ROOT}/build}" -rm -rf ${BUILD_DIR} +rm -rf "${BUILD_DIR}" if [[ -n "${CLEAR_CACHE:-}" ]]; then echo "clearing sccache" @@ -37,14 +37,14 @@ projects="${1}" targets="${2}" echo "--- cmake" -pip install -q -r ${MONOREPO_ROOT}/mlir/python/requirements.txt +pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt # The CMAKE_*_LINKER_FLAGS to disable the manifest come from research # on fixing a build reliability issue on the build server, please # see https://github.com/llvm/llvm-project/pull/82393 and # https://discourse.llvm.org/t/rfc-future-of-windows-pre-commit-ci/76840/40 # for further information. -cmake -S ${MONOREPO_ROOT}/llvm -B ${BUILD_DIR} \ +cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_ENABLE_PROJECTS="${projects}" \ -G Ninja \ -D CMAKE_BUILD_TYPE=Release \ diff --git a/bolt/include/bolt/Core/AddressMap.h b/bolt/include/bolt/Core/AddressMap.h index 85a9ab4473aafedd192145acaa334208e22ac6e6..31ed7d40ee7f215586e53a6b285f492c898ab765 100644 --- a/bolt/include/bolt/Core/AddressMap.h +++ b/bolt/include/bolt/Core/AddressMap.h @@ -14,7 +14,6 @@ #ifndef BOLT_CORE_ADDRESS_MAP_H #define BOLT_CORE_ADDRESS_MAP_H -#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSymbol.h" #include diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 741b1a36af86f871bb51430686ff229ce2e1d1b8..8b1af9e8153925760985efcb954e87a046b2c1f2 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -265,7 +265,8 @@ class BinaryContext { public: static Expected> - createBinaryContext(const ObjectFile *File, bool IsPIC, + createBinaryContext(Triple TheTriple, StringRef InputFileName, + SubtargetFeatures *Features, bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger); diff --git a/bolt/include/bolt/Core/BinaryData.h b/bolt/include/bolt/Core/BinaryData.h index 5f1efda781905db66ec18e16a3263a88c5f0816f..495163f1b61aafd2360b9699fcda4f95844f1dd3 100644 --- a/bolt/include/bolt/Core/BinaryData.h +++ b/bolt/include/bolt/Core/BinaryData.h @@ -18,7 +18,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/raw_ostream.h" -#include #include #include diff --git a/bolt/include/bolt/Core/BinaryDomTree.h b/bolt/include/bolt/Core/BinaryDomTree.h index a9565795f94631b25c6674eb699b78e9f9d5bffd..de27aa78769d23398eaf97177ad316abf3e09798 100644 --- a/bolt/include/bolt/Core/BinaryDomTree.h +++ b/bolt/include/bolt/Core/BinaryDomTree.h @@ -16,7 +16,6 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "llvm/IR/Dominators.h" -#include "llvm/Support/GenericDomTreeConstruction.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index c170fa6397cc927293f539391ea5a29b7389a7be..5089f849128010ba04efa57bdf485c131923e74e 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -27,6 +27,7 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Core/BinaryContext.h" +#include "bolt/Core/BinaryDomTree.h" #include "bolt/Core/BinaryLoop.h" #include "bolt/Core/BinarySection.h" #include "bolt/Core/DebugData.h" @@ -51,7 +52,6 @@ #include #include #include -#include #include #include @@ -266,6 +266,7 @@ private: BinaryContext &BC; std::unique_ptr BLI; + std::unique_ptr BDT; /// All labels in the function that are referenced via relocations from /// data objects. Typically these are jump table destinations and computed @@ -838,6 +839,14 @@ public: /// stats. void calculateMacroOpFusionStats(); + /// Returns if BinaryDominatorTree has been constructed for this function. + bool hasDomTree() const { return BDT != nullptr; } + + BinaryDominatorTree &getDomTree() { return *BDT.get(); } + + /// Constructs DomTree for this function. + void constructDomTree(); + /// Returns if loop detection has been run for this function. bool hasLoopInfo() const { return BLI != nullptr; } diff --git a/bolt/include/bolt/Core/BinaryLoop.h b/bolt/include/bolt/Core/BinaryLoop.h index 72dce77df8c14b970023a59b82180f6bc2bb1633..b425c75715d8b1d02e66655d8ff7e4d9115fffdd 100644 --- a/bolt/include/bolt/Core/BinaryLoop.h +++ b/bolt/include/bolt/Core/BinaryLoop.h @@ -15,7 +15,7 @@ #ifndef BOLT_CORE_BINARY_LOOP_H #define BOLT_CORE_BINARY_LOOP_H -#include "llvm/Support/GenericLoopInfoImpl.h" +#include "llvm/Support/GenericLoopInfo.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h index 0f179877bd3df3b4bf7e736d1fc00e4806c9f7d2..5b7a5b08820e6e5190559ce2ad59992c7a998e2a 100644 --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -18,7 +18,6 @@ #include "bolt/Core/DebugData.h" #include "bolt/Core/Relocation.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h index 7d10b208dc83a22c9eee5d0f5acd538258401e42..166bb3617e57f68448eb662348e2e414ed885b32 100644 --- a/bolt/include/bolt/Core/DebugData.h +++ b/bolt/include/bolt/Core/DebugData.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/bolt/include/bolt/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h index fbaa7f4e68aac9281989f8432346b1eb9546c3cb..a4fdde7c396ad886e3d8c96bb92d25a657a4a0e1 100644 --- a/bolt/include/bolt/Core/DebugNames.h +++ b/bolt/include/bolt/Core/DebugNames.h @@ -14,7 +14,7 @@ #ifndef BOLT_CORE_DEBUG_NAMES_H #define BOLT_CORE_DEBUG_NAMES_H -#include "DebugData.h" +#include "bolt/Core/DebugData.h" #include "llvm/CodeGen/AccelTable.h" namespace llvm { diff --git a/bolt/include/bolt/Core/FunctionLayout.h b/bolt/include/bolt/Core/FunctionLayout.h index 2e4c184ba4511ca6836ca9d031014c1f784385f0..b685a99c79c14cccd0e7661ed8a48991c9a53b98 100644 --- a/bolt/include/bolt/Core/FunctionLayout.h +++ b/bolt/include/bolt/Core/FunctionLayout.h @@ -25,7 +25,6 @@ #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include -#include namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/MCPlus.h b/bolt/include/bolt/Core/MCPlus.h index 1d2360c180335f9f2b1d243153dc1c6f5f92b6fd..601d709712864ebefce1a4156378b023f564be96 100644 --- a/bolt/include/bolt/Core/MCPlus.h +++ b/bolt/include/bolt/Core/MCPlus.h @@ -14,10 +14,8 @@ #ifndef BOLT_CORE_MCPLUS_H #define BOLT_CORE_MCPLUS_H -#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/Support/Casting.h" #include namespace llvm { diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 198a8d8bf48f8222cf4863d7d6d928f5ff160c6e..f7614cf9ac9777be6812e228190cc20c810b4c3d 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/MC/MCExpr.h" @@ -27,6 +28,7 @@ #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/RWMutex.h" @@ -533,9 +535,7 @@ public: return Analysis->isReturn(Inst); } - virtual bool isTerminator(const MCInst &Inst) const { - return Analysis->isTerminator(Inst); - } + virtual bool isTerminator(const MCInst &Inst) const; virtual bool isNoop(const MCInst &Inst) const { llvm_unreachable("not implemented"); diff --git a/bolt/include/bolt/Passes/BinaryPasses.h b/bolt/include/bolt/Passes/BinaryPasses.h index 046765b16f19d21b8562440f51c1b0c3c666995e..8d89ef8b5484f8e18d7ea034c3d38df57746760a 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -18,7 +18,6 @@ #include "bolt/Core/DynoStats.h" #include "llvm/Support/CommandLine.h" #include -#include #include #include #include diff --git a/bolt/include/bolt/Passes/CacheMetrics.h b/bolt/include/bolt/Passes/CacheMetrics.h index 5c88d98c76c1d5aa20b386a5398e3ee010867243..ea56d330446b9932bd021ee71be5fc0ad7107829 100644 --- a/bolt/include/bolt/Passes/CacheMetrics.h +++ b/bolt/include/bolt/Passes/CacheMetrics.h @@ -13,7 +13,6 @@ #ifndef BOLT_PASSES_CACHEMETRICS_H #define BOLT_PASSES_CACHEMETRICS_H -#include #include namespace llvm { diff --git a/bolt/include/bolt/Passes/DominatorAnalysis.h b/bolt/include/bolt/Passes/DominatorAnalysis.h index c2b5c3af01472213ef56b994b04866c2a2b7ec1e..3f3afa943c06cefe853113de6e9b29703742f7f7 100644 --- a/bolt/include/bolt/Passes/DominatorAnalysis.h +++ b/bolt/include/bolt/Passes/DominatorAnalysis.h @@ -11,7 +11,6 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" namespace opts { extern llvm::cl::opt TimeOpts; diff --git a/bolt/include/bolt/Passes/ReachingDefOrUse.h b/bolt/include/bolt/Passes/ReachingDefOrUse.h index f38d1a373e18b8de4618bdb2d95362b05d4bea00..585d673e3b84e58431ff074a01b2283315abb7a4 100644 --- a/bolt/include/bolt/Passes/ReachingDefOrUse.h +++ b/bolt/include/bolt/Passes/ReachingDefOrUse.h @@ -11,9 +11,7 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "bolt/Passes/RegAnalysis.h" -#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" #include namespace opts { diff --git a/bolt/include/bolt/Passes/ReachingInsns.h b/bolt/include/bolt/Passes/ReachingInsns.h index 65782b12064b85848d59b1d7e7d2a06cf03cdba4..ef878f5e452db30f6b4f8e3d5617e4fc285dcf19 100644 --- a/bolt/include/bolt/Passes/ReachingInsns.h +++ b/bolt/include/bolt/Passes/ReachingInsns.h @@ -11,7 +11,6 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" namespace opts { extern llvm::cl::opt TimeOpts; diff --git a/bolt/include/bolt/Passes/ReorderUtils.h b/bolt/include/bolt/Passes/ReorderUtils.h index bc82b4f436fa7553f9ae7762ad2098147080250e..8ceb8ba62690a55b87fe0933633c7ebe0239b318 100644 --- a/bolt/include/bolt/Passes/ReorderUtils.h +++ b/bolt/include/bolt/Passes/ReorderUtils.h @@ -14,7 +14,6 @@ #ifndef BOLT_PASSES_REORDER_UTILS_H #define BOLT_PASSES_REORDER_UTILS_H -#include #include #include "llvm/ADT/BitVector.h" diff --git a/bolt/include/bolt/Profile/ProfileReaderBase.h b/bolt/include/bolt/Profile/ProfileReaderBase.h index 511718f3c0ec7431310d5c722e90bbb061c9057f..3e5cf2612893907677014e01dbe08922fe8cae24 100644 --- a/bolt/include/bolt/Profile/ProfileReaderBase.h +++ b/bolt/include/bolt/Profile/ProfileReaderBase.h @@ -65,7 +65,7 @@ public: /// Return true if the function \p BF may have a profile available. /// The result is based on the name(s) of the function alone and the profile /// match is not guaranteed. - virtual bool mayHaveProfileData(const BinaryFunction &BF); + virtual bool mayHaveProfileData(const BinaryFunction &BF) { return true; } /// Return true if the profile contains an entry for a local object /// that has an associated file name. diff --git a/bolt/include/bolt/Profile/ProfileYAMLMapping.h b/bolt/include/bolt/Profile/ProfileYAMLMapping.h index 548b528ae2d6534d96cbcea298f9b283c79385f6..9dd3920dbf0943fbb1f6aac2721b170a01d34900 100644 --- a/bolt/include/bolt/Profile/ProfileYAMLMapping.h +++ b/bolt/include/bolt/Profile/ProfileYAMLMapping.h @@ -14,7 +14,6 @@ #define BOLT_PROFILE_PROFILEYAMLMAPPING_H #include "bolt/Core/BinaryFunction.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/YAMLTraits.h" #include diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h index 20972f3d0b85ae2ac553d1a8ddf85746a6bfaf24..2c482bd2b9ea965ff1bc289ead744bfe3f19737d 100644 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include namespace llvm { diff --git a/bolt/include/bolt/Rewrite/MetadataManager.h b/bolt/include/bolt/Rewrite/MetadataManager.h index efbc74b4daba9de588581719534d0a4e02f787f7..2ff70dbaab3de74d6af6ec14cf89cc84d29c69b4 100644 --- a/bolt/include/bolt/Rewrite/MetadataManager.h +++ b/bolt/include/bolt/Rewrite/MetadataManager.h @@ -11,7 +11,6 @@ #include "bolt/Rewrite/MetadataRewriter.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Error.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 97ab65cd5a4a1ffd26df3e575b8ce2853437405d..826677cd63b22b1a0abef55837f4c254a7b7ee84 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -17,7 +17,6 @@ #include "bolt/Core/Linker.h" #include "bolt/Rewrite/MetadataManager.h" #include "bolt/Utils/NameResolver.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" diff --git a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h index c845cb7f7b214d825929d7019ba1c3e7652e612a..e392029156bcea81c2fbfda93f8584a6109dd480 100644 --- a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h +++ b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h @@ -17,7 +17,6 @@ #include "bolt/Core/Linker.h" #include "llvm/ADT/StringRef.h" -#include #include namespace llvm { diff --git a/bolt/include/bolt/Utils/NameShortener.h b/bolt/include/bolt/Utils/NameShortener.h index 9c7b7ec9ba655c452e9dffa7d17e1177d1628228..fd61235f93c86bcfedd7df514658e588fd142d36 100644 --- a/bolt/include/bolt/Utils/NameShortener.h +++ b/bolt/include/bolt/Utils/NameShortener.h @@ -14,7 +14,6 @@ #define BOLT_UTILS_NAME_SHORTENER_H #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Twine.h" namespace llvm { namespace bolt { diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 267f43f65e206e65d6f65d9579f66ae2772d61a2..47eae964e816c5565697bdc2ef974bdfecdff4dc 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/BinaryEmitter.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Utils/CommandLineOpts.h" -#include "bolt/Utils/NameResolver.h" #include "bolt/Utils/Utils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" @@ -39,7 +38,6 @@ #include #include #include -#include #include using namespace llvm; @@ -162,28 +160,30 @@ BinaryContext::~BinaryContext() { /// Create BinaryContext for a given architecture \p ArchName and /// triple \p TripleName. -Expected> -BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, - std::unique_ptr DwCtx, - JournalingStreams Logger) { +Expected> BinaryContext::createBinaryContext( + Triple TheTriple, StringRef InputFileName, SubtargetFeatures *Features, + bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger) { StringRef ArchName = ""; std::string FeaturesStr = ""; - switch (File->getArch()) { + switch (TheTriple.getArch()) { case llvm::Triple::x86_64: + if (Features) + return createFatalBOLTError( + "x86_64 target does not use SubtargetFeatures"); ArchName = "x86-64"; FeaturesStr = "+nopl"; break; case llvm::Triple::aarch64: + if (Features) + return createFatalBOLTError( + "AArch64 target does not use SubtargetFeatures"); ArchName = "aarch64"; FeaturesStr = "+all"; break; case llvm::Triple::riscv64: { ArchName = "riscv64"; - Expected Features = File->getFeatures(); - - if (auto E = Features.takeError()) - return std::move(E); - + if (!Features) + return createFatalBOLTError("RISCV target needs SubtargetFeatures"); // We rely on relaxation for some transformations (e.g., promoting all calls // to PseudoCALL and then making JITLink relax them). Since the relax // feature is not stored in the object file, we manually enable it. @@ -196,12 +196,11 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, "BOLT-ERROR: Unrecognized machine in ELF file"); } - auto TheTriple = std::make_unique(File->makeTriple()); - const std::string TripleName = TheTriple->str(); + const std::string TripleName = TheTriple.str(); std::string Error; const Target *TheTarget = - TargetRegistry::lookupTarget(std::string(ArchName), *TheTriple, Error); + TargetRegistry::lookupTarget(std::string(ArchName), TheTriple, Error); if (!TheTarget) return createStringError(make_error_code(std::errc::not_supported), Twine("BOLT-ERROR: ", Error)); @@ -240,13 +239,13 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, Twine("BOLT-ERROR: no instruction info for target ", TripleName)); std::unique_ptr Ctx( - new MCContext(*TheTriple, AsmInfo.get(), MRI.get(), STI.get())); + new MCContext(TheTriple, AsmInfo.get(), MRI.get(), STI.get())); std::unique_ptr MOFI( TheTarget->createMCObjectFileInfo(*Ctx, IsPIC)); Ctx->setObjectFileInfo(MOFI.get()); // We do not support X86 Large code model. Change this in the future. bool Large = false; - if (TheTriple->getArch() == llvm::Triple::aarch64) + if (TheTriple.getArch() == llvm::Triple::aarch64) Large = true; unsigned LSDAEncoding = Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4; @@ -273,7 +272,7 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); std::unique_ptr InstructionPrinter( - TheTarget->createMCInstPrinter(*TheTriple, AsmPrinterVariant, *AsmInfo, + TheTarget->createMCInstPrinter(TheTriple, AsmPrinterVariant, *AsmInfo, *MII, *MRI)); if (!InstructionPrinter) return createStringError( @@ -285,8 +284,8 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, TheTarget->createMCCodeEmitter(*MII, *Ctx)); auto BC = std::make_unique( - std::move(Ctx), std::move(DwCtx), std::move(TheTriple), TheTarget, - std::string(TripleName), std::move(MCE), std::move(MOFI), + std::move(Ctx), std::move(DwCtx), std::make_unique(TheTriple), + TheTarget, std::string(TripleName), std::move(MCE), std::move(MOFI), std::move(AsmInfo), std::move(MII), std::move(STI), std::move(InstructionPrinter), std::move(MIA), nullptr, std::move(MRI), std::move(DisAsm), Logger); @@ -296,7 +295,7 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, BC->MAB = std::unique_ptr( BC->TheTarget->createMCAsmBackend(*BC->STI, *BC->MRI, MCTargetOptions())); - BC->setFilename(File->getFileName()); + BC->setFilename(InputFileName); BC->HasFixedLoadAddress = !IsPIC; diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index fdadef9dcd384828db57559b8be5dc76b9d9b29d..1fa96dfaabde819eeb3ff70e5340cc46af5ed49a 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -12,7 +12,6 @@ #include "bolt/Core/BinaryFunction.h" #include "bolt/Core/BinaryBasicBlock.h" -#include "bolt/Core/BinaryDomTree.h" #include "bolt/Core/DynoStats.h" #include "bolt/Core/HashUtilities.h" #include "bolt/Core/MCPlusBuilder.h" @@ -35,6 +34,8 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/GenericDomTreeConstruction.h" +#include "llvm/Support/GenericLoopInfoImpl.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/Regex.h" @@ -3547,7 +3548,7 @@ MCSymbol *BinaryFunction::getSymbolForEntryID(uint64_t EntryID) { if (!isMultiEntry()) return nullptr; - uint64_t NumEntries = 0; + uint64_t NumEntries = 1; if (hasCFG()) { for (BinaryBasicBlock *BB : BasicBlocks) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); @@ -3580,7 +3581,7 @@ uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const { return 0; // Check all secondary entries available as either basic blocks or lables. - uint64_t NumEntries = 0; + uint64_t NumEntries = 1; for (const BinaryBasicBlock *BB : BasicBlocks) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); if (!EntrySymbol) @@ -3589,7 +3590,7 @@ uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const { return NumEntries; ++NumEntries; } - NumEntries = 0; + NumEntries = 1; for (const std::pair &KV : Labels) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(KV.second); if (!EntrySymbol) @@ -4076,12 +4077,17 @@ BinaryFunction::~BinaryFunction() { delete BB; } +void BinaryFunction::constructDomTree() { + BDT.reset(new BinaryDominatorTree); + BDT->recalculate(*this); +} + void BinaryFunction::calculateLoopInfo() { + if (!hasDomTree()) + constructDomTree(); // Discover loops. - BinaryDominatorTree DomTree; - DomTree.recalculate(*this); BLI.reset(new BinaryLoopInfo()); - BLI->analyze(DomTree); + BLI->analyze(getDomTree()); // Traverse discovered loops and add depth and profile information. std::stack St; diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index 354fe5059443cca6d56a3dde6a1fe0948a666355..c4b0b251c1201fcf9f27454b3b26fc861d5235bb 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -22,7 +22,6 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" #include "llvm/Support/LEB128.h" #include diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp index a75016ede3090d5b6f77897bab9120d38e8c6057..a987a103a08b93ad7311fc81efb752ca15bac303 100644 --- a/bolt/lib/Core/DebugData.cpp +++ b/bolt/lib/Core/DebugData.cpp @@ -13,7 +13,6 @@ #include "bolt/Core/DebugData.h" #include "bolt/Core/BinaryContext.h" #include "bolt/Core/DIEBuilder.h" -#include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/Utils.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/DIE.h" @@ -23,7 +22,6 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectStreamer.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/LEB128.h" @@ -32,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/bolt/lib/Core/FunctionLayout.cpp b/bolt/lib/Core/FunctionLayout.cpp index 27e40de94be660f0ffbe9b5f6ddacb5b0393b0ac..73f4d5247d9ac06092601f1e931055223b83c00d 100644 --- a/bolt/lib/Core/FunctionLayout.cpp +++ b/bolt/lib/Core/FunctionLayout.cpp @@ -1,12 +1,17 @@ +//===- bolt/Core/FunctionLayout.cpp - Fragmented Function Layout -*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Core/FunctionLayout.h" -#include "bolt/Core/BinaryFunction.h" +#include "bolt/Core/BinaryBasicBlock.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/edit_distance.h" #include -#include -#include #include -#include using namespace llvm; using namespace bolt; diff --git a/bolt/lib/Core/HashUtilities.cpp b/bolt/lib/Core/HashUtilities.cpp index d40159b2e216d90f97b510886b7d79e468f895be..c4c67bd68198b6681b4dc95b7d3f0cb43caae5df 100644 --- a/bolt/lib/Core/HashUtilities.cpp +++ b/bolt/lib/Core/HashUtilities.cpp @@ -12,7 +12,6 @@ #include "bolt/Core/HashUtilities.h" #include "bolt/Core/BinaryContext.h" -#include "bolt/Core/BinaryFunction.h" #include "llvm/MC/MCInstPrinter.h" namespace llvm { diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp index 5b14ad5cdb880f307c12d4e72d959a9a9b432a55..7ff7a2288451c844f360f9b24878d6d335be85ee 100644 --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -12,15 +12,16 @@ #include "bolt/Core/MCPlusBuilder.h" #include "bolt/Core/MCPlus.h" +#include "bolt/Utils/CommandLineOpts.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include -#include #define DEBUG_TYPE "mcplus" @@ -28,6 +29,13 @@ using namespace llvm; using namespace bolt; using namespace MCPlus; +namespace opts { +cl::opt + TerminalTrap("terminal-trap", + cl::desc("Assume that execution stops at trap instruction"), + cl::init(true), cl::Hidden, cl::cat(BoltCategory)); +} + bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B, CompFuncTy Comp) const { if (A.getOpcode() != B.getOpcode()) @@ -121,6 +129,11 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B, llvm_unreachable("target-specific expressions are unsupported"); } +bool MCPlusBuilder::isTerminator(const MCInst &Inst) const { + return Analysis->isTerminator(Inst) || + (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()); +} + void MCPlusBuilder::setTailCall(MCInst &Inst) const { assert(!hasAnnotation(Inst, MCAnnotation::kTailCall)); setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true); diff --git a/bolt/lib/Passes/CMOVConversion.cpp b/bolt/lib/Passes/CMOVConversion.cpp index 2492ff21794634bd35bc4f7f03c9970bccf69739..cdd99b55207e0b6e92a1f0eab59f5082f57bd614 100644 --- a/bolt/lib/Passes/CMOVConversion.cpp +++ b/bolt/lib/Passes/CMOVConversion.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/PostOrderIterator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include #define DEBUG_TYPE "cmov" diff --git a/bolt/lib/Passes/FixRISCVCallsPass.cpp b/bolt/lib/Passes/FixRISCVCallsPass.cpp index 83c745facb290b70209a3243fdf4a553ca49f3e4..9011ef303a80ef1922f4f772d5e43f6a4f9f1b05 100644 --- a/bolt/lib/Passes/FixRISCVCallsPass.cpp +++ b/bolt/lib/Passes/FixRISCVCallsPass.cpp @@ -1,3 +1,11 @@ +//===- bolt/Passes/FixRISCVCallsPass.cpp ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Passes/FixRISCVCallsPass.h" #include "bolt/Core/ParallelUtilities.h" diff --git a/bolt/lib/Passes/FixRelaxationPass.cpp b/bolt/lib/Passes/FixRelaxationPass.cpp index a49fb9894e808cccdf0f222a51e6f354db2c0f8d..7c970e464a94e361626dac979546e0564f25a012 100644 --- a/bolt/lib/Passes/FixRelaxationPass.cpp +++ b/bolt/lib/Passes/FixRelaxationPass.cpp @@ -1,3 +1,11 @@ +//===- bolt/Passes/FixRelaxationPass.cpp ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Passes/FixRelaxationPass.h" #include "bolt/Core/ParallelUtilities.h" diff --git a/bolt/lib/Passes/FrameOptimizer.cpp b/bolt/lib/Passes/FrameOptimizer.cpp index fb5f8eafa5cf846e576bbfff6b4f7b1ddbec5b06..8461225e1819c169023ab1f31fb34e6ab619d08e 100644 --- a/bolt/lib/Passes/FrameOptimizer.cpp +++ b/bolt/lib/Passes/FrameOptimizer.cpp @@ -20,7 +20,6 @@ #include "bolt/Utils/CommandLineOpts.h" #include "llvm/Support/Timer.h" #include -#include #define DEBUG_TYPE "fop" diff --git a/bolt/lib/Passes/Hugify.cpp b/bolt/lib/Passes/Hugify.cpp index b77356153bfd8caf5f1e01b27c29547c3b45a704..1ac1b08573b86954f01ef3de3a5c4db2f732b984 100644 --- a/bolt/lib/Passes/Hugify.cpp +++ b/bolt/lib/Passes/Hugify.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/Hugify.h" -#include "llvm/Support/CommandLine.h" #define DEBUG_TYPE "bolt-hugify" diff --git a/bolt/lib/Passes/Inliner.cpp b/bolt/lib/Passes/Inliner.cpp index a3b2017aa32aa82dfc3dec7043bf2f9385d892d5..84e7d97067b0cf7bde944c7a139e4c5246a0ddf7 100644 --- a/bolt/lib/Passes/Inliner.cpp +++ b/bolt/lib/Passes/Inliner.cpp @@ -27,7 +27,6 @@ #include "bolt/Passes/Inliner.h" #include "bolt/Core/MCPlus.h" #include "llvm/Support/CommandLine.h" -#include #define DEBUG_TYPE "bolt-inliner" diff --git a/bolt/lib/Passes/ShrinkWrapping.cpp b/bolt/lib/Passes/ShrinkWrapping.cpp index c9706500758d1f223f5d71de45e310755f021f78..176321c58dc903fdb62e76a237f31a15c7ffba12 100644 --- a/bolt/lib/Passes/ShrinkWrapping.cpp +++ b/bolt/lib/Passes/ShrinkWrapping.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/ShrinkWrapping.h" -#include "bolt/Core/MCPlus.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/MCF.h" #include "bolt/Utils/CommandLineOpts.h" diff --git a/bolt/lib/Passes/SplitFunctions.cpp b/bolt/lib/Passes/SplitFunctions.cpp index cdbb2a15f667c6b7dc2a06674028e583bbb27aaf..f9e634d15a97244c58adf185c0ea4ec80017079c 100644 --- a/bolt/lib/Passes/SplitFunctions.cpp +++ b/bolt/lib/Passes/SplitFunctions.cpp @@ -17,7 +17,6 @@ #include "bolt/Core/ParallelUtilities.h" #include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Passes/TailDuplication.cpp b/bolt/lib/Passes/TailDuplication.cpp index 2163e3a6a008362586fc484efb97cfad71a43b52..463ea49527fa6cd5696ea1fde973f6e5e8c7e10e 100644 --- a/bolt/lib/Passes/TailDuplication.cpp +++ b/bolt/lib/Passes/TailDuplication.cpp @@ -13,9 +13,9 @@ #include "bolt/Passes/TailDuplication.h" #include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCRegisterInfo.h" -#include #include +#include #define DEBUG_TYPE "taildup" diff --git a/bolt/lib/Passes/ValidateInternalCalls.cpp b/bolt/lib/Passes/ValidateInternalCalls.cpp index 54ae621159cfa3bcd1587d4a4a680eb53089c006..88df2e5b59f3895497312e1f8536ed8358694f1c 100644 --- a/bolt/lib/Passes/ValidateInternalCalls.cpp +++ b/bolt/lib/Passes/ValidateInternalCalls.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/FrameAnalysis.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCInstPrinter.h" #include #include diff --git a/bolt/lib/Profile/CMakeLists.txt b/bolt/lib/Profile/CMakeLists.txt index 3a31a9cc191971dc487e1d54ade64c5b08f7565e..045ac47edb950bb1ebc99fd4dc56fb38cc652667 100644 --- a/bolt/lib/Profile/CMakeLists.txt +++ b/bolt/lib/Profile/CMakeLists.txt @@ -3,7 +3,6 @@ add_llvm_library(LLVMBOLTProfile DataAggregator.cpp DataReader.cpp Heatmap.cpp - ProfileReaderBase.cpp StaleProfileMatching.cpp YAMLProfileReader.cpp YAMLProfileWriter.cpp diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index aa21eb121ad65256695dfff0318058879c0b203c..67f357fe4d3f0c42f704a52ca163e328652e7136 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -18,7 +18,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" -#include #undef DEBUG_TYPE #define DEBUG_TYPE "bolt-prof" diff --git a/bolt/lib/Profile/Heatmap.cpp b/bolt/lib/Profile/Heatmap.cpp index 13541f6f6a4b64200429bf02ce2885d1e373835a..210a5cc98c1041035e7eb470d6a62fa1b2739873 100644 --- a/bolt/lib/Profile/Heatmap.cpp +++ b/bolt/lib/Profile/Heatmap.cpp @@ -10,7 +10,6 @@ #include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" diff --git a/bolt/lib/Profile/ProfileReaderBase.cpp b/bolt/lib/Profile/ProfileReaderBase.cpp deleted file mode 100644 index ee6166b1da369ec9b063481a1ca0e42f49af350a..0000000000000000000000000000000000000000 --- a/bolt/lib/Profile/ProfileReaderBase.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===- bolt/Profile/ProfileReaderBase.cpp ---------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Interface to be implemented by all profile readers. -// -//===----------------------------------------------------------------------===// - -#include "bolt/Profile/ProfileReaderBase.h" - -namespace llvm { -namespace bolt { - -bool ProfileReaderBase::mayHaveProfileData(const BinaryFunction &BF) { - return true; -} - -} // namespace bolt -} // namespace llvm diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index 6fcc4a956fa1a19400f9159c38d22686816102c7..0f082086c1fc24810d97e2a078c6648eda753585 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -25,6 +25,25 @@ extern llvm::cl::opt ProfileUseDFS; namespace llvm { namespace bolt { +/// Set CallSiteInfo destination fields from \p Symbol and return a target +/// BinaryFunction for that symbol. +static const BinaryFunction *setCSIDestination(const BinaryContext &BC, + yaml::bolt::CallSiteInfo &CSI, + const MCSymbol *Symbol) { + CSI.DestId = 0; // designated for unknown functions + CSI.EntryDiscriminator = 0; + if (Symbol) { + uint64_t EntryID = 0; + if (const BinaryFunction *const Callee = + BC.getFunctionForSymbol(Symbol, &EntryID)) { + CSI.DestId = Callee->getFunctionNumber(); + CSI.EntryDiscriminator = EntryID; + return Callee; + } + } + return nullptr; +} + yaml::bolt::BinaryFunctionProfile YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) { yaml::bolt::BinaryFunctionProfile YamlBF; @@ -79,31 +98,20 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) { continue; for (const IndirectCallProfile &CSP : ICSP.get()) { StringRef TargetName = ""; - CSI.DestId = 0; // designated for unknown functions - CSI.EntryDiscriminator = 0; - if (CSP.Symbol) { - const BinaryFunction *Callee = BC.getFunctionForSymbol(CSP.Symbol); - if (Callee) { - CSI.DestId = Callee->getFunctionNumber(); - TargetName = Callee->getOneName(); - } - } + const BinaryFunction *Callee = setCSIDestination(BC, CSI, CSP.Symbol); + if (Callee) + TargetName = Callee->getOneName(); CSI.Count = CSP.Count; CSI.Mispreds = CSP.Mispreds; CSTargets.emplace_back(TargetName, CSI); } } else { // direct call or a tail call - uint64_t EntryID = 0; - CSI.DestId = 0; StringRef TargetName = ""; const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr); const BinaryFunction *const Callee = - BC.getFunctionForSymbol(CalleeSymbol, &EntryID); - if (Callee) { - CSI.DestId = Callee->getFunctionNumber(); - CSI.EntryDiscriminator = EntryID; + setCSIDestination(BC, CSI, CalleeSymbol); + if (Callee) TargetName = Callee->getOneName(); - } auto getAnnotationWithDefault = [&](const MCInst &Inst, StringRef Ann) { return BC.MIB->getAnnotationWithDefault(Instr, Ann, 0ull); diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index 601a2105fc264f7af2168528d29af291991de27f..feeba89a40dc4d03c48b3836c0e27fa5f68903d7 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/DynoStats.h" #include "bolt/Core/ParallelUtilities.h" #include "bolt/Rewrite/RewriteInstance.h" -#include "bolt/Utils/Utils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -1685,7 +1684,7 @@ namespace { std::unique_ptr createDwarfOnlyBC(const object::ObjectFile &File) { return cantFail(BinaryContext::createBinaryContext( - &File, false, + File.makeTriple(), File.getFileName(), nullptr, false, DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, "", WithColor::defaultErrorHandler, WithColor::defaultWarningHandler), diff --git a/bolt/lib/Rewrite/JITLinkLinker.cpp b/bolt/lib/Rewrite/JITLinkLinker.cpp index 66e129bf1d05db7a8136a6c1ae819e4d69315ae5..be8f9dd03467e17d297b26e94bafbbabcde68c1c 100644 --- a/bolt/lib/Rewrite/JITLinkLinker.cpp +++ b/bolt/lib/Rewrite/JITLinkLinker.cpp @@ -5,9 +5,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #include "bolt/Rewrite/JITLinkLinker.h" +#include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryData.h" -#include "bolt/Rewrite/RewriteInstance.h" +#include "bolt/Core/BinarySection.h" #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index 42df9681727590044205e3031fcc293f1b449752..d96199e020d31a159c9505d846a3985d9df2223c 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -212,6 +212,11 @@ class LinuxKernelRewriter final : public MetadataRewriter { /// Size of bug_entry struct. static constexpr size_t BUG_TABLE_ENTRY_SIZE = 12; + /// List of bug entries per function. + using FunctionBugListType = + DenseMap>; + FunctionBugListType FunctionBugList; + /// .pci_fixup section. ErrorOr PCIFixupSection = std::errc::bad_address; static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16; @@ -254,7 +259,9 @@ class LinuxKernelRewriter final : public MetadataRewriter { Error readParaInstructions(); Error rewriteParaInstructions(); + /// __bug_table section handling. Error readBugTable(); + Error rewriteBugTable(); /// Do no process functions containing instruction annotated with /// \p Annotation. @@ -339,6 +346,9 @@ public: if (Error E = rewriteStaticKeysJumpTable()) return E; + if (Error E = rewriteBugTable()) + return E; + return Error::success(); } @@ -1164,15 +1174,17 @@ Error LinuxKernelRewriter::rewriteParaInstructions() { } /// Process __bug_table section. -/// This section contains information useful for kernel debugging. +/// This section contains information useful for kernel debugging, mostly +/// utilized by WARN()/WARN_ON() macros and deprecated BUG()/BUG_ON(). +/// /// Each entry in the section is a struct bug_entry that contains a pointer to /// the ud2 instruction corresponding to the bug, corresponding file name (both /// pointers use PC relative offset addressing), line number, and flags. /// The definition of the struct bug_entry can be found in -/// `include/asm-generic/bug.h` -/// -/// NB: find_bug() uses linear search to match an address to an entry in the bug -/// table. Hence there is no need to sort entries when rewriting the table. +/// `include/asm-generic/bug.h`. The first entry in the struct is an instruction +/// address encoded as a PC-relative offset. In theory, it could be an absolute +/// address if CONFIG_GENERIC_BUG_RELATIVE_POINTERS is not set, but in practice +/// the kernel code relies on it being a relative offset on x86-64. Error LinuxKernelRewriter::readBugTable() { BugTableSection = BC.getUniqueSectionByName("__bug_table"); if (!BugTableSection) @@ -1215,6 +1227,8 @@ Error LinuxKernelRewriter::readBugTable() { " referenced by bug table entry %d", InstAddress, EntryID); BC.MIB->addAnnotation(*Inst, "BugEntry", EntryID); + + FunctionBugList[BF].push_back(EntryID); } } @@ -1223,6 +1237,52 @@ Error LinuxKernelRewriter::readBugTable() { return Error::success(); } +/// find_bug() uses linear search to match an address to an entry in the bug +/// table. Hence, there is no need to sort entries when rewriting the table. +/// When we need to erase an entry, we set its instruction address to zero. +Error LinuxKernelRewriter::rewriteBugTable() { + if (!BugTableSection) + return Error::success(); + + for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { + if (!BC.shouldEmit(BF)) + continue; + + if (!FunctionBugList.count(&BF)) + continue; + + // Bugs that will be emitted for this function. + DenseSet EmittedIDs; + for (BinaryBasicBlock &BB : BF) { + for (MCInst &Inst : BB) { + if (!BC.MIB->hasAnnotation(Inst, "BugEntry")) + continue; + const uint32_t ID = BC.MIB->getAnnotationAs(Inst, "BugEntry"); + EmittedIDs.insert(ID); + + // Create a relocation entry for this bug entry. + MCSymbol *Label = + BC.MIB->getOrCreateInstLabel(Inst, "__BUG_", BC.Ctx.get()); + const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; + BugTableSection->addRelocation(EntryOffset, Label, ELF::R_X86_64_PC32, + /*Addend*/ 0); + } + } + + // Clear bug entries that were not emitted for this function, e.g. as a + // result of DCE, but setting their instruction address to zero. + for (const uint32_t ID : FunctionBugList[&BF]) { + if (!EmittedIDs.count(ID)) { + const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; + BugTableSection->addRelocation(EntryOffset, nullptr, ELF::R_X86_64_PC32, + /*Addend*/ 0); + } + } + } + + return Error::success(); +} + /// The kernel can replace certain instruction sequences depending on hardware /// it is running on and features specified during boot time. The information /// about alternative instruction sequences is stored in .altinstructions diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp index 0970a0507ebe8803e6ae85789b8ec10618465211..172cb640bf911a96e11c3112b007cd1636479867 100644 --- a/bolt/lib/Rewrite/MachORewriteInstance.cpp +++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp @@ -18,6 +18,7 @@ #include "bolt/Rewrite/BinaryPassManager.h" #include "bolt/Rewrite/ExecutableFileMemoryManager.h" #include "bolt/Rewrite/JITLinkLinker.h" +#include "bolt/Rewrite/RewriteInstance.h" #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" #include "bolt/Utils/Utils.h" #include "llvm/MC/MCObjectStreamer.h" @@ -54,37 +55,6 @@ extern cl::opt Verbosity; namespace llvm { namespace bolt { -extern MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *, - const MCInstrInfo *, - const MCRegisterInfo *, - const MCSubtargetInfo *); -extern MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, - const MCInstrInfo *, - const MCRegisterInfo *, - const MCSubtargetInfo *); - -namespace { - -MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, - const MCInstrAnalysis *Analysis, - const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo, - const MCSubtargetInfo *STI) { -#ifdef X86_AVAILABLE - if (Arch == Triple::x86_64) - return createX86MCPlusBuilder(Analysis, Info, RegInfo, STI); -#endif - -#ifdef AARCH64_AVAILABLE - if (Arch == Triple::aarch64) - return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); -#endif - - llvm_unreachable("architecture unsupported by MCPlusBuilder"); -} - -} // anonymous namespace - #define DEBUG_TYPE "bolt" Expected> @@ -103,7 +73,8 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile, : InputFile(InputFile), ToolPath(ToolPath) { ErrorAsOutParameter EAO(&Err); auto BCOrErr = BinaryContext::createBinaryContext( - InputFile, /* IsPIC */ true, DWARFContext::create(*InputFile), + InputFile->makeTriple(), InputFile->getFileName(), nullptr, + /* IsPIC */ true, DWARFContext::create(*InputFile), {llvm::outs(), llvm::errs()}); if (Error E = BCOrErr.takeError()) { Err = std::move(E); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 2ead51ff6a1286ffbc2a0c7b873c532c4aa4ea01..0c8ee0d417233bb5617cb7a9fc2ddfa59a3dd710 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -84,6 +84,7 @@ extern cl::opt JumpTables; extern cl::opt KeepNops; extern cl::list ReorderData; extern cl::opt ReorderFunctions; +extern cl::opt TerminalTrap; extern cl::opt TimeBuild; cl::opt AllowStripped("allow-stripped", @@ -267,6 +268,10 @@ namespace bolt { extern const char *BoltRevision; +// Weird location for createMCPlusBuilder, but this is here to avoid a +// cyclic dependency of libCore (its natural place) and libTarget. libRewrite +// can depend on libTarget, but not libCore. Since libRewrite is the only +// user of this function, we define it here. MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, @@ -344,8 +349,21 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc, Stderr.SetUnbuffered(); LLVM_DEBUG(dbgs().SetUnbuffered()); + // Read RISCV subtarget features from input file + std::unique_ptr Features; + Triple TheTriple = File->makeTriple(); + if (TheTriple.getArch() == llvm::Triple::riscv64) { + Expected FeaturesOrErr = File->getFeatures(); + if (auto E = FeaturesOrErr.takeError()) { + Err = std::move(E); + return; + } else { + Features.reset(new SubtargetFeatures(*FeaturesOrErr)); + } + } + auto BCOrErr = BinaryContext::createBinaryContext( - File, IsPIC, + TheTriple, File->getFileName(), Features.get(), IsPIC, DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, opts::DWPPathName, WithColor::defaultErrorHandler, @@ -2033,8 +2051,14 @@ void RewriteInstance::adjustCommandLineOptions() { if (opts::Lite) BC->outs() << "BOLT-INFO: enabling lite mode\n"; - if (BC->IsLinuxKernel && !opts::KeepNops.getNumOccurrences()) - opts::KeepNops = true; + if (BC->IsLinuxKernel) { + if (!opts::KeepNops.getNumOccurrences()) + opts::KeepNops = true; + + // Linux kernel may resume execution after a trap instruction in some cases. + if (!opts::TerminalTrap.getNumOccurrences()) + opts::TerminalTrap = false; + } } namespace { diff --git a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp index b6fc49d3f5d671b8a0205961f2aace7e39253418..d114d70f2d37668df5c39cf31a154126e537a109 100644 --- a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp +++ b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp @@ -11,10 +11,9 @@ //===----------------------------------------------------------------------===// #include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h" -#include "bolt/Core/BinaryFunction.h" +#include "bolt/Core/BinaryContext.h" #include "bolt/Core/Linker.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/Support/Alignment.h" #include "llvm/Support/CommandLine.h" using namespace llvm; diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index ab9623d5c51b287f4a1e6e58e1ff0784eb6508a7..74f2f0aae91e667d12d6edff81f371c1e1044bfe 100644 --- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -16,10 +16,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "mcplus" diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 15f95f8217776514ffc7253f0da7b840607a6668..8b1894953f3757f036aa2d7e58f2f033861b0efd 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -211,13 +211,6 @@ public: return false; } - // FIXME: For compatibility with old LLVM only! - bool isTerminator(const MCInst &Inst) const override { - unsigned Opcode = Inst.getOpcode(); - return Info->get(Opcode).isTerminator() || X86::isUD1(Opcode) || - X86::isUD2(Opcode); - } - bool isIndirectCall(const MCInst &Inst) const override { return isCall(Inst) && ((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(0).isReg()); diff --git a/bolt/test/X86/linux-bug-table.s b/bolt/test/X86/linux-bug-table.s index e8de2fb6cba79ddab8061705700f263200c0701e..63f70a0b35d9fe59c85a68998a019a2175a74c46 100644 --- a/bolt/test/X86/linux-bug-table.s +++ b/bolt/test/X86/linux-bug-table.s @@ -1,6 +1,7 @@ # REQUIRES: system-linux -## Check that BOLT correctly parses the Linux kernel __bug_table section. +## Check that BOLT correctly parses and updates the Linux kernel __bug_table +## section. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ @@ -8,7 +9,13 @@ ## Verify bug entry bindings to instructions. -# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized --print-only=_start -o %t.out \ +# RUN: --eliminate-unreachable=1 --bolt-info=0 | FileCheck %s + +## Verify bug entry bindings again after unreachable code elimination. + +# RUN: llvm-bolt %t.out -o %t.out.1 --print-only=_start --print-normalized \ +# RUN: |& FileCheck --check-prefix=CHECK-REOPT %s # CHECK: BOLT-INFO: Linux kernel binary detected # CHECK: BOLT-INFO: parsed 2 bug table entries @@ -17,18 +24,26 @@ .globl _start .type _start, %function _start: -# CHECK: Binary Function "_start" - nop + jmp .L1 .L0: ud2 # CHECK: ud2 # CHECK-SAME: BugEntry: 1 - nop .L1: ud2 # CHECK: ud2 # CHECK-SAME: BugEntry: 2 + +## Only the second entry should remain after the first pass. + +# CHECK-REOPT: ud2 +# CHECK-REOPT-SAME: BugEntry: 2 + ret +## The return instruction is reachable only via preceding ud2. Test that it is +## treated as a reachable instruction in the Linux kernel mode. + +# CHECK-REOPT-NEXT: ret .size _start, .-_start diff --git a/bolt/test/X86/yaml-secondary-entry-discriminator.s b/bolt/test/X86/yaml-secondary-entry-discriminator.s new file mode 100644 index 0000000000000000000000000000000000000000..43c2e2a7f05549289293a39808762cc5a68cc285 --- /dev/null +++ b/bolt/test/X86/yaml-secondary-entry-discriminator.s @@ -0,0 +1,74 @@ +# This reproduces a bug with BOLT setting incorrect discriminator for +# secondary entry points in YAML profile. + +# REQUIRES: system-linux +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: link_fdata %s %t.o %t.fdata +# RUN: llvm-strip --strip-unneeded %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata -w %t.yaml --print-profile \ +# RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG +# RUN: FileCheck %s -input-file %t.yaml +# CHECK: - name: main +# CHECK-NEXT: fid: 2 +# CHECK-NEXT: hash: 0xADF270D550151185 +# CHECK-NEXT: exec: 0 +# CHECK-NEXT: nblocks: 4 +# CHECK-NEXT: blocks: +# CHECK: - bid: 1 +# CHECK-NEXT: insns: 1 +# CHECK-NEXT: hash: 0x36A303CBA4360014 +# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1 } ] +# CHECK: - bid: 2 +# CHECK-NEXT: insns: 5 +# CHECK-NEXT: hash: 0x8B2F5747CD0019 +# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1, mis: 1 } ] + +# Make sure that the profile is attached correctly +# RUN: llvm-bolt %t.exe -o %t.out --data %t.yaml --print-profile \ +# RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG + +# CHECK-CFG: Binary Function "main" after attaching profile { +# CHECK-CFG: callq secondary_entry # Offset: [[#]] # Count: 1 +# CHECK-CFG: callq *%rax # Offset: [[#]] # CallProfile: 1 (1 misses) : +# CHECK-CFG-NEXT: { secondary_entry: 1 (1 misses) } + +.globl func +.type func, @function +func: +# FDATA: 0 [unknown] 0 1 func 0 1 0 + .cfi_startproc + pushq %rbp + movq %rsp, %rbp +.globl secondary_entry +secondary_entry: + popq %rbp + retq + nopl (%rax) + .cfi_endproc + .size func, .-func + +.globl main +.type main, @function +main: + .cfi_startproc + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + movl $0, -4(%rbp) + testq %rax, %rax + jne Lindcall +Lcall: + call secondary_entry +# FDATA: 1 main #Lcall# 1 secondary_entry 0 1 1 +Lindcall: + callq *%rax +# FDATA: 1 main #Lindcall# 1 secondary_entry 0 1 1 + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +# For relocations against .text + call exit + .cfi_endproc + .size main, .-main diff --git a/bolt/tools/bat-dump/bat-dump.cpp b/bolt/tools/bat-dump/bat-dump.cpp index 2e9b26cc137a8621eb2faeebdfca47dbfb031976..709eb076bca2da7976a0e9c6199f1c9c7b9398a6 100644 --- a/bolt/tools/bat-dump/bat-dump.cpp +++ b/bolt/tools/bat-dump/bat-dump.cpp @@ -1,9 +1,16 @@ +//===- bolt/tools/bat-dump/bat-dump.cpp - BAT dumper utility --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Profile/BoltAddressTranslation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/Error.h" @@ -18,7 +25,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" -#include #include #include #include @@ -27,7 +33,6 @@ #include #include #include -#include using namespace llvm; using namespace bolt; diff --git a/bolt/tools/heatmap/heatmap.cpp b/bolt/tools/heatmap/heatmap.cpp index 9b190dd288b279deb411b63500ef909e4cc667a9..3bb9f2ce7491db6f1dbf08cbb2dec6cdb92b3ea9 100644 --- a/bolt/tools/heatmap/heatmap.cpp +++ b/bolt/tools/heatmap/heatmap.cpp @@ -1,4 +1,11 @@ -#include "bolt/Profile/DataAggregator.h" +//===- bolt/tools/heatmap/heatmap.cpp - Profile heatmap visualization tool ===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/CommandLineOpts.h" #include "llvm/MC/TargetRegistry.h" @@ -6,7 +13,8 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Program.h" #include "llvm/Support/TargetSelect.h" using namespace llvm; diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp index 08619eccdd75ab765db3951a565466218313b64d..cfec72a34a59f24eebaf3e09b8de13e3794c8e20 100644 --- a/bolt/unittests/Core/BinaryContext.cpp +++ b/bolt/unittests/Core/BinaryContext.cpp @@ -1,7 +1,14 @@ +//===- bolt/unittest/Core/BinaryContext.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Core/BinaryContext.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" @@ -40,8 +47,8 @@ protected: void initializeBOLT() { BC = cantFail(BinaryContext::createBinaryContext( - ObjFile.get(), true, DWARFContext::create(*ObjFile.get()), - {llvm::outs(), llvm::errs()})); + ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); } diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp index daf9f392b8228198fcf77807ef1e5a9a557288a5..62f3aaab4a725cbcfcfb445bc44ffc001152fc70 100644 --- a/bolt/unittests/Core/MCPlusBuilder.cpp +++ b/bolt/unittests/Core/MCPlusBuilder.cpp @@ -1,3 +1,11 @@ +//===- bolt/unittest/Core/MCPlusBuilder.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #ifdef AARCH64_AVAILABLE #include "AArch64Subtarget.h" #endif // AARCH64_AVAILABLE @@ -11,7 +19,6 @@ #include "bolt/Rewrite/RewriteInstance.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" @@ -50,8 +57,8 @@ protected: void initializeBolt() { BC = cantFail(BinaryContext::createBinaryContext( - ObjFile.get(), true, DWARFContext::create(*ObjFile.get()), - {llvm::outs(), llvm::errs()})); + ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); BC->initializeTarget(std::unique_ptr( createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(), diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 5728c9970fb65d5334225cce3d3db69e013bdf62..dd772d692025481a9eae7475168f96ec29baf6fe 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangTidyReadabilityModule DeleteNullPointerCheck.cpp DuplicateIncludeCheck.cpp ElseAfterReturnCheck.cpp + EnumInitialValueCheck.cpp FunctionCognitiveComplexityCheck.cpp FunctionSizeCheck.cpp IdentifierLengthCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f2841c32259a254a9b2821e6382e6b51714e177 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp @@ -0,0 +1,200 @@ +//===--- EnumInitialValueCheck.cpp - clang-tidy ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "EnumInitialValueCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/Decl.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +static bool isNoneEnumeratorsInitialized(const EnumDecl &Node) { + return llvm::all_of(Node.enumerators(), [](const EnumConstantDecl *ECD) { + return ECD->getInitExpr() == nullptr; + }); +} + +static bool isOnlyFirstEnumeratorInitialized(const EnumDecl &Node) { + bool IsFirst = true; + for (const EnumConstantDecl *ECD : Node.enumerators()) { + if ((IsFirst && ECD->getInitExpr() == nullptr) || + (!IsFirst && ECD->getInitExpr() != nullptr)) + return false; + IsFirst = false; + } + return !IsFirst; +} + +static bool areAllEnumeratorsInitialized(const EnumDecl &Node) { + return llvm::all_of(Node.enumerators(), [](const EnumConstantDecl *ECD) { + return ECD->getInitExpr() != nullptr; + }); +} + +/// Check if \p Enumerator is initialized with a (potentially negated) \c +/// IntegerLiteral. +static bool isInitializedByLiteral(const EnumConstantDecl *Enumerator) { + const Expr *const Init = Enumerator->getInitExpr(); + if (!Init) + return false; + return Init->isIntegerConstantExpr(Enumerator->getASTContext()); +} + +static void cleanInitialValue(DiagnosticBuilder &Diag, + const EnumConstantDecl *ECD, + const SourceManager &SM, + const LangOptions &LangOpts) { + const SourceRange InitExprRange = ECD->getInitExpr()->getSourceRange(); + if (InitExprRange.isInvalid() || InitExprRange.getBegin().isMacroID() || + InitExprRange.getEnd().isMacroID()) + return; + std::optional EqualToken = utils::lexer::findNextTokenSkippingComments( + ECD->getLocation(), SM, LangOpts); + if (!EqualToken.has_value() || + EqualToken.value().getKind() != tok::TokenKind::equal) + return; + const SourceLocation EqualLoc{EqualToken->getLocation()}; + if (EqualLoc.isInvalid() || EqualLoc.isMacroID()) + return; + Diag << FixItHint::CreateRemoval(EqualLoc) + << FixItHint::CreateRemoval(InitExprRange); + return; +} + +namespace { + +AST_MATCHER(EnumDecl, isMacro) { + SourceLocation Loc = Node.getBeginLoc(); + return Loc.isMacroID(); +} + +AST_MATCHER(EnumDecl, hasConsistentInitialValues) { + return isNoneEnumeratorsInitialized(Node) || + isOnlyFirstEnumeratorInitialized(Node) || + areAllEnumeratorsInitialized(Node); +} + +AST_MATCHER(EnumDecl, hasZeroInitialValueForFirstEnumerator) { + const EnumDecl::enumerator_range Enumerators = Node.enumerators(); + if (Enumerators.empty()) + return false; + const EnumConstantDecl *ECD = *Enumerators.begin(); + return isOnlyFirstEnumeratorInitialized(Node) && + isInitializedByLiteral(ECD) && ECD->getInitVal().isZero(); +} + +/// Excludes bitfields because enumerators initialized with the result of a +/// bitwise operator on enumeration values or any other expr that is not a +/// potentially negative integer literal. +/// Enumerations where it is not directly clear if they are used with +/// bitmask, evident when enumerators are only initialized with (potentially +/// negative) integer literals, are ignored. This is also the case when all +/// enumerators are powers of two (e.g., 0, 1, 2). +AST_MATCHER(EnumDecl, hasSequentialInitialValues) { + const EnumDecl::enumerator_range Enumerators = Node.enumerators(); + if (Enumerators.empty()) + return false; + const EnumConstantDecl *const FirstEnumerator = *Node.enumerator_begin(); + llvm::APSInt PrevValue = FirstEnumerator->getInitVal(); + if (!isInitializedByLiteral(FirstEnumerator)) + return false; + bool AllEnumeratorsArePowersOfTwo = true; + for (const EnumConstantDecl *Enumerator : llvm::drop_begin(Enumerators)) { + const llvm::APSInt NewValue = Enumerator->getInitVal(); + if (NewValue != ++PrevValue) + return false; + if (!isInitializedByLiteral(Enumerator)) + return false; + PrevValue = NewValue; + AllEnumeratorsArePowersOfTwo &= NewValue.isPowerOf2(); + } + return !AllEnumeratorsArePowersOfTwo; +} + +} // namespace + +EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + AllowExplicitZeroFirstInitialValue( + Options.get("AllowExplicitZeroFirstInitialValue", true)), + AllowExplicitSequentialInitialValues( + Options.get("AllowExplicitSequentialInitialValues", true)) {} + +void EnumInitialValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "AllowExplicitZeroFirstInitialValue", + AllowExplicitZeroFirstInitialValue); + Options.store(Opts, "AllowExplicitSequentialInitialValues", + AllowExplicitSequentialInitialValues); +} + +void EnumInitialValueCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + enumDecl(unless(isMacro()), unless(hasConsistentInitialValues())) + .bind("inconsistent"), + this); + if (!AllowExplicitZeroFirstInitialValue) + Finder->addMatcher( + enumDecl(hasZeroInitialValueForFirstEnumerator()).bind("zero_first"), + this); + if (!AllowExplicitSequentialInitialValues) + Finder->addMatcher(enumDecl(unless(isMacro()), hasSequentialInitialValues()) + .bind("sequential"), + this); +} + +void EnumInitialValueCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Enum = Result.Nodes.getNodeAs("inconsistent")) { + DiagnosticBuilder Diag = + diag(Enum->getBeginLoc(), + "inital values in enum %0 are not consistent, consider explicit " + "initialization of all, none or only the first enumerator") + << Enum; + for (const EnumConstantDecl *ECD : Enum->enumerators()) + if (ECD->getInitExpr() == nullptr) { + const SourceLocation EndLoc = Lexer::getLocForEndOfToken( + ECD->getLocation(), 0, *Result.SourceManager, getLangOpts()); + if (EndLoc.isMacroID()) + continue; + llvm::SmallString<8> Str{" = "}; + ECD->getInitVal().toString(Str); + Diag << FixItHint::CreateInsertion(EndLoc, Str); + } + return; + } + + if (const auto *Enum = Result.Nodes.getNodeAs("zero_first")) { + const EnumConstantDecl *ECD = *Enum->enumerator_begin(); + const SourceLocation Loc = ECD->getLocation(); + if (Loc.isInvalid() || Loc.isMacroID()) + return; + DiagnosticBuilder Diag = diag(Loc, "zero initial value for the first " + "enumerator in %0 can be disregarded") + << Enum; + cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); + return; + } + if (const auto *Enum = Result.Nodes.getNodeAs("sequential")) { + DiagnosticBuilder Diag = + diag(Enum->getBeginLoc(), + "sequential initial value in %0 can be ignored") + << Enum; + for (const EnumConstantDecl *ECD : llvm::drop_begin(Enum->enumerators())) + cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); + return; + } +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h new file mode 100644 index 0000000000000000000000000000000000000000..66087e4ee170da955c43bfa6cb553a092442705b --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h @@ -0,0 +1,38 @@ +//===--- EnumInitialValueCheck.h - clang-tidy -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Enforces consistent style for enumerators' initialization, covering three +/// styles: none, first only, or all initialized explicitly. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability/enum-initial-value.html +class EnumInitialValueCheck : public ClangTidyCheck { +public: + EnumInitialValueCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool AllowExplicitZeroFirstInitialValue; + const bool AllowExplicitSequentialInitialValues; +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index bca2c425111f6cd1594316ca05971d290dbf1062..376b84683df74e4e8880431b58a70220b600e486 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -22,6 +22,7 @@ #include "DeleteNullPointerCheck.h" #include "DuplicateIncludeCheck.h" #include "ElseAfterReturnCheck.h" +#include "EnumInitialValueCheck.h" #include "FunctionCognitiveComplexityCheck.h" #include "FunctionSizeCheck.h" #include "IdentifierLengthCheck.h" @@ -92,6 +93,8 @@ public: "readability-duplicate-include"); CheckFactories.registerCheck( "readability-else-after-return"); + CheckFactories.registerCheck( + "readability-enum-initial-value"); CheckFactories.registerCheck( "readability-function-cognitive-complexity"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp index b6d9c50d0b109c1c24323e304500165a607287d3..a44720c47eca2d7eb9ef815d7cea3dc18a44c616 100644 --- a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp +++ b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp @@ -108,7 +108,7 @@ int compareHeaders(StringRef LHS, StringRef RHS, IncludeSorter::IncludeStyle Style) { if (Style == IncludeSorter::IncludeStyle::IS_Google_ObjC) { const std::pair &Mismatch = - std::mismatch(LHS.begin(), LHS.end(), RHS.begin()); + std::mismatch(LHS.begin(), LHS.end(), RHS.begin(), RHS.end()); if ((Mismatch.first != LHS.end()) && (Mismatch.second != RHS.end())) { if ((*Mismatch.first == '.') && (*Mismatch.second == '+')) { return -1; diff --git a/clang-tools-extra/clangd/support/Trace.h b/clang-tools-extra/clangd/support/Trace.h index 1bfc75b874d8a9b1bee0de26990e9fff3f0cacdb..36c3745a41e969f03866931aa9bcefddffda4ce3 100644 --- a/clang-tools-extra/clangd/support/Trace.h +++ b/clang-tools-extra/clangd/support/Trace.h @@ -143,8 +143,8 @@ bool enabled(); class Span { public: Span(llvm::Twine Name); - /// Records span's duration in seconds to \p LatencyMetric with \p Name as the - /// label. + /// Records span's duration in milliseconds to \p LatencyMetric with \p Name + /// as the label. Span(llvm::Twine Name, const Metric &LatencyMetric); ~Span(); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 78b09d23d4427f567e40e7c1d4ef479992760abe..309b844615a1212c4983815ae6eabee086e68e3c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -123,6 +123,12 @@ New checks Finds initializer lists for aggregate types that could be written as designated initializers instead. +- New :doc:`readability-enum-initial-value + ` check. + + Enforces consistent style for enumerators' initialization, covering three + styles: none, first only, or all initialized explicitly. + - New :doc:`readability-use-std-min-max ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 79e81dd174e4f3d4eace4161f9023142d3648210..188a42bfddd383619ed1e143543bf5a5201c7881 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -352,6 +352,7 @@ Clang-Tidy Checks :doc:`readability-delete-null-pointer `, "Yes" :doc:`readability-duplicate-include `, "Yes" :doc:`readability-else-after-return `, "Yes" + :doc:`readability-enum-initial-value `, "Yes" :doc:`readability-function-cognitive-complexity `, :doc:`readability-function-size `, :doc:`readability-identifier-length `, diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst new file mode 100644 index 0000000000000000000000000000000000000000..660efc1eaff3e53527aad41a19151be0fe13062d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst @@ -0,0 +1,75 @@ +.. title:: clang-tidy - readability-enum-initial-value + +readability-enum-initial-value +============================== + +Enforces consistent style for enumerators' initialization, covering three +styles: none, first only, or all initialized explicitly. + +When adding new enumerations, inconsistent initial value will cause potential +enumeration value conflicts. + +In an enumeration, the following three cases are accepted. +1. none of enumerators are explicit initialized. +2. the first enumerator is explicit initialized. +3. all of enumerators are explicit initialized. + +.. code-block:: c++ + + // valid, none of enumerators are initialized. + enum A { + e0, + e1, + e2, + }; + + // valid, the first enumerator is initialized. + enum A { + e0 = 0, + e1, + e2, + }; + + // valid, all of enumerators are initialized. + enum A { + e0 = 0, + e1 = 1, + e2 = 2, + }; + + // invalid, e1 is not explicit initialized. + enum A { + e0 = 0, + e1, + e2 = 2, + }; + +Options +------- + +.. option:: AllowExplicitZeroFirstInitialValue + + If set to `false`, the first enumerator must not be explicitly initialized. + See examples below. Default is `true`. + + .. code-block:: c++ + + enum A { + e0 = 0, // not allowed if AllowExplicitZeroFirstInitialValue is false + e1, + e2, + }; + + +.. option:: AllowExplicitSequentialInitialValues + + If set to `false`, sequential initializations are not allowed. + See examples below. Default is `true`. + + .. code-block:: c++ + + enum A { + e0 = 1, // not allowed if AllowExplicitSequentialInitialValues is false + e1 = 2, + e2 = 3, + }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c new file mode 100644 index 0000000000000000000000000000000000000000..c66288cbe3e9575da8f963d59874cf5ab76bddd0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c @@ -0,0 +1,80 @@ +// RUN: %check_clang_tidy %s readability-enum-initial-value %t +// RUN: %check_clang_tidy -check-suffix=ENABLE %s readability-enum-initial-value %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-enum-initial-value.AllowExplicitZeroFirstInitialValue: false, \ +// RUN: readability-enum-initial-value.AllowExplicitSequentialInitialValues: false, \ +// RUN: }}' + +enum EError { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EError' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EError' are not consistent + EError_a = 1, + EError_b, + // CHECK-FIXES: EError_b = 2, + EError_c = 3, +}; + +enum ENone { + ENone_a, + ENone_b, + EENone_c, +}; + +enum EFirst { + EFirst_a = 1, + EFirst_b, + EFirst_c, +}; + +enum EAll { + EAll_a = 1, + EAll_b = 2, + EAll_c = 4, +}; + +#define ENUMERATOR_1 EMacro1_b +enum EMacro1 { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EMacro1' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EMacro1' are not consistent + EMacro1_a = 1, + ENUMERATOR_1, + // CHECK-FIXES: ENUMERATOR_1 = 2, + EMacro1_c = 3, +}; + + +#define ENUMERATOR_2 EMacro2_b = 2 +enum EMacro2 { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EMacro2' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EMacro2' are not consistent + EMacro2_a = 1, + ENUMERATOR_2, + EMacro2_c, + // CHECK-FIXES: EMacro2_c = 3, +}; + +enum EnumZeroFirstInitialValue { + EnumZeroFirstInitialValue_0 = 0, + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:3: warning: zero initial value for the first enumerator in 'EnumZeroFirstInitialValue' can be disregarded + // CHECK-FIXES-ENABLE: EnumZeroFirstInitialValue_0 , + EnumZeroFirstInitialValue_1, + EnumZeroFirstInitialValue_2, +}; + +enum EnumZeroFirstInitialValueWithComment { + EnumZeroFirstInitialValueWithComment_0 = /* == */ 0, + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:3: warning: zero initial value for the first enumerator in 'EnumZeroFirstInitialValueWithComment' can be disregarded + // CHECK-FIXES-ENABLE: EnumZeroFirstInitialValueWithComment_0 /* == */ , + EnumZeroFirstInitialValueWithComment_1, + EnumZeroFirstInitialValueWithComment_2, +}; + +enum EnumSequentialInitialValue { + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:1: warning: sequential initial value in 'EnumSequentialInitialValue' can be ignored + EnumSequentialInitialValue_0 = 2, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_0 = 2, + EnumSequentialInitialValue_1 = 3, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_1 , + EnumSequentialInitialValue_2 = 4, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_2 , +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c4ba970372a077bf12ad7bb84dc7ce1836ed8ac --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy %s readability-enum-initial-value %t + +enum class EError { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EError' are not consistent + EError_a = 1, + EError_b, + // CHECK-FIXES: EError_b = 2, + EError_c = 3, +}; + +enum class ENone { + ENone_a, + ENone_b, + EENone_c, +}; + +enum class EFirst { + EFirst_a = 1, + EFirst_b, + EFirst_c, +}; + +enum class EAll { + EAll_a = 1, + EAll_b = 2, + EAll_c = 3, +}; diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index 2a0953af53faddfdc7885cdd1021bb715165dc50..736a54ece550c62a589e0a48b97e7a61eccd01af 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -29,6 +29,11 @@ # cmake --build . --target check-cxxabi- # cmake --build . --target check-unwind- # cmake --build . --target check-cxx- +# (another way to execute the tests) +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes-bins/libunwind/test 2>&1 | tee libunwind-tests.log +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes--bins/libcxxabi/test 2>&1 | tee libcxxabi-tests.log +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes--bins/libcxx/test 2>&1 | tee libcxx-tests.log + # LLVM_PROJECT_DIR is the path to the llvm-project directory. # The right way to compute it would probably be to use "${CMAKE_SOURCE_DIR}/../", @@ -42,9 +47,6 @@ if (NOT DEFINED DEFAULT_SYSROOT) message(WARNING "DEFAULT_SYSROOT must be specified for the cross toolchain build.") endif() -if (NOT DEFINED LLVM_TARGETS_TO_BUILD) - set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "") -endif() if (NOT DEFINED LLVM_ENABLE_ASSERTIONS) set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "") endif() @@ -56,7 +58,7 @@ if (NOT DEFINED LLVM_ENABLE_RUNTIMES) endif() if (NOT DEFINED TOOLCHAIN_TARGET_TRIPLE) - set(TOOLCHAIN_TARGET_TRIPLE "armv7-unknown-linux-gnueabihf") + set(TOOLCHAIN_TARGET_TRIPLE "aarch64-unknown-linux-gnu") else() #NOTE: we must normalize specified target triple to a fully specified triple, # including the vendor part. It is necessary to synchronize the runtime library @@ -74,24 +76,38 @@ else() string(REPLACE ";" "-" TOOLCHAIN_TARGET_TRIPLE "${TOOLCHAIN_TARGET_TRIPLE}") endif() +message(STATUS "Toolchain target triple: ${TOOLCHAIN_TARGET_TRIPLE}") + +if (NOT DEFINED LLVM_TARGETS_TO_BUILD) + if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(armv|arm32)+") + set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "") + endif() + if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(aarch64|arm64)+") + set(LLVM_TARGETS_TO_BUILD "AArch64" CACHE STRING "") + endif() +endif() + +message(STATUS "Toolchain target to build: ${LLVM_TARGETS_TO_BUILD}") + if (NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") endif() -message(STATUS "Toolchain target triple: ${TOOLCHAIN_TARGET_TRIPLE}") - set(CMAKE_CROSSCOMPILING ON CACHE BOOL "") set(CMAKE_CL_SHOWINCLUDES_PREFIX "Note: including file: " CACHE STRING "") # Required if COMPILER_RT_DEFAULT_TARGET_ONLY is ON set(CMAKE_C_COMPILER_TARGET "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(CMAKE_CXX_COMPILER_TARGET "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") -set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(LLVM_DEFAULT_TARGET_TRIPLE "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(LLVM_TARGET_ARCH "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(LLVM_LIT_ARGS "-vv ${LLVM_LIT_ARGS}" CACHE STRING "" FORCE) +set(CLANG_DEFAULT_CXX_STDLIB "libc++" CACHE STRING "") set(CLANG_DEFAULT_LINKER "lld" CACHE STRING "") +set(CLANG_DEFAULT_OBJCOPY "llvm-objcopy" CACHE STRING "") +set(CLANG_DEFAULT_RTLIB "compiler-rt" CACHE STRING "") +set(CLANG_DEFAULT_UNWINDLIB "libunwind" CACHE STRING "") if(WIN32) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded" CACHE STRING "") @@ -109,9 +125,10 @@ set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSTEM_NAME set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH "${RUNTIMES_INSTALL_RPATH}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "") - +set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_CMAKE_DIR "${LLVM_PROJECT_DIR}/llvm/cmake/modules" CACHE PATH "") set(LLVM_RUNTIME_TARGETS "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") +set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_ENABLE_RUNTIMES "${LLVM_ENABLE_RUNTIMES}" CACHE STRING "") @@ -125,13 +142,16 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_SANITIZERS set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_PROFILE OFF CACHE BOOL "") -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_CRT OFF CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_CRT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_DEFAULT_TARGET_ONLY ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_INCLUDE_TESTS ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CAN_EXECUTE_TESTS ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CXX_LIBRARY libcxx CACHE STRING "") +# Tell Clang to seach C++ headers alongside with the just-built binaries for the C++ compiler-rt tests. +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_TEST_COMPILER_CFLAGS "--stdlib=libc++" CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "") @@ -148,8 +168,10 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!! set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "") - +# Avoid searching for the python3 interpreter during the runtimes configuration for the cross builds. +# It starts searching the python3 package using the target's sysroot path, that usually is not compatible with the build host. find_package(Python3 COMPONENTS Interpreter) +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_Python3_EXECUTABLE ${Python3_EXECUTABLE} CACHE PATH "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") diff --git a/clang/docs/HLSL/FunctionCalls.rst b/clang/docs/HLSL/FunctionCalls.rst index 7317de2163f8975b3d9d283a55aa8d4d9ba2ac55..6d65fe6e3fb20b90a3a755a13123042de2226958 100644 --- a/clang/docs/HLSL/FunctionCalls.rst +++ b/clang/docs/HLSL/FunctionCalls.rst @@ -157,22 +157,23 @@ Clang Implementation of the changes in the prototype implementation are restoring Clang-3.7 code that was previously modified to its original state. -The implementation in clang depends on two new AST nodes and minor extensions to -Clang's existing support for Objective-C write-back arguments. The goal of this -design is to capture the semantic details of HLSL function calls in the AST, and -minimize the amount of magic that needs to occur during IR generation. - -The two new AST nodes are ``HLSLArrayTemporaryExpr`` and ``HLSLOutParamExpr``, -which respectively represent the temporaries used for passing arrays by value -and the temporaries created for function outputs. +The implementation in clang adds a new non-decaying array type, a new AST node +to represent output parameters, and minor extensions to Clang's existing support +for Objective-C write-back arguments. The goal of this design is to capture the +semantic details of HLSL function calls in the AST, and minimize the amount of +magic that needs to occur during IR generation. Array Temporaries ----------------- -The ``HLSLArrayTemporaryExpr`` represents temporary values for input -constant-sized array arguments. This applies for all constant-sized array -arguments regardless of whether or not the parameter is constant-sized or -unsized. +The new ``ArrayParameterType`` is a sub-class of ``ConstantArrayType`` +inheriting all the behaviors and methods of the parent except that it does not +decay to a pointer during overload resolution or template type deduction. + +An argument of ``ConstantArrayType`` can be implicitly converted to an +equivalent non-decayed ``ArrayParameterType`` if the underlying canonical +``ConstantArrayType`` is the same. This occurs during overload resolution +instead of array to pointer decay. .. code-block:: c++ @@ -193,7 +194,7 @@ In the example above, the following AST is generated for the call to CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [4])' | `-DeclRefExpr 'void (float [4])' lvalue Function 'SizedArray' 'void (float [4])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' In the example above, the following AST is generated for the call to @@ -204,7 +205,7 @@ In the example above, the following AST is generated for the call to CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [])' | `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' In both of these cases the argument expression is of known array size so we can @@ -236,7 +237,7 @@ An expected AST should be something like: CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [])' | `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' Out Parameter Temporaries diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0fdd9e3fb3eee263cc76cca8afa86ca7505e1a46..76eaf0bf11c303dc4f0b46c3ff3b75dca65f04fc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -304,6 +304,15 @@ Improvements to Clang's diagnostics annotated with the ``clang::always_destroy`` attribute. Fixes #GH68686, #GH86486 +- ``-Wmicrosoft``, ``-Wgnu``, or ``-pedantic`` is now required to diagnose C99 + flexible array members in a union or alone in a struct. Fixes GH#84565. + +- Clang now no longer diagnoses type definitions in ``offsetof`` in C23 mode. + Fixes #GH83658. + +- New ``-Wformat-signedness`` diagnostic that warn if the format string requires an + unsigned argument and the argument is signed and vice versa. + Improvements to Clang's time-trace ---------------------------------- @@ -354,6 +363,9 @@ Bug Fixes in This Version - Fixes an assertion failure on invalid code when trying to define member functions in lambdas. +- Fixed a regression in CTAD that a friend declaration that befriends itself may cause + incorrect constraint substitution. (#GH86769). + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -455,6 +467,7 @@ Bug Fixes to C++ Support - Fix an issue where a namespace alias could be defined using a qualified name (all name components following the first `::` were ignored). - Fix an out-of-bounds crash when checking the validity of template partial specializations. (part of #GH86757). +- Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 8af99a021ebdfd643223e77411839002031130f9..f188f18ba5557e48efe4b5586e93cf90e1b1fafe 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3120,44 +3120,82 @@ Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fcl alpha.unix.Stream (C) """"""""""""""""""""" -Check stream handling functions: ``fopen, tmpfile, fclose, fread, fwrite, fseek, ftell, rewind, fgetpos,`` -``fsetpos, clearerr, feof, ferror, fileno``. +Check C stream handling functions: +``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. + +The checker maintains information about the C stream objects (``FILE *``) and +can detect error conditions related to use of streams. The following conditions +are detected: + +* The ``FILE *`` pointer passed to the function is NULL (the single exception is + ``fflush`` where NULL is allowed). +* Use of stream after close. +* Opened stream is not closed. +* Read from a stream after end-of-file. (This is not a fatal error but reported + by the checker. Stream remains in EOF state and the read operation fails.) +* Use of stream when the file position is indeterminate after a previous failed + operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are + allowed in this state. +* Invalid 3rd ("``whence``") argument to ``fseek``. + +The checker does not track the correspondence between integer file descriptors +and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not +treated specially and are therefore often not recognized (because these streams +are usually not opened explicitly by the program, and are global variables). .. code-block:: c - void test() { + void test1() { FILE *p = fopen("foo", "r"); } // warn: opened file is never closed - void test() { + void test2() { FILE *p = fopen("foo", "r"); fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL fclose(p); } - void test() { + void test3() { FILE *p = fopen("foo", "r"); + if (p) { + fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + fclose(p); + } + } - if (p) - fseek(p, 1, 3); - // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + void test4() { + FILE *p = fopen("foo", "r"); + if (!p) + return; fclose(p); + fclose(p); // warn: stream already closed } - void test() { + void test5() { FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!ferror(p)) + fgetc(p); // warn: possible read after end-of-file + fclose(p); - fclose(p); // warn: already closed } - void test() { - FILE *p = tmpfile(); - ftell(p); // warn: stream pointer might be NULL + void test6() { + FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!feof(p)) + fgetc(p); // warn: file position may be indeterminate after I/O error + fclose(p); } - .. _alpha-unix-cstring-BufferOverlap: alpha.unix.cstring.BufferOverlap (C) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 60db3cf0966c0263083b82e1dec923ffe42bcff2..7a8bd985a91fc00b2c3a6c488aca5030fc211c8d 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2991,6 +2991,7 @@ enum CXCallingConv { CXCallingConv_AArch64SVEPCS = 18, CXCallingConv_M68kRTD = 19, CXCallingConv_PreserveNone = 20, + CXCallingConv_RISCVVectorCall = 21, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 002f36ecbbaa3f3a1dca7e02b6f3e913f6eaa07c..08f71051e6cbf32c20830d2503f8c511099f8908 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -260,6 +260,9 @@ class ASTContext : public RefCountedBase { ASTContext&> SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + ArrayParameterTypes; + /// The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. @@ -1367,6 +1370,10 @@ public: /// type to the decayed type. QualType getDecayedType(QualType Orig, QualType Decayed) const; + /// Return the uniqued reference to a specified array parameter type from the + /// original array type. + QualType getArrayParameterType(QualType Ty) const; + /// Return the uniqued reference to the atomic type for the specified /// type. QualType getAtomicType(QualType T) const; diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 47ed6d0d1db0df804f55cdfca4c5c0ddd4868bb9..858450926455c602030671323257a4470bc096f7 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -669,9 +669,8 @@ public: /// Whether this declaration comes from another module unit. bool isInAnotherModuleUnit() const; - /// FIXME: Implement discarding declarations actually in global module - /// fragment. See [module.global.frag]p3,4 for details. - bool isDiscardedInGlobalModuleFragment() const { return false; } + /// Whether this declaration comes from explicit global module. + bool isFromExplicitGlobalModule() const; /// Check if we should skip checking ODRHash for declaration \param D. /// diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index e2232fb4a47153f77882427d83046108525c691b..a074dd23e2ad4c7600b4206e3f36ec10f85b3d73 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -284,6 +284,8 @@ public: /// The conversion specifier and the argument type are disallowed by the C /// standard, but are in practice harmless. For instance, "%p" and int*. NoMatchPedantic, + /// The conversion specifier and the argument type have different sign. + NoMatchSignedness, /// The conversion specifier and the argument type are compatible, but still /// seems likely to be an error. For instance, "%hd" and _Bool. NoMatchTypeConfusion, diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def index ef05072800f11a1bcd6a7ee48824150ea92104b6..8788b8ff0ef0a4538ff8bed81b05f1993d3a6c24 100644 --- a/clang/include/clang/AST/OperationKinds.def +++ b/clang/include/clang/AST/OperationKinds.def @@ -364,6 +364,9 @@ CAST_OPERATION(IntToOCLSampler) // Truncate a vector type by dropping elements from the end (HLSL only). CAST_OPERATION(HLSLVectorTruncation) +// Non-decaying array RValue cast (HLSL only). +CAST_OPERATION(HLSLArrayRValue) + //===- Binary Operations -------------------------------------------------===// // Operators listed in order of precedence. // Note that additions to this should also update the StmtVisitor class, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 4a1ff222ecadcda0b37c231c3a243c8d40d922b7..8630317795a9ad94313f59bba25eac6db36422b6 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -993,6 +993,12 @@ DEF_TRAVERSE_TYPE(ConstantArrayType, { TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); }) +DEF_TRAVERSE_TYPE(ArrayParameterType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); +}) + DEF_TRAVERSE_TYPE(IncompleteArrayType, { TRY_TO(TraverseType(T->getElementType())); }) @@ -1260,6 +1266,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, { TRY_TO(TraverseArrayTypeLocHelper(TL)); }) +DEF_TRAVERSE_TYPELOC(ArrayParameterType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { TRY_TO(TraverseTypeLoc(TL.getElementLoc())); TRY_TO(TraverseArrayTypeLocHelper(TL)); diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index de67f0b5714846f11ff2c5c2f76e8b1d972158f0..efb5bfe7f83d408717179e17a401dbb3075d1115 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -352,6 +352,7 @@ public: void VisitEnumConstantDecl(const EnumConstantDecl *D); void VisitIndirectFieldDecl(const IndirectFieldDecl *D); void VisitFunctionDecl(const FunctionDecl *D); + void VisitCXXDeductionGuideDecl(const CXXDeductionGuideDecl *D); void VisitFieldDecl(const FieldDecl *D); void VisitVarDecl(const VarDecl *D); void VisitBindingDecl(const BindingDecl *D); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 5d8dde37e769698d30a40ed23d273ce9305c2fa8..99f45d518c7960fab956a317719a6870a2c8fdf4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2300,6 +2300,7 @@ public: bool isConstantArrayType() const; bool isIncompleteArrayType() const; bool isVariableArrayType() const; + bool isArrayParameterType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; bool isClassType() const; @@ -3334,14 +3335,15 @@ public: return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || - T->getTypeClass() == DependentSizedArray; + T->getTypeClass() == DependentSizedArray || + T->getTypeClass() == ArrayParameter; } }; /// Represents the canonical version of C arrays with a specified constant size. /// For example, the canonical type for 'int A[4 + 4*100]' is a /// ConstantArrayType where the element type is 'int' and the size is 404. -class ConstantArrayType final : public ArrayType { +class ConstantArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. struct ExternalSize { @@ -3382,6 +3384,19 @@ class ConstantArrayType final : public ArrayType { const Expr *SzExpr, ArraySizeModifier SzMod, unsigned Qual); +protected: + ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can) + : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(), + ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) { + ConstantArrayTypeBits.HasExternalSize = + ATy->ConstantArrayTypeBits.HasExternalSize; + if (!ConstantArrayTypeBits.HasExternalSize) { + ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth; + Size = ATy->Size; + } else + SizePtr = ATy->SizePtr; + } + public: /// Return the constant array size as an APInt. llvm::APInt getSize() const { @@ -3453,7 +3468,22 @@ public: ArraySizeModifier SizeMod, unsigned TypeQuals); static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray; + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == ArrayParameter; + } +}; + +/// Represents a constant array type that does not decay to a pointer when used +/// as a function parameter. +class ArrayParameterType : public ConstantArrayType { + friend class ASTContext; // ASTContext creates these. + + ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy) + : ConstantArrayType(ArrayParameter, ATy, CanTy) {} + +public: + static bool classof(const Type *T) { + return T->getTypeClass() == ArrayParameter; } }; @@ -7185,7 +7215,8 @@ inline bool QualType::isCanonicalAsParam() const { if (T->isVariablyModifiedType() && T->hasSizedVLAType()) return false; - return !isa(T) && !isa(T); + return !isa(T) && + (!isa(T) || isa(T)); } inline bool QualType::isConstQualified() const { @@ -7450,6 +7481,10 @@ inline bool Type::isVariableArrayType() const { return isa(CanonicalType); } +inline bool Type::isArrayParameterType() const { + return isa(CanonicalType); +} + inline bool Type::isDependentSizedArrayType() const { return isa(CanonicalType); } @@ -7813,7 +7848,7 @@ inline bool Type::isTypedefNameType() const { /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { - return isFunctionType() || isArrayType(); + return isFunctionType() || (isArrayType() && !isArrayParameterType()); } inline bool Type::hasPointerRepresentation() const { diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index b09eb3539a4badb306ec2e3abe6c82164028eacc..9f2dff7a782cb328289f3be17e6ab42f144689da 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -1611,6 +1611,11 @@ class ConstantArrayTypeLoc : ConstantArrayType> { }; +/// Wrapper for source info for array parameter types. +class ArrayParameterTypeLoc + : public InheritingConcreteTypeLoc< + ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {}; + class IncompleteArrayTypeLoc : public InheritingConcreteTypeLoc; } +let Class = ArrayParameterType in { + def : Creator<[{ return ctx.getAdjustedParameterType( + ctx.getConstantArrayType(elementType,sizeValue, + size,sizeModifier, + indexQualifiers.getCVRQualifiers())); }]>; +} + let Class = IncompleteArrayType in { def : Creator<[{ return ctx.getIncompleteArrayType(elementType, sizeModifier, diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 2330697299fdd7aaffe728dae049c33cb5efdf9f..c30bccd06674a4d9036930a386b9da4afae78418 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -744,6 +744,35 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, std::vector getFieldsForInitListExpr(const InitListExpr *InitList); +/// Helper class for initialization of a record with an `InitListExpr`. +/// `InitListExpr::inits()` contains the initializers for both the base classes +/// and the fields of the record; this helper class separates these out into two +/// different lists. In addition, it deals with special cases associated with +/// unions. +class RecordInitListHelper { +public: + // `InitList` must have record type. + RecordInitListHelper(const InitListExpr *InitList); + + // Base classes with their associated initializer expressions. + ArrayRef> base_inits() const { + return BaseInits; + } + + // Fields with their associated initializer expressions. + ArrayRef> field_inits() const { + return FieldInits; + } + +private: + SmallVector> BaseInits; + SmallVector> FieldInits; + + // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a + // member variable because we store a pointer to it in `FieldInits`. + std::optional ImplicitValueInitForUnion; +}; + /// Associates a new `RecordValue` with `Loc` and returns the new value. RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 318d4e5ac5ba44e30d7a7d224297d8505690332c..80e607525a0a37dcdaff9f508cb222b3a402da8d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3011,6 +3011,13 @@ def PreserveNone : DeclOrTypeAttr, TargetSpecificAttr { let Documentation = [PreserveNoneDocs]; } +def RISCVVectorCC: DeclOrTypeAttr, TargetSpecificAttr { + let Spellings = [CXX11<"riscv", "vector_cc">, + C23<"riscv", "vector_cc">, + Clang<"riscv_vector_cc">]; + let Documentation = [RISCVVectorCCDocs]; +} + def Target : InheritableAttr { let Spellings = [GCC<"target">]; let Args = [StringArgument<"featuresStr">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 384aebbdf2e32a5518cf9098952a59879c4dc7f1..3ea4d676b4f89d30eb03a5e80419dfccfeca06e9 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5494,6 +5494,17 @@ for clang builtin functions. }]; } +def RISCVVectorCCDocs : Documentation { + let Category = DocCatCallingConvs; + let Heading = "riscv::vector_cc, riscv_vector_cc, clang::riscv_vector_cc"; + let Content = [{ +The ``riscv_vector_cc`` attribute can be applied to a function. It preserves 15 +registers namely, v1-v7 and v24-v31 as callee-saved. Callers thus don't need +to save these registers before function calls, and callees only need to save +them if they use them. + }]; +} + def PreferredNameDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 52c0dd52c28b11baf2ed087f1b12865a5e51cdb0..f421223ff087de69fe33cfda2fbbda15876b058d 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4599,6 +4599,12 @@ def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Prototype = "unsigned int(bool)"; } +def HLSLWaveGetLaneIndex : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_get_lane_index"]; + let Attributes = [NoThrow, Const]; + let Prototype = "unsigned int()"; +} + def HLSLClamp : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_clamp"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index e33a1f4c45b949733798ab5fb648260bcaddd7f3..592ed3bda51506624b0438f6fdce1ab31a7ab0b0 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -753,7 +753,8 @@ def err_drv_hlsl_unsupported_target : Error< "HLSL code generation is unsupported for target '%0'">; def err_drv_hlsl_bad_shader_required_in_target : Error< "%select{shader model|Vulkan environment|shader stage}0 is required as %select{OS|environment}1 in target '%2' for HLSL code generation">; - +def err_drv_hlsl_16bit_types_unsupported: Error< + "'%0' option requires target HLSL Version >= 2018%select{| and shader model >= 6.2}1, but HLSL Version is '%2'%select{| and shader model is '%3'}1">; def err_drv_hlsl_bad_shader_unsupported : Error< "%select{shader model|Vulkan environment|shader stage}0 '%1' in target '%2' is invalid for HLSL code generation">; def warn_drv_dxc_missing_dxv : Warning<"dxv not found. " diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 44035e2fd16f2e8277f3f5dab0ea9395e86fb6bc..520168f01fd846c540c22e958b709f9d72b2e9c1 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -985,6 +985,7 @@ def FormatSecurity : DiagGroup<"format-security">; def FormatNonStandard : DiagGroup<"format-non-iso">; def FormatY2K : DiagGroup<"format-y2k">; def FormatPedantic : DiagGroup<"format-pedantic">; +def FormatSignedness : DiagGroup<"format-signedness">; def FormatTypeConfusion : DiagGroup<"format-type-confusion">; def FormatOverflowNonKprintf: DiagGroup<"format-overflow-non-kprintf">; diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627b32359a4c6a51ed23d23b02f5e..e3263fe9ccb9d4177a70b83ab5cf260693ed7278 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fc727cef9cd835805ad1641f7045aa3a447c912f..df57f5e6ce11ba02faf873f677242a26a8a2f881 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1748,8 +1748,8 @@ def err_type_defined_in_condition : Error< def err_type_defined_in_enum : Error< "%0 cannot be defined in an enumeration">; def ext_type_defined_in_offsetof : Extension< - "defining a type within '%select{__builtin_offsetof|offsetof}0' is a Clang " - "extension">, InGroup; + "defining a type within '%select{__builtin_offsetof|offsetof}0' is a C23 " + "extension">, InGroup; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; @@ -6464,9 +6464,6 @@ def ext_c99_flexible_array_member : Extension< def err_flexible_array_virtual_base : Error< "flexible array member %0 not allowed in " "%select{struct|interface|union|class|enum}1 which has a virtual base class">; -def err_flexible_array_empty_aggregate : Error< - "flexible array member %0 not allowed in otherwise empty " - "%select{struct|interface|union|class|enum}1">; def err_flexible_array_has_nontrivial_dtor : Error< "flexible array member %0 of type %1 with non-trivial destruction">; def ext_flexible_array_in_struct : Extension< @@ -6481,8 +6478,6 @@ def ext_flexible_array_empty_aggregate_ms : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, InGroup; -def err_flexible_array_union : Error< - "flexible array member %0 in a union is not allowed">; def ext_flexible_array_union_ms : Extension< "flexible array member %0 in a union is a Microsoft extension">, InGroup; @@ -9826,6 +9821,9 @@ def warn_format_conversion_argument_type_mismatch : Warning< def warn_format_conversion_argument_type_mismatch_pedantic : Extension< warn_format_conversion_argument_type_mismatch.Summary>, InGroup; +def warn_format_conversion_argument_type_mismatch_signedness : Warning< + warn_format_conversion_argument_type_mismatch.Summary>, + InGroup, DefaultIgnore; def warn_format_conversion_argument_type_mismatch_confusion : Warning< warn_format_conversion_argument_type_mismatch.Summary>, InGroup, DefaultIgnore; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 8586405825cfe01514754591f0855be2f5667c62..fb11e8212f8b68f235faa690aab875b56096c8f6 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -273,29 +273,30 @@ namespace clang { /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { - CC_C, // __attribute__((cdecl)) - CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall, // __attribute__((fastcall)) - CC_X86ThisCall, // __attribute__((thiscall)) - CC_X86VectorCall, // __attribute__((vectorcall)) - CC_X86Pascal, // __attribute__((pascal)) - CC_Win64, // __attribute__((ms_abi)) - CC_X86_64SysV, // __attribute__((sysv_abi)) - CC_X86RegCall, // __attribute__((regcall)) - CC_AAPCS, // __attribute__((pcs("aapcs"))) - CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) - CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) - CC_SpirFunction, // default for OpenCL functions on SPIR target - CC_OpenCLKernel, // inferred for OpenCL kernels - CC_Swift, // __attribute__((swiftcall)) + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86VectorCall, // __attribute__((vectorcall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_Win64, // __attribute__((ms_abi)) + CC_X86_64SysV, // __attribute__((sysv_abi)) + CC_X86RegCall, // __attribute__((regcall)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + CC_SpirFunction, // default for OpenCL functions on SPIR target + CC_OpenCLKernel, // inferred for OpenCL kernels + CC_Swift, // __attribute__((swiftcall)) CC_SwiftAsync, // __attribute__((swiftasynccall)) - CC_PreserveMost, // __attribute__((preserve_most)) - CC_PreserveAll, // __attribute__((preserve_all)) + CC_PreserveMost, // __attribute__((preserve_most)) + CC_PreserveAll, // __attribute__((preserve_all)) CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) - CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) - CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) - CC_M68kRTD, // __attribute__((m68k_rtd)) - CC_PreserveNone, // __attribute__((preserve_none)) + CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) + CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) + CC_M68kRTD, // __attribute__((m68k_rtd)) + CC_PreserveNone, // __attribute__((preserve_none)) + CC_RISCVVectorCall, // __attribute__((riscv_vector_cc)) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 374595edd2ce4a2e8f92842ccce97b066291e0b8..e1ef7454f01669c4ecff7f1998275a0b2512ed71 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -267,6 +267,9 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned AllowAMDGPUUnsafeFPAtomics : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned HasUnalignedAccess : 1; + unsigned ARMCDECoprocMask : 8; unsigned MaxOpenCLWorkGroupSize; @@ -859,6 +862,18 @@ public: return PointerWidth; } + /// Return true iff unaligned accesses are a single instruction (rather than + /// a synthesized sequence). + bool hasUnalignedAccess() const { return HasUnalignedAccess; } + + /// Return true iff unaligned accesses are cheap. This affects placement and + /// size of bitfield loads/stores. (Not the ABI-mandated placement of + /// the bitfields themselves.) + bool hasCheapUnalignedBitFieldAccess() const { + // Simply forward to the unaligned access getter. + return hasUnalignedAccess(); + } + /// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro, /// which is the prefix given to user symbols by default. /// diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 3625f063758915f285f96d93871d55c0ebb11b2c..fee49cf4326dfca96d040f0a369d72b5a1f0a506 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -64,6 +64,7 @@ def ConstantArrayType : TypeNode; def IncompleteArrayType : TypeNode; def VariableArrayType : TypeNode; def DependentSizedArrayType : TypeNode, AlwaysDependent; +def ArrayParameterType : TypeNode; def DependentSizedExtVectorType : TypeNode, AlwaysDependent; def DependentAddressSpaceType : TypeNode, AlwaysDependent; def VectorType : TypeNode; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 29066ea14280c2a38663a55f0ba5bab8453b6d86..f5289fb00c895e676c43e20169ff2dffef359ab0 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3635,6 +3635,9 @@ defm preserve_as_comments : BoolFOption<"preserve-as-comments", "Do not preserve comments in inline assembly">, PosFlag>; def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; +def reexport_framework : Separate<["-"], "reexport_framework">, Flags<[LinkerInput]>; +def reexport_l : Joined<["-"], "reexport-l">, Flags<[LinkerInput]>; +def reexport_library : JoinedOrSeparate<["-"], "reexport_library">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group; def freg_struct_return : Flag<["-"], "freg-struct-return">, Group, Visibility<[ClangOption, CC1Option]>, @@ -4507,6 +4510,9 @@ def mwindows : Joined<["-"], "mwindows">, Group; def mdll : Joined<["-"], "mdll">, Group; def municode : Joined<["-"], "municode">, Group; def mthreads : Joined<["-"], "mthreads">, Group; +def marm64x : Joined<["-"], "marm64x">, Group, + Visibility<[ClangOption, CLOption]>, + HelpText<"Link as a hybrid ARM64X image">; def mguard_EQ : Joined<["-"], "mguard=">, Group, HelpText<"Enable or disable Control Flow Guard checks and guard tables emission">, Values<"none,cf,cf-nochecks">; @@ -8307,6 +8313,7 @@ def _SLASH_Fi : CLCompileJoined<"Fi">, def _SLASH_Fo : CLCompileJoined<"Fo">, HelpText<"Set output object file (with /c)">, MetaVarName<"">; +def _SLASH_Fo_COLON : CLCompileJoined<"Fo:">, Alias<_SLASH_Fo>; def _SLASH_guard : CLJoined<"guard:">, HelpText<"Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks. " "Enable EH Continuation Guard with /guard:ehcont">; diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index cce91862ae3d03b210d5939ab17f29bb1f231f80..3464654284f199c73beeef8ea9d7858882e1173f 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -133,6 +133,24 @@ class CompilerInstance : public ModuleLoader { std::vector> DependencyCollectors; + /// Records the set of modules + class FailedModulesSet { + llvm::StringSet<> Failed; + + public: + bool hasAlreadyFailed(StringRef module) { return Failed.count(module) > 0; } + + void addFailed(StringRef module) { Failed.insert(module); } + }; + + /// The set of modules that failed to build. + /// + /// This pointer will be shared among all of the compiler instances created + /// to (re)build modules, so that once a module fails to build anywhere, + /// other instances will see that the module has failed and won't try to + /// build it again. + std::shared_ptr FailedModules; + /// The set of top-level modules that has already been built on the /// fly as part of this overall compilation action. std::map> BuiltModules; @@ -619,6 +637,24 @@ public: } /// @} + /// @name Failed modules set + /// @{ + + bool hasFailedModulesSet() const { return (bool)FailedModules; } + + void createFailedModulesSet() { + FailedModules = std::make_shared(); + } + + std::shared_ptr getFailedModulesSetPtr() const { + return FailedModules; + } + + void setFailedModulesSet(std::shared_ptr FMS) { + FailedModules = FMS; + } + + /// } /// @name Output Files /// @{ diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index a620ddfc40447d7795df64c407300b6ca8da5d44..0518a8823a03ea94ca284aee9256bbb5f7295ac0 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -34,12 +34,18 @@ public: /// Preprocessor-based frontend action that also loads PCH files. class ReadPCHAndPreprocessAction : public FrontendAction { + llvm::unique_function AdjustCI; + void ExecuteAction() override; std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; public: + ReadPCHAndPreprocessAction( + llvm::unique_function AdjustCI) + : AdjustCI(std::move(AdjustCI)) {} + bool usesPreprocessorOnly() const override { return false; } }; @@ -321,11 +327,15 @@ protected: class GetDependenciesByModuleNameAction : public PreprocessOnlyAction { StringRef ModuleName; + llvm::unique_function AdjustCI; + void ExecuteAction() override; public: - GetDependenciesByModuleNameAction(StringRef ModuleName) - : ModuleName(ModuleName) {} + GetDependenciesByModuleNameAction( + StringRef ModuleName, + llvm::unique_function AdjustCI) + : ModuleName(ModuleName), AdjustCI(std::move(AdjustCI)) {} }; } // end namespace clang diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 49de24763f1f938d88ba6e2f2ab41d593fc34a38..22cdc234486cf330084c7c20629ac583036705f1 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -31,6 +31,7 @@ enum class VerificationMode { class DylibVerifier : llvm::MachO::RecordVisitor { private: struct SymbolContext; + struct DWARFContext; public: enum class Result { NoVerify, Ignore, Valid, Invalid }; @@ -54,7 +55,7 @@ public: DiagnosticsEngine *Diag = nullptr; // Handle diagnostics reporting for target level violations. - void emitDiag(llvm::function_ref Report); + void emitDiag(llvm::function_ref Report, RecordLoc *Loc = nullptr); VerifierContext() = default; VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {} @@ -63,9 +64,10 @@ public: DylibVerifier() = default; DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, - VerificationMode Mode, bool Demangle) + VerificationMode Mode, bool Demangle, StringRef DSYMPath) : Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle), - Exports(std::make_unique()), Ctx(VerifierContext{Diag}) {} + DSYMPath(DSYMPath), Exports(std::make_unique()), + Ctx(VerifierContext{Diag}) {} Result verify(GlobalRecord *R, const FrontendAttrs *FA); Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA); @@ -143,6 +145,12 @@ private: std::string getAnnotatedName(const Record *R, SymbolContext &SymCtx, bool ValidSourceLoc = true); + /// Extract source location for symbol implementations. + /// As this is a relatively expensive operation, it is only used + /// when there is a violation to report and there is not a known declaration + /// in the interface. + void accumulateSrcLocForDylibSymbols(); + // Symbols in dylib. llvm::MachO::Records Dylib; @@ -152,11 +160,17 @@ private: // Attempt to demangle when reporting violations. bool Demangle = false; + // File path to DSYM file. + StringRef DSYMPath; + // Valid symbols in final text file. std::unique_ptr Exports = std::make_unique(); // Track current state of verification while traversing AST. VerifierContext Ctx; + + // Track DWARF provided source location for dylibs. + DWARFContext *DWARFCtx = nullptr; }; } // namespace installapi diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840e8eabe8064f7ce0253aa05e2ab..c67503d4ad49e934a6e4ac6927e9bd95fabd4567 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -24,8 +24,6 @@ namespace clang::installapi { enum class HeaderType { - /// Unset or unknown type. - Unknown, /// Represents declarations accessible to all clients. Public, /// Represents declarations accessible to a disclosed set of clients. @@ -33,6 +31,8 @@ enum class HeaderType { /// Represents declarations only accessible as implementation details to the /// input library. Project, + /// Unset or unknown type. + Unknown, }; inline StringRef getName(const HeaderType T) { @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ public: void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { - return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, - Other.Language, Other.Excluded, Other.Extra); + return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, + Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/include/clang/InstallAPI/MachO.h b/clang/include/clang/InstallAPI/MachO.h index 4961c596fd68ae2fb41d672b831140f9afc505da..827220dbf39fb8aaaae1d1dac1bdc3d2e496cd9b 100644 --- a/clang/include/clang/InstallAPI/MachO.h +++ b/clang/include/clang/InstallAPI/MachO.h @@ -34,6 +34,7 @@ using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord; using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord; using ObjCIFSymbolKind = llvm::MachO::ObjCIFSymbolKind; using Records = llvm::MachO::Records; +using RecordLoc = llvm::MachO::RecordLoc; using RecordsSlice = llvm::MachO::RecordsSlice; using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs; using SymbolSet = llvm::MachO::SymbolSet; diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d7bf04bfa8e32c5e073170f7816..2e28ff6823cb2a73cd577bd96e483c71bd513011 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ private: Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed - /// inferred modules. Otherwise, nullopt. - OptionalFileEntryRef ModuleMapFile; + /// inferred modules. Otherwise, invalid. + FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ private: /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ public: /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ public: /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 0836b7d439bb049054074c4cfa845d4e56bd085e..24e146a589a758baf7080d7dfcd066ec910a8f70 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -736,6 +736,19 @@ private: State ConditionalStackState = Off; } PreambleConditionalStack; + /// Function for getting the dependency preprocessor directives of a file. + /// + /// These are directives derived from a special form of lexing where the + /// source input is scanned for the preprocessor directives that might have an + /// effect on the dependencies for a compilation unit. + /// + /// Enables a client to cache the directives for a file and provide them + /// across multiple compiler invocations. + /// FIXME: Allow returning an error. + using DependencyDirectivesFn = llvm::unique_function>(FileEntryRef)>; + DependencyDirectivesFn DependencyDirectivesForFile; + /// The current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// @@ -1270,6 +1283,11 @@ public: /// false if it is producing tokens to be consumed by Parse and Sema. bool isPreprocessedOutput() const { return PreprocessedOutput; } + /// Set the function used to get dependency directives for a file. + void setDependencyDirectivesFn(DependencyDirectivesFn Fn) { + DependencyDirectivesForFile = std::move(Fn); + } + /// Return true if we are lexing directly from the specified lexer. bool isCurrentLexer(const PreprocessorLexer *L) const { return CurPPLexer == L; diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index f841e4a028df50d3030a21145fa8d9af8bb047a3..50b5fba0ff773ec5ba6aa4bdc2d1bcce9a38b02f 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -186,41 +186,6 @@ public: /// with support for lifetime-qualified pointers. ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; - /// Records the set of modules - class FailedModulesSet { - llvm::StringSet<> Failed; - - public: - bool hasAlreadyFailed(StringRef module) { - return Failed.count(module) > 0; - } - - void addFailed(StringRef module) { - Failed.insert(module); - } - }; - - /// The set of modules that failed to build. - /// - /// This pointer will be shared among all of the compiler instances created - /// to (re)build modules, so that once a module fails to build anywhere, - /// other instances will see that the module has failed and won't try to - /// build it again. - std::shared_ptr FailedModules; - - /// Function for getting the dependency preprocessor directives of a file. - /// - /// These are directives derived from a special form of lexing where the - /// source input is scanned for the preprocessor directives that might have an - /// effect on the dependencies for a compilation unit. - /// - /// Enables a client to cache the directives for a file and provide them - /// across multiple compiler invocations. - /// FIXME: Allow returning an error. - std::function>( - FileEntryRef)> - DependencyDirectivesForFile; - /// Set up preprocessor for RunAnalysis action. bool SetUpStaticAnalyzer = false; diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index e4717dd5baf1e8d2fd91f47291803ff81a72971c..76311b00d2fc586fc249b1a3e0456412ddc4b05e 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -198,6 +198,9 @@ class Sema; /// HLSL vector truncation. ICK_HLSL_Vector_Truncation, + /// HLSL non-decaying array rvalue cast. + ICK_HLSL_Array_RValue, + /// The number of conversion kinds ICK_Num_Conversion_Kinds, }; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ecd2f9eb2881f3d6e5e19a0409b8b8f5d533117..a02b684f2c77e230b819d683e0cbb466533b1d37 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -33,7 +33,6 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtOpenACC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" @@ -42,7 +41,6 @@ #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" -#include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" @@ -183,6 +181,7 @@ class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; +class SemaOpenACC; class StandardConversionSequence; class Stmt; class StringLiteral; @@ -466,9 +465,8 @@ class Sema final { // 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp) // 38. CUDA (SemaCUDA.cpp) // 39. HLSL Constructs (SemaHLSL.cpp) - // 40. OpenACC Constructs (SemaOpenACC.cpp) - // 41. OpenMP Directives and Clauses (SemaOpenMP.cpp) - // 42. SYCL Constructs (SemaSYCL.cpp) + // 40. OpenMP Directives and Clauses (SemaOpenMP.cpp) + // 41. SYCL Constructs (SemaSYCL.cpp) /// \name Semantic Analysis /// Implementations are in Sema.cpp @@ -1162,6 +1160,11 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + SemaOpenACC &OpenACC() { + assert(OpenACCPtr); + return *OpenACCPtr; + } + protected: friend class Parser; friend class InitializationSequence; @@ -1192,6 +1195,8 @@ private: mutable IdentifierInfo *Ident_super; + std::unique_ptr OpenACCPtr; + ///@} // @@ -2234,7 +2239,8 @@ private: bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); - void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D); + void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap); bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, @@ -13350,56 +13356,6 @@ public: // // - /// \name OpenACC Constructs - /// Implementations are in SemaOpenACC.cpp - ///@{ - -public: - /// Called after parsing an OpenACC Clause so that it can be checked. - bool ActOnOpenACCClause(OpenACCClauseKind ClauseKind, - SourceLocation StartLoc); - - /// Called after the construct has been parsed, but clauses haven't been - /// parsed. This allows us to diagnose not-implemented, as well as set up any - /// state required for parsing the clauses. - void ActOnOpenACCConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); - - /// Called after the directive, including its clauses, have been parsed and - /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES - /// happen before any associated declarations or statements have been parsed. - /// This function is only called when we are parsing a 'statement' context. - bool ActOnStartOpenACCStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc); - - /// Called after the directive, including its clauses, have been parsed and - /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES - /// happen before any associated declarations or statements have been parsed. - /// This function is only called when we are parsing a 'Decl' context. - bool ActOnStartOpenACCDeclDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc); - /// Called when we encounter an associated statement for our construct, this - /// should check legality of the statement as it appertains to this Construct. - StmtResult ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, - StmtResult AssocStmt); - - /// Called after the directive has been completely parsed, including the - /// declaration group or associated statement. - StmtResult ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation EndLoc, - StmtResult AssocStmt); - /// Called after the directive has been completely parsed, including the - /// declaration group or associated statement. - DeclGroupRef ActOnEndOpenACCDeclDirective(); - - ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - /// \name OpenMP Directives and Clauses /// Implementations are in SemaOpenMP.cpp ///@{ diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h new file mode 100644 index 0000000000000000000000000000000000000000..7f50d7889ad79bf237eeb3b7d6abdd7e013fd7cb --- /dev/null +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -0,0 +1,74 @@ +//===----- SemaOpenACC.h - Semantic Analysis for OpenACC constructs -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis for OpenACC constructs and +/// clauses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAOPENACC_H +#define LLVM_CLANG_SEMA_SEMAOPENACC_H + +#include "clang/AST/DeclGroup.h" +#include "clang/Basic/OpenACCKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" + +namespace clang { + +class ASTContext; +class DiagnosticEngine; +class LangOptions; +class Sema; + +class SemaOpenACC { +public: + SemaOpenACC(Sema &S); + + ASTContext &getASTContext() const; + DiagnosticsEngine &getDiagnostics() const; + const LangOptions &getLangOpts() const; + + Sema &SemaRef; + + /// Called after parsing an OpenACC Clause so that it can be checked. + bool ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc); + + /// Called after the construct has been parsed, but clauses haven't been + /// parsed. This allows us to diagnose not-implemented, as well as set up any + /// state required for parsing the clauses. + void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); + + /// Called after the directive, including its clauses, have been parsed and + /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES + /// happen before any associated declarations or statements have been parsed. + /// This function is only called when we are parsing a 'statement' context. + bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); + + /// Called after the directive, including its clauses, have been parsed and + /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES + /// happen before any associated declarations or statements have been parsed. + /// This function is only called when we are parsing a 'Decl' context. + bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); + /// Called when we encounter an associated statement for our construct, this + /// should check legality of the statement as it appertains to this Construct. + StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt); + + /// Called after the directive has been completely parsed, including the + /// declaration group or associated statement. + StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, + SourceLocation StartLoc, + SourceLocation EndLoc, StmtResult AssocStmt); + /// Called after the directive has been completely parsed, including the + /// declaration group or associated statement. + DeclGroupRef ActOnEndDeclDirective(); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAOPENACC_H diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 3c82dfed9497d587a6eaf985b809e9263d2a78c5..82b053d4caca63514d3179b5f358cd650312cbec 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -66,5 +66,6 @@ TYPE_BIT_CODE(Using, USING, 54) TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55) TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56) TYPE_BIT_CODE(CountAttributed, COUNT_ATTRIBUTED, 57) +TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58) #undef TYPE_BIT_CODE diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp index f60f09e2b3c23198b2cb58eea29beba8312efdb0..789bb97d81de004724f759f16f0dc7a496909f9d 100644 --- a/clang/lib/APINotes/APINotesManager.cpp +++ b/clang/lib/APINotes/APINotesManager.cpp @@ -221,6 +221,7 @@ APINotesManager::getCurrentModuleAPINotes(Module *M, bool LookInModule, ArrayRef SearchPaths) { FileManager &FM = SM.getFileManager(); auto ModuleName = M->getTopLevelModuleName(); + auto ExportedModuleName = M->getTopLevelModule()->ExportAsModule; llvm::SmallVector APINotes; // First, look relative to the module itself. @@ -233,6 +234,10 @@ APINotesManager::getCurrentModuleAPINotes(Module *M, bool LookInModule, APINotes.push_back(*File); } + // If module FooCore is re-exported through module Foo, try Foo.apinotes. + if (!ExportedModuleName.empty()) + if (auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic)) + APINotes.push_back(*File); }; if (M->IsFramework) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 76fd24ccfae98469d96b41e4729f51983775ab83..e3f5d102fcd07fe5b398bfd95c0edc7df0cc5b2d 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -441,7 +441,7 @@ void emitVersionedInfo( std::sort(VI.begin(), VI.end(), [](const std::pair &LHS, const std::pair &RHS) -> bool { - assert(LHS.first != RHS.first && + assert((&LHS == &RHS || LHS.first != RHS.first) && "two entries for the same version"); return LHS.first < RHS.first; }); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 20a5ecc99e44a7cb41851d850be7a644bd1072ea..f7f55dc4e7a9f436cf3a84b2c54849514c352662 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -879,7 +879,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), - CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), + ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), + SourceMgr(SM), LangOpts(LOpts), NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -1906,7 +1907,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::IncompleteArray: case Type::VariableArray: - case Type::ConstantArray: { + case Type::ConstantArray: + case Type::ArrayParameter: { // Model non-constant sized arrays as size zero, but track the alignment. uint64_t Size = 0; if (const auto *CAT = dyn_cast(T)) @@ -3396,6 +3398,37 @@ QualType ASTContext::getDecayedType(QualType T) const { return getDecayedType(T, Decayed); } +QualType ASTContext::getArrayParameterType(QualType Ty) const { + if (Ty->isArrayParameterType()) + return Ty; + assert(Ty->isConstantArrayType() && "Ty must be an array type."); + const auto *ATy = cast(Ty); + llvm::FoldingSetNodeID ID; + ATy->Profile(ID, *this, ATy->getElementType(), ATy->getZExtSize(), + ATy->getSizeExpr(), ATy->getSizeModifier(), + ATy->getIndexTypeQualifiers().getAsOpaqueValue()); + void *InsertPos = nullptr; + ArrayParameterType *AT = + ArrayParameterTypes.FindNodeOrInsertPos(ID, InsertPos); + if (AT) + return QualType(AT, 0); + + QualType Canonical; + if (!Ty.isCanonical()) { + Canonical = getArrayParameterType(getCanonicalType(Ty)); + + // Get the new insert position for the node we care about. + AT = ArrayParameterTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!AT && "Shouldn't be in the map!"); + } + + AT = new (*this, alignof(ArrayParameterType)) + ArrayParameterType(ATy, Canonical); + Types.push_back(AT); + ArrayParameterTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); +} + /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) const { @@ -3642,6 +3675,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::PackIndexing: case Type::BitInt: case Type::DependentBitInt: + case Type::ArrayParameter: llvm_unreachable("type should never be variably-modified"); // These types can be variably-modified but should never need to @@ -6051,7 +6085,9 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const { T = getVariableArrayDecayedType(T); const Type *Ty = T.getTypePtr(); QualType Result; - if (isa(Ty)) { + if (getLangOpts().HLSL && isa(Ty)) { + Result = getArrayParameterType(QualType(Ty, 0)); + } else if (isa(Ty)) { Result = getArrayDecayedType(QualType(Ty,0)); } else if (isa(Ty)) { Result = getPointerType(QualType(Ty, 0)); @@ -6973,6 +7009,8 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } QualType ASTContext::getAdjustedParameterType(QualType T) const { + if (getLangOpts().HLSL && T->isConstantArrayType()) + return getArrayParameterType(T); if (T->isArrayType() || T->isFunctionType()) return getDecayedType(T); return T; @@ -8583,6 +8621,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, case Type::DeducedTemplateSpecialization: return; + case Type::ArrayParameter: case Type::Pipe: #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) @@ -9600,11 +9639,11 @@ static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) { ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty); - unsigned EltSize = Context.getTypeSize(Info.ElementType); + uint64_t EltSize = Context.getTypeSize(Info.ElementType); if (Info.ElementType == Context.BoolTy) EltSize = 1; - unsigned MinElts = Info.EC.getKnownMinValue(); + uint64_t MinElts = Info.EC.getKnownMinValue(); return VScale->first * MinElts * EltSize; } @@ -10926,6 +10965,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, assert(LHS != RHS && "Equivalent pipe types should have already been handled!"); return {}; + case Type::ArrayParameter: + assert(LHS != RHS && + "Equivalent ArrayParameter types should have already been handled!"); + return {}; case Type::BitInt: { // Merge two bit-precise int types, while trying to preserve typedef info. bool LHSUnsigned = LHS->castAs()->isUnsigned(); @@ -12817,6 +12860,18 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); } + case Type::ArrayParameter: { + const auto *AX = cast(X), + *AY = cast(Y); + assert(AX->getSize() == AY->getSize()); + const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr()) + ? AX->getSizeExpr() + : nullptr; + auto ArrayTy = Ctx.getConstantArrayType( + getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, + getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); + return Ctx.getArrayParameterType(ArrayTy); + } case Type::Atomic: { const auto *AX = cast(X), *AY = cast(Y); return Ctx.getAtomicType( @@ -13078,6 +13133,7 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, CANONICAL_TYPE(Builtin) CANONICAL_TYPE(Complex) CANONICAL_TYPE(ConstantArray) + CANONICAL_TYPE(ArrayParameter) CANONICAL_TYPE(ConstantMatrix) CANONICAL_TYPE(Enum) CANONICAL_TYPE(ExtVector) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 786695f00fadccc37cc67fcb83dc03ff45cf25c9..94a47a8f6190181a8dbf9ac6fb513d21294ff072 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1218,6 +1218,15 @@ ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { T->getIndexTypeCVRQualifiers()); } +ExpectedType +ASTNodeImporter::VisitArrayParameterType(const ArrayParameterType *T) { + ExpectedType ToArrayTypeOrErr = VisitConstantArrayType(T); + if (!ToArrayTypeOrErr) + return ToArrayTypeOrErr.takeError(); + + return Importer.getToContext().getArrayParameterType(*ToArrayTypeOrErr); +} + ExpectedType ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 226e0aa38ece70bb990dee34bcf2de8eda6b2957..d56bf21b459e035cea410a56828dd78fec082686 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -840,6 +840,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: if (!IsStructurallyEquivalent(Context, cast(T1)->getOriginalType(), cast(T2)->getOriginalType())) diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 04bbc49ab2f3192aea29e9dd2d198c3d3fa6908c..2cbb86b31b5e2eda2ec09ad8004aeebc60e2610b 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1102,9 +1102,13 @@ bool Decl::isInAnotherModuleUnit() const { return M != getASTContext().getCurrentNamedModule(); } +bool Decl::isFromExplicitGlobalModule() const { + return getOwningModule() && getOwningModule()->isExplicitGlobalModule(); +} + bool Decl::shouldSkipCheckingODR() const { - return getASTContext().getLangOpts().SkipODRCheckInGMF && getOwningModule() && - getOwningModule()->isExplicitGlobalModule(); + return getASTContext().getLangOpts().SkipODRCheckInGMF && + isFromExplicitGlobalModule(); } static Decl::Kind getKind(const Decl *D) { return D->getKind(); } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 6221ebd5c9b4e99371d4998f7381e5673de10a67..26efaa4624056b17fcd0aa0074dd8610dc6fb399 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1948,6 +1948,7 @@ bool CastExpr::CastConsistency() const { case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: case CK_FixedPointToBoolean: + case CK_HLSLArrayRValue: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5a36621dc5cce28780753e647219c806e7fb9f5f..0058e86519985e7519758c25be9589d2a6fbeea7 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11699,6 +11699,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T, case Type::IncompleteArray: case Type::FunctionNoProto: case Type::FunctionProto: + case Type::ArrayParameter: return GCCTypeClass::Pointer; case Type::MemberPointer: @@ -12361,12 +12362,17 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; + std::optional Fallback; + if (BuiltinOp == Builtin::BI__builtin_clzg && E->getNumArgs() > 1) { + APSInt FallbackTemp; + if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) + return false; + Fallback = FallbackTemp; + } + if (!Val) { - if (BuiltinOp == Builtin::BI__builtin_clzg && E->getNumArgs() > 1) { - if (!EvaluateInteger(E->getArg(1), Val, Info)) - return false; - return Success(Val, E); - } + if (Fallback) + return Success(*Fallback, E); // When the argument is 0, the result of GCC builtins is undefined, // whereas for Microsoft intrinsics, the result is the bit-width of the @@ -12425,12 +12431,17 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; + std::optional Fallback; + if (BuiltinOp == Builtin::BI__builtin_ctzg && E->getNumArgs() > 1) { + APSInt FallbackTemp; + if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) + return false; + Fallback = FallbackTemp; + } + if (!Val) { - if (BuiltinOp == Builtin::BI__builtin_ctzg && E->getNumArgs() > 1) { - if (!EvaluateInteger(E->getArg(1), Val, Info)) - return false; - return Success(Val, E); - } + if (Fallback) + return Success(*Fallback, E); return Error(E); } @@ -14075,6 +14086,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AtomicToNonAtomic: case CK_NoOp: case CK_LValueToRValueBitCast: + case CK_HLSLArrayRValue: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: @@ -14903,6 +14915,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AtomicToNonAtomic: case CK_NoOp: case CK_LValueToRValueBitCast: + case CK_HLSLArrayRValue: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_Dependent: diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 0c80ad109ccbb272236706fefb6cbc70b2c66d7b..da8164bad518ec7d646030cabbcbb0bb0d26cb8f 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -413,7 +413,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return Match; if (const auto *BT = argTy->getAs()) { // Check if the only difference between them is signed vs unsigned - // if true, we consider they are compatible. + // if true, return match signedness. switch (BT->getKind()) { default: break; @@ -423,44 +423,53 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { [[fallthrough]]; case BuiltinType::Char_S: case BuiltinType::SChar: + if (T == C.UnsignedShortTy || T == C.ShortTy) + return NoMatchTypeConfusion; + if (T == C.UnsignedCharTy) + return NoMatchSignedness; + if (T == C.SignedCharTy) + return Match; + break; case BuiltinType::Char_U: case BuiltinType::UChar: if (T == C.UnsignedShortTy || T == C.ShortTy) return NoMatchTypeConfusion; - if (T == C.UnsignedCharTy || T == C.SignedCharTy) + if (T == C.UnsignedCharTy) return Match; + if (T == C.SignedCharTy) + return NoMatchSignedness; break; case BuiltinType::Short: if (T == C.UnsignedShortTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::UShort: if (T == C.ShortTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::Int: if (T == C.UnsignedIntTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::UInt: if (T == C.IntTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::Long: if (T == C.UnsignedLongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::ULong: if (T == C.LongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::LongLong: if (T == C.UnsignedLongLongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::ULongLong: if (T == C.LongLongTy) - return Match; + return NoMatchSignedness; break; } // "Partially matched" because of promotions? diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h index ab7a591fb798ee6fb8e1d97c12d7a491fe84c536..d7e6e5042c2740b72c38a219fcaf1a89ba9d3c7c 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -82,6 +82,7 @@ private: OptLabelTy DefaultLabel; }; +extern template class ByteCodeStmtGen; extern template class ByteCodeExprGen; } // namespace interp diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index f619d657ae9f50c4491532d497eaf7d54522acdd..d632c697fa20dbc4e88e15a6715f923020680b19 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2398,6 +2398,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Complex: case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -3445,6 +3446,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_PreserveAll: case CC_M68kRTD: case CC_PreserveNone: + case CC_RISCVVectorCall: // FIXME: we should be mangling all of the above. return ""; @@ -4445,6 +4447,10 @@ void CXXNameMangler::mangleType(const DependentBitIntType *T) { Out << "_"; } +void CXXNameMangler::mangleType(const ArrayParameterType *T) { + mangleType(cast(T)); +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // ::= L E # integer literal diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index addc3140546a46385618e72b24362f8a510a59fb..a0bb04e69c9be8ad244618fb51277344309811a6 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -3079,6 +3079,11 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { mangleType(ElementTy, SourceRange(), QMM_Escape); } +void MicrosoftCXXNameMangler::mangleType(const ArrayParameterType *T, + Qualifiers, SourceRange) { + mangleArrayType(cast(T)); +} + // ::= // ::= // diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 2dbc259138a897d46db6e76df532df62a4dda2e0..e159a1b00be552bab566c07313ff64264f9951ff 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -944,6 +944,10 @@ public: VisitArrayType(T); } + void VisitArrayParameterType(const ArrayParameterType *T) { + VisitConstantArrayType(T); + } + void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { AddStmt(T->getSizeExpr()); VisitArrayType(T); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index b683eb1edd8f136eb9c878ce995a635f1685a721..413e452146bdb27ce55478e034b330302634e50a 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1990,6 +1990,19 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { } } +void TextNodeDumper::VisitCXXDeductionGuideDecl( + const CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); + switch (D->getDeductionCandidateKind()) { + case DeductionCandidate::Normal: + case DeductionCandidate::Copy: + return; + case DeductionCandidate::Aggregate: + OS << " aggregate "; + break; + } +} + void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl( const LifetimeExtendedTemporaryDecl *D) { OS << " extended by "; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index d2ffb23845acab673d4bad25835777c1305a0b5d..779d8a810820d29238e40874b148b19a23dd1713 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1197,6 +1197,14 @@ public: return Ctx.getDecayedType(originalType); } + QualType VisitArrayParameterType(const ArrayParameterType *T) { + QualType ArrTy = VisitConstantArrayType(T); + if (ArrTy.isNull()) + return {}; + + return Ctx.getArrayParameterType(ArrTy); + } + SUGARED_TYPE_CLASS(TypeOfExpr) SUGARED_TYPE_CLASS(TypeOf) SUGARED_TYPE_CLASS(Decltype) @@ -3484,6 +3492,9 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_PreserveAll: return "preserve_all"; case CC_M68kRTD: return "m68k_rtd"; case CC_PreserveNone: return "preserve_none"; + // clang-format off + case CC_RISCVVectorCall: return "riscv_vector_cc"; + // clang-format on } llvm_unreachable("Invalid calling convention."); @@ -4074,6 +4085,7 @@ bool AttributedType::isCallingConv() const { case attr::PreserveAll: case attr::M68kRTD: case attr::PreserveNone: + case attr::RISCVVectorCC: return true; } llvm_unreachable("invalid attr kind"); @@ -4450,6 +4462,7 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: return Cache::get(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: @@ -4538,6 +4551,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: return computeTypeLinkageInfo(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: @@ -4732,6 +4746,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::Pipe: case Type::BitInt: case Type::DependentBitInt: + case Type::ArrayParameter: return false; } llvm_unreachable("bad type kind!"); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index f176d043d52521606d59c21a5ac60163b234b968..9d551ff83151fd752ca7544cc11ffdf639d62061 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -268,6 +268,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -595,6 +596,16 @@ void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) { printAdjustedBefore(T, OS); } +void TypePrinter::printArrayParameterAfter(const ArrayParameterType *T, + raw_ostream &OS) { + printConstantArrayAfter(T, OS); +} + +void TypePrinter::printArrayParameterBefore(const ArrayParameterType *T, + raw_ostream &OS) { + printConstantArrayBefore(T, OS); +} + void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) { printAdjustedAfter(T, OS); } @@ -1071,6 +1082,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_PreserveNone: OS << " __attribute__((preserve_none))"; break; + case CC_RISCVVectorCall: + OS << "__attribute__((riscv_vector_cc))"; + break; } } @@ -1960,6 +1974,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::PreserveNone: OS << "preserve_none"; break; + case attr::RISCVVectorCC: + OS << "riscv_vector_cc"; + break; case attr::NoDeref: OS << "noderef"; break; diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 70e0623805a8cfb46fb7c76237b4af9a5083a550..f729d676dd0de8c0d06d0dc71efd4908828b3d1c 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -1169,6 +1169,42 @@ getFieldsForInitListExpr(const InitListExpr *InitList) { return Fields; } +RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) { + auto *RD = InitList->getType()->getAsCXXRecordDecl(); + assert(RD != nullptr); + + std::vector Fields = getFieldsForInitListExpr(InitList); + ArrayRef Inits = InitList->inits(); + + // Unions initialized with an empty initializer list need special treatment. + // For structs/classes initialized with an empty initializer list, Clang + // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, + // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. + SmallVector InitsForUnion; + if (InitList->getType()->isUnionType() && Inits.empty()) { + assert(Fields.size() == 1); + ImplicitValueInitForUnion.emplace(Fields.front()->getType()); + InitsForUnion.push_back(&*ImplicitValueInitForUnion); + Inits = InitsForUnion; + } + + size_t InitIdx = 0; + + assert(Fields.size() + RD->getNumBases() == Inits.size()); + for (const CXXBaseSpecifier &Base : RD->bases()) { + assert(InitIdx < Inits.size()); + Expr *Init = Inits[InitIdx++]; + BaseInits.emplace_back(&Base, Init); + } + + assert(Fields.size() == Inits.size() - InitIdx); + for (const FieldDecl *Field : Fields) { + assert(InitIdx < Inits.size()); + Expr *Init = Inits[InitIdx++]; + FieldInits.emplace_back(Field, Init); + } +} + RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { auto &NewVal = Env.create(Loc); Env.setValue(Loc, NewVal); diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index dbf4878622eba93f731927987cad6153478af198..cadb1ceb2d850733829a9d18e1a0ddef67e80946 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -512,27 +512,26 @@ void constructOptionalValue(const Expr &E, Environment &Env, /// Returns a symbolic value for the "has_value" property of an `optional` /// value that is constructed/assigned from a value of type `U` or `optional` /// where `T` is constructible from `U`. -BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E, +BoolValue &valueOrConversionHasValue(QualType DestType, const Expr &E, const MatchFinder::MatchResult &MatchRes, LatticeTransferState &State) { - assert(F.getTemplateSpecializationArgs() != nullptr); - assert(F.getTemplateSpecializationArgs()->size() > 0); - - const int TemplateParamOptionalWrappersCount = - countOptionalWrappers(*MatchRes.Context, F.getTemplateSpecializationArgs() - ->get(0) - .getAsType() - .getNonReferenceType()); + const int DestTypeOptionalWrappersCount = + countOptionalWrappers(*MatchRes.Context, DestType); const int ArgTypeOptionalWrappersCount = countOptionalWrappers( *MatchRes.Context, E.getType().getNonReferenceType()); - // Check if this is a constructor/assignment call for `optional` with - // argument of type `U` such that `T` is constructible from `U`. - if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount) + // Is this an constructor of the form `template optional(U &&)` / + // assignment of the form `template optional& operator=(U &&)` + // (where `T` is assignable / constructible from `U`)? + // We recognize this because the number of optionals in the optional being + // assigned to is different from the function argument type. + if (DestTypeOptionalWrappersCount != ArgTypeOptionalWrappersCount) return State.Env.getBoolLiteralValue(true); - // This is a constructor/assignment call for `optional` with argument of - // type `optional` such that `T` is constructible from `U`. + // Otherwise, this must be a constructor of the form + // `template optional &&)` / assignment of the form + // `template optional& operator=(optional &&) + // (where, again, `T` is assignable / constructible from `U`). auto *Loc = State.Env.get(E); if (auto *HasValueVal = getHasValue(State.Env, Loc)) return *HasValueVal; @@ -544,10 +543,11 @@ void transferValueOrConversionConstructor( LatticeTransferState &State) { assert(E->getNumArgs() > 0); - constructOptionalValue(*E, State.Env, - valueOrConversionHasValue(*E->getConstructor(), - *E->getArg(0), MatchRes, - State)); + constructOptionalValue( + *E, State.Env, + valueOrConversionHasValue( + E->getConstructor()->getThisType()->getPointeeType(), *E->getArg(0), + MatchRes, State)); } void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal, @@ -566,10 +566,11 @@ void transferValueOrConversionAssignment( const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes, LatticeTransferState &State) { assert(E->getNumArgs() > 1); - transferAssignment(E, - valueOrConversionHasValue(*E->getDirectCallee(), - *E->getArg(1), MatchRes, State), - State); + transferAssignment( + E, + valueOrConversionHasValue(E->getArg(0)->getType().getNonReferenceType(), + *E->getArg(1), MatchRes, State), + State); } void transferNulloptAssignment(const CXXOperatorCallExpr *E, diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 960e9688ffb725977dc035f2c43e594e52537c01..0a2e8368d541dd0f684d7e8672b7b8fc82aeb40b 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -689,51 +689,22 @@ public: } llvm::DenseMap FieldLocs; - - // This only contains the direct fields for the given type. - std::vector FieldsForInit = getFieldsForInitListExpr(S); - - // `S->inits()` contains all the initializer expressions, including the - // ones for direct base classes. - ArrayRef Inits = S->inits(); - size_t InitIdx = 0; - - // Unions initialized with an empty initializer list need special treatment. - // For structs/classes initialized with an empty initializer list, Clang - // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, - // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. - std::optional ImplicitValueInitForUnion; - SmallVector InitsForUnion; - if (S->getType()->isUnionType() && Inits.empty()) { - assert(FieldsForInit.size() == 1); - ImplicitValueInitForUnion.emplace(FieldsForInit.front()->getType()); - InitsForUnion.push_back(&*ImplicitValueInitForUnion); - Inits = InitsForUnion; - } - - // Initialize base classes. - if (auto* R = S->getType()->getAsCXXRecordDecl()) { - assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); - for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { - assert(InitIdx < Inits.size()); - auto Init = Inits[InitIdx++]; - assert(Base.getType().getCanonicalType() == - Init->getType().getCanonicalType()); - auto *BaseVal = Env.get(*Init); - if (!BaseVal) - BaseVal = cast(Env.createValue(Init->getType())); - // Take ownership of the fields of the `RecordValue` for the base class - // and incorporate them into the "flattened" set of fields for the - // derived class. - auto Children = BaseVal->getLoc().children(); - FieldLocs.insert(Children.begin(), Children.end()); - } - } - - assert(FieldsForInit.size() == Inits.size() - InitIdx); - for (auto Field : FieldsForInit) { - assert(InitIdx < Inits.size()); - auto Init = Inits[InitIdx++]; + RecordInitListHelper InitListHelper(S); + + for (auto [Base, Init] : InitListHelper.base_inits()) { + assert(Base->getType().getCanonicalType() == + Init->getType().getCanonicalType()); + auto *BaseVal = Env.get(*Init); + if (!BaseVal) + BaseVal = cast(Env.createValue(Init->getType())); + // Take ownership of the fields of the `RecordValue` for the base class + // and incorporate them into the "flattened" set of fields for the + // derived class. + auto Children = BaseVal->getLoc().children(); + FieldLocs.insert(Children.begin(), Children.end()); + } + + for (auto [Field, Init] : InitListHelper.field_inits()) { assert( // The types are same, or Field->getType().getCanonicalType().getUnqualifiedType() == diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 5d9055174c089ad8d11bdf32e0eb46b952527d82..f96956f31d50dc404a05d7b691aec694ad9c4999 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -157,6 +157,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { HasAArch64SVETypes = false; HasRISCVVTypes = false; AllowAMDGPUUnsafeFPAtomics = false; + HasUnalignedAccess = false; ARMCDECoprocMask = 0; // Default to no types using fpret. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 1c3199bd76eed6591574013cdb4f4e7293a626d2..1569b5e04b770a0d2b8ef045263abb12d2c8f769 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -188,6 +188,8 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); UseZeroLengthBitfieldAlignment = true; + HasUnalignedAccess = true; + // AArch64 targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericAArch64); @@ -496,7 +498,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasPAuthLR) Builder.defineMacro("__ARM_FEATURE_PAUTH_LR", "1"); - if (HasUnaligned) + if (HasUnalignedAccess) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); if ((FPU & NeonMode) && HasFullFP16) @@ -921,7 +923,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, HasSM4 = true; } if (Feature == "+strict-align") - HasUnaligned = false; + HasUnalignedAccess = false; + // All predecessor archs are added but select the latest one for ArchKind. if (Feature == "+v8a" && ArchInfo->Version < llvm::AArch64::ARMV8A.Version) ArchInfo = &llvm::AArch64::ARMV8A; diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 542894c66412dc88b09302fc526aed653678f576..12fb50286f7511a6c5bf461ba3cf041d5f8bda4b 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -38,7 +38,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { bool HasSHA2 = false; bool HasSHA3 = false; bool HasSM4 = false; - bool HasUnaligned = true; bool HasFullFP16 = false; bool HasDotProd = false; bool HasFP16FML = false; diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 55b71557452fa04db6b60512368d8ab17c45cac0..877799c66ec4f234cb2682d76a1fd40994b09304 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -509,7 +509,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, SHA2 = 0; AES = 0; DSP = 0; - Unaligned = 1; + HasUnalignedAccess = true; SoftFloat = false; // Note that SoftFloatABI is initialized in our constructor. HWDiv = 0; @@ -576,7 +576,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, return false; } } else if (Feature == "+strict-align") { - Unaligned = 0; + HasUnalignedAccess = false; } else if (Feature == "+fp16") { HW_FP |= HW_FP_HP; } else if (Feature == "+fullfp16") { @@ -785,7 +785,7 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); // ACLE 6.4.3 Unaligned access supported in hardware - if (Unaligned) + if (HasUnalignedAccess) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); // ACLE 6.4.4 LDREX/STREX diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 71322a094f5edba2cd9a31a433accc1efac54ebf..e69adbe754739f66f6084b252661404bf96b892b 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -88,8 +88,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { LLVM_PREFERRED_TYPE(bool) unsigned DSP : 1; LLVM_PREFERRED_TYPE(bool) - unsigned Unaligned : 1; - LLVM_PREFERRED_TYPE(bool) unsigned DotProd : 1; LLVM_PREFERRED_TYPE(bool) unsigned HasMatMul : 1; diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 88537989a05129f553b89ac2e74a444e9472bea0..280bd1d8033cc6ff7de12b5c122632276026e461 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -285,6 +285,8 @@ bool LoongArchTargetInfo::handleTargetFeatures( HasFeatureLSX = true; else if (Feature == "+lasx") HasFeatureLASX = true; + else if (Feature == "-ual") + HasUnalignedAccess = false; } return true; } diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h index 3313102492cb8dc41b484c650630d5f451992c8c..68572843f2d7486398361271abda589ab075ca69 100644 --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -132,6 +132,7 @@ public: : LoongArchTargetInfo(Triple, Opts) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; IntMaxType = Int64Type = SignedLong; + HasUnalignedAccess = true; resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128"); // TODO: select appropriate ABI. setABI("lp64d"); diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 23d4e1b598fa1e44d470cea120c016a82a954431..c9dcf434c93b0b0579f5d94f3c28a2fead582384 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -328,6 +328,8 @@ public: IsMips16 = true; else if (Feature == "+micromips") IsMicromips = true; + else if (Feature == "+mips32r6" || Feature == "+mips64r6") + HasUnalignedAccess = true; else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); else if (Feature == "+dspr2") diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 70683916a8b04f6616eb363c6c5f0501909bad4b..fa2f442e25846de4ed0386e543a8613a213120b2 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -92,6 +92,7 @@ public: LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); HasStrictFP = true; HasIbm128 = true; + HasUnalignedAccess = true; } // Set the language option for altivec based on our value. diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index a6d4af2b88111a4821b7292d3eacb3c1eafab6b5..f3d705e1551fe29fca69fcb610b9bc15d7ee3b24 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -467,3 +467,14 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { } return Ret; } + +TargetInfo::CallingConvCheckResult +RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_RISCVVectorCall: + return CCCR_OK; + } +} diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index bfbdafb682c851333d8371de12436f9dfaed278c..78580b5b1c1063cd5f39f44ca20dbafff121818a 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -110,6 +110,8 @@ public: bool hasBFloat16Type() const override { return true; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + bool useFP16ConversionIntrinsics() const override { return false; } diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 3e08b27972fa3966df5d5e5ffa83c21460b6773c..8e302acd51b8ad1d40e175e65c3e5ab7a2895dc6 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -47,6 +47,7 @@ public: LongDoubleFormat = &llvm::APFloat::IEEEquad(); DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; + HasUnalignedAccess = true; if (Triple.isOSzOS()) { TLSSupported = false; // All vector types are default aligned on an 8-byte boundary, even if the diff --git a/clang/lib/Basic/Targets/VE.h b/clang/lib/Basic/Targets/VE.h index ea9a092cad80908539d279402458f93a9b06b45b..7e8fdf6096ef232c2212f883db2eb36309d6b3db 100644 --- a/clang/lib/Basic/Targets/VE.h +++ b/clang/lib/Basic/Targets/VE.h @@ -40,6 +40,7 @@ public: Int64Type = SignedLong; RegParmMax = 8; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + HasUnalignedAccess = true; WCharType = UnsignedInt; WIntType = UnsignedInt; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 83b1711f9fdf6a8ce8632913b7666d348c6b4550..5568aa28eaefa7152637b70f4343937676f2a3d4 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -84,6 +84,7 @@ public: SizeType = UnsignedLong; PtrDiffType = SignedLong; IntPtrType = SignedLong; + HasUnalignedAccess = true; } StringRef getABI() const override; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index d2232c7d5275abf47a4955b5e30c1ae36f5ad584..c14e4d5f433d8244f3a45e9752a6d19cd7bd2aac 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -188,6 +188,7 @@ public: LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); AddrSpaceMap = &X86AddrSpaceMap; HasStrictFP = true; + HasUnalignedAccess = true; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index dd59101ecc81b8269cddd7605b34c60824c9654f..3e34d82cb399ba05f880cc7fd470cfac0af08a8d 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -187,7 +187,7 @@ CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, CharUnits FullDirectSize = DirectSize.alignTo(SlotSize); Address NextPtr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next"); - CGF.Builder.CreateStore(NextPtr.getPointer(), VAListAddr); + CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr); // If the argument is smaller than a slot, and this is a big-endian // target, the argument will be right-adjusted in its slot. @@ -239,8 +239,8 @@ Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, const llvm::Twine &Name) { assert(Addr1.getType() == Addr2.getType()); llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name); - PHI->addIncoming(Addr1.getPointer(), Block1); - PHI->addIncoming(Addr2.getPointer(), Block2); + PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1); + PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2); CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment()); return Address(PHI, Addr1.getElementType(), Align); } @@ -400,7 +400,7 @@ Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty); llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy); llvm::Value *Addr = - CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy); + CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy); return Address(Addr, ElementTy, TyAlignForABI); } else { assert((AI.isDirect() || AI.isExtend()) && @@ -416,7 +416,7 @@ Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!"); Address Temp = CGF.CreateMemTemp(Ty, "varet"); - Val = CGF.Builder.CreateVAArg(VAListAddr.getPointer(), + Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Ty)); CGF.Builder.CreateStore(Val, Temp); return Temp; diff --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h index cf48df8f5e7367e0c3737f837b83cd057dc07142..35ec370a139c92efc4686eac311947d74952a270 100644 --- a/clang/lib/CodeGen/Address.h +++ b/clang/lib/CodeGen/Address.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H #include "clang/AST/CharUnits.h" +#include "clang/AST/Type.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Constants.h" #include "llvm/Support/MathExtras.h" @@ -22,28 +23,41 @@ namespace clang { namespace CodeGen { +class Address; +class CGBuilderTy; +class CodeGenFunction; +class CodeGenModule; + // Indicates whether a pointer is known not to be null. enum KnownNonNull_t { NotKnownNonNull, KnownNonNull }; -/// An aligned address. -class Address { +/// An abstract representation of an aligned address. This is designed to be an +/// IR-level abstraction, carrying just the information necessary to perform IR +/// operations on an address like loads and stores. In particular, it doesn't +/// carry C type information or allow the representation of things like +/// bit-fields; clients working at that level should generally be using +/// `LValue`. +/// The pointer contained in this class is known to be unsigned. +class RawAddress { llvm::PointerIntPair PointerAndKnownNonNull; llvm::Type *ElementType; CharUnits Alignment; protected: - Address(std::nullptr_t) : ElementType(nullptr) {} + RawAddress(std::nullptr_t) : ElementType(nullptr) {} public: - Address(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, - KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + RawAddress(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) : PointerAndKnownNonNull(Pointer, IsKnownNonNull), ElementType(ElementType), Alignment(Alignment) { assert(Pointer != nullptr && "Pointer cannot be null"); assert(ElementType != nullptr && "Element type cannot be null"); } - static Address invalid() { return Address(nullptr); } + inline RawAddress(Address Addr); + + static RawAddress invalid() { return RawAddress(nullptr); } bool isValid() const { return PointerAndKnownNonNull.getPointer() != nullptr; } @@ -80,6 +94,133 @@ public: return Alignment; } + /// Return address with different element type, but same pointer and + /// alignment. + RawAddress withElementType(llvm::Type *ElemTy) const { + return RawAddress(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); + } + + KnownNonNull_t isKnownNonNull() const { + assert(isValid()); + return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); + } +}; + +/// Like RawAddress, an abstract representation of an aligned address, but the +/// pointer contained in this class is possibly signed. +class Address { + friend class CGBuilderTy; + + // The boolean flag indicates whether the pointer is known to be non-null. + llvm::PointerIntPair Pointer; + + /// The expected IR type of the pointer. Carrying accurate element type + /// information in Address makes it more convenient to work with Address + /// values and allows frontend assertions to catch simple mistakes. + llvm::Type *ElementType = nullptr; + + CharUnits Alignment; + + /// Offset from the base pointer. + llvm::Value *Offset = nullptr; + + llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const; + +protected: + Address(std::nullptr_t) : ElementType(nullptr) {} + +public: + Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + : Pointer(pointer, IsKnownNonNull), ElementType(elementType), + Alignment(alignment) { + assert(pointer != nullptr && "Pointer cannot be null"); + assert(elementType != nullptr && "Element type cannot be null"); + assert(!alignment.isZero() && "Alignment cannot be zero"); + } + + Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment, + llvm::Value *Offset, KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType), + Alignment(Alignment), Offset(Offset) {} + + Address(RawAddress RawAddr) + : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr), + ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr), + Alignment(RawAddr.isValid() ? RawAddr.getAlignment() + : CharUnits::Zero()) {} + + static Address invalid() { return Address(nullptr); } + bool isValid() const { return Pointer.getPointer() != nullptr; } + + /// This function is used in situations where the caller is doing some sort of + /// opaque "laundering" of the pointer. + void replaceBasePointer(llvm::Value *P) { + assert(isValid() && "pointer isn't valid"); + assert(P->getType() == Pointer.getPointer()->getType() && + "Pointer's type changed"); + Pointer.setPointer(P); + assert(isValid() && "pointer is invalid after replacement"); + } + + CharUnits getAlignment() const { return Alignment; } + + void setAlignment(CharUnits Value) { Alignment = Value; } + + llvm::Value *getBasePointer() const { + assert(isValid() && "pointer isn't valid"); + return Pointer.getPointer(); + } + + /// Return the type of the pointer value. + llvm::PointerType *getType() const { + return llvm::PointerType::get( + ElementType, + llvm::cast(Pointer.getPointer()->getType()) + ->getAddressSpace()); + } + + /// Return the type of the values stored in this address. + llvm::Type *getElementType() const { + assert(isValid()); + return ElementType; + } + + /// Return the address space that this address resides in. + unsigned getAddressSpace() const { return getType()->getAddressSpace(); } + + /// Return the IR name of the pointer value. + llvm::StringRef getName() const { return Pointer.getPointer()->getName(); } + + // This function is called only in CGBuilderBaseTy::CreateElementBitCast. + void setElementType(llvm::Type *Ty) { + assert(hasOffset() && + "this funcion shouldn't be called when there is no offset"); + ElementType = Ty; + } + + /// Whether the pointer is known not to be null. + KnownNonNull_t isKnownNonNull() const { + assert(isValid()); + return (KnownNonNull_t)Pointer.getInt(); + } + + Address setKnownNonNull() { + assert(isValid()); + Pointer.setInt(KnownNonNull); + return *this; + } + + bool hasOffset() const { return Offset; } + + llvm::Value *getOffset() const { return Offset; } + + /// Return the pointer contained in this class after authenticating it and + /// adding offset to it if necessary. + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { + return getBasePointer(); + } + /// Return address with different pointer, but same element type and /// alignment. Address withPointer(llvm::Value *NewPointer, @@ -91,61 +232,59 @@ public: /// Return address with different alignment, but same pointer and element /// type. Address withAlignment(CharUnits NewAlignment) const { - return Address(getPointer(), getElementType(), NewAlignment, + return Address(Pointer.getPointer(), getElementType(), NewAlignment, isKnownNonNull()); } /// Return address with different element type, but same pointer and /// alignment. Address withElementType(llvm::Type *ElemTy) const { - return Address(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); - } - - /// Whether the pointer is known not to be null. - KnownNonNull_t isKnownNonNull() const { - assert(isValid()); - return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); - } - - /// Set the non-null bit. - Address setKnownNonNull() { - assert(isValid()); - PointerAndKnownNonNull.setInt(true); - return *this; + if (!hasOffset()) + return Address(getBasePointer(), ElemTy, getAlignment(), nullptr, + isKnownNonNull()); + Address A(*this); + A.ElementType = ElemTy; + return A; } }; +inline RawAddress::RawAddress(Address Addr) + : PointerAndKnownNonNull(Addr.isValid() ? Addr.getBasePointer() : nullptr, + Addr.isValid() ? Addr.isKnownNonNull() + : NotKnownNonNull), + ElementType(Addr.isValid() ? Addr.getElementType() : nullptr), + Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} + /// A specialization of Address that requires the address to be an /// LLVM Constant. -class ConstantAddress : public Address { - ConstantAddress(std::nullptr_t) : Address(nullptr) {} +class ConstantAddress : public RawAddress { + ConstantAddress(std::nullptr_t) : RawAddress(nullptr) {} public: ConstantAddress(llvm::Constant *pointer, llvm::Type *elementType, CharUnits alignment) - : Address(pointer, elementType, alignment) {} + : RawAddress(pointer, elementType, alignment) {} static ConstantAddress invalid() { return ConstantAddress(nullptr); } llvm::Constant *getPointer() const { - return llvm::cast(Address::getPointer()); + return llvm::cast(RawAddress::getPointer()); } ConstantAddress withElementType(llvm::Type *ElemTy) const { return ConstantAddress(getPointer(), ElemTy, getAlignment()); } - static bool isaImpl(Address addr) { + static bool isaImpl(RawAddress addr) { return llvm::isa(addr.getPointer()); } - static ConstantAddress castImpl(Address addr) { + static ConstantAddress castImpl(RawAddress addr) { return ConstantAddress(llvm::cast(addr.getPointer()), addr.getElementType(), addr.getAlignment()); } }; - } // Present a minimal LLVM-like casting interface. diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index fb03d013e8afc7ba7c9e952eadabd44ae9e005a9..56198385de9dcbdec1a1990c22c5e5e80608b79e 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -80,7 +80,7 @@ namespace { AtomicSizeInBits = C.toBits( C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1) .alignTo(lvalue.getAlignment())); - llvm::Value *BitFieldPtr = lvalue.getBitFieldPointer(); + llvm::Value *BitFieldPtr = lvalue.getRawBitFieldPointer(CGF); auto OffsetInChars = (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) * lvalue.getAlignment(); @@ -139,13 +139,13 @@ namespace { const LValue &getAtomicLValue() const { return LVal; } llvm::Value *getAtomicPointer() const { if (LVal.isSimple()) - return LVal.getPointer(CGF); + return LVal.emitRawPointer(CGF); else if (LVal.isBitField()) - return LVal.getBitFieldPointer(); + return LVal.getRawBitFieldPointer(CGF); else if (LVal.isVectorElt()) - return LVal.getVectorPointer(); + return LVal.getRawVectorPointer(CGF); assert(LVal.isExtVectorElt()); - return LVal.getExtVectorPointer(); + return LVal.getRawExtVectorPointer(CGF); } Address getAtomicAddress() const { llvm::Type *ElTy; @@ -368,7 +368,7 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const { return false; CGF.Builder.CreateMemSet( - addr.getPointer(), llvm::ConstantInt::get(CGF.Int8Ty, 0), + addr.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.Int8Ty, 0), CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(), LVal.getAlignment().getAsAlign()); return true; @@ -1055,7 +1055,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { return getTargetHooks().performAddrSpaceCast( *this, V, AS, LangAS::opencl_generic, DestType, false); }; - Args.add(RValue::get(CastToGenericAddrSpace(Ptr.getPointer(), + + Args.add(RValue::get(CastToGenericAddrSpace(Ptr.emitRawPointer(*this), E->getPtr()->getType())), getContext().VoidPtrTy); @@ -1086,10 +1087,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LibCallName = "__atomic_compare_exchange"; RetTy = getContext().BoolTy; HaveRetTy = true; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); - Args.add(RValue::get(CastToGenericAddrSpace(Val2.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val2.emitRawPointer(*this), E->getVal2()->getType())), getContext().VoidPtrTy); Args.add(RValue::get(Order), getContext().IntTy); @@ -1105,7 +1106,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__scoped_atomic_exchange: case AtomicExpr::AO__scoped_atomic_exchange_n: LibCallName = "__atomic_exchange"; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); break; @@ -1120,7 +1121,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LibCallName = "__atomic_store"; RetTy = getContext().VoidTy; HaveRetTy = true; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); break; @@ -1199,7 +1200,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { if (!HaveRetTy) { // Value is returned through parameter before the order. RetTy = getContext().VoidTy; - Args.add(RValue::get(CastToGenericAddrSpace(Dest.getPointer(), RetTy)), + Args.add(RValue::get( + CastToGenericAddrSpace(Dest.emitRawPointer(*this), RetTy)), getContext().VoidPtrTy); } // Order is always the last parameter. @@ -1513,7 +1515,7 @@ RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, } else TempAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(TempAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(TempAddr.emitRawPointer(CGF), AO, IsVolatile); // Okay, turn that back into the original value or whole atomic (for // non-simple lvalues) type. @@ -1673,9 +1675,9 @@ std::pair AtomicInfo::EmitAtomicCompareExchange( if (shouldUseLibcall()) { // Produce a source address. Address ExpectedAddr = materializeRValue(Expected); - Address DesiredAddr = materializeRValue(Desired); - auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = materializeRValue(Desired).emitRawPointer(CGF); + auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, Success, Failure); return std::make_pair( convertAtomicTempToRValue(ExpectedAddr, AggValueSlot::ignored(), @@ -1757,7 +1759,7 @@ void AtomicInfo::EmitAtomicUpdateLibcall( Address ExpectedAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile); auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); CGF.EmitBlock(ContBB); @@ -1771,10 +1773,10 @@ void AtomicInfo::EmitAtomicUpdateLibcall( AggValueSlot::ignored(), SourceLocation(), /*AsValue=*/false); EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr); + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF); auto *Res = - EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), - AO, Failure); + EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure); CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); CGF.EmitBlock(ExitBB, /*IsFinished=*/true); } @@ -1843,7 +1845,7 @@ void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, Address ExpectedAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile); auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); CGF.EmitBlock(ContBB); @@ -1854,10 +1856,10 @@ void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, CGF.Builder.CreateStore(OldVal, DesiredAddr); } EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr); + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF); auto *Res = - EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), - AO, Failure); + EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure); CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); CGF.EmitBlock(ExitBB, /*IsFinished=*/true); } @@ -1957,7 +1959,8 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, args.add(RValue::get(atomics.getAtomicSizeValue()), getContext().getSizeType()); args.add(RValue::get(atomics.getAtomicPointer()), getContext().VoidPtrTy); - args.add(RValue::get(srcAddr.getPointer()), getContext().VoidPtrTy); + args.add(RValue::get(srcAddr.emitRawPointer(*this)), + getContext().VoidPtrTy); args.add( RValue::get(llvm::ConstantInt::get(IntTy, (int)llvm::toCABI(AO))), getContext().IntTy); diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index ad0b50d799618ed7ec7ecb581dd1bec84538a40c..a01f2c7c979840ca8be2cf10c6462633e70855bb 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -36,7 +36,8 @@ CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name) : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), NoEscape(false), HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false), CapturesNonExternalType(false), - LocalAddress(Address::invalid()), StructureType(nullptr), Block(block) { + LocalAddress(RawAddress::invalid()), StructureType(nullptr), + Block(block) { // Skip asm prefix, if any. 'name' is usually taken directly from // the mangled name of the enclosing function. @@ -794,7 +795,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // Otherwise, we have to emit this as a local block. - Address blockAddr = blockInfo.LocalAddress; + RawAddress blockAddr = blockInfo.LocalAddress; assert(blockAddr.isValid() && "block has no address!"); llvm::Constant *isa; @@ -939,7 +940,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (CI.isNested()) byrefPointer = Builder.CreateLoad(src, "byref.capture"); else - byrefPointer = src.getPointer(); + byrefPointer = src.emitRawPointer(*this); // Write that void* into the capture field. Builder.CreateStore(byrefPointer, blockField); @@ -961,10 +962,10 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } // If it's a reference variable, copy the reference into the block field. - } else if (type->isReferenceType()) { - Builder.CreateStore(src.getPointer(), blockField); + } else if (auto refType = type->getAs()) { + Builder.CreateStore(src.emitRawPointer(*this), blockField); - // If type is const-qualified, copy the value into the block field. + // If type is const-qualified, copy the value into the block field. } else if (type.isConstQualified() && type.getObjCLifetime() == Qualifiers::OCL_Strong && CGM.getCodeGenOpts().OptimizationLevel != 0) { @@ -1377,7 +1378,7 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D, // Allocate a stack slot like for any local variable to guarantee optimal // debug info at -O0. The mem2reg pass will eliminate it when optimizing. - Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); + RawAddress alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); Builder.CreateStore(arg, alloc); if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { @@ -1497,7 +1498,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( // frame setup instruction by llvm::DwarfDebug::beginFunction(). auto NL = ApplyDebugLocation::CreateEmpty(*this); Builder.CreateStore(BlockPointer, Alloca); - BlockPointerDbgLoc = Alloca.getPointer(); + BlockPointerDbgLoc = Alloca.emitRawPointer(*this); } // If we have a C++ 'this' reference, go ahead and force it into @@ -1557,8 +1558,8 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { auto addr = LocalDeclMap.find(variable)->second; - (void)DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(), - Builder); + (void)DI->EmitDeclareOfAutoVariable( + variable, addr.emitRawPointer(*this), Builder); continue; } @@ -1662,7 +1663,7 @@ struct CallBlockRelease final : EHScopeStack::Cleanup { if (LoadBlockVarAddr) { BlockVarAddr = CGF.Builder.CreateLoad(Addr); } else { - BlockVarAddr = Addr.getPointer(); + BlockVarAddr = Addr.emitRawPointer(CGF); } CGF.BuildBlockRelease(BlockVarAddr, FieldFlags, CanThrow); @@ -1962,13 +1963,15 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // it. It's not quite worth the annoyance to avoid creating it in the // first place. if (!needsEHCleanup(captureType.isDestructedType())) - cast(dstField.getPointer())->eraseFromParent(); + if (auto *I = + cast_or_null(dstField.getBasePointer())) + I->eraseFromParent(); } break; } case BlockCaptureEntityKind::BlockObject: { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); - llvm::Value *dstAddr = dstField.getPointer(); + llvm::Value *dstAddr = dstField.emitRawPointer(*this); llvm::Value *args[] = { dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask()) }; @@ -2139,7 +2142,7 @@ public: llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags); llvm::FunctionCallee fn = CGF.CGM.getBlockObjectAssign(); - llvm::Value *args[] = { destField.getPointer(), srcValue, flagsVal }; + llvm::Value *args[] = {destField.emitRawPointer(CGF), srcValue, flagsVal}; CGF.EmitNounwindRuntimeCall(fn, args); } @@ -2696,7 +2699,8 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { storeHeaderField(V, getPointerSize(), "byref.isa"); // Store the address of the variable into its own forwarding pointer. - storeHeaderField(addr.getPointer(), getPointerSize(), "byref.forwarding"); + storeHeaderField(addr.emitRawPointer(*this), getPointerSize(), + "byref.forwarding"); // Blocks ABI: // c) the flags field is set to either 0 if no helper functions are diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h index 4ef1ae9f33655cb8b76fbf19af4557be46f140c4..8d10c4f69b2026b4c5d254eadc2d037e88058d36 100644 --- a/clang/lib/CodeGen/CGBlocks.h +++ b/clang/lib/CodeGen/CGBlocks.h @@ -271,7 +271,8 @@ public: /// The block's captures. Non-constant captures are sorted by their offsets. llvm::SmallVector SortedCaptures; - Address LocalAddress; + // Currently we assume that block-pointer types are never signed. + RawAddress LocalAddress; llvm::StructType *StructureType; const BlockDecl *Block; const BlockExpr *BlockExpression; diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index bf5ab171d720d9b148544ac6467652a5efea0edb..6dd9da7c4cadefb2063b5f55fdf3230476128c22 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -10,7 +10,9 @@ #define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H #include "Address.h" +#include "CGValue.h" #include "CodeGenTypeCache.h" +#include "llvm/Analysis/Utils/Local.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Type.h" @@ -18,12 +20,15 @@ namespace clang { namespace CodeGen { +class CGBuilderTy; class CodeGenFunction; /// This is an IRBuilder insertion helper that forwards to /// CodeGenFunction::InsertHelper, which adds necessary metadata to /// instructions. class CGBuilderInserter final : public llvm::IRBuilderDefaultInserter { + friend CGBuilderTy; + public: CGBuilderInserter() = default; explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {} @@ -43,10 +48,42 @@ typedef llvm::IRBuilder CGBuilderBaseTy; class CGBuilderTy : public CGBuilderBaseTy { + friend class Address; + /// Storing a reference to the type cache here makes it a lot easier /// to build natural-feeling, target-specific IR. const CodeGenTypeCache &TypeCache; + CodeGenFunction *getCGF() const { return getInserter().CGF; } + + llvm::Value *emitRawPointerFromAddress(Address Addr) const { + return Addr.getBasePointer(); + } + + template + Address createConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, + const llvm::Twine &Name) { + const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + llvm::GetElementPtrInst *GEP; + if (IsInBounds) + GEP = cast(CreateConstInBoundsGEP2_32( + Addr.getElementType(), emitRawPointerFromAddress(Addr), Idx0, Idx1, + Name)); + else + GEP = cast(CreateConstGEP2_32( + Addr.getElementType(), emitRawPointerFromAddress(Addr), Idx0, Idx1, + Name)); + llvm::APInt Offset( + DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0, + /*isSigned=*/true); + if (!GEP->accumulateConstantOffset(DL, Offset)) + llvm_unreachable("offset of GEP with constants is always computable"); + return Address(GEP, GEP->getResultElementType(), + Addr.getAlignment().alignmentAtOffset( + CharUnits::fromQuantity(Offset.getSExtValue())), + IsInBounds ? Addr.isKnownNonNull() : NotKnownNonNull); + } + public: CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::LLVMContext &C) : CGBuilderBaseTy(C), TypeCache(TypeCache) {} @@ -69,20 +106,22 @@ public: // Note that we intentionally hide the CreateLoad APIs that don't // take an alignment. llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") { - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), + return CreateAlignedLoad(Addr.getElementType(), + emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), Name); } llvm::LoadInst *CreateLoad(Address Addr, const char *Name) { // This overload is required to prevent string literals from // ending up in the IsVolatile overload. - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), + return CreateAlignedLoad(Addr.getElementType(), + emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), Name); } llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile, const llvm::Twine &Name = "") { - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), - Addr.getAlignment().getAsAlign(), IsVolatile, - Name); + return CreateAlignedLoad( + Addr.getElementType(), emitRawPointerFromAddress(Addr), + Addr.getAlignment().getAsAlign(), IsVolatile, Name); } using CGBuilderBaseTy::CreateAlignedLoad; @@ -96,7 +135,7 @@ public: // take an alignment. llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile = false) { - return CreateAlignedStore(Val, Addr.getPointer(), + return CreateAlignedStore(Val, emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), IsVolatile); } @@ -132,33 +171,41 @@ public: llvm::AtomicOrdering FailureOrdering, llvm::SyncScope::ID SSID = llvm::SyncScope::System) { return CGBuilderBaseTy::CreateAtomicCmpXchg( - Addr.getPointer(), Cmp, New, Addr.getAlignment().getAsAlign(), - SuccessOrdering, FailureOrdering, SSID); + Addr.emitRawPointer(*getCGF()), Cmp, New, + Addr.getAlignment().getAsAlign(), SuccessOrdering, FailureOrdering, + SSID); } llvm::AtomicRMWInst * CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val, llvm::AtomicOrdering Ordering, llvm::SyncScope::ID SSID = llvm::SyncScope::System) { - return CGBuilderBaseTy::CreateAtomicRMW(Op, Addr.getPointer(), Val, - Addr.getAlignment().getAsAlign(), - Ordering, SSID); + return CGBuilderBaseTy::CreateAtomicRMW( + Op, Addr.emitRawPointer(*getCGF()), Val, + Addr.getAlignment().getAsAlign(), Ordering, SSID); } using CGBuilderBaseTy::CreateAddrSpaceCast; Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty, + llvm::Type *ElementTy, const llvm::Twine &Name = "") { - return Addr.withPointer(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name), - Addr.isKnownNonNull()); + if (!Addr.hasOffset()) + return Address(CreateAddrSpaceCast(Addr.getBasePointer(), Ty, Name), + ElementTy, Addr.getAlignment(), nullptr, + Addr.isKnownNonNull()); + // Eagerly force a raw address if these is an offset. + return RawAddress( + CreateAddrSpaceCast(Addr.emitRawPointer(*getCGF()), Ty, Name), + ElementTy, Addr.getAlignment(), Addr.isKnownNonNull()); } using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast; Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name = "") { - llvm::Value *Ptr = - CreatePointerBitCastOrAddrSpaceCast(Addr.getPointer(), Ty, Name); - return Address(Ptr, ElementTy, Addr.getAlignment(), Addr.isKnownNonNull()); + if (Addr.getType()->getAddressSpace() == Ty->getPointerAddressSpace()) + return Addr.withElementType(ElementTy); + return CreateAddrSpaceCast(Addr, Ty, ElementTy, Name); } /// Given @@ -176,10 +223,11 @@ public: const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - return Address( - CreateStructGEP(Addr.getElementType(), Addr.getPointer(), Index, Name), - ElTy->getElementType(Index), - Addr.getAlignment().alignmentAtOffset(Offset), Addr.isKnownNonNull()); + return Address(CreateStructGEP(Addr.getElementType(), Addr.getBasePointer(), + Index, Name), + ElTy->getElementType(Index), + Addr.getAlignment().alignmentAtOffset(Offset), + Addr.isKnownNonNull()); } /// Given @@ -198,7 +246,7 @@ public: CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy->getElementType())); return Address( - CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), + CreateInBoundsGEP(Addr.getElementType(), Addr.getBasePointer(), {getSize(CharUnits::Zero()), getSize(Index)}, Name), ElTy->getElementType(), Addr.getAlignment().alignmentAtOffset(Index * EltSize), @@ -216,10 +264,10 @@ public: const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); - return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Index), Name), - ElTy, Addr.getAlignment().alignmentAtOffset(Index * EltSize), - Addr.isKnownNonNull()); + return Address( + CreateInBoundsGEP(ElTy, Addr.getBasePointer(), getSize(Index), Name), + ElTy, Addr.getAlignment().alignmentAtOffset(Index * EltSize), + Addr.isKnownNonNull()); } /// Given @@ -229,110 +277,133 @@ public: /// where i64 is actually the target word size. Address CreateConstGEP(Address Addr, uint64_t Index, const llvm::Twine &Name = "") { + llvm::Type *ElTy = Addr.getElementType(); const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); - CharUnits EltSize = - CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType())); + CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); - return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Index), Name), + return Address(CreateGEP(ElTy, Addr.getBasePointer(), getSize(Index), Name), Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Index * EltSize), - NotKnownNonNull); + Addr.getAlignment().alignmentAtOffset(Index * EltSize)); } /// Create GEP with single dynamic index. The address alignment is reduced /// according to the element size. using CGBuilderBaseTy::CreateGEP; - Address CreateGEP(Address Addr, llvm::Value *Index, + Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name = "") { const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType())); return Address( - CreateGEP(Addr.getElementType(), Addr.getPointer(), Index, Name), + CreateGEP(Addr.getElementType(), Addr.emitRawPointer(CGF), Index, Name), Addr.getElementType(), - Addr.getAlignment().alignmentOfArrayElement(EltSize), NotKnownNonNull); + Addr.getAlignment().alignmentOfArrayElement(EltSize)); } /// Given a pointer to i8, adjust it by a given constant offset. Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset, const llvm::Twine &Name = "") { assert(Addr.getElementType() == TypeCache.Int8Ty); - return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Offset), Name), - Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Offset), - Addr.isKnownNonNull()); + return Address( + CreateInBoundsGEP(Addr.getElementType(), Addr.getBasePointer(), + getSize(Offset), Name), + Addr.getElementType(), Addr.getAlignment().alignmentAtOffset(Offset), + Addr.isKnownNonNull()); } + Address CreateConstByteGEP(Address Addr, CharUnits Offset, const llvm::Twine &Name = "") { assert(Addr.getElementType() == TypeCache.Int8Ty); - return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(), + return Address(CreateGEP(Addr.getElementType(), Addr.getBasePointer(), getSize(Offset), Name), Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Offset), - NotKnownNonNull); + Addr.getAlignment().alignmentAtOffset(Offset)); } using CGBuilderBaseTy::CreateConstInBoundsGEP2_32; Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, const llvm::Twine &Name = "") { - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + return createConstGEP2_32(Addr, Idx0, Idx1, Name); + } - auto *GEP = cast(CreateConstInBoundsGEP2_32( - Addr.getElementType(), Addr.getPointer(), Idx0, Idx1, Name)); - llvm::APInt Offset( - DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0, - /*isSigned=*/true); - if (!GEP->accumulateConstantOffset(DL, Offset)) - llvm_unreachable("offset of GEP with constants is always computable"); - return Address(GEP, GEP->getResultElementType(), - Addr.getAlignment().alignmentAtOffset( - CharUnits::fromQuantity(Offset.getSExtValue())), - Addr.isKnownNonNull()); + using CGBuilderBaseTy::CreateConstGEP2_32; + Address CreateConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, + const llvm::Twine &Name = "") { + return createConstGEP2_32(Addr, Idx0, Idx1, Name); + } + + Address CreateGEP(Address Addr, ArrayRef IdxList, + llvm::Type *ElementType, CharUnits Align, + const Twine &Name = "") { + llvm::Value *Ptr = emitRawPointerFromAddress(Addr); + return RawAddress(CreateGEP(Addr.getElementType(), Ptr, IdxList, Name), + ElementType, Align); + } + + using CGBuilderBaseTy::CreateInBoundsGEP; + Address CreateInBoundsGEP(Address Addr, ArrayRef IdxList, + llvm::Type *ElementType, CharUnits Align, + const Twine &Name = "") { + return RawAddress(CreateInBoundsGEP(Addr.getElementType(), + emitRawPointerFromAddress(Addr), + IdxList, Name), + ElementType, Align, Addr.isKnownNonNull()); + } + + using CGBuilderBaseTy::CreateIsNull; + llvm::Value *CreateIsNull(Address Addr, const Twine &Name = "") { + if (!Addr.hasOffset()) + return CreateIsNull(Addr.getBasePointer(), Name); + // The pointer isn't null if Addr has an offset since offsets can always + // be applied inbound. + return llvm::ConstantInt::getFalse(Context); } using CGBuilderBaseTy::CreateMemCpy; llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), Size, - IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpy(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), Size, - IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpy(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } using CGBuilderBaseTy::CreateMemCpyInline; llvm::CallInst *CreateMemCpyInline(Address Dest, Address Src, uint64_t Size) { - return CreateMemCpyInline( - Dest.getPointer(), Dest.getAlignment().getAsAlign(), Src.getPointer(), - Src.getAlignment().getAsAlign(), getInt64(Size)); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpyInline(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), getInt64(Size)); } using CGBuilderBaseTy::CreateMemMove; llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), - Size, IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemMove(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } using CGBuilderBaseTy::CreateMemSet; llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemSet(Dest.getPointer(), Value, Size, + return CreateMemSet(emitRawPointerFromAddress(Dest), Value, Size, Dest.getAlignment().getAsAlign(), IsVolatile); } using CGBuilderBaseTy::CreateMemSetInline; llvm::CallInst *CreateMemSetInline(Address Dest, llvm::Value *Value, uint64_t Size) { - return CreateMemSetInline(Dest.getPointer(), + return CreateMemSetInline(emitRawPointerFromAddress(Dest), Dest.getAlignment().getAsAlign(), Value, getInt64(Size)); } @@ -346,16 +417,31 @@ public: const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - return Address(CreatePreserveStructAccessIndex(ElTy, Addr.getPointer(), - Index, FieldIndex, DbgInfo), - ElTy->getElementType(Index), - Addr.getAlignment().alignmentAtOffset(Offset)); + return Address( + CreatePreserveStructAccessIndex(ElTy, emitRawPointerFromAddress(Addr), + Index, FieldIndex, DbgInfo), + ElTy->getElementType(Index), + Addr.getAlignment().alignmentAtOffset(Offset)); + } + + using CGBuilderBaseTy::CreatePreserveUnionAccessIndex; + Address CreatePreserveUnionAccessIndex(Address Addr, unsigned FieldIndex, + llvm::MDNode *DbgInfo) { + Addr.replaceBasePointer(CreatePreserveUnionAccessIndex( + Addr.getBasePointer(), FieldIndex, DbgInfo)); + return Addr; } using CGBuilderBaseTy::CreateLaunderInvariantGroup; Address CreateLaunderInvariantGroup(Address Addr) { - return Addr.withPointer(CreateLaunderInvariantGroup(Addr.getPointer()), - Addr.isKnownNonNull()); + Addr.replaceBasePointer(CreateLaunderInvariantGroup(Addr.getBasePointer())); + return Addr; + } + + using CGBuilderBaseTy::CreateStripInvariantGroup; + Address CreateStripInvariantGroup(Address Addr) { + Addr.replaceBasePointer(CreateStripInvariantGroup(Addr.getBasePointer())); + return Addr; } }; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index fdb517eb254d3b0262e941b5befb6bb9a39ef104..bb007231c0b783474f68ec2b089b2c5934ea805c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1131,8 +1131,92 @@ struct BitTest { static BitTest decodeBitTestBuiltin(unsigned BuiltinID); }; + +// Returns the first convergence entry/loop/anchor instruction found in |BB|. +// std::nullptr otherwise. +llvm::IntrinsicInst *getConvergenceToken(llvm::BasicBlock *BB) { + for (auto &I : *BB) { + auto *II = dyn_cast(&I); + if (II && isConvergenceControlIntrinsic(II->getIntrinsicID())) + return II; + } + return nullptr; +} + } // namespace +llvm::CallBase * +CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input, + llvm::Value *ParentToken) { + llvm::Value *bundleArgs[] = {ParentToken}; + llvm::OperandBundleDef OB("convergencectrl", bundleArgs); + auto Output = llvm::CallBase::addOperandBundle( + Input, llvm::LLVMContext::OB_convergencectrl, OB, Input); + Input->replaceAllUsesWith(Output); + Input->eraseFromParent(); + return Output; +} + +llvm::IntrinsicInst * +CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB, + llvm::Value *ParentToken) { + CGBuilderTy::InsertPoint IP = Builder.saveIP(); + Builder.SetInsertPoint(&BB->front()); + auto CB = Builder.CreateIntrinsic( + llvm::Intrinsic::experimental_convergence_loop, {}, {}); + Builder.restoreIP(IP); + + auto I = addConvergenceControlToken(CB, ParentToken); + return cast(I); +} + +llvm::IntrinsicInst * +CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) { + auto *BB = &F->getEntryBlock(); + auto *token = getConvergenceToken(BB); + if (token) + return token; + + // Adding a convergence token requires the function to be marked as + // convergent. + F->setConvergent(); + + CGBuilderTy::InsertPoint IP = Builder.saveIP(); + Builder.SetInsertPoint(&BB->front()); + auto I = Builder.CreateIntrinsic( + llvm::Intrinsic::experimental_convergence_entry, {}, {}); + assert(isa(I)); + Builder.restoreIP(IP); + + return cast(I); +} + +llvm::IntrinsicInst * +CodeGenFunction::getOrEmitConvergenceLoopToken(const LoopInfo *LI) { + assert(LI != nullptr); + + auto *token = getConvergenceToken(LI->getHeader()); + if (token) + return token; + + llvm::IntrinsicInst *PII = + LI->getParent() + ? emitConvergenceLoopToken( + LI->getHeader(), getOrEmitConvergenceLoopToken(LI->getParent())) + : getOrEmitConvergenceEntryToken(LI->getHeader()->getParent()); + + return emitConvergenceLoopToken(LI->getHeader(), PII); +} + +llvm::CallBase * +CodeGenFunction::addControlledConvergenceToken(llvm::CallBase *Input) { + llvm::Value *ParentToken = + LoopStack.hasInfo() + ? getOrEmitConvergenceLoopToken(&LoopStack.getInfo()) + : getOrEmitConvergenceEntryToken(Input->getFunction()); + return addConvergenceControlToken(Input, ParentToken); +} + BitTest BitTest::decodeBitTestBuiltin(unsigned BuiltinID) { switch (BuiltinID) { // Main portable variants. @@ -2117,9 +2201,9 @@ llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction( auto AL = ApplyDebugLocation::CreateArtificial(*this); CharUnits Offset; - Address BufAddr = - Address(Builder.CreateLoad(GetAddrOfLocalVar(Args[0]), "buf"), Int8Ty, - BufferAlignment); + Address BufAddr = makeNaturalAddressForPointer( + Builder.CreateLoad(GetAddrOfLocalVar(Args[0]), "buf"), Ctx.VoidTy, + BufferAlignment); Builder.CreateStore(Builder.getInt8(Layout.getSummaryByte()), Builder.CreateConstByteGEP(BufAddr, Offset++, "summary")); Builder.CreateStore(Builder.getInt8(Layout.getNumArgsByte()), @@ -2162,7 +2246,7 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { // Ignore argument 1, the format string. It is not currently used. CallArgList Args; - Args.add(RValue::get(BufAddr.getPointer()), Ctx.VoidPtrTy); + Args.add(RValue::get(BufAddr.emitRawPointer(*this)), Ctx.VoidPtrTy); for (const auto &Item : Layout.Items) { int Size = Item.getSizeByte(); @@ -2202,8 +2286,8 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { if (!isa(ArgVal)) { CleanupKind Cleanup = getARCCleanupKind(); QualType Ty = TheExpr->getType(); - Address Alloca = Address::invalid(); - Address Addr = CreateMemTemp(Ty, "os.log.arg", &Alloca); + RawAddress Alloca = RawAddress::invalid(); + RawAddress Addr = CreateMemTemp(Ty, "os.log.arg", &Alloca); ArgVal = EmitARCRetain(Ty, ArgVal); Builder.CreateStore(ArgVal, Addr); pushLifetimeExtendedDestroy(Cleanup, Alloca, Ty, @@ -2236,7 +2320,7 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { llvm::Function *F = CodeGenFunction(CGM).generateBuiltinOSLogHelperFunction( Layout, BufAddr.getAlignment()); EmitCall(FI, CGCallee::forDirect(F), ReturnValueSlot(), Args); - return RValue::get(BufAddr.getPointer()); + return RValue::get(BufAddr, *this); } static bool isSpecialUnsignedMultiplySignedResult( @@ -2984,7 +3068,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // Check NonnullAttribute/NullabilityArg and Alignment. auto EmitArgCheck = [&](TypeCheckKind Kind, Address A, const Expr *Arg, unsigned ParmNum) { - Value *Val = A.getPointer(); + Value *Val = A.emitRawPointer(*this); EmitNonNullArgCheck(RValue::get(Val), Arg->getType(), Arg->getExprLoc(), FD, ParmNum); @@ -3013,12 +3097,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_va_end: EmitVAStartEnd(BuiltinID == Builtin::BI__va_start ? EmitScalarExpr(E->getArg(0)) - : EmitVAListRef(E->getArg(0)).getPointer(), + : EmitVAListRef(E->getArg(0)).emitRawPointer(*this), BuiltinID != Builtin::BI__builtin_va_end); return RValue::get(nullptr); case Builtin::BI__builtin_va_copy: { - Value *DstPtr = EmitVAListRef(E->getArg(0)).getPointer(); - Value *SrcPtr = EmitVAListRef(E->getArg(1)).getPointer(); + Value *DstPtr = EmitVAListRef(E->getArg(0)).emitRawPointer(*this); + Value *SrcPtr = EmitVAListRef(E->getArg(1)).emitRawPointer(*this); Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy, {DstPtr->getType()}), {DstPtr, SrcPtr}); return RValue::get(nullptr); @@ -3849,13 +3933,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, bool IsVolatile = PtrTy->getPointeeType().isVolatileQualified(); Address Src = EmitPointerWithAlignment(E->getArg(0)); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Src.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); Value *Result = MB.CreateColumnMajorLoad( - Src.getElementType(), Src.getPointer(), + Src.getElementType(), Src.emitRawPointer(*this), Align(Src.getAlignment().getQuantity()), Stride, IsVolatile, - ResultTy->getNumRows(), ResultTy->getNumColumns(), - "matrix"); + ResultTy->getNumRows(), ResultTy->getNumColumns(), "matrix"); return RValue::get(Result); } @@ -3870,11 +3954,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, assert(PtrTy && "arg1 must be of pointer type"); bool IsVolatile = PtrTy->getPointeeType().isVolatileQualified(); - EmitNonNullArgCheck(RValue::get(Dst.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Dst.emitRawPointer(*this)), + E->getArg(1)->getType(), E->getArg(1)->getExprLoc(), FD, + 0); Value *Result = MB.CreateColumnMajorStore( - Matrix, Dst.getPointer(), Align(Dst.getAlignment().getQuantity()), - Stride, IsVolatile, MatrixTy->getNumRows(), MatrixTy->getNumColumns()); + Matrix, Dst.emitRawPointer(*this), + Align(Dst.getAlignment().getQuantity()), Stride, IsVolatile, + MatrixTy->getNumRows(), MatrixTy->getNumColumns()); return RValue::get(Result); } @@ -4033,7 +4119,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_bzero: { Address Dest = EmitPointerWithAlignment(E->getArg(0)); Value *SizeVal = EmitScalarExpr(E->getArg(1)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), + EmitNonNullArgCheck(Dest, E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, 0); Builder.CreateMemSet(Dest, Builder.getInt8(0), SizeVal, false); return RValue::get(nullptr); @@ -4044,10 +4130,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(0)); Address Dest = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Src.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); + EmitNonNullArgCheck(RValue::get(Dest.emitRawPointer(*this)), + E->getArg(1)->getType(), E->getArg(1)->getExprLoc(), FD, + 0); Builder.CreateMemMove(Dest, Src, SizeVal, false); return RValue::get(nullptr); } @@ -4064,10 +4152,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateMemCpy(Dest, Src, SizeVal, false); if (BuiltinID == Builtin::BImempcpy || BuiltinID == Builtin::BI__builtin_mempcpy) - return RValue::get(Builder.CreateInBoundsGEP(Dest.getElementType(), - Dest.getPointer(), SizeVal)); + return RValue::get(Builder.CreateInBoundsGEP( + Dest.getElementType(), Dest.emitRawPointer(*this), SizeVal)); else - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_memcpy_inline: { @@ -4099,7 +4187,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemCpy(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_objc_memmove_collectable: { @@ -4108,7 +4196,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *SizeVal = EmitScalarExpr(E->getArg(2)); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestAddr, SrcAddr, SizeVal); - return RValue::get(DestAddr.getPointer()); + return RValue::get(DestAddr, *this); } case Builtin::BI__builtin___memmove_chk: { @@ -4125,7 +4213,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemMove(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BImemmove: @@ -4136,7 +4224,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, EmitArgCheck(TCK_Store, Dest, E->getArg(0), 0); EmitArgCheck(TCK_Load, Src, E->getArg(1), 1); Builder.CreateMemMove(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BImemset: case Builtin::BI__builtin_memset: { @@ -4144,10 +4232,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), + EmitNonNullArgCheck(Dest, E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, 0); Builder.CreateMemSet(Dest, ByteVal, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_memset_inline: { Address Dest = EmitPointerWithAlignment(E->getArg(0)); @@ -4155,8 +4243,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); uint64_t Size = E->getArg(2)->EvaluateKnownConstInt(getContext()).getZExtValue(); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Dest.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); Builder.CreateMemSetInline(Dest, ByteVal, Size); return RValue::get(nullptr); } @@ -4175,7 +4264,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.getInt8Ty()); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemSet(Dest, ByteVal, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_wmemchr: { // The MSVC runtime library does not provide a definition of wmemchr, so we @@ -4397,14 +4486,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // Store the stack pointer to the setjmp buffer. Value *StackAddr = Builder.CreateStackSave(); - assert(Buf.getPointer()->getType() == StackAddr->getType()); + assert(Buf.emitRawPointer(*this)->getType() == StackAddr->getType()); Address StackSaveSlot = Builder.CreateConstInBoundsGEP(Buf, 2); Builder.CreateStore(StackAddr, StackSaveSlot); // Call LLVM's EH setjmp, which is lightweight. Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp); - return RValue::get(Builder.CreateCall(F, Buf.getPointer())); + return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this))); } case Builtin::BI__builtin_longjmp: { Value *Buf = EmitScalarExpr(E->getArg(0)); @@ -5577,7 +5666,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Queue = EmitScalarExpr(E->getArg(0)); llvm::Value *Flags = EmitScalarExpr(E->getArg(1)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(2)); - llvm::Value *Range = NDRangeL.getAddress(*this).getPointer(); + llvm::Value *Range = NDRangeL.getAddress(*this).emitRawPointer(*this); llvm::Type *RangeTy = NDRangeL.getAddress(*this).getType(); if (NumArgs == 4) { @@ -5686,9 +5775,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, getContext(), Expr::NPC_ValueDependentIsNotNull)) { EventWaitList = llvm::ConstantPointerNull::get(PtrTy); } else { - EventWaitList = E->getArg(4)->getType()->isArrayType() - ? EmitArrayToPointerDecay(E->getArg(4)).getPointer() - : EmitScalarExpr(E->getArg(4)); + EventWaitList = + E->getArg(4)->getType()->isArrayType() + ? EmitArrayToPointerDecay(E->getArg(4)).emitRawPointer(*this) + : EmitScalarExpr(E->getArg(4)); // Convert to generic address space. EventWaitList = Builder.CreatePointerCast(EventWaitList, PtrTy); } @@ -5784,7 +5874,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Type *GenericVoidPtrTy = Builder.getPtrTy( getContext().getTargetAddressSpace(LangAS::opencl_generic)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(0)); - llvm::Value *NDRange = NDRangeL.getAddress(*this).getPointer(); + llvm::Value *NDRange = NDRangeL.getAddress(*this).emitRawPointer(*this); auto Info = CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1)); Value *Kernel = @@ -5802,7 +5892,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Name), {NDRange, Kernel, Block})); } - case Builtin::BI__builtin_store_half: case Builtin::BI__builtin_store_halff: { Value *Val = EmitScalarExpr(E->getArg(0)); @@ -5869,7 +5958,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto PTy0 = FTy->getParamType(0); if (PTy0 != Arg0Val->getType()) { if (Arg0Ty->isArrayType()) - Arg0Val = EmitArrayToPointerDecay(Arg0).getPointer(); + Arg0Val = EmitArrayToPointerDecay(Arg0).emitRawPointer(*this); else Arg0Val = Builder.CreatePointerCast(Arg0Val, PTy0); } @@ -5907,7 +5996,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto PTy1 = FTy->getParamType(1); if (PTy1 != Arg1Val->getType()) { if (Arg1Ty->isArrayType()) - Arg1Val = EmitArrayToPointerDecay(Arg1).getPointer(); + Arg1Val = EmitArrayToPointerDecay(Arg1).emitRawPointer(*this); else Arg1Val = Builder.CreatePointerCast(Arg1Val, PTy1); } @@ -5921,7 +6010,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ms_va_start: case Builtin::BI__builtin_ms_va_end: return RValue::get( - EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(), + EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).emitRawPointer(*this), BuiltinID == Builtin::BI__builtin_ms_va_start)); case Builtin::BI__builtin_ms_va_copy: { @@ -5963,8 +6052,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // If this is a predefined lib function (e.g. malloc), emit the call // using exactly the normal call path. if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return emitLibraryCall(*this, FD, E, - cast(EmitScalarExpr(E->getCallee()))); + return emitLibraryCall( + *this, FD, E, cast(EmitScalarExpr(E->getCallee()))); // Check that a call to a target specific builtin has the correct target // features. @@ -6081,7 +6170,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); return RValue::get(V); case TEK_Aggregate: - return RValue::getAggregate(ReturnValue.getValue(), + return RValue::getAggregate(ReturnValue.getAddress(), ReturnValue.isVolatile()); case TEK_Complex: llvm_unreachable("No current target builtin returns complex"); @@ -8851,7 +8940,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp0 = EmitPointerWithAlignment(E->getArg(0)); - Ops.push_back(PtrOp0.getPointer()); + Ops.push_back(PtrOp0.emitRawPointer(*this)); continue; } } @@ -8878,7 +8967,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp1 = EmitPointerWithAlignment(E->getArg(1)); - Ops.push_back(PtrOp1.getPointer()); + Ops.push_back(PtrOp1.emitRawPointer(*this)); continue; } } @@ -9299,7 +9388,7 @@ Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID, if (ReturnValue.isNull()) return MvecOut; else - return Builder.CreateStore(MvecOut, ReturnValue.getValue()); + return Builder.CreateStore(MvecOut, ReturnValue.getAddress()); } case CustomCodeGen::VST24: { @@ -11479,7 +11568,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp0 = EmitPointerWithAlignment(E->getArg(0)); - Ops.push_back(PtrOp0.getPointer()); + Ops.push_back(PtrOp0.emitRawPointer(*this)); continue; } } @@ -13345,15 +13434,15 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, if (!getDebugInfo()) { CGM.Error(E->getExprLoc(), "using __builtin_preserve_field_info() without -g"); - return IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(*this); + return IsBitField ? EmitLValue(Arg).getRawBitFieldPointer(*this) + : EmitLValue(Arg).emitRawPointer(*this); } // Enable underlying preserve_*_access_index() generation. bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; IsInPreservedAIRegion = true; - Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(*this); + Value *FieldAddr = IsBitField ? EmitLValue(Arg).getRawBitFieldPointer(*this) + : EmitLValue(Arg).emitRawPointer(*this); IsInPreservedAIRegion = OldIsInPreservedAIRegion; ConstantInt *C = cast(EmitScalarExpr(E->getArg(1))); @@ -14345,14 +14434,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } case X86::BI_mm_setcsr: case X86::BI__builtin_ia32_ldmxcsr: { - Address Tmp = CreateMemTemp(E->getArg(0)->getType()); + RawAddress Tmp = CreateMemTemp(E->getArg(0)->getType()); Builder.CreateStore(Ops[0], Tmp); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr), Tmp.getPointer()); } case X86::BI_mm_getcsr: case X86::BI__builtin_ia32_stmxcsr: { - Address Tmp = CreateMemTemp(E->getType()); + RawAddress Tmp = CreateMemTemp(E->getType()); Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr), Tmp.getPointer()); return Builder.CreateLoad(Tmp, "stmxcsr"); @@ -17627,7 +17716,8 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, SmallVector Ops; for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) if (E->getArg(i)->getType()->isArrayType()) - Ops.push_back(EmitArrayToPointerDecay(E->getArg(i)).getPointer()); + Ops.push_back( + EmitArrayToPointerDecay(E->getArg(i)).emitRawPointer(*this)); else Ops.push_back(EmitScalarExpr(E->getArg(i))); // The first argument of these two builtins is a pointer used to store their @@ -18217,6 +18307,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, /*ReturnType=*/Op0->getType(), Intrinsic::dx_rsqrt, ArrayRef{Op0}, nullptr, "dx.rsqrt"); } + case Builtin::BI__builtin_hlsl_wave_get_lane_index: { + auto *CI = EmitRuntimeCall(CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index", + {}, false, true)); + if (getTarget().getTriple().isSPIRVLogical()) + CI = dyn_cast(addControlledConvergenceToken(CI)); + return CI; + } } return nullptr; } @@ -20089,14 +20187,14 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, // Save returned values. assert(II.NumResults); if (II.NumResults == 1) { - Builder.CreateAlignedStore(Result, Dst.getPointer(), + Builder.CreateAlignedStore(Result, Dst.emitRawPointer(*this), CharUnits::fromQuantity(4)); } else { for (unsigned i = 0; i < II.NumResults; ++i) { Builder.CreateAlignedStore( Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), Dst.getElementType()), - Builder.CreateGEP(Dst.getElementType(), Dst.getPointer(), + Builder.CreateGEP(Dst.getElementType(), Dst.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); } @@ -20136,7 +20234,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < II.NumResults; ++i) { Value *V = Builder.CreateAlignedLoad( Src.getElementType(), - Builder.CreateGEP(Src.getElementType(), Src.getPointer(), + Builder.CreateGEP(Src.getElementType(), Src.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, ParamType)); @@ -20208,7 +20306,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsA; ++i) { Value *V = Builder.CreateAlignedLoad( SrcA.getElementType(), - Builder.CreateGEP(SrcA.getElementType(), SrcA.getPointer(), + Builder.CreateGEP(SrcA.getElementType(), SrcA.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, AType)); @@ -20218,7 +20316,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsB; ++i) { Value *V = Builder.CreateAlignedLoad( SrcB.getElementType(), - Builder.CreateGEP(SrcB.getElementType(), SrcB.getPointer(), + Builder.CreateGEP(SrcB.getElementType(), SrcB.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, BType)); @@ -20229,7 +20327,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsC; ++i) { Value *V = Builder.CreateAlignedLoad( SrcC.getElementType(), - Builder.CreateGEP(SrcC.getElementType(), SrcC.getPointer(), + Builder.CreateGEP(SrcC.getElementType(), SrcC.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, CType)); @@ -20239,7 +20337,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsD; ++i) Builder.CreateAlignedStore( Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), DType), - Builder.CreateGEP(Dst.getElementType(), Dst.getPointer(), + Builder.CreateGEP(Dst.getElementType(), Dst.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); return Result; @@ -20497,7 +20595,7 @@ struct BuiltinAlignArgs { BuiltinAlignArgs(const CallExpr *E, CodeGenFunction &CGF) { QualType AstType = E->getArg(0)->getType(); if (AstType->isArrayType()) - Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(CGF); else Src = CGF.EmitScalarExpr(E->getArg(0)); SrcType = Src->getType(); @@ -21115,7 +21213,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_get: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Function *Callee; if (E->getType().isWebAssemblyExternrefType()) @@ -21129,7 +21227,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_set: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Value *Val = EmitScalarExpr(E->getArg(2)); Function *Callee; @@ -21144,13 +21242,13 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_size: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Value = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size); return Builder.CreateCall(Callee, Value); } case WebAssembly::BI__builtin_wasm_table_grow: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Val = EmitScalarExpr(E->getArg(1)); Value *NElems = EmitScalarExpr(E->getArg(2)); @@ -21167,7 +21265,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_fill: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Value *Val = EmitScalarExpr(E->getArg(2)); Value *NElems = EmitScalarExpr(E->getArg(3)); @@ -21185,8 +21283,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_copy: { assert(E->getArg(0)->getType()->isArrayType()); - Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); - Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).getPointer(); + Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); + Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this); Value *DstIdx = EmitScalarExpr(E->getArg(2)); Value *SrcIdx = EmitScalarExpr(E->getArg(3)); Value *NElems = EmitScalarExpr(E->getArg(4)); @@ -21265,7 +21363,7 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, auto MakeCircOp = [this, E](unsigned IntID, bool IsLoad) { // The base pointer is passed by address, so it needs to be loaded. Address A = EmitPointerWithAlignment(E->getArg(0)); - Address BP = Address(A.getPointer(), Int8PtrTy, A.getAlignment()); + Address BP = Address(A.emitRawPointer(*this), Int8PtrTy, A.getAlignment()); llvm::Value *Base = Builder.CreateLoad(BP); // The treatment of both loads and stores is the same: the arguments for // the builtin are the same as the arguments for the intrinsic. @@ -21306,8 +21404,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, // EmitPointerWithAlignment and EmitScalarExpr evaluates the expression // per call. Address DestAddr = EmitPointerWithAlignment(E->getArg(1)); - DestAddr = Address(DestAddr.getPointer(), Int8Ty, DestAddr.getAlignment()); - llvm::Value *DestAddress = DestAddr.getPointer(); + DestAddr = DestAddr.withElementType(Int8Ty); + llvm::Value *DestAddress = DestAddr.emitRawPointer(*this); // Operands are Base, Dest, Modifier. // The intrinsic format in LLVM IR is defined as @@ -21358,8 +21456,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), PredIn}); llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1); - Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.getPointer(), - PredAddr.getAlignment()); + Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this), + PredAddr.getAlignment()); return Builder.CreateExtractValue(Result, 0); } // These are identical to the builtins above, except they don't consume @@ -21377,8 +21475,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))}); llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1); - Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.getPointer(), - PredAddr.getAlignment()); + Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this), + PredAddr.getAlignment()); return Builder.CreateExtractValue(Result, 0); } diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index b756318c46a900abc16eb9f01b2a0947749e57c3..0cb5b06a519c0098773e6ecafdd1c315048a8007 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -331,11 +331,11 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, llvm::ConstantInt::get(SizeTy, std::max(1, Args.size()))); // Store pointers to the arguments in a locally allocated launch_args. for (unsigned i = 0; i < Args.size(); ++i) { - llvm::Value* VarPtr = CGF.GetAddrOfLocalVar(Args[i]).getPointer(); + llvm::Value *VarPtr = CGF.GetAddrOfLocalVar(Args[i]).emitRawPointer(CGF); llvm::Value *VoidVarPtr = CGF.Builder.CreatePointerCast(VarPtr, PtrTy); CGF.Builder.CreateDefaultAlignedStore( - VoidVarPtr, - CGF.Builder.CreateConstGEP1_32(PtrTy, KernelArgs.getPointer(), i)); + VoidVarPtr, CGF.Builder.CreateConstGEP1_32( + PtrTy, KernelArgs.emitRawPointer(CGF), i)); } llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end"); @@ -393,9 +393,10 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, /*isVarArg=*/false), addUnderscoredPrefixToName("PopCallConfiguration")); - CGF.EmitRuntimeCallOrInvoke(cudaPopConfigFn, - {GridDim.getPointer(), BlockDim.getPointer(), - ShmemSize.getPointer(), Stream.getPointer()}); + CGF.EmitRuntimeCallOrInvoke(cudaPopConfigFn, {GridDim.emitRawPointer(CGF), + BlockDim.emitRawPointer(CGF), + ShmemSize.emitRawPointer(CGF), + Stream.emitRawPointer(CGF)}); // Emit the call to cudaLaunch llvm::Value *Kernel = @@ -405,7 +406,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, cudaLaunchKernelFD->getParamDecl(0)->getType()); LaunchKernelArgs.add(RValue::getAggregate(GridDim), Dim3Ty); LaunchKernelArgs.add(RValue::getAggregate(BlockDim), Dim3Ty); - LaunchKernelArgs.add(RValue::get(KernelArgs.getPointer()), + LaunchKernelArgs.add(RValue::get(KernelArgs, CGF), cudaLaunchKernelFD->getParamDecl(3)->getType()); LaunchKernelArgs.add(RValue::get(CGF.Builder.CreateLoad(ShmemSize)), cudaLaunchKernelFD->getParamDecl(4)->getType()); @@ -438,8 +439,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyLegacy(CodeGenFunction &CGF, auto TInfo = CGM.getContext().getTypeInfoInChars(A->getType()); Offset = Offset.alignTo(TInfo.Align); llvm::Value *Args[] = { - CGF.Builder.CreatePointerCast(CGF.GetAddrOfLocalVar(A).getPointer(), - PtrTy), + CGF.Builder.CreatePointerCast( + CGF.GetAddrOfLocalVar(A).emitRawPointer(CGF), PtrTy), llvm::ConstantInt::get(SizeTy, TInfo.Width.getQuantity()), llvm::ConstantInt::get(SizeTy, Offset.getQuantity()), }; diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index a8bf57a277e90963350a58848acdaa6579ce2236..7c6dfc3e59d8c0eb547fbd786378db2457f6a96f 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -20,6 +20,12 @@ using namespace CodeGen; CGCXXABI::~CGCXXABI() { } +Address CGCXXABI::getThisAddress(CodeGenFunction &CGF) { + return CGF.makeNaturalAddressForPointer( + CGF.CXXABIThisValue, CGF.CXXABIThisDecl->getType()->getPointeeType(), + CGF.CXXABIThisAlignment); +} + void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -44,8 +50,12 @@ CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer( llvm::Value *MemPtr, const MemberPointerType *MPT) { ErrorUnsupportedABI(CGF, "calls through member pointers"); - ThisPtrForCall = This.getPointer(); - const auto *FPT = MPT->getPointeeType()->castAs(); + const auto *RD = + cast(MPT->getClass()->castAs()->getDecl()); + ThisPtrForCall = + CGF.getAsNaturalPointerTo(This, CGF.getContext().getRecordType(RD)); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); llvm::Constant *FnPtr = llvm::Constant::getNullValue( llvm::PointerType::getUnqual(CGM.getLLVMContext())); return CGCallee::forDirect(FnPtr, FPT); @@ -251,16 +261,15 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr, // If we don't need an array cookie, bail out early. if (!requiresArrayCookie(expr, eltTy)) { - allocPtr = ptr.getPointer(); + allocPtr = ptr.emitRawPointer(CGF); numElements = nullptr; cookieSize = CharUnits::Zero(); return; } cookieSize = getArrayCookieSizeImpl(eltTy); - Address allocAddr = - CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize); - allocPtr = allocAddr.getPointer(); + Address allocAddr = CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize); + allocPtr = allocAddr.emitRawPointer(CGF); numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize); } diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index ad1ad08d0856887e9c37e9d9358e76a87f521a39..c7eccbd0095a94c494e13f9f3785294adad95aae 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -57,12 +57,8 @@ protected: llvm::Value *getThisValue(CodeGenFunction &CGF) { return CGF.CXXABIThisValue; } - Address getThisAddress(CodeGenFunction &CGF) { - return Address( - CGF.CXXABIThisValue, - CGF.ConvertTypeForMem(CGF.CXXABIThisDecl->getType()->getPointeeType()), - CGF.CXXABIThisAlignment); - } + + Address getThisAddress(CodeGenFunction &CGF); /// Issue a diagnostic about unsupported features in the ABI. void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S); @@ -475,12 +471,6 @@ public: BaseSubobject Base, const CXXRecordDecl *NearestVBase) = 0; - /// Get the address point of the vtable for the given base subobject while - /// building a constexpr. - virtual llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) = 0; - /// Get the address of the vtable for the given record decl which should be /// used for the vptr at the given offset in RD. virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 475d96b0e87d749c005dcfc1de1718e9ef0732a5..9308528ac9382328feb31e4c55e4fb67dd6d5ee1 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -74,6 +74,9 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_SwiftAsync: return llvm::CallingConv::SwiftTail; case CC_M68kRTD: return llvm::CallingConv::M68k_RTD; case CC_PreserveNone: return llvm::CallingConv::PreserveNone; + // clang-format off + case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall; + // clang-format on } } @@ -260,6 +263,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, if (D->hasAttr()) return CC_PreserveNone; + if (D->hasAttr()) + return CC_RISCVVectorCall; + return CC_C; } @@ -1031,15 +1037,9 @@ static void forConstantArrayExpansion(CodeGenFunction &CGF, ConstantArrayExpansion *CAE, Address BaseAddr, llvm::function_ref Fn) { - CharUnits EltSize = CGF.getContext().getTypeSizeInChars(CAE->EltTy); - CharUnits EltAlign = - BaseAddr.getAlignment().alignmentOfArrayElement(EltSize); - llvm::Type *EltTy = CGF.ConvertTypeForMem(CAE->EltTy); - for (int i = 0, n = CAE->NumElts; i < n; i++) { - llvm::Value *EltAddr = CGF.Builder.CreateConstGEP2_32( - BaseAddr.getElementType(), BaseAddr.getPointer(), 0, i); - Fn(Address(EltAddr, EltTy, EltAlign)); + Address EltAddr = CGF.Builder.CreateConstGEP2_32(BaseAddr, 0, i); + Fn(EltAddr); } } @@ -1154,9 +1154,10 @@ void CodeGenFunction::ExpandTypeToArgs( } /// Create a temporary allocation for the purposes of coercion. -static Address CreateTempAllocaForCoercion(CodeGenFunction &CGF, llvm::Type *Ty, - CharUnits MinAlign, - const Twine &Name = "tmp") { +static RawAddress CreateTempAllocaForCoercion(CodeGenFunction &CGF, + llvm::Type *Ty, + CharUnits MinAlign, + const Twine &Name = "tmp") { // Don't use an alignment that's worse than what LLVM would prefer. auto PrefAlign = CGF.CGM.getDataLayout().getPrefTypeAlign(Ty); CharUnits Align = std::max(MinAlign, CharUnits::fromQuantity(PrefAlign)); @@ -1326,11 +1327,11 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty, } // Otherwise do coercion through memory. This is stupid, but simple. - Address Tmp = + RawAddress Tmp = CreateTempAllocaForCoercion(CGF, Ty, Src.getAlignment(), Src.getName()); CGF.Builder.CreateMemCpy( - Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), Src.getPointer(), - Src.getAlignment().getAsAlign(), + Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), + Src.emitRawPointer(CGF), Src.getAlignment().getAsAlign(), llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize.getKnownMinValue())); return CGF.Builder.CreateLoad(Tmp); } @@ -1414,11 +1415,12 @@ static void CreateCoercedStore(llvm::Value *Src, // // FIXME: Assert that we aren't truncating non-padding bits when have access // to that information. - Address Tmp = CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment()); + RawAddress Tmp = + CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment()); CGF.Builder.CreateStore(Src, Tmp); CGF.Builder.CreateMemCpy( - Dst.getPointer(), Dst.getAlignment().getAsAlign(), Tmp.getPointer(), - Tmp.getAlignment().getAsAlign(), + Dst.emitRawPointer(CGF), Dst.getAlignment().getAsAlign(), + Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), llvm::ConstantInt::get(CGF.IntPtrTy, DstSize.getFixedValue())); } } @@ -3018,17 +3020,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Indirect: case ABIArgInfo::IndirectAliased: { assert(NumIRArgs == 1); - Address ParamAddr = Address(Fn->getArg(FirstIRArg), ConvertTypeForMem(Ty), - ArgI.getIndirectAlign(), KnownNonNull); + Address ParamAddr = makeNaturalAddressForPointer( + Fn->getArg(FirstIRArg), Ty, ArgI.getIndirectAlign(), false, nullptr, + nullptr, KnownNonNull); if (!hasScalarEvaluationKind(Ty)) { // Aggregates and complex variables are accessed by reference. All we // need to do is realign the value, if requested. Also, if the address // may be aliased, copy it to ensure that the parameter variable is // mutable and has a unique adress, as C requires. - Address V = ParamAddr; if (ArgI.getIndirectRealign() || ArgI.isIndirectAliased()) { - Address AlignedTemp = CreateMemTemp(Ty, "coerce"); + RawAddress AlignedTemp = CreateMemTemp(Ty, "coerce"); // Copy from the incoming argument pointer to the temporary with the // appropriate alignment. @@ -3038,11 +3040,12 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, CharUnits Size = getContext().getTypeSizeInChars(Ty); Builder.CreateMemCpy( AlignedTemp.getPointer(), AlignedTemp.getAlignment().getAsAlign(), - ParamAddr.getPointer(), ParamAddr.getAlignment().getAsAlign(), + ParamAddr.emitRawPointer(*this), + ParamAddr.getAlignment().getAsAlign(), llvm::ConstantInt::get(IntPtrTy, Size.getQuantity())); - V = AlignedTemp; + ParamAddr = AlignedTemp; } - ArgVals.push_back(ParamValue::forIndirect(V)); + ArgVals.push_back(ParamValue::forIndirect(ParamAddr)); } else { // Load scalar value from indirect argument. llvm::Value *V = @@ -3156,10 +3159,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, == ParameterABI::SwiftErrorResult) { QualType pointeeTy = Ty->getPointeeType(); assert(pointeeTy->isPointerType()); - Address temp = - CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); - Address arg(V, ConvertTypeForMem(pointeeTy), - getContext().getTypeAlignInChars(pointeeTy)); + RawAddress temp = + CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); + Address arg = makeNaturalAddressForPointer( + V, pointeeTy, getContext().getTypeAlignInChars(pointeeTy)); llvm::Value *incomingErrorValue = Builder.CreateLoad(arg); Builder.CreateStore(incomingErrorValue, temp); V = temp.getPointer(); @@ -3496,7 +3499,7 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF, llvm::LoadInst *load = dyn_cast(retainedValue->stripPointerCasts()); if (!load || load->isAtomic() || load->isVolatile() || - load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getPointer()) + load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getBasePointer()) return nullptr; // Okay! Burn it all down. This relies for correctness on the @@ -3533,12 +3536,15 @@ static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF, /// Heuristically search for a dominating store to the return-value slot. static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { + llvm::Value *ReturnValuePtr = CGF.ReturnValue.getBasePointer(); + // Check if a User is a store which pointerOperand is the ReturnValue. // We are looking for stores to the ReturnValue, not for stores of the // ReturnValue to some other location. - auto GetStoreIfValid = [&CGF](llvm::User *U) -> llvm::StoreInst * { + auto GetStoreIfValid = [&CGF, + ReturnValuePtr](llvm::User *U) -> llvm::StoreInst * { auto *SI = dyn_cast(U); - if (!SI || SI->getPointerOperand() != CGF.ReturnValue.getPointer() || + if (!SI || SI->getPointerOperand() != ReturnValuePtr || SI->getValueOperand()->getType() != CGF.ReturnValue.getElementType()) return nullptr; // These aren't actually possible for non-coerced returns, and we @@ -3552,7 +3558,7 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { // for something immediately preceding the IP. Sometimes this can // happen with how we generate implicit-returns; it can also happen // with noreturn cleanups. - if (!CGF.ReturnValue.getPointer()->hasOneUse()) { + if (!ReturnValuePtr->hasOneUse()) { llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock(); if (IP->empty()) return nullptr; @@ -3570,8 +3576,7 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { return nullptr; } - llvm::StoreInst *store = - GetStoreIfValid(CGF.ReturnValue.getPointer()->user_back()); + llvm::StoreInst *store = GetStoreIfValid(ReturnValuePtr->user_back()); if (!store) return nullptr; // Now do a first-and-dirty dominance check: just walk up the @@ -4115,7 +4120,11 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, } static bool isProvablyNull(llvm::Value *addr) { - return isa(addr); + return llvm::isa_and_nonnull(addr); +} + +static bool isProvablyNonNull(Address Addr, CodeGenFunction &CGF) { + return llvm::isKnownNonZero(Addr.getBasePointer(), CGF.CGM.getDataLayout()); } /// Emit the actual writing-back of a writeback. @@ -4123,21 +4132,20 @@ static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { const LValue &srcLV = writeback.Source; Address srcAddr = srcLV.getAddress(CGF); - assert(!isProvablyNull(srcAddr.getPointer()) && + assert(!isProvablyNull(srcAddr.getBasePointer()) && "shouldn't have writeback for provably null argument"); llvm::BasicBlock *contBB = nullptr; // If the argument wasn't provably non-null, we need to null check // before doing the store. - bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), - CGF.CGM.getDataLayout()); + bool provablyNonNull = isProvablyNonNull(srcAddr, CGF); + if (!provablyNonNull) { llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback"); contBB = CGF.createBasicBlock("icr.done"); - llvm::Value *isNull = - CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); + llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull"); CGF.Builder.CreateCondBr(isNull, contBB, writebackBB); CGF.EmitBlock(writebackBB); } @@ -4241,7 +4249,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, CGF.ConvertTypeForMem(CRE->getType()->getPointeeType()); // If the address is a constant null, just pass the appropriate null. - if (isProvablyNull(srcAddr.getPointer())) { + if (isProvablyNull(srcAddr.getBasePointer())) { args.add(RValue::get(llvm::ConstantPointerNull::get(destType)), CRE->getType()); return; @@ -4270,17 +4278,16 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // If the address is *not* known to be non-null, we need to switch. llvm::Value *finalArgument; - bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), - CGF.CGM.getDataLayout()); + bool provablyNonNull = isProvablyNonNull(srcAddr, CGF); + if (provablyNonNull) { - finalArgument = temp.getPointer(); + finalArgument = temp.emitRawPointer(CGF); } else { - llvm::Value *isNull = - CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); + llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull"); - finalArgument = CGF.Builder.CreateSelect(isNull, - llvm::ConstantPointerNull::get(destType), - temp.getPointer(), "icr.argument"); + finalArgument = CGF.Builder.CreateSelect( + isNull, llvm::ConstantPointerNull::get(destType), + temp.emitRawPointer(CGF), "icr.argument"); // If we need to copy, then the load has to be conditional, which // means we need control flow. @@ -4404,6 +4411,16 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, std::nullopt); } +void CodeGenFunction::EmitNonNullArgCheck(Address Addr, QualType ArgType, + SourceLocation ArgLoc, + AbstractCallee AC, unsigned ParmNum) { + if (!AC.getDecl() || !(SanOpts.has(SanitizerKind::NonnullAttribute) || + SanOpts.has(SanitizerKind::NullabilityArg))) + return; + + EmitNonNullArgCheck(RValue::get(Addr, *this), ArgType, ArgLoc, AC, ParmNum); +} + // Check if the call is going to use the inalloca convention. This needs to // agree with CGFunctionInfo::usesInAlloca. The CGFunctionInfo is arranged // later, so we can't check it directly. @@ -4702,7 +4719,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, } if (HasAggregateEvalKind && isa(E) && - cast(E)->getCastKind() == CK_LValueToRValue) { + cast(E)->getCastKind() == CK_LValueToRValue && + !type->isArrayParameterType()) { LValue L = EmitLValue(cast(E)->getSubExpr()); assert(L.isSimple()); args.addUncopiedAggregate(L, type); @@ -4744,10 +4762,20 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) { llvm::CallInst * CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, const llvm::Twine &name) { - return EmitNounwindRuntimeCall(callee, std::nullopt, name); + return EmitNounwindRuntimeCall(callee, ArrayRef(), name); } /// Emits a call to the given nounwind runtime function. +llvm::CallInst * +CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, + ArrayRef
args, + const llvm::Twine &name) { + SmallVector values; + for (auto arg : args) + values.push_back(arg.emitRawPointer(*this)); + return EmitNounwindRuntimeCall(callee, values, name); +} + llvm::CallInst * CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, ArrayRef args, @@ -5026,7 +5054,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If we're using inalloca, insert the allocation after the stack save. // FIXME: Do this earlier rather than hacking it in here! - Address ArgMemory = Address::invalid(); + RawAddress ArgMemory = RawAddress::invalid(); if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) { const llvm::DataLayout &DL = CGM.getDataLayout(); llvm::Instruction *IP = CallArgs.getStackBase(); @@ -5042,7 +5070,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, AI->setAlignment(Align.getAsAlign()); AI->setUsedWithInAlloca(true); assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca()); - ArgMemory = Address(AI, ArgStruct, Align); + ArgMemory = RawAddress(AI, ArgStruct, Align); } ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), CallInfo); @@ -5051,11 +5079,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the call returns a temporary with struct return, create a temporary // alloca to hold the result, unless one is given to us. Address SRetPtr = Address::invalid(); - Address SRetAlloca = Address::invalid(); + RawAddress SRetAlloca = RawAddress::invalid(); llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { if (!ReturnValue.isNull()) { - SRetPtr = ReturnValue.getValue(); + SRetPtr = ReturnValue.getAddress(); } else { SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca); if (HaveInsertPoint() && ReturnValue.isUnused()) { @@ -5065,15 +5093,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } } if (IRFunctionArgs.hasSRetArg()) { - IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr.getPointer(); + IRCallArgs[IRFunctionArgs.getSRetArgNo()] = + getAsNaturalPointerTo(SRetPtr, RetTy); } else if (RetAI.isInAlloca()) { Address Addr = Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex()); - Builder.CreateStore(SRetPtr.getPointer(), Addr); + Builder.CreateStore(getAsNaturalPointerTo(SRetPtr, RetTy), Addr); } } - Address swiftErrorTemp = Address::invalid(); + RawAddress swiftErrorTemp = RawAddress::invalid(); Address swiftErrorArg = Address::invalid(); // When passing arguments using temporary allocas, we need to add the @@ -5106,9 +5135,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(NumIRArgs == 0); assert(getTarget().getTriple().getArch() == llvm::Triple::x86); if (I->isAggregate()) { - Address Addr = I->hasLValue() - ? I->getKnownLValue().getAddress(*this) - : I->getKnownRValue().getAggregateAddress(); + RawAddress Addr = I->hasLValue() + ? I->getKnownLValue().getAddress(*this) + : I->getKnownRValue().getAggregateAddress(); llvm::Instruction *Placeholder = cast(Addr.getPointer()); @@ -5132,7 +5161,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } else if (ArgInfo.getInAllocaIndirect()) { // Make a temporary alloca and store the address of it into the argument // struct. - Address Addr = CreateMemTempWithoutCast( + RawAddress Addr = CreateMemTempWithoutCast( I->Ty, getContext().getTypeAlignInChars(I->Ty), "indirect-arg-temp"); I->copyInto(*this, Addr); @@ -5154,12 +5183,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(NumIRArgs == 1); if (!I->isAggregate()) { // Make a temporary alloca to pass the argument. - Address Addr = CreateMemTempWithoutCast( + RawAddress Addr = CreateMemTempWithoutCast( I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); - llvm::Value *Val = Addr.getPointer(); + llvm::Value *Val = getAsNaturalPointerTo(Addr, I->Ty); if (ArgHasMaybeUndefAttr) - Val = Builder.CreateFreeze(Addr.getPointer()); + Val = Builder.CreateFreeze(Val); IRCallArgs[FirstIRArg] = Val; I->copyInto(*this, Addr); @@ -5175,7 +5204,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Address Addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); - llvm::Value *V = Addr.getPointer(); CharUnits Align = ArgInfo.getIndirectAlign(); const llvm::DataLayout *TD = &CGM.getDataLayout(); @@ -5186,8 +5214,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, bool NeedCopy = false; if (Addr.getAlignment() < Align && - llvm::getOrEnforceKnownAlignment(V, Align.getAsAlign(), *TD) < - Align.getAsAlign()) { + llvm::getOrEnforceKnownAlignment(Addr.emitRawPointer(*this), + Align.getAsAlign(), + *TD) < Align.getAsAlign()) { NeedCopy = true; } else if (I->hasLValue()) { auto LV = I->getKnownLValue(); @@ -5218,11 +5247,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (NeedCopy) { // Create an aligned temporary, and copy to it. - Address AI = CreateMemTempWithoutCast( + RawAddress AI = CreateMemTempWithoutCast( I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); - llvm::Value *Val = AI.getPointer(); + llvm::Value *Val = getAsNaturalPointerTo(AI, I->Ty); if (ArgHasMaybeUndefAttr) - Val = Builder.CreateFreeze(AI.getPointer()); + Val = Builder.CreateFreeze(Val); IRCallArgs[FirstIRArg] = Val; // Emit lifetime markers for the temporary alloca. @@ -5239,6 +5268,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, I->copyInto(*this, AI); } else { // Skip the extra memcpy call. + llvm::Value *V = getAsNaturalPointerTo(Addr, I->Ty); auto *T = llvm::PointerType::get( CGM.getLLVMContext(), CGM.getDataLayout().getAllocaAddrSpace()); @@ -5278,8 +5308,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(!swiftErrorTemp.isValid() && "multiple swifterror args"); QualType pointeeTy = I->Ty->getPointeeType(); - swiftErrorArg = Address(V, ConvertTypeForMem(pointeeTy), - getContext().getTypeAlignInChars(pointeeTy)); + swiftErrorArg = makeNaturalAddressForPointer( + V, pointeeTy, getContext().getTypeAlignInChars(pointeeTy)); swiftErrorTemp = CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); @@ -5416,7 +5446,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); - Address AllocaAddr = Address::invalid(); + RawAddress AllocaAddr = RawAddress::invalid(); if (I->isAggregate()) { addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); @@ -5686,6 +5716,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (!CI->getType()->isVoidTy()) CI->setName("call"); + if (getTarget().getTriple().isSPIRVLogical() && CI->isConvergent()) + CI = addControlledConvergenceToken(CI); + // Update largest vector width from the return type. LargestVectorWidth = std::max(LargestVectorWidth, getMaxVectorWidth(CI->getType())); @@ -5850,7 +5883,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return RValue::getComplex(std::make_pair(Real, Imag)); } case TEK_Aggregate: { - Address DestPtr = ReturnValue.getValue(); + Address DestPtr = ReturnValue.getAddress(); bool DestIsVolatile = ReturnValue.isVolatile(); if (!DestPtr.isValid()) { diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 1bd48a07259307486a53f2eba0de9f221274d219..6b676ac196db2a9a19f721b924da2e9ea274324c 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -377,6 +377,7 @@ public: Address getValue() const { return Addr; } bool isUnused() const { return IsUnused; } bool isExternallyDestructed() const { return IsExternallyDestructed; } + Address getAddress() const { return Addr; } }; /// Adds attributes to \p F according to our \p CodeGenOpts and \p LangOpts, as diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 34319381901af6c9458fd6cea2af18cf97be75e7..8c1c8ee455d2e634dc83a8845f2a970125184b9d 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -139,8 +139,9 @@ Address CodeGenFunction::LoadCXXThisAddress() { CXXThisAlignment = CGM.getClassPointerAlignment(MD->getParent()); } - llvm::Type *Ty = ConvertType(MD->getFunctionObjectParameterType()); - return Address(LoadCXXThis(), Ty, CXXThisAlignment, KnownNonNull); + return makeNaturalAddressForPointer( + LoadCXXThis(), MD->getFunctionObjectParameterType(), CXXThisAlignment, + false, nullptr, nullptr, KnownNonNull); } /// Emit the address of a field using a member data pointer. @@ -270,7 +271,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, Address addr, } // Apply the base offset. - llvm::Value *ptr = addr.getPointer(); + llvm::Value *ptr = addr.emitRawPointer(CGF); ptr = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ptr, baseOffset, "add.ptr"); // If we have a virtual component, the alignment of the result will @@ -338,8 +339,8 @@ Address CodeGenFunction::GetAddressOfBaseClass( if (sanitizePerformTypeCheck()) { SanitizerSet SkippedChecks; SkippedChecks.set(SanitizerKind::Null, !NullCheckValue); - EmitTypeCheck(TCK_Upcast, Loc, Value.getPointer(), - DerivedTy, DerivedAlign, SkippedChecks); + EmitTypeCheck(TCK_Upcast, Loc, Value.emitRawPointer(*this), DerivedTy, + DerivedAlign, SkippedChecks); } return Value.withElementType(BaseValueTy); } @@ -354,7 +355,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( llvm::BasicBlock *notNullBB = createBasicBlock("cast.notnull"); endBB = createBasicBlock("cast.end"); - llvm::Value *isNull = Builder.CreateIsNull(Value.getPointer()); + llvm::Value *isNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(isNull, endBB, notNullBB); EmitBlock(notNullBB); } @@ -363,14 +364,15 @@ Address CodeGenFunction::GetAddressOfBaseClass( SanitizerSet SkippedChecks; SkippedChecks.set(SanitizerKind::Null, true); EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc, - Value.getPointer(), DerivedTy, DerivedAlign, SkippedChecks); + Value.emitRawPointer(*this), DerivedTy, DerivedAlign, + SkippedChecks); } // Compute the virtual offset. llvm::Value *VirtualOffset = nullptr; if (VBase) { VirtualOffset = - CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase); + CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase); } // Apply both offsets. @@ -387,7 +389,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( EmitBlock(endBB); llvm::PHINode *PHI = Builder.CreatePHI(PtrTy, 2, "cast.result"); - PHI->addIncoming(Value.getPointer(), notNullBB); + PHI->addIncoming(Value.emitRawPointer(*this), notNullBB); PHI->addIncoming(llvm::Constant::getNullValue(PtrTy), origBB); Value = Value.withPointer(PHI, NotKnownNonNull); } @@ -424,15 +426,19 @@ CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr, CastNotNull = createBasicBlock("cast.notnull"); CastEnd = createBasicBlock("cast.end"); - llvm::Value *IsNull = Builder.CreateIsNull(BaseAddr.getPointer()); + llvm::Value *IsNull = Builder.CreateIsNull(BaseAddr); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } // Apply the offset. - llvm::Value *Value = BaseAddr.getPointer(); - Value = Builder.CreateInBoundsGEP( - Int8Ty, Value, Builder.CreateNeg(NonVirtualOffset), "sub.ptr"); + Address Addr = BaseAddr.withElementType(Int8Ty); + Addr = Builder.CreateInBoundsGEP( + Addr, Builder.CreateNeg(NonVirtualOffset), Int8Ty, + CGM.getClassPointerAlignment(Derived), "sub.ptr"); + + // Just cast. + Addr = Addr.withElementType(DerivedValueTy); // Produce a PHI if we had a null-check. if (NullCheckValue) { @@ -441,13 +447,15 @@ CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr, Builder.CreateBr(CastEnd); EmitBlock(CastEnd); + llvm::Value *Value = Addr.emitRawPointer(*this); llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); - Value = PHI; + return Address(PHI, Addr.getElementType(), + CGM.getClassPointerAlignment(Derived)); } - return Address(Value, DerivedValueTy, CGM.getClassPointerAlignment(Derived)); + return Addr; } llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, @@ -1719,7 +1727,7 @@ namespace { // Use the base class declaration location as inline DebugLocation. All // fields of the class are destroyed. DeclAsInlineDebugLocation InlineHere(CGF, *BaseClass); - EmitSanitizerDtorFieldsCallback(CGF, Addr.getPointer(), + EmitSanitizerDtorFieldsCallback(CGF, Addr.emitRawPointer(CGF), BaseSize.getQuantity()); // Prevent the current stack frame from disappearing from the stack trace. @@ -2022,7 +2030,7 @@ void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, // Find the end of the array. llvm::Type *elementType = arrayBase.getElementType(); - llvm::Value *arrayBegin = arrayBase.getPointer(); + llvm::Value *arrayBegin = arrayBase.emitRawPointer(*this); llvm::Value *arrayEnd = Builder.CreateInBoundsGEP( elementType, arrayBegin, numElements, "arrayctor.end"); @@ -2118,14 +2126,15 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, Address This = ThisAVS.getAddress(); LangAS SlotAS = ThisAVS.getQualifiers().getAddressSpace(); LangAS ThisAS = D->getFunctionObjectParameterType().getAddressSpace(); - llvm::Value *ThisPtr = This.getPointer(); + llvm::Value *ThisPtr = + getAsNaturalPointerTo(This, D->getThisType()->getPointeeType()); if (SlotAS != ThisAS) { unsigned TargetThisAS = getContext().getTargetAddressSpace(ThisAS); llvm::Type *NewType = llvm::PointerType::get(getLLVMContext(), TargetThisAS); - ThisPtr = getTargetHooks().performAddrSpaceCast(*this, This.getPointer(), - ThisAS, SlotAS, NewType); + ThisPtr = getTargetHooks().performAddrSpaceCast(*this, ThisPtr, ThisAS, + SlotAS, NewType); } // Push the this ptr. @@ -2194,7 +2203,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, const CXXRecordDecl *ClassDecl = D->getParent(); if (!NewPointerIsChecked) - EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This.getPointer(), + EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This, getContext().getRecordType(ClassDecl), CharUnits::Zero()); if (D->isTrivial() && D->isDefaultConstructor()) { @@ -2207,10 +2216,9 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, // model that copy. if (isMemcpyEquivalentSpecialMember(D)) { assert(Args.size() == 2 && "unexpected argcount for trivial ctor"); - QualType SrcTy = D->getParamDecl(0)->getType().getNonReferenceType(); - Address Src = Address(Args[1].getRValue(*this).getScalarVal(), ConvertTypeForMem(SrcTy), - CGM.getNaturalTypeAlignment(SrcTy)); + Address Src = makeNaturalAddressForPointer( + Args[1].getRValue(*this).getScalarVal(), SrcTy); LValue SrcLVal = MakeAddrLValue(Src, SrcTy); QualType DestTy = getContext().getTypeDeclType(ClassDecl); LValue DestLVal = MakeAddrLValue(This, DestTy); @@ -2263,7 +2271,9 @@ void CodeGenFunction::EmitInheritedCXXConstructorCall( const CXXConstructorDecl *D, bool ForVirtualBase, Address This, bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E) { CallArgList Args; - CallArg ThisArg(RValue::get(This.getPointer()), D->getThisType()); + CallArg ThisArg(RValue::get(getAsNaturalPointerTo( + This, D->getThisType()->getPointeeType())), + D->getThisType()); // Forward the parameters. if (InheritedFromVBase && @@ -2388,12 +2398,14 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, CallArgList Args; // Push the this ptr. - Args.add(RValue::get(This.getPointer()), D->getThisType()); + Args.add(RValue::get(getAsNaturalPointerTo(This, D->getThisType())), + D->getThisType()); // Push the src ptr. QualType QT = *(FPT->param_type_begin()); llvm::Type *t = CGM.getTypes().ConvertType(QT); - llvm::Value *SrcVal = Builder.CreateBitCast(Src.getPointer(), t); + llvm::Value *Val = getAsNaturalPointerTo(Src, D->getThisType()); + llvm::Value *SrcVal = Builder.CreateBitCast(Val, t); Args.add(RValue::get(SrcVal), QT); // Skip over first argument (Src). @@ -2418,7 +2430,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, // this Address This = LoadCXXThisAddress(); - DelegateArgs.add(RValue::get(This.getPointer()), (*I)->getType()); + DelegateArgs.add(RValue::get(getAsNaturalPointerTo( + This, (*I)->getType()->getPointeeType())), + (*I)->getType()); ++I; // FIXME: The location of the VTT parameter in the parameter list is @@ -2775,7 +2789,7 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived, if (MayBeNull) { llvm::Value *DerivedNotNull = - Builder.CreateIsNotNull(Derived.getPointer(), "cast.nonnull"); + Builder.CreateIsNotNull(Derived.emitRawPointer(*this), "cast.nonnull"); llvm::BasicBlock *CheckBlock = createBasicBlock("cast.check"); ContBlock = createBasicBlock("cast.cont"); @@ -2976,7 +2990,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda)); Address ThisPtr = GetAddrOfBlockDecl(variable); - CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType); + CallArgs.add(RValue::get(getAsNaturalPointerTo(ThisPtr, ThisType)), ThisType); // Add the rest of the parameters. for (auto *param : BD->parameters()) @@ -3004,7 +3018,7 @@ void CodeGenFunction::EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD) { QualType LambdaType = getContext().getRecordType(Lambda); QualType ThisType = getContext().getPointerType(LambdaType); Address ThisPtr = CreateMemTemp(LambdaType, "unused.capture"); - CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType); + CallArgs.add(RValue::get(ThisPtr.emitRawPointer(*this)), ThisType); EmitLambdaDelegatingInvokeBody(MD, CallArgs); } diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index f87caf050eeaa74b31de1452327e67f6139afaa8..e6f8e6873004f29d716caea0e82fb902be0f8117 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -27,7 +27,7 @@ bool DominatingValue::saved_type::needsSaving(RValue rv) { if (rv.isScalar()) return DominatingLLVMValue::needsSaving(rv.getScalarVal()); if (rv.isAggregate()) - return DominatingLLVMValue::needsSaving(rv.getAggregatePointer()); + return DominatingValue
::needsSaving(rv.getAggregateAddress()); return true; } @@ -35,69 +35,40 @@ DominatingValue::saved_type DominatingValue::saved_type::save(CodeGenFunction &CGF, RValue rv) { if (rv.isScalar()) { llvm::Value *V = rv.getScalarVal(); - - // These automatically dominate and don't need to be saved. - if (!DominatingLLVMValue::needsSaving(V)) - return saved_type(V, nullptr, ScalarLiteral); - - // Everything else needs an alloca. - Address addr = - CGF.CreateDefaultAlignTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, addr); - return saved_type(addr.getPointer(), nullptr, ScalarAddress); + return saved_type(DominatingLLVMValue::save(CGF, V), + DominatingLLVMValue::needsSaving(V) ? ScalarAddress + : ScalarLiteral); } if (rv.isComplex()) { CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); - llvm::Type *ComplexTy = - llvm::StructType::get(V.first->getType(), V.second->getType()); - Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex"); - CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0)); - CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1)); - return saved_type(addr.getPointer(), nullptr, ComplexAddress); + return saved_type(DominatingLLVMValue::save(CGF, V.first), + DominatingLLVMValue::save(CGF, V.second)); } assert(rv.isAggregate()); - Address V = rv.getAggregateAddress(); // TODO: volatile? - if (!DominatingLLVMValue::needsSaving(V.getPointer())) - return saved_type(V.getPointer(), V.getElementType(), AggregateLiteral, - V.getAlignment().getQuantity()); - - Address addr = - CGF.CreateTempAlloca(V.getType(), CGF.getPointerAlign(), "saved-rvalue"); - CGF.Builder.CreateStore(V.getPointer(), addr); - return saved_type(addr.getPointer(), V.getElementType(), AggregateAddress, - V.getAlignment().getQuantity()); + Address V = rv.getAggregateAddress(); + return saved_type( + DominatingValue
::save(CGF, V), rv.isVolatileQualified(), + DominatingValue
::needsSaving(V) ? AggregateAddress + : AggregateLiteral); } /// Given a saved r-value produced by SaveRValue, perform the code /// necessary to restore it to usability at the current insertion /// point. RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { - auto getSavingAddress = [&](llvm::Value *value) { - auto *AI = cast(value); - return Address(value, AI->getAllocatedType(), - CharUnits::fromQuantity(AI->getAlign().value())); - }; switch (K) { case ScalarLiteral: - return RValue::get(Value); case ScalarAddress: - return RValue::get(CGF.Builder.CreateLoad(getSavingAddress(Value))); + return RValue::get(DominatingLLVMValue::restore(CGF, Vals.first)); case AggregateLiteral: + case AggregateAddress: return RValue::getAggregate( - Address(Value, ElementType, CharUnits::fromQuantity(Align))); - case AggregateAddress: { - auto addr = CGF.Builder.CreateLoad(getSavingAddress(Value)); - return RValue::getAggregate( - Address(addr, ElementType, CharUnits::fromQuantity(Align))); - } + DominatingValue
::restore(CGF, AggregateAddr), IsVolatile); case ComplexAddress: { - Address address = getSavingAddress(Value); - llvm::Value *real = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 0)); - llvm::Value *imag = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 1)); + llvm::Value *real = DominatingLLVMValue::restore(CGF, Vals.first); + llvm::Value *imag = DominatingLLVMValue::restore(CGF, Vals.second); return RValue::getComplex(real, imag); } } @@ -294,14 +265,14 @@ void EHScopeStack::popNullFixups() { BranchFixups.pop_back(); } -Address CodeGenFunction::createCleanupActiveFlag() { +RawAddress CodeGenFunction::createCleanupActiveFlag() { // Create a variable to decide whether the cleanup needs to be run. - Address active = CreateTempAllocaWithoutCast( + RawAddress active = CreateTempAllocaWithoutCast( Builder.getInt1Ty(), CharUnits::One(), "cleanup.cond"); // Initialize it to false at a site that's guaranteed to be run // before each evaluation. - setBeforeOutermostConditional(Builder.getFalse(), active); + setBeforeOutermostConditional(Builder.getFalse(), active, *this); // Initialize it to true at the current location. Builder.CreateStore(Builder.getTrue(), active); @@ -309,7 +280,7 @@ Address CodeGenFunction::createCleanupActiveFlag() { return active; } -void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) { +void CodeGenFunction::initFullExprCleanupWithFlag(RawAddress ActiveFlag) { // Set that as the active flag in the cleanup. EHCleanupScope &cleanup = cast(*EHStack.begin()); assert(!cleanup.hasActiveFlag() && "cleanup already has active flag?"); @@ -322,15 +293,17 @@ void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) { void EHScopeStack::Cleanup::anchor() {} static void createStoreInstBefore(llvm::Value *value, Address addr, - llvm::Instruction *beforeInst) { - auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst); + llvm::Instruction *beforeInst, + CodeGenFunction &CGF) { + auto store = new llvm::StoreInst(value, addr.emitRawPointer(CGF), beforeInst); store->setAlignment(addr.getAlignment().getAsAlign()); } static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name, - llvm::Instruction *beforeInst) { - return new llvm::LoadInst(addr.getElementType(), addr.getPointer(), name, - false, addr.getAlignment().getAsAlign(), + llvm::Instruction *beforeInst, + CodeGenFunction &CGF) { + return new llvm::LoadInst(addr.getElementType(), addr.emitRawPointer(CGF), + name, false, addr.getAlignment().getAsAlign(), beforeInst); } @@ -357,8 +330,8 @@ static void ResolveAllBranchFixups(CodeGenFunction &CGF, // entry which we're currently popping. if (Fixup.OptimisticBranchBlock == nullptr) { createStoreInstBefore(CGF.Builder.getInt32(Fixup.DestinationIndex), - CGF.getNormalCleanupDestSlot(), - Fixup.InitialBranch); + CGF.getNormalCleanupDestSlot(), Fixup.InitialBranch, + CGF); Fixup.InitialBranch->setSuccessor(0, CleanupEntry); } @@ -385,7 +358,7 @@ static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF, if (llvm::BranchInst *Br = dyn_cast(Term)) { assert(Br->isUnconditional()); auto Load = createLoadInstBefore(CGF.getNormalCleanupDestSlot(), - "cleanup.dest", Term); + "cleanup.dest", Term, CGF); llvm::SwitchInst *Switch = llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block); Br->eraseFromParent(); @@ -513,8 +486,8 @@ void CodeGenFunction::PopCleanupBlocks( I += Header.getSize(); if (Header.isConditional()) { - Address ActiveFlag = - reinterpret_cast
(LifetimeExtendedCleanupStack[I]); + RawAddress ActiveFlag = + reinterpret_cast(LifetimeExtendedCleanupStack[I]); initFullExprCleanupWithFlag(ActiveFlag); I += sizeof(ActiveFlag); } @@ -888,7 +861,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (NormalCleanupDestSlot->hasOneUse()) { NormalCleanupDestSlot->user_back()->eraseFromParent(); NormalCleanupDestSlot->eraseFromParent(); - NormalCleanupDest = Address::invalid(); + NormalCleanupDest = RawAddress::invalid(); } llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); @@ -912,9 +885,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // pass the abnormal exit flag to Fn (SEH cleanup) cleanupFlags.setHasExitSwitch(); - llvm::LoadInst *Load = - createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest", - nullptr); + llvm::LoadInst *Load = createLoadInstBefore( + getNormalCleanupDestSlot(), "cleanup.dest", nullptr, *this); llvm::SwitchInst *Switch = llvm::SwitchInst::Create(Load, Default, SwitchCapacity); @@ -961,8 +933,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (!Fixup.Destination) continue; if (!Fixup.OptimisticBranchBlock) { createStoreInstBefore(Builder.getInt32(Fixup.DestinationIndex), - getNormalCleanupDestSlot(), - Fixup.InitialBranch); + getNormalCleanupDestSlot(), Fixup.InitialBranch, + *this); Fixup.InitialBranch->setSuccessor(0, NormalEntry); } Fixup.OptimisticBranchBlock = NormalExit; @@ -1135,7 +1107,7 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { // Store the index at the start. llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); - createStoreInstBefore(Index, getNormalCleanupDestSlot(), BI); + createStoreInstBefore(Index, getNormalCleanupDestSlot(), BI, *this); // Adjust BI to point to the first cleanup block. { @@ -1269,9 +1241,9 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF, // If we're in a conditional block, ignore the dominating IP and // use the outermost conditional branch. if (CGF.isInConditionalBranch()) { - CGF.setBeforeOutermostConditional(value, var); + CGF.setBeforeOutermostConditional(value, var, CGF); } else { - createStoreInstBefore(value, var, dominatingIP); + createStoreInstBefore(value, var, dominatingIP, CGF); } } @@ -1321,7 +1293,7 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C, Scope.setActive(false); } -Address CodeGenFunction::getNormalCleanupDestSlot() { +RawAddress CodeGenFunction::getNormalCleanupDestSlot() { if (!NormalCleanupDest.isValid()) NormalCleanupDest = CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h index 7a7344c07160db388ba8d743a37c245069c9af9c..03e4a29d7b3dbfa5b3953725e9fc1fe0fe55bb44 100644 --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -333,7 +333,7 @@ public: Address getActiveFlag() const { return ActiveFlag; } - void setActiveFlag(Address Var) { + void setActiveFlag(RawAddress Var) { assert(Var.getAlignment().isOne()); ActiveFlag = Var; } diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index b7142ec08af986d16656fdb7e10aed35b98912d1..93ca711f716fce5bec80f56f81e0f3749de5d3f8 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -867,8 +867,8 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { EmitStmt(S.getPromiseDeclStmt()); Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl()); - auto *PromiseAddrVoidPtr = - new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId); + auto *PromiseAddrVoidPtr = new llvm::BitCastInst( + PromiseAddr.emitRawPointer(*this), VoidPtrTy, "", CoroId); // Update CoroId to refer to the promise. We could not do it earlier because // promise local variable was not emitted yet. CoroId->setArgOperand(1, PromiseAddrVoidPtr); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0e20de2005b24b41846cc845d50ae59c558075e1..8c284c332171a1bbdd9a3af14692e7de5ac81ec2 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1440,8 +1440,7 @@ static unsigned getDwarfCC(CallingConv CC) { case CC_Swift: return llvm::dwarf::DW_CC_LLVM_Swift; case CC_SwiftAsync: - // [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands. - return llvm::dwarf::DW_CC_LLVM_Swift; + return llvm::dwarf::DW_CC_LLVM_SwiftTail; case CC_PreserveMost: return llvm::dwarf::DW_CC_LLVM_PreserveMost; case CC_PreserveAll: @@ -1452,6 +1451,8 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_M68kRTD; case CC_PreserveNone: return llvm::dwarf::DW_CC_LLVM_PreserveNone; + case CC_RISCVVectorCall: + return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; } return 0; } @@ -3640,6 +3641,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: + case Type::ArrayParameter: return CreateType(cast(Ty), Unit); case Type::LValueReference: diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 2ef5ed04af30b6e99b59e2570e0c27da25500777..267f2e40a7bbaa198ed551bcc67702a38d783f11 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1461,7 +1461,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { bool EmitDebugInfo = DI && CGM.getCodeGenOpts().hasReducedDebugInfo(); Address address = Address::invalid(); - Address AllocaAddr = Address::invalid(); + RawAddress AllocaAddr = RawAddress::invalid(); Address OpenMPLocalAddr = Address::invalid(); if (CGM.getLangOpts().OpenMPIRBuilder) OpenMPLocalAddr = OMPBuilderCBHelpers::getAddressOfLocalVariable(*this, &D); @@ -1524,7 +1524,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // return slot, so that we can elide the copy when returning this // variable (C++0x [class.copy]p34). address = ReturnValue; - AllocaAddr = ReturnValue; + AllocaAddr = + RawAddress(ReturnValue.emitRawPointer(*this), + ReturnValue.getElementType(), ReturnValue.getAlignment()); + ; if (const RecordType *RecordTy = Ty->getAs()) { const auto *RD = RecordTy->getDecl(); @@ -1535,7 +1538,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // to this variable. Set it to zero to indicate that NRVO was not // applied. llvm::Value *Zero = Builder.getFalse(); - Address NRVOFlag = + RawAddress NRVOFlag = CreateTempAlloca(Zero->getType(), CharUnits::One(), "nrvo"); EnsureInsertPoint(); Builder.CreateStore(Zero, NRVOFlag); @@ -1678,7 +1681,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { } if (D.hasAttr() && HaveInsertPoint()) - EmitVarAnnotations(&D, address.getPointer()); + EmitVarAnnotations(&D, address.emitRawPointer(*this)); // Make sure we call @llvm.lifetime.end. if (emission.useLifetimeMarkers()) @@ -1851,12 +1854,13 @@ void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type, llvm::Value *BaseSizeInChars = llvm::ConstantInt::get(IntPtrTy, EltSize.getQuantity()); Address Begin = Loc.withElementType(Int8Ty); - llvm::Value *End = Builder.CreateInBoundsGEP( - Begin.getElementType(), Begin.getPointer(), SizeVal, "vla.end"); + llvm::Value *End = Builder.CreateInBoundsGEP(Begin.getElementType(), + Begin.emitRawPointer(*this), + SizeVal, "vla.end"); llvm::BasicBlock *OriginBB = Builder.GetInsertBlock(); EmitBlock(LoopBB); llvm::PHINode *Cur = Builder.CreatePHI(Begin.getType(), 2, "vla.cur"); - Cur->addIncoming(Begin.getPointer(), OriginBB); + Cur->addIncoming(Begin.emitRawPointer(*this), OriginBB); CharUnits CurAlign = Loc.getAlignment().alignmentOfArrayElement(EltSize); auto *I = Builder.CreateMemCpy(Address(Cur, Int8Ty, CurAlign), @@ -2283,7 +2287,7 @@ void CodeGenFunction::emitDestroy(Address addr, QualType type, checkZeroLength = false; } - llvm::Value *begin = addr.getPointer(); + llvm::Value *begin = addr.emitRawPointer(*this); llvm::Value *end = Builder.CreateInBoundsGEP(addr.getElementType(), begin, length); emitArrayDestroy(begin, end, type, elementAlign, destroyer, @@ -2543,7 +2547,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, } Address DeclPtr = Address::invalid(); - Address AllocaPtr = Address::invalid(); + RawAddress AllocaPtr = Address::invalid(); bool DoStore = false; bool IsScalar = hasScalarEvaluationKind(Ty); bool UseIndirectDebugAddress = false; @@ -2555,8 +2559,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Indirect argument is in alloca address space, which may be different // from the default address space. auto AllocaAS = CGM.getASTAllocaAddressSpace(); - auto *V = DeclPtr.getPointer(); - AllocaPtr = DeclPtr; + auto *V = DeclPtr.emitRawPointer(*this); + AllocaPtr = RawAddress(V, DeclPtr.getElementType(), DeclPtr.getAlignment()); // For truly ABI indirect arguments -- those that are not `byval` -- store // the address of the argument on the stack to preserve debug information. @@ -2695,7 +2699,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, } if (D.hasAttr()) - EmitVarAnnotations(&D, DeclPtr.getPointer()); + EmitVarAnnotations(&D, DeclPtr.emitRawPointer(*this)); // We can only check return value nullability if all arguments to the // function satisfy their nullability preconditions. This makes it necessary diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 5a9d06da12de571ab376e8740b06fd63ac66cc9f..34f289334a7df90584d9b7f80bf57a99060a7af0 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -397,7 +397,7 @@ namespace { void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { // Make sure the exception object is cleaned up if there's an // exception during initialization. - pushFullExprCleanup(EHCleanup, addr.getPointer()); + pushFullExprCleanup(EHCleanup, addr.emitRawPointer(*this)); EHScopeStack::stable_iterator cleanup = EHStack.stable_begin(); // __cxa_allocate_exception returns a void*; we need to cast this @@ -416,8 +416,8 @@ void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { /*IsInit*/ true); // Deactivate the cleanup block. - DeactivateCleanupBlock(cleanup, - cast(typedAddr.getPointer())); + DeactivateCleanupBlock( + cleanup, cast(typedAddr.emitRawPointer(*this))); } Address CodeGenFunction::getExceptionSlot() { @@ -1834,7 +1834,8 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, llvm::Value *ParentFP) { llvm::CallInst *RecoverCall = nullptr; CGBuilderTy Builder(*this, AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast(ParentVar.getPointer())) { + if (auto *ParentAlloca = + dyn_cast_or_null(ParentVar.getBasePointer())) { // Mark the variable escaped if nobody else referenced it and compute the // localescape index. auto InsertPair = ParentCGF.EscapedLocals.insert( @@ -1851,8 +1852,8 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, // If the parent didn't have an alloca, we're doing some nested outlining. // Just clone the existing localrecover call, but tweak the FP argument to // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast(ParentVar.getPointer()->stripPointerCasts()); + auto *ParentRecover = cast( + ParentVar.emitRawPointer(*this)->stripPointerCasts()); assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover && "expected alloca or localrecover in parent LocalDeclMap"); RecoverCall = cast(ParentRecover->clone()); @@ -1925,7 +1926,8 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, if (isa(D) && D->getType() == getContext().VoidPtrTy) { assert(D->getName().starts_with("frame_pointer")); - FramePtrAddrAlloca = cast(I.second.getPointer()); + FramePtrAddrAlloca = + cast(I.second.getBasePointer()); break; } } @@ -1986,7 +1988,8 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { - CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); + CXXThisValue = + ThisFieldLValue.getAddress(*this).emitRawPointer(*this); } else { CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation()) .getScalarVal(); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6491835cf8ef170699859e913bd74e47806783d1..e0d5575d57d02d5260febf21a605dab225e57c0c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -65,21 +65,21 @@ static llvm::cl::opt ClSanitizeDebugDeoptimization( /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. -Address CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty, - CharUnits Align, - const Twine &Name, - llvm::Value *ArraySize) { +RawAddress +CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits Align, + const Twine &Name, + llvm::Value *ArraySize) { auto Alloca = CreateTempAlloca(Ty, Name, ArraySize); Alloca->setAlignment(Align.getAsAlign()); - return Address(Alloca, Ty, Align, KnownNonNull); + return RawAddress(Alloca, Ty, Align, KnownNonNull); } /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. The alloca is casted to default address space if necessary. -Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, - const Twine &Name, - llvm::Value *ArraySize, - Address *AllocaAddr) { +RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, + const Twine &Name, + llvm::Value *ArraySize, + RawAddress *AllocaAddr) { auto Alloca = CreateTempAllocaWithoutCast(Ty, Align, Name, ArraySize); if (AllocaAddr) *AllocaAddr = Alloca; @@ -101,7 +101,7 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); } - return Address(V, Ty, Align, KnownNonNull); + return RawAddress(V, Ty, Align, KnownNonNull); } /// CreateTempAlloca - This creates an alloca and inserts it into the entry @@ -120,28 +120,29 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, /// default alignment of the corresponding LLVM type, which is *not* /// guaranteed to be related in any way to the expected alignment of /// an AST type that might have been lowered to Ty. -Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, - const Twine &Name) { +RawAddress CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, + const Twine &Name) { CharUnits Align = CharUnits::fromQuantity(CGM.getDataLayout().getPrefTypeAlign(Ty)); return CreateTempAlloca(Ty, Align, Name); } -Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { +RawAddress CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { CharUnits Align = getContext().getTypeAlignInChars(Ty); return CreateTempAlloca(ConvertType(Ty), Align, Name); } -Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, - Address *Alloca) { +RawAddress CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, + RawAddress *Alloca) { // FIXME: Should we prefer the preferred type alignment here? return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, Alloca); } -Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, - const Twine &Name, Address *Alloca) { - Address Result = CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, - /*ArraySize=*/nullptr, Alloca); +RawAddress CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, + const Twine &Name, + RawAddress *Alloca) { + RawAddress Result = CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, + /*ArraySize=*/nullptr, Alloca); if (Ty->isConstantMatrixType()) { auto *ArrayTy = cast(Result.getElementType()); @@ -154,13 +155,14 @@ Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, return Result; } -Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, CharUnits Align, - const Twine &Name) { +RawAddress CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, + CharUnits Align, + const Twine &Name) { return CreateTempAllocaWithoutCast(ConvertTypeForMem(Ty), Align, Name); } -Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, - const Twine &Name) { +RawAddress CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, + const Twine &Name) { return CreateMemTempWithoutCast(Ty, getContext().getTypeAlignInChars(Ty), Name); } @@ -359,7 +361,7 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } else { CleanupFn = CGF.CGM.getAddrAndTypeOfCXXStructor( GlobalDecl(ReferenceTemporaryDtor, Dtor_Complete)); - CleanupArg = cast(ReferenceTemporary.getPointer()); + CleanupArg = cast(ReferenceTemporary.emitRawPointer(CGF)); } CGF.CGM.getCXXABI().registerGlobalDtor( CGF, *cast(M->getExtendingDecl()), CleanupFn, CleanupArg); @@ -384,10 +386,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } } -static Address createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, - const Expr *Inner, - Address *Alloca = nullptr) { +static RawAddress createReferenceTemporary(CodeGenFunction &CGF, + const MaterializeTemporaryExpr *M, + const Expr *Inner, + RawAddress *Alloca = nullptr) { auto &TCG = CGF.getTargetHooks(); switch (M->getStorageDuration()) { case SD_FullExpression: @@ -416,7 +418,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, GV->getValueType()->getPointerTo( CGF.getContext().getTargetAddressSpace(LangAS::Default))); // FIXME: Should we put the new global into a COMDAT? - return Address(C, GV->getValueType(), alignment); + return RawAddress(C, GV->getValueType(), alignment); } return CGF.CreateMemTemp(Ty, "ref.tmp", Alloca); } @@ -448,7 +450,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { auto ownership = M->getType().getObjCLifetime(); if (ownership != Qualifiers::OCL_None && ownership != Qualifiers::OCL_ExplicitNone) { - Address Object = createReferenceTemporary(*this, M, E); + RawAddress Object = createReferenceTemporary(*this, M, E); if (auto *Var = dyn_cast(Object.getPointer())) { llvm::Type *Ty = ConvertTypeForMem(E->getType()); Object = Object.withElementType(Ty); @@ -502,8 +504,8 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { } // Create and initialize the reference temporary. - Address Alloca = Address::invalid(); - Address Object = createReferenceTemporary(*this, M, E, &Alloca); + RawAddress Alloca = Address::invalid(); + RawAddress Object = createReferenceTemporary(*this, M, E, &Alloca); if (auto *Var = dyn_cast( Object.getPointer()->stripPointerCasts())) { llvm::Type *TemporaryType = ConvertTypeForMem(E->getType()); @@ -1111,12 +1113,12 @@ llvm::Value *CodeGenFunction::EmitCountedByFieldExpr( } else if (const MemberExpr *ME = dyn_cast(StructBase)) { LValue LV = EmitMemberExpr(ME); Address Addr = LV.getAddress(*this); - Res = Addr.getPointer(); + Res = Addr.emitRawPointer(*this); } else if (StructBase->getType()->isPointerType()) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; Address Addr = EmitPointerWithAlignment(StructBase, &BaseInfo, &TBAAInfo); - Res = Addr.getPointer(); + Res = Addr.emitRawPointer(*this); } else { return nullptr; } @@ -1282,8 +1284,7 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, if (InnerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) { if (BaseInfo) BaseInfo->mergeForCast(TargetTypeBaseInfo); - Addr = Address(Addr.getPointer(), Addr.getElementType(), Align, - IsKnownNonNull); + Addr.setAlignment(Align); } } @@ -1300,8 +1301,8 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, CGF.ConvertTypeForMem(E->getType()->getPointeeType()); Addr = Addr.withElementType(ElemTy); if (CE->getCastKind() == CK_AddressSpaceConversion) - Addr = CGF.Builder.CreateAddrSpaceCast(Addr, - CGF.ConvertType(E->getType())); + Addr = CGF.Builder.CreateAddrSpaceCast( + Addr, CGF.ConvertType(E->getType()), ElemTy); return Addr; } break; @@ -1364,10 +1365,9 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, // TODO: conditional operators, comma. // Otherwise, use the alignment of the type. - CharUnits Align = - CGF.CGM.getNaturalPointeeTypeAlignment(E->getType(), BaseInfo, TBAAInfo); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(E->getType()->getPointeeType()); - return Address(CGF.EmitScalarExpr(E), ElemTy, Align, IsKnownNonNull); + return CGF.makeNaturalAddressForPointer( + CGF.EmitScalarExpr(E), E->getType()->getPointeeType(), CharUnits(), + /*ForPointeeType=*/true, BaseInfo, TBAAInfo, IsKnownNonNull); } /// EmitPointerWithAlignment - Given an expression of pointer type, try to @@ -1468,8 +1468,7 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { if (IsBaseCXXThis || isa(ME->getBase())) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(*this), E->getType(), - LV.getAlignment(), SkippedChecks); + EmitTypeCheck(TCK, E->getExprLoc(), LV, E->getType(), SkippedChecks); } return LV; } @@ -1581,11 +1580,11 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E, // Defend against branches out of gnu statement expressions surrounded by // cleanups. Address Addr = LV.getAddress(*this); - llvm::Value *V = Addr.getPointer(); + llvm::Value *V = Addr.getBasePointer(); Scope.ForceCleanup({&V}); - return LValue::MakeAddr(Addr.withPointer(V, Addr.isKnownNonNull()), - LV.getType(), getContext(), LV.getBaseInfo(), - LV.getTBAAInfo()); + Addr.replaceBasePointer(V); + return LValue::MakeAddr(Addr, LV.getType(), getContext(), + LV.getBaseInfo(), LV.getTBAAInfo()); } // FIXME: Is it possible to create an ExprWithCleanups that produces a // bitfield lvalue or some other non-simple lvalue? @@ -1929,7 +1928,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isNontemporal) { - if (auto *GV = dyn_cast(Addr.getPointer())) + if (auto *GV = dyn_cast(Addr.getBasePointer())) if (GV->isThreadLocal()) Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV), NotKnownNonNull); @@ -2039,8 +2038,9 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { // Convert the pointer of \p Addr to a pointer to a vector (the value type of // MatrixType), if it points to a array (the memory type of MatrixType). -static Address MaybeConvertMatrixAddress(Address Addr, CodeGenFunction &CGF, - bool IsVector = true) { +static RawAddress MaybeConvertMatrixAddress(RawAddress Addr, + CodeGenFunction &CGF, + bool IsVector = true) { auto *ArrayTy = dyn_cast(Addr.getElementType()); if (ArrayTy && IsVector) { auto *VectorTy = llvm::FixedVectorType::get(ArrayTy->getElementType(), @@ -2077,7 +2077,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isInit, bool isNontemporal) { - if (auto *GV = dyn_cast(Addr.getPointer())) + if (auto *GV = dyn_cast(Addr.getBasePointer())) if (GV->isThreadLocal()) Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV), NotKnownNonNull); @@ -2432,14 +2432,12 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL"); llvm::Type *ResultType = IntPtrTy; Address dst = EmitPointerWithAlignment(Dst.getBaseIvarExp()); - llvm::Value *RHS = dst.getPointer(); + llvm::Value *RHS = dst.emitRawPointer(*this); RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); - llvm::Value *LHS = - Builder.CreatePtrToInt(LvalueDst.getPointer(), ResultType, - "sub.ptr.lhs.cast"); + llvm::Value *LHS = Builder.CreatePtrToInt(LvalueDst.emitRawPointer(*this), + ResultType, "sub.ptr.lhs.cast"); llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); - CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, - BytesBetween); + CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, BytesBetween); } else if (Dst.isGlobalObjCRef()) { CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst, Dst.isThreadLocalRef()); @@ -2770,12 +2768,9 @@ CodeGenFunction::EmitLoadOfReference(LValue RefLVal, llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(*this), RefLVal.isVolatile()); CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo()); - - QualType PointeeType = RefLVal.getType()->getPointeeType(); - CharUnits Align = CGM.getNaturalTypeAlignment( - PointeeType, PointeeBaseInfo, PointeeTBAAInfo, - /* forPointeeType= */ true); - return Address(Load, ConvertTypeForMem(PointeeType), Align); + return makeNaturalAddressForPointer(Load, RefLVal.getType()->getPointeeType(), + CharUnits(), /*ForPointeeType=*/true, + PointeeBaseInfo, PointeeTBAAInfo); } LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) { @@ -2792,10 +2787,9 @@ Address CodeGenFunction::EmitLoadOfPointer(Address Ptr, LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) { llvm::Value *Addr = Builder.CreateLoad(Ptr); - return Address(Addr, ConvertTypeForMem(PtrTy->getPointeeType()), - CGM.getNaturalTypeAlignment(PtrTy->getPointeeType(), BaseInfo, - TBAAInfo, - /*forPointeeType=*/true)); + return makeNaturalAddressForPointer(Addr, PtrTy->getPointeeType(), + CharUnits(), /*ForPointeeType=*/true, + BaseInfo, TBAAInfo); } LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr, @@ -2991,7 +2985,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { /* BaseInfo= */ nullptr, /* TBAAInfo= */ nullptr, /* forPointeeType= */ true); - Addr = Address(Val, ConvertTypeForMem(E->getType()), Alignment); + Addr = makeNaturalAddressForPointer(Val, T, Alignment); } return MakeAddrLValue(Addr, T, AlignmentSource::Decl); } @@ -3023,11 +3017,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD), CapturedStmtInfo->getContextValue()); Address LValueAddress = CapLVal.getAddress(*this); - CapLVal = MakeAddrLValue( - Address(LValueAddress.getPointer(), LValueAddress.getElementType(), - getContext().getDeclAlign(VD)), - CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl), - CapLVal.getTBAAInfo()); + CapLVal = MakeAddrLValue(Address(LValueAddress.emitRawPointer(*this), + LValueAddress.getElementType(), + getContext().getDeclAlign(VD)), + CapLVal.getType(), + LValueBaseInfo(AlignmentSource::Decl), + CapLVal.getTBAAInfo()); // Mark lvalue as nontemporal if the variable is marked as nontemporal // in simd context. if (getLangOpts().OpenMP && @@ -3083,7 +3078,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // Handle threadlocal function locals. if (VD->getTLSKind() != VarDecl::TLS_None) addr = addr.withPointer( - Builder.CreateThreadLocalAddress(addr.getPointer()), NotKnownNonNull); + Builder.CreateThreadLocalAddress(addr.getBasePointer()), + NotKnownNonNull); // Check for OpenMP threadprivate variables. if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd && @@ -3351,7 +3347,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { // Pointers are passed directly, everything else is passed by address. if (!V->getType()->isPointerTy()) { - Address Ptr = CreateDefaultAlignTempAlloca(V->getType()); + RawAddress Ptr = CreateDefaultAlignTempAlloca(V->getType()); Builder.CreateStore(V, Ptr); V = Ptr.getPointer(); } @@ -3924,6 +3920,21 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF, } } +static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, + ArrayRef indices, + llvm::Type *elementType, bool inbounds, + bool signedIndices, SourceLocation loc, + CharUnits align, + const llvm::Twine &name = "arrayidx") { + if (inbounds) { + return CGF.EmitCheckedInBoundsGEP(addr, indices, elementType, signedIndices, + CodeGenFunction::NotSubtraction, loc, + align, name); + } else { + return CGF.Builder.CreateGEP(addr, indices, elementType, align, name); + } +} + static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx, CharUnits eltSize) { @@ -3971,7 +3982,7 @@ static Address wrapWithBPFPreserveStaticOffset(CodeGenFunction &CGF, llvm::Function *Fn = CGF.CGM.getIntrinsic(llvm::Intrinsic::preserve_static_offset); - llvm::CallInst *Call = CGF.Builder.CreateCall(Fn, {Addr.getPointer()}); + llvm::CallInst *Call = CGF.Builder.CreateCall(Fn, {Addr.emitRawPointer(CGF)}); return Address(Call, Addr.getElementType(), Addr.getAlignment()); } @@ -4034,7 +4045,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, // We can use that to compute the best alignment of the element. CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType); CharUnits eltAlign = - getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); + getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); if (hasBPFPreserveStaticOffset(Base)) addr = wrapWithBPFPreserveStaticOffset(CGF, addr); @@ -4043,19 +4054,19 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, auto LastIndex = dyn_cast(indices.back()); if (!LastIndex || (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) { - eltPtr = emitArraySubscriptGEP( - CGF, addr.getElementType(), addr.getPointer(), indices, inbounds, - signedIndices, loc, name); + addr = emitArraySubscriptGEP(CGF, addr, indices, + CGF.ConvertTypeForMem(eltType), inbounds, + signedIndices, loc, eltAlign, name); + return addr; } else { // Remember the original array subscript for bpf target unsigned idx = LastIndex->getZExtValue(); llvm::DIType *DbgInfo = nullptr; if (arrayType) DbgInfo = CGF.getDebugInfo()->getOrCreateStandaloneType(*arrayType, loc); - eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getElementType(), - addr.getPointer(), - indices.size() - 1, - idx, DbgInfo); + eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex( + addr.getElementType(), addr.emitRawPointer(CGF), indices.size() - 1, + idx, DbgInfo); } return Address(eltPtr, CGF.ConvertTypeForMem(eltType), eltAlign); @@ -4224,8 +4235,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, CharUnits EltAlign = getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize); llvm::Value *EltPtr = - emitArraySubscriptGEP(*this, Int8Ty, Addr.getPointer(), ScaledIdx, - false, SignedIndices, E->getExprLoc()); + emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this), + ScaledIdx, false, SignedIndices, E->getExprLoc()); Addr = Address(EltPtr, OrigBaseElemTy, EltAlign); } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) { // If this is A[i] where A is an array, the frontend will have decayed the @@ -4271,7 +4282,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, llvm::Type *CountTy = ConvertType(CountFD->getType()); llvm::Value *Res = Builder.CreateInBoundsGEP( - Int8Ty, Addr.getPointer(), + Int8Ty, Addr.emitRawPointer(*this), Builder.getInt32(OffsetDiff.getQuantity()), ".counted_by.gep"); Res = Builder.CreateAlignedLoad(CountTy, Res, getIntAlign(), ".counted_by.load"); @@ -4517,9 +4528,9 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, BaseInfo = ArrayLV.getBaseInfo(); TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy); } else { - Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, - TBAAInfo, BaseTy, ResultExprTy, - IsLowerBound); + Address Base = + emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo, BaseTy, + ResultExprTy, IsLowerBound); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), /*signedIndices=*/false, E->getExprLoc()); @@ -4606,7 +4617,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { SkippedChecks.set(SanitizerKind::Alignment, true); if (IsBaseCXXThis || isa(BaseExpr)) SkippedChecks.set(SanitizerKind::Null, true); - EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy, + EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr, PtrTy, /*Alignment=*/CharUnits::Zero(), SkippedChecks); BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo); } else @@ -4655,8 +4666,8 @@ LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field, LambdaLV = EmitLoadOfReferenceLValue(AddrOfExplicitObject, D->getType(), AlignmentSource::Decl); else - LambdaLV = MakeNaturalAlignAddrLValue(AddrOfExplicitObject.getPointer(), - D->getType().getNonReferenceType()); + LambdaLV = MakeAddrLValue(AddrOfExplicitObject, + D->getType().getNonReferenceType()); } else { QualType LambdaTagType = getContext().getTagDeclType(Field->getParent()); LambdaLV = MakeNaturalAlignAddrLValue(ThisValue, LambdaTagType); @@ -4846,7 +4857,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, // information provided by invariant.group. This is because accessing // fields may leak the real address of dynamic object, which could result // in miscompilation when leaked pointer would be compared. - auto *stripped = Builder.CreateStripInvariantGroup(addr.getPointer()); + auto *stripped = + Builder.CreateStripInvariantGroup(addr.emitRawPointer(*this)); addr = Address(stripped, addr.getElementType(), addr.getAlignment()); } } @@ -4865,10 +4877,11 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, // Remember the original union field index llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType(base.getType(), rec->getLocation()); - addr = Address( - Builder.CreatePreserveUnionAccessIndex( - addr.getPointer(), getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo), - addr.getElementType(), addr.getAlignment()); + addr = + Address(Builder.CreatePreserveUnionAccessIndex( + addr.emitRawPointer(*this), + getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo), + addr.getElementType(), addr.getAlignment()); } if (FieldType->isReferenceType()) @@ -5105,11 +5118,9 @@ LValue CodeGenFunction::EmitConditionalOperatorLValue( if (Info.LHS && Info.RHS) { Address lhsAddr = Info.LHS->getAddress(*this); Address rhsAddr = Info.RHS->getAddress(*this); - llvm::PHINode *phi = Builder.CreatePHI(lhsAddr.getType(), 2, "cond-lvalue"); - phi->addIncoming(lhsAddr.getPointer(), Info.lhsBlock); - phi->addIncoming(rhsAddr.getPointer(), Info.rhsBlock); - Address result(phi, lhsAddr.getElementType(), - std::min(lhsAddr.getAlignment(), rhsAddr.getAlignment())); + Address result = mergeAddressesInConditionalExpr( + lhsAddr, rhsAddr, Info.lhsBlock, Info.rhsBlock, + Builder.GetInsertBlock(), expr->getType()); AlignmentSource alignSource = std::max(Info.LHS->getBaseInfo().getAlignmentSource(), Info.RHS->getBaseInfo().getAlignmentSource()); @@ -5179,6 +5190,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_IntegralToFixedPoint: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); case CK_Dependent: @@ -5196,7 +5208,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); Address V = LV.getAddress(*this); const auto *DCE = cast(E); - return MakeNaturalAlignAddrLValue(EmitDynamicCast(V, DCE), E->getType()); + return MakeNaturalAlignRawAddrLValue(EmitDynamicCast(V, DCE), E->getType()); } case CK_ConstructorConversion: @@ -5261,8 +5273,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is // performed and the object is not of the derived type. if (sanitizePerformTypeCheck()) - EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), - Derived.getPointer(), E->getType()); + EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), Derived, + E->getType()); if (SanOpts.has(SanitizerKind::CFIDerivedCast)) EmitVTablePtrCheckForCast(E->getType(), Derived, @@ -5618,7 +5630,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { LValue CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { - return MakeNaturalAlignAddrLValue(EmitCXXTypeidExpr(E), E->getType()); + return MakeNaturalAlignRawAddrLValue(EmitCXXTypeidExpr(E), E->getType()); } Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) { diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 5190b22bcc162254b09ef81bae7f7f3d7deb0502..1b9287ea239347d334c2c7d52e2cc092e281aeb5 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -294,10 +294,10 @@ void AggExprEmitter::withReturnValueSlot( // Otherwise, EmitCall will emit its own, notice that it's "unused", and end // its lifetime before we have the chance to emit a proper destructor call. bool UseTemp = Dest.isPotentiallyAliased() || Dest.requiresGCollection() || - (RequiresDestruction && !Dest.getAddress().isValid()); + (RequiresDestruction && Dest.isIgnored()); Address RetAddr = Address::invalid(); - Address RetAllocaAddr = Address::invalid(); + RawAddress RetAllocaAddr = RawAddress::invalid(); EHScopeStack::stable_iterator LifetimeEndBlock; llvm::Value *LifetimeSizePtr = nullptr; @@ -329,7 +329,8 @@ void AggExprEmitter::withReturnValueSlot( if (!UseTemp) return; - assert(Dest.isIgnored() || Dest.getPointer() != Src.getAggregatePointer()); + assert(Dest.isIgnored() || Dest.emitRawPointer(CGF) != + Src.getAggregatePointer(E->getType(), CGF)); EmitFinalDestCopy(E->getType(), Src); if (!RequiresDestruction && LifetimeStartInst) { @@ -448,7 +449,8 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); llvm::Value *IdxStart[] = { Zero, Zero }; llvm::Value *ArrayStart = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxStart, "arraystart"); + ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxStart, + "arraystart"); CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); ++Field; @@ -465,7 +467,8 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { // End pointer. llvm::Value *IdxEnd[] = { Zero, Size }; llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxEnd, "arrayend"); + ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd, + "arrayend"); CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) { // Length. @@ -516,9 +519,9 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, // down a level. llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); llvm::Value *indices[] = { zero, zero }; - llvm::Value *begin = Builder.CreateInBoundsGEP( - DestPtr.getElementType(), DestPtr.getPointer(), indices, - "arrayinit.begin"); + llvm::Value *begin = Builder.CreateInBoundsGEP(DestPtr.getElementType(), + DestPtr.emitRawPointer(CGF), + indices, "arrayinit.begin"); CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType); CharUnits elementAlign = @@ -880,6 +883,9 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { [[fallthrough]]; + case CK_HLSLArrayRValue: + Visit(E->getSubExpr()); + break; case CK_NoOp: case CK_UserDefinedConversion: @@ -1059,7 +1065,7 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) { if (RV.isScalar()) return {RV.getScalarVal(), nullptr}; if (RV.isAggregate()) - return {RV.getAggregatePointer(), nullptr}; + return {RV.getAggregatePointer(E->getType(), CGF), nullptr}; assert(RV.isComplex()); return RV.getComplexVal(); }; @@ -1521,6 +1527,7 @@ static bool castPreservesZero(const CastExpr *CE) { case CK_LValueToRValue: case CK_LValueToRValueBitCast: case CK_UncheckedDerivedToBase: + case CK_HLSLArrayRValue: return false; } llvm_unreachable("Unhandled clang::CastKind enum"); @@ -1818,7 +1825,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // else, clean it up for -O0 builds and general tidiness. if (!pushedCleanup && LV.isSimple()) if (llvm::GetElementPtrInst *GEP = - dyn_cast(LV.getPointer(CGF))) + dyn_cast(LV.emitRawPointer(CGF))) if (GEP->use_empty()) GEP->eraseFromParent(); } @@ -1849,9 +1856,9 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, // destPtr is an array*. Construct an elementType* by drilling down a level. llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); llvm::Value *indices[] = {zero, zero}; - llvm::Value *begin = Builder.CreateInBoundsGEP( - destPtr.getElementType(), destPtr.getPointer(), indices, - "arrayinit.begin"); + llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getElementType(), + destPtr.emitRawPointer(CGF), + indices, "arrayinit.begin"); // Prepare to special-case multidimensional array initialization: we avoid // emitting multiple destructor loops in that case. diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 35da0f1a89bc3fb23709ab27c692d4dc1b67c8a2..a4fb673284ceca6bde6cc331279a4c4b42b6e39d 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -280,7 +280,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; Address ThisValue = EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo); - This = MakeAddrLValue(ThisValue, Base->getType(), BaseInfo, TBAAInfo); + This = MakeAddrLValue(ThisValue, Base->getType()->getPointeeType(), + BaseInfo, TBAAInfo); } else { This = EmitLValue(Base); } @@ -353,10 +354,12 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( if (IsImplicitObjectCXXThis || isa(IOA)) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, - This.getPointer(*this), - C.getRecordType(CalleeDecl->getParent()), - /*Alignment=*/CharUnits::Zero(), SkippedChecks); + + if (sanitizePerformTypeCheck()) + EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, + This.emitRawPointer(*this), + C.getRecordType(CalleeDecl->getParent()), + /*Alignment=*/CharUnits::Zero(), SkippedChecks); // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the @@ -455,7 +458,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, else This = EmitLValue(BaseExpr, KnownNonNull).getAddress(*this); - EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.getPointer(), + EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.emitRawPointer(*this), QualType(MPT->getClass(), 0)); // Get the member function pointer. @@ -1109,9 +1112,10 @@ void CodeGenFunction::EmitNewArrayInitializer( // alloca. EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(), "array.init.end"); - CleanupDominator = Builder.CreateStore(BeginPtr.getPointer(), EndOfInit); - pushIrregularPartialArrayCleanup(BeginPtr.getPointer(), EndOfInit, - ElementType, ElementAlign, + CleanupDominator = + Builder.CreateStore(BeginPtr.emitRawPointer(*this), EndOfInit); + pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this), + EndOfInit, ElementType, ElementAlign, getDestroyer(DtorKind)); Cleanup = EHStack.stable_begin(); } @@ -1123,16 +1127,17 @@ void CodeGenFunction::EmitNewArrayInitializer( // element. TODO: some of these stores can be trivially // observed to be unnecessary. if (EndOfInit.isValid()) { - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); } // FIXME: If the last initializer is an incomplete initializer list for // an array, and we have an array filler, we can fold together the two // initialization loops. StoreAnyExprIntoOneUnit(*this, IE, IE->getType(), CurPtr, AggValueSlot::DoesNotOverlap); - CurPtr = Address(Builder.CreateInBoundsGEP( - CurPtr.getElementType(), CurPtr.getPointer(), - Builder.getSize(1), "array.exp.next"), + CurPtr = Address(Builder.CreateInBoundsGEP(CurPtr.getElementType(), + CurPtr.emitRawPointer(*this), + Builder.getSize(1), + "array.exp.next"), CurPtr.getElementType(), StartAlign.alignmentAtOffset((++i) * ElementSize)); } @@ -1186,7 +1191,7 @@ void CodeGenFunction::EmitNewArrayInitializer( // FIXME: Share this cleanup with the constructor call emission rather than // having it create a cleanup of its own. if (EndOfInit.isValid()) - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); // Emit a constructor call loop to initialize the remaining elements. if (InitListElements) @@ -1249,15 +1254,15 @@ void CodeGenFunction::EmitNewArrayInitializer( llvm::BasicBlock *ContBB = createBasicBlock("new.loop.end"); // Find the end of the array, hoisted out of the loop. - llvm::Value *EndPtr = - Builder.CreateInBoundsGEP(BeginPtr.getElementType(), BeginPtr.getPointer(), - NumElements, "array.end"); + llvm::Value *EndPtr = Builder.CreateInBoundsGEP( + BeginPtr.getElementType(), BeginPtr.emitRawPointer(*this), NumElements, + "array.end"); // If the number of elements isn't constant, we have to now check if there is // anything left to initialize. if (!ConstNum) { - llvm::Value *IsEmpty = - Builder.CreateICmpEQ(CurPtr.getPointer(), EndPtr, "array.isempty"); + llvm::Value *IsEmpty = Builder.CreateICmpEQ(CurPtr.emitRawPointer(*this), + EndPtr, "array.isempty"); Builder.CreateCondBr(IsEmpty, ContBB, LoopBB); } @@ -1267,19 +1272,20 @@ void CodeGenFunction::EmitNewArrayInitializer( // Set up the current-element phi. llvm::PHINode *CurPtrPhi = Builder.CreatePHI(CurPtr.getType(), 2, "array.cur"); - CurPtrPhi->addIncoming(CurPtr.getPointer(), EntryBB); + CurPtrPhi->addIncoming(CurPtr.emitRawPointer(*this), EntryBB); CurPtr = Address(CurPtrPhi, CurPtr.getElementType(), ElementAlign); // Store the new Cleanup position for irregular Cleanups. if (EndOfInit.isValid()) - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); // Enter a partial-destruction Cleanup if necessary. if (!CleanupDominator && needsEHCleanup(DtorKind)) { - pushRegularPartialArrayCleanup(BeginPtr.getPointer(), CurPtr.getPointer(), - ElementType, ElementAlign, - getDestroyer(DtorKind)); + llvm::Value *BeginPtrRaw = BeginPtr.emitRawPointer(*this); + llvm::Value *CurPtrRaw = CurPtr.emitRawPointer(*this); + pushRegularPartialArrayCleanup(BeginPtrRaw, CurPtrRaw, ElementType, + ElementAlign, getDestroyer(DtorKind)); Cleanup = EHStack.stable_begin(); CleanupDominator = Builder.CreateUnreachable(); } @@ -1295,9 +1301,8 @@ void CodeGenFunction::EmitNewArrayInitializer( } // Advance to the next element by adjusting the pointer type as necessary. - llvm::Value *NextPtr = - Builder.CreateConstInBoundsGEP1_32(ElementTy, CurPtr.getPointer(), 1, - "array.next"); + llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32( + ElementTy, CurPtr.emitRawPointer(*this), 1, "array.next"); // Check whether we've gotten to the end of the array and, if so, // exit the loop. @@ -1523,14 +1528,9 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, typedef CallDeleteDuringNew DirectCleanup; - DirectCleanup *Cleanup = CGF.EHStack - .pushCleanupWithExtra(EHCleanup, - E->getNumPlacementArgs(), - E->getOperatorDelete(), - NewPtr.getPointer(), - AllocSize, - E->passAlignment(), - AllocAlign); + DirectCleanup *Cleanup = CGF.EHStack.pushCleanupWithExtra( + EHCleanup, E->getNumPlacementArgs(), E->getOperatorDelete(), + NewPtr.emitRawPointer(CGF), AllocSize, E->passAlignment(), AllocAlign); for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) { auto &Arg = NewArgs[I + NumNonPlacementArgs]; Cleanup->setPlacementArg(I, Arg.getRValue(CGF), Arg.Ty); @@ -1541,7 +1541,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, // Otherwise, we need to save all this stuff. DominatingValue::saved_type SavedNewPtr = - DominatingValue::save(CGF, RValue::get(NewPtr.getPointer())); + DominatingValue::save(CGF, RValue::get(NewPtr, CGF)); DominatingValue::saved_type SavedAllocSize = DominatingValue::save(CGF, RValue::get(AllocSize)); @@ -1618,14 +1618,14 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // In these cases, discard the computed alignment and use the // formal alignment of the allocated type. if (BaseInfo.getAlignmentSource() != AlignmentSource::Decl) - allocation = allocation.withAlignment(allocAlign); + allocation.setAlignment(allocAlign); // Set up allocatorArgs for the call to operator delete if it's not // the reserved global operator. if (E->getOperatorDelete() && !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) { allocatorArgs.add(RValue::get(allocSize), getContext().getSizeType()); - allocatorArgs.add(RValue::get(allocation.getPointer()), arg->getType()); + allocatorArgs.add(RValue::get(allocation, *this), arg->getType()); } } else { @@ -1713,8 +1713,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::BasicBlock *notNullBB = createBasicBlock("new.notnull"); contBB = createBasicBlock("new.cont"); - llvm::Value *isNull = - Builder.CreateIsNull(allocation.getPointer(), "new.isnull"); + llvm::Value *isNull = Builder.CreateIsNull(allocation, "new.isnull"); Builder.CreateCondBr(isNull, contBB, notNullBB); EmitBlock(notNullBB); } @@ -1760,12 +1759,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { SkippedChecks.set(SanitizerKind::Null, nullCheck); EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(), - result.getPointer(), allocType, result.getAlignment(), - SkippedChecks, numElements); + result, allocType, result.getAlignment(), SkippedChecks, + numElements); EmitNewInitializer(*this, E, allocType, elementTy, result, numElements, allocSizeWithoutCookie); - llvm::Value *resultPtr = result.getPointer(); + llvm::Value *resultPtr = result.emitRawPointer(*this); if (E->isArray()) { // NewPtr is a pointer to the base element type. If we're // allocating an array of arrays, we'll need to cast back to the @@ -1909,7 +1908,8 @@ static void EmitDestroyingObjectDelete(CodeGenFunction &CGF, CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, Dtor); else - CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType); + CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.emitRawPointer(CGF), + ElementType); } /// Emit the code for deleting a single object. @@ -1925,8 +1925,7 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, // dynamic type, the static type shall be a base class of the dynamic type // of the object to be deleted and the static type shall have a virtual // destructor or the behavior is undefined. - CGF.EmitTypeCheck(CodeGenFunction::TCK_MemberCall, - DE->getExprLoc(), Ptr.getPointer(), + CGF.EmitTypeCheck(CodeGenFunction::TCK_MemberCall, DE->getExprLoc(), Ptr, ElementType); const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); @@ -1975,9 +1974,8 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, // Make sure that we call delete even if the dtor throws. // This doesn't have to a conditional cleanup because we're going // to pop it off in a second. - CGF.EHStack.pushCleanup(NormalAndEHCleanup, - Ptr.getPointer(), - OperatorDelete, ElementType); + CGF.EHStack.pushCleanup( + NormalAndEHCleanup, Ptr.emitRawPointer(CGF), OperatorDelete, ElementType); if (Dtor) CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, @@ -2064,7 +2062,7 @@ static void EmitArrayDelete(CodeGenFunction &CGF, CharUnits elementAlign = deletedPtr.getAlignment().alignmentOfArrayElement(elementSize); - llvm::Value *arrayBegin = deletedPtr.getPointer(); + llvm::Value *arrayBegin = deletedPtr.emitRawPointer(CGF); llvm::Value *arrayEnd = CGF.Builder.CreateInBoundsGEP( deletedPtr.getElementType(), arrayBegin, numElements, "delete.end"); @@ -2095,7 +2093,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); - llvm::Value *IsNull = Builder.CreateIsNull(Ptr.getPointer(), "isnull"); + llvm::Value *IsNull = Builder.CreateIsNull(Ptr, "isnull"); Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); @@ -2130,10 +2128,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { GEP.push_back(Zero); } - Ptr = Address(Builder.CreateInBoundsGEP(Ptr.getElementType(), - Ptr.getPointer(), GEP, "del.first"), - ConvertTypeForMem(DeleteTy), Ptr.getAlignment(), - Ptr.isKnownNonNull()); + Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, ConvertTypeForMem(DeleteTy), + Ptr.getAlignment(), "del.first"); } assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); @@ -2191,7 +2187,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, // destruction and the static type of the operand is neither the constructor // or destructor’s class nor one of its bases, the behavior is undefined. CGF.EmitTypeCheck(CodeGenFunction::TCK_DynamicOperation, E->getExprLoc(), - ThisPtr.getPointer(), SrcRecordTy); + ThisPtr, SrcRecordTy); // C++ [expr.typeid]p2: // If the glvalue expression is obtained by applying the unary * operator to @@ -2207,7 +2203,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, CGF.createBasicBlock("typeid.bad_typeid"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end"); - llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr.getPointer()); + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr); CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock); CGF.EmitBlock(BadTypeidBlock); @@ -2293,8 +2289,7 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, // construction or destruction and the static type of the operand is not a // pointer to or object of the constructor or destructor’s own class or one // of its bases, the dynamic_cast results in undefined behavior. - EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(), - SrcRecordTy); + EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr, SrcRecordTy); if (DCE->isAlwaysNull()) { if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) { @@ -2329,7 +2324,7 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, CastNull = createBasicBlock("dynamic_cast.null"); CastNotNull = createBasicBlock("dynamic_cast.notnull"); - llvm::Value *IsNull = Builder.CreateIsNull(ThisAddr.getPointer()); + llvm::Value *IsNull = Builder.CreateIsNull(ThisAddr); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index b873bc6737bb0a61d17d2eaa6e29db0abca12619..a793b214645cb3d8f30635cc383ad73f07c8371a 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -289,7 +289,7 @@ public: const BinOpInfo &Op); QualType GetHigherPrecisionFPType(QualType ElementType) { - const auto *CurrentBT = dyn_cast(ElementType); + const auto *CurrentBT = cast(ElementType); switch (CurrentBT->getKind()) { case BuiltinType::Kind::Float16: return CGF.getContext().FloatTy; @@ -616,6 +616,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, case CK_IntegralToFixedPoint: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 67a3cdc770426efd7edd4b5861f91382a81979d4..9f1b06eebf9ed089c4dc1d2cbce75a203ff951f9 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -800,8 +800,8 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, // Add a vtable pointer, if we need one and it hasn't already been added. if (Layout.hasOwnVFPtr()) { llvm::Constant *VTableAddressPoint = - CGM.getCXXABI().getVTableAddressPointForConstExpr( - BaseSubobject(CD, Offset), VTableClass); + CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset), + VTableClass); if (!AppendBytes(Offset, VTableAddressPoint)) return false; } @@ -1226,6 +1226,7 @@ public: case CK_ZeroToOCLOpaqueType: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: return nullptr; } llvm_unreachable("Invalid CastKind"); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 8536570087ad0fe96016f169b6dfbbe031c3035d..397b4977acc3e9d536c000c12955a55f51262156 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2250,7 +2250,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // performed and the object is not of the derived type. if (CGF.sanitizePerformTypeCheck()) CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(), - Derived.getPointer(), DestTy->getPointeeType()); + Derived, DestTy->getPointeeType()); if (CGF.SanOpts.has(SanitizerKind::CFIDerivedCast)) CGF.EmitVTablePtrCheckForCast(DestTy->getPointeeType(), Derived, @@ -2258,13 +2258,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { CodeGenFunction::CFITCK_DerivedCast, CE->getBeginLoc()); - return Derived.getPointer(); + return CGF.getAsNaturalPointerTo(Derived, CE->getType()->getPointeeType()); } case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { // The EmitPointerWithAlignment path does this fine; just discard // the alignment. - return CGF.EmitPointerWithAlignment(CE).getPointer(); + return CGF.getAsNaturalPointerTo(CGF.EmitPointerWithAlignment(CE), + CE->getType()->getPointeeType()); } case CK_Dynamic: { @@ -2274,7 +2275,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } case CK_ArrayToPointerDecay: - return CGF.EmitArrayToPointerDecay(E).getPointer(); + return CGF.getAsNaturalPointerTo(CGF.EmitArrayToPointerDecay(E), + CE->getType()->getPointeeType()); case CK_FunctionToPointerDecay: return EmitLValue(E).getPointer(CGF); @@ -2327,6 +2329,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_FloatingComplexToIntegralComplex: case CK_ConstructorConversion: case CK_ToUnion: + case CK_HLSLArrayRValue: llvm_unreachable("scalar cast to non-scalar value"); case CK_LValueToRValue: @@ -5588,3 +5591,16 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, return GEPVal; } + +Address CodeGenFunction::EmitCheckedInBoundsGEP( + Address Addr, ArrayRef IdxList, llvm::Type *elementType, + bool SignedIndices, bool IsSubtraction, SourceLocation Loc, CharUnits Align, + const Twine &Name) { + if (!SanOpts.has(SanitizerKind::PointerOverflow)) + return Builder.CreateInBoundsGEP(Addr, IdxList, elementType, Align, Name); + + return RawAddress( + EmitCheckedInBoundsGEP(Addr.getElementType(), Addr.emitRawPointer(*this), + IdxList, SignedIndices, IsSubtraction, Loc, Name), + elementType, Align); +} diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h index a1c8c7e5307fd9c01b554a1e9cf98a40bd70e4af..0fe33b289130635586765a0714902eaf26012ce4 100644 --- a/clang/lib/CodeGen/CGLoopInfo.h +++ b/clang/lib/CodeGen/CGLoopInfo.h @@ -110,6 +110,10 @@ public: /// been processed. void finish(); + /// Returns the first outer loop containing this loop if any, nullptr + /// otherwise. + const LoopInfo *getParent() const { return Parent; } + private: /// Loop ID metadata. llvm::TempMDTuple TempLoopID; @@ -291,12 +295,13 @@ public: /// Set no progress for the next loop pushed. void setMustProgress(bool P) { StagedAttrs.MustProgress = P; } -private: /// Returns true if there is LoopInfo on the stack. bool hasInfo() const { return !Active.empty(); } /// Return the LoopInfo for the current loop. HasInfo should be called /// first to ensure LoopInfo is present. const LoopInfo &getInfo() const { return *Active.back(); } + +private: /// The set of attributes that will be applied to the next pushed loop. LoopAttributes StagedAttrs; /// Stack of active loops. diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 75c1d7fbea840688ebe63d5939a08a09cdfd1243..8fade0fac21e9379df8c06aec1c301fdbaff6e85 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -366,7 +366,7 @@ template struct GenFuncBase { llvm::Value *SizeInBytes = CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts); llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP( - CGF.Int8Ty, DstAddr.getPointer(), SizeInBytes); + CGF.Int8Ty, DstAddr.emitRawPointer(CGF), SizeInBytes); llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock(); // Create the header block and insert the phi instructions. @@ -376,7 +376,7 @@ template struct GenFuncBase { for (unsigned I = 0; I < N; ++I) { PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur"); - PHIs[I]->addIncoming(StartAddrs[I].getPointer(), PreheaderBB); + PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB); } // Create the exit and loop body blocks. @@ -410,7 +410,7 @@ template struct GenFuncBase { // Instrs to update the destination and source addresses. // Update phi instructions. NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize); - PHIs[I]->addIncoming(NewAddrs[I].getPointer(), LoopBB); + PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB); } // Insert an unconditional branch to the header block. @@ -488,7 +488,7 @@ template struct GenFuncBase { for (unsigned I = 0; I < N; ++I) { Alignments[I] = Addrs[I].getAlignment(); - Ptrs[I] = Addrs[I].getPointer(); + Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF); } if (llvm::Function *F = diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index f3a948cf13f9c9098f8497a28aa1ee9102f59939..c7f497a7c8451be6918c726ebdb3423a600170db 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -94,8 +94,8 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) { // and cast value to correct type Address Temporary = CreateMemTemp(SubExpr->getType()); EmitAnyExprToMem(SubExpr, Temporary, Qualifiers(), /*isInit*/ true); - llvm::Value *BitCast = - Builder.CreateBitCast(Temporary.getPointer(), ConvertType(ArgQT)); + llvm::Value *BitCast = Builder.CreateBitCast( + Temporary.emitRawPointer(*this), ConvertType(ArgQT)); Args.add(RValue::get(BitCast), ArgQT); // Create char array to store type encoding @@ -204,11 +204,11 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, ObjCMethodDecl::param_const_iterator PI = MethodWithObjects->param_begin(); const ParmVarDecl *argDecl = *PI++; QualType ArgQT = argDecl->getType().getUnqualifiedType(); - Args.add(RValue::get(Objects.getPointer()), ArgQT); + Args.add(RValue::get(Objects, *this), ArgQT); if (DLE) { argDecl = *PI++; ArgQT = argDecl->getType().getUnqualifiedType(); - Args.add(RValue::get(Keys.getPointer()), ArgQT); + Args.add(RValue::get(Keys, *this), ArgQT); } argDecl = *PI; ArgQT = argDecl->getType().getUnqualifiedType(); @@ -827,7 +827,7 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar, // sizeof (Type of Ivar), isAtomic, false); CallArgList args; - llvm::Value *dest = CGF.ReturnValue.getPointer(); + llvm::Value *dest = CGF.ReturnValue.emitRawPointer(CGF); args.add(RValue::get(dest), Context.VoidPtrTy); args.add(RValue::get(src), Context.VoidPtrTy); @@ -1147,8 +1147,8 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, callCStructCopyConstructor(Dst, Src); } else { ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), ivar, - AtomicHelperFn); + emitCPPObjectAtomicGetterCall(*this, ReturnValue.emitRawPointer(*this), + ivar, AtomicHelperFn); } return; } @@ -1163,7 +1163,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, } else { ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), + emitCPPObjectAtomicGetterCall(*this, ReturnValue.emitRawPointer(*this), ivar, AtomicHelperFn); } return; @@ -1287,7 +1287,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, case TEK_Scalar: { llvm::Value *value; if (propType->isReferenceType()) { - value = LV.getAddress(*this).getPointer(); + value = LV.getAddress(*this).emitRawPointer(*this); } else { // We want to load and autoreleaseReturnValue ARC __weak ivars. if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -1821,16 +1821,14 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CallArgList Args; // The first argument is a temporary of the enumeration-state type. - Args.add(RValue::get(StatePtr.getPointer()), - getContext().getPointerType(StateTy)); + Args.add(RValue::get(StatePtr, *this), getContext().getPointerType(StateTy)); // The second argument is a temporary array with space for NumItems // pointers. We'll actually be loading elements from the array // pointer written into the control state; this buffer is so that // collections that *aren't* backed by arrays can still queue up // batches of elements. - Args.add(RValue::get(ItemsPtr.getPointer()), - getContext().getPointerType(ItemsTy)); + Args.add(RValue::get(ItemsPtr, *this), getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType()); @@ -2198,7 +2196,7 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, Address addr, if (!fn) fn = getARCIntrinsic(IntID, CGF.CGM); - return CGF.EmitNounwindRuntimeCall(fn, addr.getPointer()); + return CGF.EmitNounwindRuntimeCall(fn, addr.emitRawPointer(CGF)); } /// Perform an operation having the following signature: @@ -2216,9 +2214,8 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, Address addr, llvm::Type *origType = value->getType(); llvm::Value *args[] = { - CGF.Builder.CreateBitCast(addr.getPointer(), CGF.Int8PtrPtrTy), - CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy) - }; + CGF.Builder.CreateBitCast(addr.emitRawPointer(CGF), CGF.Int8PtrPtrTy), + CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)}; llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args); if (ignored) return nullptr; @@ -2237,9 +2234,8 @@ static void emitARCCopyOperation(CodeGenFunction &CGF, Address dst, Address src, fn = getARCIntrinsic(IntID, CGF.CGM); llvm::Value *args[] = { - CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy), - CGF.Builder.CreateBitCast(src.getPointer(), CGF.Int8PtrPtrTy) - }; + CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), CGF.Int8PtrPtrTy), + CGF.Builder.CreateBitCast(src.emitRawPointer(CGF), CGF.Int8PtrPtrTy)}; CGF.EmitNounwindRuntimeCall(fn, args); } @@ -2490,9 +2486,8 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr, fn = getARCIntrinsic(llvm::Intrinsic::objc_storeStrong, CGM); llvm::Value *args[] = { - Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy), - Builder.CreateBitCast(value, Int8PtrTy) - }; + Builder.CreateBitCast(addr.emitRawPointer(*this), Int8PtrPtrTy), + Builder.CreateBitCast(value, Int8PtrTy)}; EmitNounwindRuntimeCall(fn, args); if (ignored) return nullptr; @@ -2643,7 +2638,7 @@ void CodeGenFunction::EmitARCDestroyWeak(Address addr) { if (!fn) fn = getARCIntrinsic(llvm::Intrinsic::objc_destroyWeak, CGM); - EmitNounwindRuntimeCall(fn, addr.getPointer()); + EmitNounwindRuntimeCall(fn, addr.emitRawPointer(*this)); } /// void \@objc_moveWeak(i8** %dest, i8** %src) diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index a36b0cdddaf0afd293592aac7fe7124ab8613db2..4e7f777ba1d9160fd872c7a3466fcf2a438f12e2 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -706,7 +706,8 @@ protected: llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = { - EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd}; + EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), PtrToObjCSuperTy), + cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } @@ -761,8 +762,8 @@ class CGObjCGNUstep : public CGObjCGNU { llvm::FunctionCallee LookupFn = SlotLookupFn; // Store the receiver on the stack so that we can reload it later - Address ReceiverPtr = - CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); + RawAddress ReceiverPtr = + CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); Builder.CreateStore(Receiver, ReceiverPtr); llvm::Value *self; @@ -778,9 +779,9 @@ class CGObjCGNUstep : public CGObjCGNU { LookupFn2->addParamAttr(0, llvm::Attribute::NoCapture); llvm::Value *args[] = { - EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), - EnforceType(Builder, cmd, SelectorTy), - EnforceType(Builder, self, IdTy) }; + EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), + EnforceType(Builder, cmd, SelectorTy), + EnforceType(Builder, self, IdTy)}; llvm::CallBase *slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args); slot->setOnlyReadsMemory(); slot->setMetadata(msgSendMDKind, node); @@ -800,7 +801,7 @@ class CGObjCGNUstep : public CGObjCGNU { llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *lookupArgs[] = {ObjCSuper.getPointer(), cmd}; + llvm::Value *lookupArgs[] = {ObjCSuper.emitRawPointer(CGF), cmd}; llvm::CallInst *slot = CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs); @@ -1221,10 +1222,10 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { llvm::Value *cmd, MessageSendInfo &MSI) override { // Don't access the slot unless we're trying to cache the result. CGBuilderTy &Builder = CGF.Builder; - llvm::Value *lookupArgs[] = {CGObjCGNU::EnforceType(Builder, - ObjCSuper.getPointer(), - PtrToObjCSuperTy), - cmd}; + llvm::Value *lookupArgs[] = { + CGObjCGNU::EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), + PtrToObjCSuperTy), + cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } @@ -2186,7 +2187,8 @@ protected: llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = { - EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd, + EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), PtrToObjCSuperTy), + cmd, }; if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) @@ -4201,15 +4203,15 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, Address AddrWeakObj) { CGBuilderTy &B = CGF.Builder; - return B.CreateCall(WeakReadFn, - EnforceType(B, AddrWeakObj.getPointer(), PtrToIdTy)); + return B.CreateCall( + WeakReadFn, EnforceType(B, AddrWeakObj.emitRawPointer(CGF), PtrToIdTy)); } void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); B.CreateCall(WeakAssignFn, {src, dstVal}); } @@ -4218,7 +4220,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, bool threadlocal) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); // FIXME. Add threadloca assign API assert(!threadlocal && "EmitObjCGlobalAssign - Threal Local API NYI"); B.CreateCall(GlobalAssignFn, {src, dstVal}); @@ -4229,7 +4231,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *ivarOffset) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), IdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), IdTy); B.CreateCall(IvarAssignFn, {src, dstVal, ivarOffset}); } @@ -4237,7 +4239,7 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); B.CreateCall(StrongCastAssignFn, {src, dstVal}); } @@ -4246,8 +4248,8 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address SrcPtr, llvm::Value *Size) { CGBuilderTy &B = CGF.Builder; - llvm::Value *DestPtrVal = EnforceType(B, DestPtr.getPointer(), PtrTy); - llvm::Value *SrcPtrVal = EnforceType(B, SrcPtr.getPointer(), PtrTy); + llvm::Value *DestPtrVal = EnforceType(B, DestPtr.emitRawPointer(CGF), PtrTy); + llvm::Value *SrcPtrVal = EnforceType(B, SrcPtr.emitRawPointer(CGF), PtrTy); B.CreateCall(MemMoveFn, {DestPtrVal, SrcPtrVal, Size}); } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index ed8d7b9a065d7b0e9c7acff9fdfce87f7e999b85..8a599c10e1caf17328d7f3e1d70f3b7d499aacbc 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1310,7 +1310,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(Selector Sel); + ConstantAddress EmitSelectorAddr(Selector Sel); public: CGObjCMac(CodeGen::CodeGenModule &cgm); @@ -1538,7 +1538,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(Selector Sel); + ConstantAddress EmitSelectorAddr(Selector Sel); /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C /// interface. The return value has type EHTypePtrTy. @@ -2064,9 +2064,8 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMethodDecl *Method) { // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. - Address ObjCSuper = - CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(), - "objc_super"); + RawAddress ObjCSuper = CGF.CreateTempAlloca( + ObjCTypes.SuperTy, CGF.getPointerAlign(), "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateStore(ReceiverAsObject, @@ -4259,7 +4258,7 @@ namespace { CGF.EmitBlock(FinallyCallExit); CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); CGF.EmitBlock(FinallyNoCallExit); @@ -4425,7 +4424,9 @@ void FragileHazards::emitHazardsInNewBlocks() { } static void addIfPresent(llvm::DenseSet &S, Address V) { - if (V.isValid()) S.insert(V.getPointer()); + if (V.isValid()) + if (llvm::Value *Ptr = V.getBasePointer()) + S.insert(Ptr); } void FragileHazards::collectLocals() { @@ -4628,13 +4629,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // - Call objc_exception_try_enter to push ExceptionData on top of // the EH stack. CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); // - Call setjmp on the exception data buffer. llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0); llvm::Value *GEPIndexes[] = { Zero, Zero, Zero }; llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP( - ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes, + ObjCTypes.ExceptionDataTy, ExceptionData.emitRawPointer(CGF), GEPIndexes, "setjmp_buffer"); llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall( ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result"); @@ -4673,9 +4674,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, } else { // Retrieve the exception object. We may emit multiple blocks but // nothing can cross this so the value is already in SSA form. - llvm::CallInst *Caught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer(), "caught"); + llvm::CallInst *Caught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF), + "caught"); // Push the exception to rethrow onto the EH value stack for the // benefit of any @throws in the handlers. @@ -4698,7 +4699,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Enter a new exception try block (in case a @catch block // throws an exception). CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(), @@ -4829,9 +4830,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Extract the new exception and save it to the // propagating-exception slot. assert(PropagatingExnVar.isValid()); - llvm::CallInst *NewCaught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer(), "caught"); + llvm::CallInst *NewCaught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF), + "caught"); CGF.Builder.CreateStore(NewCaught, PropagatingExnVar); // Don't pop the catch handler; the throw already did. @@ -4861,9 +4862,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Otherwise, just look in the buffer for the exception to throw. } else { - llvm::CallInst *Caught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer()); + llvm::CallInst *Caught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF)); PropagatingExn = Caught; } @@ -4906,7 +4906,7 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, Address AddrWeakObj) { llvm::Type* DestTy = AddrWeakObj.getElementType(); llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast( - AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy); + AddrWeakObj.emitRawPointer(CGF), ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObjVal, "weakread"); @@ -4928,8 +4928,8 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = { src, dstVal }; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(), args, "weakassign"); @@ -4950,8 +4950,8 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; if (!threadlocal) CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(), @@ -4977,8 +4977,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal, ivarOffset}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args); } @@ -4997,8 +4997,8 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(), args, "strongassign"); @@ -5007,7 +5007,8 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *size) { - llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size }; + llvm::Value *args[] = {DestPtr.emitRawPointer(CGF), + SrcPtr.emitRawPointer(CGF), size}; CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args); } @@ -5243,7 +5244,7 @@ llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) { return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel)); } -Address CGObjCMac::EmitSelectorAddr(Selector Sel) { +ConstantAddress CGObjCMac::EmitSelectorAddr(Selector Sel) { CharUnits Align = CGM.getPointerAlign(); llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; @@ -5254,7 +5255,7 @@ Address CGObjCMac::EmitSelectorAddr(Selector Sel) { Entry->setExternallyInitialized(true); } - return Address(Entry, ObjCTypes.SelectorPtrTy, Align); + return ConstantAddress(Entry, ObjCTypes.SelectorPtrTy, Align); } llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) { @@ -7323,7 +7324,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, ObjCTypes.MessageRefTy, CGF.getPointerAlign()); // Update the message ref argument. - args[1].setRValue(RValue::get(mref.getPointer())); + args[1].setRValue(RValue::get(mref, CGF)); // Load the function to call from the message ref table. Address calleeAddr = CGF.Builder.CreateStructGEP(mref, 0); @@ -7552,9 +7553,8 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // ... // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. - Address ObjCSuper = - CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(), - "objc_super"); + RawAddress ObjCSuper = CGF.CreateTempAlloca( + ObjCTypes.SuperTy, CGF.getPointerAlign(), "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); @@ -7594,7 +7594,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF, return LI; } -Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { +ConstantAddress CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; CharUnits Align = CGM.getPointerAlign(); if (!Entry) { @@ -7610,7 +7610,7 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { CGM.addCompilerUsedGlobal(Entry); } - return Address(Entry, ObjCTypes.SelectorPtrTy, Align); + return ConstantAddress(Entry, ObjCTypes.SelectorPtrTy, Align); } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. @@ -7629,8 +7629,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal, ivarOffset}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args); } @@ -7650,8 +7650,8 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(), args, "weakassign"); @@ -7660,7 +7660,8 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable( CodeGen::CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *Size) { - llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size }; + llvm::Value *args[] = {DestPtr.emitRawPointer(CGF), + SrcPtr.emitRawPointer(CGF), Size}; CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args); } @@ -7672,7 +7673,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( Address AddrWeakObj) { llvm::Type *DestTy = AddrWeakObj.getElementType(); llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast( - AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy); + AddrWeakObj.emitRawPointer(CGF), ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObjVal, "weakread"); @@ -7694,8 +7695,8 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(), args, "weakassign"); @@ -7716,8 +7717,8 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; if (!threadlocal) CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(), diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 424564f9759995267ff2061cfbc6371ecbc7c2df..01d0f35da19643cf1d0b5b21439f6fbbe4ade22e 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -67,7 +67,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, V = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, V, Offset, "add.ptr"); if (!Ivar->isBitField()) { - LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); + LValue LV = CGF.MakeNaturalAlignRawAddrLValue(V, IvarTy); return LV; } @@ -233,7 +233,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, llvm::Instruction *CPICandidate = Handler.Block->getFirstNonPHI(); if (auto *CPI = dyn_cast_or_null(CPICandidate)) { CGF.CurrentFuncletPad = CPI; - CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); + CPI->setOperand(2, CGF.getExceptionSlot().emitRawPointer(CGF)); CGF.EHStack.pushCleanup(NormalCleanup, CPI); } } @@ -405,7 +405,7 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, auto self = curMethod->getSelfDecl(); if (self->getType().isConstQualified()) { if (auto LI = dyn_cast(receiver->stripPointerCasts())) { - llvm::Value *selfAddr = CGF.GetAddrOfLocalVar(self).getPointer(); + llvm::Value *selfAddr = CGF.GetAddrOfLocalVar(self).emitRawPointer(CGF); if (selfAddr == LI->getPointerOperand()) { return false; } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 00e395c2a207f9c6556972b6c0542cd0640fcd65..bc363313dec6f8ba350eb4f8c29ea9f0df6effde 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -622,7 +622,7 @@ static void emitInitWithReductionInitializer(CodeGenFunction &CGF, auto *GV = new llvm::GlobalVariable( CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, Name); - LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty); + LValue LV = CGF.MakeNaturalAlignRawAddrLValue(GV, Ty); RValue InitRVal; switch (CGF.getEvaluationKind(Ty)) { case TEK_Scalar: @@ -668,8 +668,8 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, llvm::Value *SrcBegin = nullptr; if (DRD) - SrcBegin = SrcAddr.getPointer(); - llvm::Value *DestBegin = DestAddr.getPointer(); + SrcBegin = SrcAddr.emitRawPointer(CGF); + llvm::Value *DestBegin = DestAddr.emitRawPointer(CGF); // Cast from pointer to array type to pointer to single element. llvm::Value *DestEnd = CGF.Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements); @@ -912,7 +912,7 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, Address OriginalBaseAddress, llvm::Value *Addr) { - Address Tmp = Address::invalid(); + RawAddress Tmp = RawAddress::invalid(); Address TopTmp = Address::invalid(); Address MostTopTmp = Address::invalid(); BaseTy = BaseTy.getNonReferenceType(); @@ -971,10 +971,10 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, Address SharedAddr = SharedAddresses[N].first.getAddress(CGF); llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff( SharedAddr.getElementType(), BaseLValue.getPointer(CGF), - SharedAddr.getPointer()); + SharedAddr.emitRawPointer(CGF)); llvm::Value *PrivatePointer = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - PrivateAddr.getPointer(), SharedAddr.getType()); + PrivateAddr.emitRawPointer(CGF), SharedAddr.getType()); llvm::Value *Ptr = CGF.Builder.CreateGEP( SharedAddr.getElementType(), PrivatePointer, Adjustment); return castToBase(CGF, OrigVD->getType(), @@ -1557,7 +1557,7 @@ static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc( return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack, ParentName); } -Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { +ConstantAddress CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); }; auto LinkageForVariable = [&VD, this]() { @@ -1579,8 +1579,8 @@ Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { LinkageForVariable); if (!addr) - return Address::invalid(); - return Address(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); + return ConstantAddress::invalid(); + return ConstantAddress(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); } llvm::Constant * @@ -1604,7 +1604,7 @@ Address CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF, llvm::Type *VarTy = VDAddr.getElementType(); llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), - CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.Int8PtrTy), + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy), CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)), getOrCreateThreadPrivateCache(VD)}; return Address( @@ -1627,7 +1627,8 @@ void CGOpenMPRuntime::emitThreadPrivateVarInit( // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor) // to register constructor/destructor for variable. llvm::Value *Args[] = { - OMPLoc, CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.VoidPtrTy), + OMPLoc, + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.VoidPtrTy), Ctor, CopyCtor, Dtor}; CGF.EmitRuntimeCall( OMPBuilder.getOrCreateRuntimeFunction( @@ -1900,13 +1901,13 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, // OutlinedFn(>id, &zero_bound, CapturedStruct); Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc); - Address ZeroAddrBound = + RawAddress ZeroAddrBound = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".bound.zero.addr"); CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound); llvm::SmallVector OutlinedFnArgs; // ThreadId for serialized parallels is 0. - OutlinedFnArgs.push_back(ThreadIDAddr.getPointer()); + OutlinedFnArgs.push_back(ThreadIDAddr.emitRawPointer(CGF)); OutlinedFnArgs.push_back(ZeroAddrBound.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); @@ -2272,7 +2273,7 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF, emitUpdateLocation(CGF, Loc), // ident_t * getThreadID(CGF, Loc), // i32 BufSize, // size_t - CL.getPointer(), // void * + CL.emitRawPointer(CGF), // void * CpyFn, // void (*) (void *, void *) DidItVal // i32 did_it }; @@ -2591,10 +2592,10 @@ static void emitForStaticInitCall( ThreadId, CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1, M2)), // Schedule type - Values.IL.getPointer(), // &isLastIter - Values.LB.getPointer(), // &LB - Values.UB.getPointer(), // &UB - Values.ST.getPointer(), // &Stride + Values.IL.emitRawPointer(CGF), // &isLastIter + Values.LB.emitRawPointer(CGF), // &LB + Values.UB.emitRawPointer(CGF), // &UB + Values.ST.emitRawPointer(CGF), // &Stride CGF.Builder.getIntN(Values.IVSize, 1), // Incr Chunk // Chunk }; @@ -2697,12 +2698,11 @@ llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF, // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper, // kmp_int[32|64] *p_stride); llvm::Value *Args[] = { - emitUpdateLocation(CGF, Loc), - getThreadID(CGF, Loc), - IL.getPointer(), // &isLastIter - LB.getPointer(), // &Lower - UB.getPointer(), // &Upper - ST.getPointer() // &Stride + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + IL.emitRawPointer(CGF), // &isLastIter + LB.emitRawPointer(CGF), // &Lower + UB.emitRawPointer(CGF), // &Upper + ST.emitRawPointer(CGF) // &Stride }; llvm::Value *Call = CGF.EmitRuntimeCall( OMPBuilder.createDispatchNextFunction(IVSize, IVSigned), Args); @@ -3047,7 +3047,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, CGF.Builder .CreatePointerBitCastOrAddrSpaceCast(TDBase.getAddress(CGF), CGF.VoidPtrTy, CGF.Int8Ty) - .getPointer()}; + .emitRawPointer(CGF)}; SmallVector CallArgs(std::begin(CommonArgs), std::end(CommonArgs)); if (isOpenMPTaskLoopDirective(Kind)) { @@ -3574,7 +3574,8 @@ getPointerAndSize(CodeGenFunction &CGF, const Expr *E) { CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false); Address UpAddrAddress = UpAddrLVal.getAddress(CGF); llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32( - UpAddrAddress.getElementType(), UpAddrAddress.getPointer(), /*Idx0=*/1); + UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF), + /*Idx0=*/1); llvm::Value *LowIntPtr = CGF.Builder.CreatePtrToInt(Addr, CGF.SizeTy); llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGF.SizeTy); SizeVal = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr); @@ -3888,8 +3889,9 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *Size; std::tie(Addr, Size) = getPointerAndSize(CGF, E); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); - LValue Base = CGF.MakeAddrLValue( - CGF.Builder.CreateGEP(AffinitiesArray, Idx), KmpTaskAffinityInfoTy); + LValue Base = + CGF.MakeAddrLValue(CGF.Builder.CreateGEP(CGF, AffinitiesArray, Idx), + KmpTaskAffinityInfoTy); // affs[i].base_addr = &; LValue BaseAddrLVal = CGF.EmitLValueForField( Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr)); @@ -3910,7 +3912,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *LocRef = emitUpdateLocation(CGF, Loc); llvm::Value *GTid = getThreadID(CGF, Loc); llvm::Value *AffinListPtr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - AffinitiesArray.getPointer(), CGM.VoidPtrTy); + AffinitiesArray.emitRawPointer(CGF), CGM.VoidPtrTy); // FIXME: Emit the function and ignore its result for now unless the // runtime function is properly implemented. (void)CGF.EmitRuntimeCall( @@ -3921,8 +3923,8 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *NewTaskNewTaskTTy = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( NewTask, KmpTaskTWithPrivatesPtrTy); - LValue Base = CGF.MakeNaturalAlignAddrLValue(NewTaskNewTaskTTy, - KmpTaskTWithPrivatesQTy); + LValue Base = CGF.MakeNaturalAlignRawAddrLValue(NewTaskNewTaskTTy, + KmpTaskTWithPrivatesQTy); LValue TDBase = CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin()); // Fill the data in the resulting kmp_task_t record. @@ -4047,7 +4049,7 @@ CGOpenMPRuntime::getDepobjElements(CodeGenFunction &CGF, LValue DepobjLVal, CGF.ConvertTypeForMem(KmpDependInfoPtrTy)), KmpDependInfoPtrTy->castAs()); Address DepObjAddr = CGF.Builder.CreateGEP( - Base.getAddress(CGF), + CGF, Base.getAddress(CGF), llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true)); LValue NumDepsBase = CGF.MakeAddrLValue( DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo()); @@ -4097,7 +4099,7 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, LValue &PosLVal = *Pos.get(); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); Base = CGF.MakeAddrLValue( - CGF.Builder.CreateGEP(DependenciesArray, Idx), KmpDependInfoTy); + CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy); } // deps[i].base_addr = &; LValue BaseAddrLVal = CGF.EmitLValueForField( @@ -4195,7 +4197,7 @@ void CGOpenMPRuntime::emitDepobjElements(CodeGenFunction &CGF, ElSize, CGF.Builder.CreateIntCast(NumDeps, CGF.SizeTy, /*isSigned=*/false)); llvm::Value *Pos = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); - Address DepAddr = CGF.Builder.CreateGEP(DependenciesArray, Pos); + Address DepAddr = CGF.Builder.CreateGEP(CGF, DependenciesArray, Pos); CGF.Builder.CreateMemCpy(DepAddr, Base.getAddress(CGF), Size); // Increase pos. @@ -4430,7 +4432,7 @@ void CGOpenMPRuntime::emitDestroyClause(CodeGenFunction &CGF, LValue DepobjLVal, Base.getAddress(CGF), CGF.ConvertTypeForMem(KmpDependInfoPtrTy), CGF.ConvertTypeForMem(KmpDependInfoTy)); llvm::Value *DepObjAddr = CGF.Builder.CreateGEP( - Addr.getElementType(), Addr.getPointer(), + Addr.getElementType(), Addr.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true)); DepObjAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(DepObjAddr, CGF.VoidPtrTy); @@ -4460,8 +4462,8 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, Address Begin = Base.getAddress(CGF); // Cast from pointer to array type to pointer to single element. - llvm::Value *End = CGF.Builder.CreateGEP( - Begin.getElementType(), Begin.getPointer(), NumDeps); + llvm::Value *End = CGF.Builder.CreateGEP(Begin.getElementType(), + Begin.emitRawPointer(CGF), NumDeps); // The basic structure here is a while-do loop. llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.body"); llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.done"); @@ -4469,7 +4471,7 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, CGF.EmitBlock(BodyBB); llvm::PHINode *ElementPHI = CGF.Builder.CreatePHI(Begin.getType(), 2, "omp.elementPast"); - ElementPHI->addIncoming(Begin.getPointer(), EntryBB); + ElementPHI->addIncoming(Begin.emitRawPointer(CGF), EntryBB); Begin = Begin.withPointer(ElementPHI, KnownNonNull); Base = CGF.MakeAddrLValue(Begin, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo()); @@ -4483,12 +4485,12 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, FlagsLVal); // Shift the address forward by one element. - Address ElementNext = - CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext"); - ElementPHI->addIncoming(ElementNext.getPointer(), - CGF.Builder.GetInsertBlock()); + llvm::Value *ElementNext = + CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext") + .emitRawPointer(CGF); + ElementPHI->addIncoming(ElementNext, CGF.Builder.GetInsertBlock()); llvm::Value *IsEmpty = - CGF.Builder.CreateICmpEQ(ElementNext.getPointer(), End, "omp.isempty"); + CGF.Builder.CreateICmpEQ(ElementNext, End, "omp.isempty"); CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Done. CGF.EmitBlock(DoneBB, /*IsFinished=*/true); @@ -4531,7 +4533,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, DepTaskArgs[1] = ThreadID; DepTaskArgs[2] = NewTask; DepTaskArgs[3] = NumOfElements; - DepTaskArgs[4] = DependenciesArray.getPointer(); + DepTaskArgs[4] = DependenciesArray.emitRawPointer(CGF); DepTaskArgs[5] = CGF.Builder.getInt32(0); DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); } @@ -4563,7 +4565,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, DepWaitTaskArgs[0] = UpLoc; DepWaitTaskArgs[1] = ThreadID; DepWaitTaskArgs[2] = NumOfElements; - DepWaitTaskArgs[3] = DependenciesArray.getPointer(); + DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF); DepWaitTaskArgs[4] = CGF.Builder.getInt32(0); DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); DepWaitTaskArgs[6] = @@ -4725,8 +4727,8 @@ static void EmitOMPAggregateReduction( const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe(); llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr); - llvm::Value *RHSBegin = RHSAddr.getPointer(); - llvm::Value *LHSBegin = LHSAddr.getPointer(); + llvm::Value *RHSBegin = RHSAddr.emitRawPointer(CGF); + llvm::Value *LHSBegin = LHSAddr.emitRawPointer(CGF); // Cast from pointer to array type to pointer to single element. llvm::Value *LHSEnd = CGF.Builder.CreateGEP(LHSAddr.getElementType(), LHSBegin, NumElements); @@ -4990,7 +4992,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, QualType ReductionArrayTy = C.getConstantArrayType( C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0); - Address ReductionList = + RawAddress ReductionList = CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); const auto *IPriv = Privates.begin(); unsigned Idx = 0; @@ -5462,7 +5464,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( C.getConstantArrayType(RDType, ArraySize, nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0); // kmp_task_red_input_t .rd_input.[Size]; - Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input."); + RawAddress TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input."); ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionOrigs, Data.ReductionCopies, Data.ReductionOps); for (unsigned Cnt = 0; Cnt < Size; ++Cnt) { @@ -5473,7 +5475,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( TaskRedInput.getElementType(), TaskRedInput.getPointer(), Idxs, /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc, ".rd_input.gep."); - LValue ElemLVal = CGF.MakeNaturalAlignAddrLValue(GEP, RDType); + LValue ElemLVal = CGF.MakeNaturalAlignRawAddrLValue(GEP, RDType); // ElemLVal.reduce_shar = &Shareds[Cnt]; LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD); RCG.emitSharedOrigLValue(CGF, Cnt); @@ -5629,7 +5631,7 @@ void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, DepWaitTaskArgs[0] = UpLoc; DepWaitTaskArgs[1] = ThreadID; DepWaitTaskArgs[2] = NumOfElements; - DepWaitTaskArgs[3] = DependenciesArray.getPointer(); + DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF); DepWaitTaskArgs[4] = CGF.Builder.getInt32(0); DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); DepWaitTaskArgs[6] = @@ -5852,7 +5854,7 @@ void CGOpenMPRuntime::emitUsesAllocatorsInit(CodeGenFunction &CGF, AllocatorTraitsLVal = CGF.MakeAddrLValue(Addr, CGF.getContext().VoidPtrTy, AllocatorTraitsLVal.getBaseInfo(), AllocatorTraitsLVal.getTBAAInfo()); - llvm::Value *Traits = Addr.getPointer(); + llvm::Value *Traits = Addr.emitRawPointer(CGF); llvm::Value *AllocatorVal = CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( @@ -7312,17 +7314,19 @@ private: CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()) .getAddress(CGF); } - Size = CGF.Builder.CreatePtrDiff( - CGF.Int8Ty, ComponentLB.getPointer(), LB.getPointer()); + llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF); + llvm::Value *LBPtr = LB.emitRawPointer(CGF); + Size = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, ComponentLBPtr, + LBPtr); break; } } assert(Size && "Failed to determine structure size"); CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.Types.push_back(Flags); @@ -7332,13 +7336,14 @@ private: LB = CGF.Builder.CreateConstGEP(ComponentLB, 1); } CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); + llvm::Value *LBPtr = LB.emitRawPointer(CGF); Size = CGF.Builder.CreatePtrDiff( - CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).getPointer(), - LB.getPointer()); + CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), + LBPtr); CombinedInfo.Sizes.push_back( CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.Types.push_back(Flags); @@ -7356,20 +7361,21 @@ private: (Next == CE && MapType != OMPC_MAP_unknown)) { if (!IsMappingWholeStruct) { CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1); } else { StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - StructBaseCombinedInfo.BasePointers.push_back(BP.getPointer()); + StructBaseCombinedInfo.BasePointers.push_back( + BP.emitRawPointer(CGF)); StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr); StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - StructBaseCombinedInfo.Pointers.push_back(LB.getPointer()); + StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); StructBaseCombinedInfo.NonContigInfo.Dims.push_back( @@ -8211,11 +8217,11 @@ public: } CombinedInfo.Exprs.push_back(VD); // Base is the base of the struct - CombinedInfo.BasePointers.push_back(PartialStruct.Base.getPointer()); + CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); // Pointer is the address of the lowest element - llvm::Value *LB = LBAddr.getPointer(); + llvm::Value *LB = LBAddr.emitRawPointer(CGF); const CXXMethodDecl *MD = CGF.CurFuncDecl ? dyn_cast(CGF.CurFuncDecl) : nullptr; const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr; @@ -8229,7 +8235,7 @@ public: // if the this[:1] expression had appeared in a map clause with a map-type // of tofrom. // Emit this[:1] - CombinedInfo.Pointers.push_back(PartialStruct.Base.getPointer()); + CombinedInfo.Pointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); QualType Ty = MD->getFunctionObjectParameterType(); llvm::Value *Size = CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty, @@ -8238,7 +8244,7 @@ public: } else { CombinedInfo.Pointers.push_back(LB); // Size is (addr of {highest+1} element) - (addr of lowest element) - llvm::Value *HB = HBAddr.getPointer(); + llvm::Value *HB = HBAddr.emitRawPointer(CGF); llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32( HBAddr.getElementType(), HB, /*Idx0=*/1); llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy); @@ -8747,7 +8753,7 @@ public: Address PtrAddr = CGF.EmitLoadOfReference(CGF.MakeAddrLValue( CV, ElementType, CGF.getContext().getDeclAlign(VD), AlignmentSource::Decl)); - CombinedInfo.Pointers.push_back(PtrAddr.getPointer()); + CombinedInfo.Pointers.push_back(PtrAddr.emitRawPointer(CGF)); } else { CombinedInfo.Pointers.push_back(CV); } @@ -9558,10 +9564,11 @@ static void emitTargetCallKernelLaunch( bool HasNoWait = D.hasClausesOfKind(); unsigned NumTargetItems = InputInfo.NumberOfTargetItems; - llvm::Value *BasePointersArray = InputInfo.BasePointersArray.getPointer(); - llvm::Value *PointersArray = InputInfo.PointersArray.getPointer(); - llvm::Value *SizesArray = InputInfo.SizesArray.getPointer(); - llvm::Value *MappersArray = InputInfo.MappersArray.getPointer(); + llvm::Value *BasePointersArray = + InputInfo.BasePointersArray.emitRawPointer(CGF); + llvm::Value *PointersArray = InputInfo.PointersArray.emitRawPointer(CGF); + llvm::Value *SizesArray = InputInfo.SizesArray.emitRawPointer(CGF); + llvm::Value *MappersArray = InputInfo.MappersArray.emitRawPointer(CGF); auto &&EmitTargetCallFallbackCB = [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS, @@ -10309,15 +10316,16 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( // Source location for the ident struct llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc()); - llvm::Value *OffloadingArgs[] = {RTLoc, - DeviceID, - PointerNum, - InputInfo.BasePointersArray.getPointer(), - InputInfo.PointersArray.getPointer(), - InputInfo.SizesArray.getPointer(), - MapTypesArray, - MapNamesArray, - InputInfo.MappersArray.getPointer()}; + llvm::Value *OffloadingArgs[] = { + RTLoc, + DeviceID, + PointerNum, + InputInfo.BasePointersArray.emitRawPointer(CGF), + InputInfo.PointersArray.emitRawPointer(CGF), + InputInfo.SizesArray.emitRawPointer(CGF), + MapTypesArray, + MapNamesArray, + InputInfo.MappersArray.emitRawPointer(CGF)}; // Select the right runtime function call for each standalone // directive. @@ -11128,7 +11136,7 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF, getThreadID(CGF, D.getBeginLoc()), llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()), CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).getPointer(), + CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).emitRawPointer(CGF), CGM.VoidPtrTy)}; llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction( @@ -11162,7 +11170,8 @@ static void EmitDoacrossOrdered(CodeGenFunction &CGF, CodeGenModule &CGM, /*Volatile=*/false, Int64Ty); } llvm::Value *Args[] = { - ULoc, ThreadID, CGF.Builder.CreateConstArrayGEP(CntAddr, 0).getPointer()}; + ULoc, ThreadID, + CGF.Builder.CreateConstArrayGEP(CntAddr, 0).emitRawPointer(CGF)}; llvm::FunctionCallee RTLFn; llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); OMPDoacrossKind ODK; @@ -11332,7 +11341,7 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, Args[0] = CGF.CGM.getOpenMPRuntime().getThreadID( CGF, SourceLocation::getFromRawEncoding(LocEncoding)); Args[1] = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - Addr.getPointer(), CGF.VoidPtrTy); + Addr.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr); Args[2] = AllocVal; CGF.EmitRuntimeCall(RTLFn, Args); @@ -11690,15 +11699,17 @@ void CGOpenMPRuntime::emitLastprivateConditionalUpdate(CodeGenFunction &CGF, LLIVTy, getName({UniqueDeclName, "iv"})); cast(LastIV)->setAlignment( IVLVal.getAlignment().getAsAlign()); - LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType()); + LValue LastIVLVal = + CGF.MakeNaturalAlignRawAddrLValue(LastIV, IVLVal.getType()); // Last value of the lastprivate conditional. // decltype(priv_a) last_a; llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable( CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName); - Last->setAlignment(LVal.getAlignment().getAsAlign()); - LValue LastLVal = CGF.MakeAddrLValue( - Address(Last, Last->getValueType(), LVal.getAlignment()), LVal.getType()); + cast(Last)->setAlignment( + LVal.getAlignment().getAsAlign()); + LValue LastLVal = + CGF.MakeRawAddrLValue(Last, LVal.getType(), LVal.getAlignment()); // Global loop counter. Required to handle inner parallel-for regions. // iv @@ -11871,9 +11882,8 @@ void CGOpenMPRuntime::emitLastprivateConditionalFinalUpdate( // The variable was not updated in the region - exit. if (!GV) return; - LValue LPLVal = CGF.MakeAddrLValue( - Address(GV, GV->getValueType(), PrivLVal.getAlignment()), - PrivLVal.getType().getNonReferenceType()); + LValue LPLVal = CGF.MakeRawAddrLValue( + GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment()); llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc); CGF.EmitStoreOfScalar(Res, PrivLVal); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index c3206427b143e12b616bf5b1501ab6c6871870d0..522ae3d35d22d76e269b03ca0d26ef9ecc0b7bd2 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -1068,13 +1068,12 @@ public: /// \param Loc Location of the reference to threadprivate var. /// \return Address of the threadprivate variable for the current thread. virtual Address getAddrOfThreadPrivate(CodeGenFunction &CGF, - const VarDecl *VD, - Address VDAddr, + const VarDecl *VD, Address VDAddr, SourceLocation Loc); /// Returns the address of the variable marked as declare target with link /// clause OR as declare target with to clause and unified memory. - virtual Address getAddrOfDeclareTargetVar(const VarDecl *VD); + virtual ConstantAddress getAddrOfDeclareTargetVar(const VarDecl *VD); /// Emit a code for initialization of threadprivate variable. It emits /// a call to runtime library which adds initial value to the newly created diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 299ee1460b3db0ef895c681246a8cc7f8bd42fb2..5baac8f0e3e268bf2789014edae018ec0436f557 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -1096,7 +1096,8 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF, llvm::PointerType *VarPtrTy = CGF.ConvertTypeForMem(VarTy)->getPointerTo(); llvm::Value *CastedVoidPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( VoidPtr, VarPtrTy, VD->getName() + "_on_stack"); - LValue VarAddr = CGF.MakeNaturalAlignAddrLValue(CastedVoidPtr, VarTy); + LValue VarAddr = + CGF.MakeNaturalAlignPointeeRawAddrLValue(CastedVoidPtr, VarTy); Rec.second.PrivateAddr = VarAddr.getAddress(CGF); Rec.second.GlobalizedVal = VoidPtr; @@ -1206,8 +1207,8 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, bool IsBareKernel = D.getSingleClause(); - Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, - /*Name=*/".zero.addr"); + RawAddress ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, + /*Name=*/".zero.addr"); CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr); llvm::SmallVector OutlinedFnArgs; // We don't emit any thread id function call in bare kernel, but because the @@ -1215,7 +1216,7 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, if (IsBareKernel) OutlinedFnArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy)); else - OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer()); + OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).emitRawPointer(CGF)); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); @@ -1289,7 +1290,7 @@ void CGOpenMPRuntimeGPU::emitParallelCall(CodeGenFunction &CGF, llvm::ConstantInt::get(CGF.Int32Ty, -1), FnPtr, ID, - Bld.CreateBitOrPointerCast(CapturedVarsAddrs.getPointer(), + Bld.CreateBitOrPointerCast(CapturedVarsAddrs.emitRawPointer(CGF), CGF.VoidPtrPtrTy), llvm::ConstantInt::get(CGM.SizeTy, CapturedVars.size())}; CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( @@ -1503,17 +1504,18 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, CGF.EmitBlock(PreCondBB); llvm::PHINode *PhiSrc = Bld.CreatePHI(Ptr.getType(), /*NumReservedValues=*/2); - PhiSrc->addIncoming(Ptr.getPointer(), CurrentBB); + PhiSrc->addIncoming(Ptr.emitRawPointer(CGF), CurrentBB); llvm::PHINode *PhiDest = Bld.CreatePHI(ElemPtr.getType(), /*NumReservedValues=*/2); - PhiDest->addIncoming(ElemPtr.getPointer(), CurrentBB); + PhiDest->addIncoming(ElemPtr.emitRawPointer(CGF), CurrentBB); Ptr = Address(PhiSrc, Ptr.getElementType(), Ptr.getAlignment()); ElemPtr = Address(PhiDest, ElemPtr.getElementType(), ElemPtr.getAlignment()); + llvm::Value *PtrEndRaw = PtrEnd.emitRawPointer(CGF); + llvm::Value *PtrRaw = Ptr.emitRawPointer(CGF); llvm::Value *PtrDiff = Bld.CreatePtrDiff( - CGF.Int8Ty, PtrEnd.getPointer(), - Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr.getPointer(), - CGF.VoidPtrTy)); + CGF.Int8Ty, PtrEndRaw, + Bld.CreatePointerBitCastOrAddrSpaceCast(PtrRaw, CGF.VoidPtrTy)); Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)), ThenBB, ExitBB); CGF.EmitBlock(ThenBB); @@ -1528,8 +1530,8 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, TBAAAccessInfo()); Address LocalPtr = Bld.CreateConstGEP(Ptr, 1); Address LocalElemPtr = Bld.CreateConstGEP(ElemPtr, 1); - PhiSrc->addIncoming(LocalPtr.getPointer(), ThenBB); - PhiDest->addIncoming(LocalElemPtr.getPointer(), ThenBB); + PhiSrc->addIncoming(LocalPtr.emitRawPointer(CGF), ThenBB); + PhiDest->addIncoming(LocalElemPtr.emitRawPointer(CGF), ThenBB); CGF.EmitBranch(PreCondBB); CGF.EmitBlock(ExitBB); } else { @@ -1676,10 +1678,10 @@ static void emitReductionListCopy( // scope and that of functions it invokes (i.e., reduce_function). // RemoteReduceData[i] = (void*)&RemoteElem if (UpdateDestListPtr) { - CGF.EmitStoreOfScalar(Bld.CreatePointerBitCastOrAddrSpaceCast( - DestElementAddr.getPointer(), CGF.VoidPtrTy), - DestElementPtrAddr, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar( + Bld.CreatePointerBitCastOrAddrSpaceCast( + DestElementAddr.emitRawPointer(CGF), CGF.VoidPtrTy), + DestElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy); } ++Idx; @@ -1830,7 +1832,7 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, // elemptr = ((CopyType*)(elemptrptr)) + I Address ElemPtr(ElemPtrPtr, CopyType, Align); if (NumIters > 1) - ElemPtr = Bld.CreateGEP(ElemPtr, Cnt); + ElemPtr = Bld.CreateGEP(CGF, ElemPtr, Cnt); // Get pointer to location in transfer medium. // MediumPtr = &medium[warp_id] @@ -1894,7 +1896,7 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, TargetElemPtrPtr, /*Volatile=*/false, C.VoidPtrTy, Loc); Address TargetElemPtr(TargetElemPtrVal, CopyType, Align); if (NumIters > 1) - TargetElemPtr = Bld.CreateGEP(TargetElemPtr, Cnt); + TargetElemPtr = Bld.CreateGEP(CGF, TargetElemPtr, Cnt); // *TargetElemPtr = SrcMediumVal; llvm::Value *SrcMediumValue = @@ -2105,9 +2107,9 @@ static llvm::Function *emitShuffleAndReduceFunction( CGF.EmitBlock(ThenBB); // reduce_function(LocalReduceList, RemoteReduceList) llvm::Value *LocalReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - LocalReduceList.getPointer(), CGF.VoidPtrTy); + LocalReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Value *RemoteReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - RemoteReduceList.getPointer(), CGF.VoidPtrTy); + RemoteReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); CGM.getOpenMPRuntime().emitOutlinedFunctionCall( CGF, Loc, ReduceFn, {LocalReduceListPtr, RemoteReduceListPtr}); Bld.CreateBr(MergeBB); @@ -2218,9 +2220,9 @@ static llvm::Value *emitListToGlobalCopyFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - GlobLVal.setAddress(Address(GlobAddr.getPointer(), + GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Private->getType()), GlobAddr.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { @@ -2304,7 +2306,7 @@ static llvm::Value *emitListToGlobalReduceFunction( // 1. Build a list of reduction variables. // void *RedList[] = {[0], ..., [-1]}; - Address ReductionList = + RawAddress ReductionList = CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); auto IPriv = Privates.begin(); llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), @@ -2319,10 +2321,10 @@ static llvm::Value *emitListToGlobalReduceFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - CGF.EmitStoreOfScalar(GlobAddr.getPointer(), Elem, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, + /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. ++Idx; @@ -2425,9 +2427,9 @@ static llvm::Value *emitGlobalToListCopyFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - GlobLVal.setAddress(Address(GlobAddr.getPointer(), + GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Private->getType()), GlobAddr.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { @@ -2526,10 +2528,10 @@ static llvm::Value *emitGlobalToListReduceFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - CGF.EmitStoreOfScalar(GlobAddr.getPointer(), Elem, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, + /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. ++Idx; @@ -2545,7 +2547,7 @@ static llvm::Value *emitGlobalToListReduceFunction( } // Call reduce_function(ReduceList, GlobalReduceList) - llvm::Value *GlobalReduceList = ReductionList.getPointer(); + llvm::Value *GlobalReduceList = ReductionList.emitRawPointer(CGF); Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); llvm::Value *ReducedPtr = CGF.EmitLoadOfScalar( AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc); @@ -2876,7 +2878,7 @@ void CGOpenMPRuntimeGPU::emitReduction( } llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - ReductionList.getPointer(), CGF.VoidPtrTy); + ReductionList.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Function *ReductionFn = emitReductionFunction( CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy), Privates, LHSExprs, RHSExprs, ReductionOps); @@ -3106,15 +3108,15 @@ llvm::Function *CGOpenMPRuntimeGPU::createParallelDataSharingWrapper( // Get the array of arguments. SmallVector Args; - Args.emplace_back(CGF.GetAddrOfLocalVar(&WrapperArg).getPointer()); - Args.emplace_back(ZeroAddr.getPointer()); + Args.emplace_back(CGF.GetAddrOfLocalVar(&WrapperArg).emitRawPointer(CGF)); + Args.emplace_back(ZeroAddr.emitRawPointer(CGF)); CGBuilderTy &Bld = CGF.Builder; auto CI = CS.capture_begin(); // Use global memory for data sharing. // Handle passing of global args to workers. - Address GlobalArgs = + RawAddress GlobalArgs = CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, "global_args"); llvm::Value *GlobalArgsPtr = GlobalArgs.getPointer(); llvm::Value *DataSharingArgs[] = {GlobalArgsPtr}; @@ -3400,7 +3402,7 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas( VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType().getCanonicalType()) .getAddress(CGF); - CGF.EmitStoreOfScalar(VDAddr.getPointer(), VarLVal); + CGF.EmitStoreOfScalar(VDAddr.emitRawPointer(CGF), VarLVal); } } } diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 7822903b89ce47e174d24508d86609a42cb3dba7..e32023aeac1e6f8719fe54bd75064dca4cf50fae 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -47,8 +47,10 @@ namespace { /// [i8 x 3] instead of i24. The function clipTailPadding does this. /// C++ examples that require clipping: /// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3 -/// struct A { int a : 24; }; // a must be clipped because a struct like B -// could exist: struct B : A { char b; }; // b goes at offset 3 +/// struct A { int a : 24; ~A(); }; // a must be clipped because: +/// struct B : A { char b; }; // b goes at offset 3 +/// * The allocation of bitfield access units is described in more detail in +/// CGRecordLowering::accumulateBitFields. /// * Clang ignores 0 sized bitfields and 0 sized bases but *not* zero sized /// fields. The existing asserts suggest that LLVM assumes that *every* field /// has an underlying storage type. Therefore empty structures containing @@ -184,8 +186,9 @@ struct CGRecordLowering { void lower(bool NonVirtualBaseType); void lowerUnion(bool isNoUniqueAddress); void accumulateFields(); - void accumulateBitFields(RecordDecl::field_iterator Field, - RecordDecl::field_iterator FieldEnd); + RecordDecl::field_iterator + accumulateBitFields(RecordDecl::field_iterator Field, + RecordDecl::field_iterator FieldEnd); void computeVolatileBitfields(); void accumulateBases(); void accumulateVPtrs(); @@ -378,13 +381,15 @@ void CGRecordLowering::lowerUnion(bool isNoUniqueAddress) { void CGRecordLowering::accumulateFields() { for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); - Field != FieldEnd;) { + Field != FieldEnd;) { if (Field->isBitField()) { - RecordDecl::field_iterator Start = Field; - // Iterate to gather the list of bitfields. - for (++Field; Field != FieldEnd && Field->isBitField(); ++Field); - accumulateBitFields(Start, Field); - } else if (!Field->isZeroSize(Context)) { + Field = accumulateBitFields(Field, FieldEnd); + assert((Field == FieldEnd || !Field->isBitField()) && + "Failed to accumulate all the bitfields"); + } else if (Field->isZeroSize(Context)) { + // Empty fields have no storage. + ++Field; + } else { // Use base subobject layout for the potentially-overlapping field, // as it is done in RecordLayoutBuilder Members.push_back(MemberInfo( @@ -394,33 +399,33 @@ void CGRecordLowering::accumulateFields() { : getStorageType(*Field), *Field)); ++Field; - } else { - ++Field; } } } -void +// Create members for bitfields. Field is a bitfield, and FieldEnd is the end +// iterator of the record. Return the first non-bitfield encountered. +RecordDecl::field_iterator CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, RecordDecl::field_iterator FieldEnd) { - // Run stores the first element of the current run of bitfields. FieldEnd is - // used as a special value to note that we don't have a current run. A - // bitfield run is a contiguous collection of bitfields that can be stored in - // the same storage block. Zero-sized bitfields and bitfields that would - // cross an alignment boundary break a run and start a new one. - RecordDecl::field_iterator Run = FieldEnd; - // Tail is the offset of the first bit off the end of the current run. It's - // used to determine if the ASTRecordLayout is treating these two bitfields as - // contiguous. StartBitOffset is offset of the beginning of the Run. - uint64_t StartBitOffset, Tail = 0; if (isDiscreteBitFieldABI()) { - for (; Field != FieldEnd; ++Field) { - uint64_t BitOffset = getFieldBitOffset(*Field); + // Run stores the first element of the current run of bitfields. FieldEnd is + // used as a special value to note that we don't have a current run. A + // bitfield run is a contiguous collection of bitfields that can be stored + // in the same storage block. Zero-sized bitfields and bitfields that would + // cross an alignment boundary break a run and start a new one. + RecordDecl::field_iterator Run = FieldEnd; + // Tail is the offset of the first bit off the end of the current run. It's + // used to determine if the ASTRecordLayout is treating these two bitfields + // as contiguous. StartBitOffset is offset of the beginning of the Run. + uint64_t StartBitOffset, Tail = 0; + for (; Field != FieldEnd && Field->isBitField(); ++Field) { // Zero-width bitfields end runs. if (Field->isZeroLengthBitField(Context)) { Run = FieldEnd; continue; } + uint64_t BitOffset = getFieldBitOffset(*Field); llvm::Type *Type = Types.ConvertTypeForMem(Field->getType(), /*ForBitField=*/true); // If we don't have a run yet, or don't live within the previous run's @@ -439,82 +444,248 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), MemberInfo::Field, nullptr, *Field)); } - return; + return Field; } - // Check if OffsetInRecord (the size in bits of the current run) is better - // as a single field run. When OffsetInRecord has legal integer width, and - // its bitfield offset is naturally aligned, it is better to make the - // bitfield a separate storage component so as it can be accessed directly - // with lower cost. - auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord, - uint64_t StartBitOffset) { - if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses) - return false; - if (OffsetInRecord < 8 || !llvm::isPowerOf2_64(OffsetInRecord) || - !DataLayout.fitsInLegalInteger(OffsetInRecord)) - return false; - // Make sure StartBitOffset is naturally aligned if it is treated as an - // IType integer. - if (StartBitOffset % - Context.toBits(getAlignment(getIntNType(OffsetInRecord))) != - 0) - return false; - return true; - }; + // The SysV ABI can overlap bitfield storage units with both other bitfield + // storage units /and/ other non-bitfield data members. Accessing a sequence + // of bitfields mustn't interfere with adjacent non-bitfields -- they're + // permitted to be accessed in separate threads for instance. + + // We split runs of bit-fields into a sequence of "access units". When we emit + // a load or store of a bit-field, we'll load/store the entire containing + // access unit. As mentioned, the standard requires that these loads and + // stores must not interfere with accesses to other memory locations, and it + // defines the bit-field's memory location as the current run of + // non-zero-width bit-fields. So an access unit must never overlap with + // non-bit-field storage or cross a zero-width bit-field. Otherwise, we're + // free to draw the lines as we see fit. + + // Drawing these lines well can be complicated. LLVM generally can't modify a + // program to access memory that it didn't before, so using very narrow access + // units can prevent the compiler from using optimal access patterns. For + // example, suppose a run of bit-fields occupies four bytes in a struct. If we + // split that into four 1-byte access units, then a sequence of assignments + // that doesn't touch all four bytes may have to be emitted with multiple + // 8-bit stores instead of a single 32-bit store. On the other hand, if we use + // very wide access units, we may find ourselves emitting accesses to + // bit-fields we didn't really need to touch, just because LLVM was unable to + // clean up after us. + + // It is desirable to have access units be aligned powers of 2 no larger than + // a register. (On non-strict alignment ISAs, the alignment requirement can be + // dropped.) A three byte access unit will be accessed using 2-byte and 1-byte + // accesses and bit manipulation. If no bitfield straddles across the two + // separate accesses, it is better to have separate 2-byte and 1-byte access + // units, as then LLVM will not generate unnecessary memory accesses, or bit + // manipulation. Similarly, on a strict-alignment architecture, it is better + // to keep access-units naturally aligned, to avoid similar bit + // manipulation synthesizing larger unaligned accesses. + + // Bitfields that share parts of a single byte are, of necessity, placed in + // the same access unit. That unit will encompass a consecutive run where + // adjacent bitfields share parts of a byte. (The first bitfield of such an + // access unit will start at the beginning of a byte.) + + // We then try and accumulate adjacent access units when the combined unit is + // naturally sized, no larger than a register, and (on a strict alignment + // ISA), naturally aligned. Note that this requires lookahead to one or more + // subsequent access units. For instance, consider a 2-byte access-unit + // followed by 2 1-byte units. We can merge that into a 4-byte access-unit, + // but we would not want to merge a 2-byte followed by a single 1-byte (and no + // available tail padding). We keep track of the best access unit seen so far, + // and use that when we determine we cannot accumulate any more. Then we start + // again at the bitfield following that best one. + + // The accumulation is also prevented when: + // *) it would cross a character-aigned zero-width bitfield, or + // *) fine-grained bitfield access option is in effect. + + CharUnits RegSize = + bitsToCharUnits(Context.getTargetInfo().getRegisterWidth()); + unsigned CharBits = Context.getCharWidth(); + + // Data about the start of the span we're accumulating to create an access + // unit from. Begin is the first bitfield of the span. If Begin is FieldEnd, + // we've not got a current span. The span starts at the BeginOffset character + // boundary. BitSizeSinceBegin is the size (in bits) of the span -- this might + // include padding when we've advanced to a subsequent bitfield run. + RecordDecl::field_iterator Begin = FieldEnd; + CharUnits BeginOffset; + uint64_t BitSizeSinceBegin; + + // The (non-inclusive) end of the largest acceptable access unit we've found + // since Begin. If this is Begin, we're gathering the initial set of bitfields + // of a new span. BestEndOffset is the end of that acceptable access unit -- + // it might extend beyond the last character of the bitfield run, using + // available padding characters. + RecordDecl::field_iterator BestEnd = Begin; + CharUnits BestEndOffset; - // The start field is better as a single field run. - bool StartFieldAsSingleRun = false; for (;;) { - // Check to see if we need to start a new run. - if (Run == FieldEnd) { - // If we're out of fields, return. - if (Field == FieldEnd) + // AtAlignedBoundary is true iff Field is the (potential) start of a new + // span (or the end of the bitfields). When true, LimitOffset is the + // character offset of that span and Barrier indicates whether the new + // span cannot be merged into the current one. + bool AtAlignedBoundary = false; + bool Barrier = false; + + if (Field != FieldEnd && Field->isBitField()) { + uint64_t BitOffset = getFieldBitOffset(*Field); + if (Begin == FieldEnd) { + // Beginning a new span. + Begin = Field; + BestEnd = Begin; + + assert((BitOffset % CharBits) == 0 && "Not at start of char"); + BeginOffset = bitsToCharUnits(BitOffset); + BitSizeSinceBegin = 0; + } else if ((BitOffset % CharBits) != 0) { + // Bitfield occupies the same character as previous bitfield, it must be + // part of the same span. This can include zero-length bitfields, should + // the target not align them to character boundaries. Such non-alignment + // is at variance with the standards, which require zero-length + // bitfields be a barrier between access units. But of course we can't + // achieve that in the middle of a character. + assert(BitOffset == Context.toBits(BeginOffset) + BitSizeSinceBegin && + "Concatenating non-contiguous bitfields"); + } else { + // Bitfield potentially begins a new span. This includes zero-length + // bitfields on non-aligning targets that lie at character boundaries + // (those are barriers to merging). + if (Field->isZeroLengthBitField(Context)) + Barrier = true; + AtAlignedBoundary = true; + } + } else { + // We've reached the end of the bitfield run. Either we're done, or this + // is a barrier for the current span. + if (Begin == FieldEnd) break; - // Any non-zero-length bitfield can start a new run. - if (!Field->isZeroLengthBitField(Context)) { - Run = Field; - StartBitOffset = getFieldBitOffset(*Field); - Tail = StartBitOffset + Field->getBitWidthValue(Context); - StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Tail - StartBitOffset, - StartBitOffset); + + Barrier = true; + AtAlignedBoundary = true; + } + + // InstallBest indicates whether we should create an access unit for the + // current best span: fields [Begin, BestEnd) occupying characters + // [BeginOffset, BestEndOffset). + bool InstallBest = false; + if (AtAlignedBoundary) { + // Field is the start of a new span or the end of the bitfields. The + // just-seen span now extends to BitSizeSinceBegin. + + // Determine if we can accumulate that just-seen span into the current + // accumulation. + CharUnits AccessSize = bitsToCharUnits(BitSizeSinceBegin + CharBits - 1); + if (BestEnd == Begin) { + // This is the initial run at the start of a new span. By definition, + // this is the best seen so far. + BestEnd = Field; + BestEndOffset = BeginOffset + AccessSize; + if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses) + // Fine-grained access, so no merging of spans. + InstallBest = true; + else if (!BitSizeSinceBegin) + // A zero-sized initial span -- this will install nothing and reset + // for another. + InstallBest = true; + } else if (AccessSize > RegSize) + // Accumulating the just-seen span would create a multi-register access + // unit, which would increase register pressure. + InstallBest = true; + + if (!InstallBest) { + // Determine if accumulating the just-seen span will create an expensive + // access unit or not. + llvm::Type *Type = getIntNType(Context.toBits(AccessSize)); + if (!Context.getTargetInfo().hasCheapUnalignedBitFieldAccess()) { + // Unaligned accesses are expensive. Only accumulate if the new unit + // is naturally aligned. Otherwise install the best we have, which is + // either the initial access unit (can't do better), or a naturally + // aligned accumulation (since we would have already installed it if + // it wasn't naturally aligned). + CharUnits Align = getAlignment(Type); + if (Align > Layout.getAlignment()) + // The alignment required is greater than the containing structure + // itself. + InstallBest = true; + else if (!BeginOffset.isMultipleOf(Align)) + // The access unit is not at a naturally aligned offset within the + // structure. + InstallBest = true; + } + + if (!InstallBest) { + // Find the next used storage offset to determine what the limit of + // the current span is. That's either the offset of the next field + // with storage (which might be Field itself) or the end of the + // non-reusable tail padding. + CharUnits LimitOffset; + for (auto Probe = Field; Probe != FieldEnd; ++Probe) + if (!Probe->isZeroSize(Context)) { + // A member with storage sets the limit. + assert((getFieldBitOffset(*Probe) % CharBits) == 0 && + "Next storage is not byte-aligned"); + LimitOffset = bitsToCharUnits(getFieldBitOffset(*Probe)); + goto FoundLimit; + } + // We reached the end of the fields. We can't necessarily use tail + // padding in C++ structs, so the NonVirtual size is what we must + // use there. + LimitOffset = RD ? Layout.getNonVirtualSize() : Layout.getDataSize(); + FoundLimit:; + + CharUnits TypeSize = getSize(Type); + if (BeginOffset + TypeSize <= LimitOffset) { + // There is space before LimitOffset to create a naturally-sized + // access unit. + BestEndOffset = BeginOffset + TypeSize; + BestEnd = Field; + } + + if (Barrier) + // The next field is a barrier that we cannot merge across. + InstallBest = true; + else + // Otherwise, we're not installing. Update the bit size + // of the current span to go all the way to LimitOffset, which is + // the (aligned) offset of next bitfield to consider. + BitSizeSinceBegin = Context.toBits(LimitOffset - BeginOffset); + } } - ++Field; - continue; } - // If the start field of a new run is better as a single run, or - // if current field (or consecutive fields) is better as a single run, or - // if current field has zero width bitfield and either - // UseZeroLengthBitfieldAlignment or UseBitFieldTypeAlignment is set to - // true, or - // if the offset of current field is inconsistent with the offset of - // previous field plus its offset, - // skip the block below and go ahead to emit the storage. - // Otherwise, try to add bitfields to the run. - if (!StartFieldAsSingleRun && Field != FieldEnd && - !IsBetterAsSingleFieldRun(Tail - StartBitOffset, StartBitOffset) && - (!Field->isZeroLengthBitField(Context) || - (!Context.getTargetInfo().useZeroLengthBitfieldAlignment() && - !Context.getTargetInfo().useBitFieldTypeAlignment())) && - Tail == getFieldBitOffset(*Field)) { - Tail += Field->getBitWidthValue(Context); + if (InstallBest) { + assert((Field == FieldEnd || !Field->isBitField() || + (getFieldBitOffset(*Field) % CharBits) == 0) && + "Installing but not at an aligned bitfield or limit"); + CharUnits AccessSize = BestEndOffset - BeginOffset; + if (!AccessSize.isZero()) { + // Add the storage member for the access unit to the record. The + // bitfields get the offset of their storage but come afterward and + // remain there after a stable sort. + llvm::Type *Type = getIntNType(Context.toBits(AccessSize)); + Members.push_back(StorageInfo(BeginOffset, Type)); + for (; Begin != BestEnd; ++Begin) + if (!Begin->isZeroLengthBitField(Context)) + Members.push_back( + MemberInfo(BeginOffset, MemberInfo::Field, nullptr, *Begin)); + } + // Reset to start a new span. + Field = BestEnd; + Begin = FieldEnd; + } else { + assert(Field != FieldEnd && Field->isBitField() && + "Accumulating past end of bitfields"); + assert(!Barrier && "Accumulating across barrier"); + // Accumulate this bitfield into the current (potential) span. + BitSizeSinceBegin += Field->getBitWidthValue(Context); ++Field; - continue; } - - // We've hit a break-point in the run and need to emit a storage field. - llvm::Type *Type = getIntNType(Tail - StartBitOffset); - // Add the storage member to the record and set the bitfield info for all of - // the bitfields in the run. Bitfields get the offset of their storage but - // come afterward and remain there after a stable sort. - Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type)); - for (; Run != Field; ++Run) - Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), - MemberInfo::Field, nullptr, *Run)); - Run = FieldEnd; - StartFieldAsSingleRun = false; } + + return Field; } void CGRecordLowering::accumulateBases() { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index cb5a004e4f4a6cf802758169cb211728b6d0e42e..576fe2f7a2d46f41aa6c60b4139a28753fd3314f 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2294,7 +2294,7 @@ std::pair CodeGenFunction::EmitAsmInputLValue( Address Addr = InputValue.getAddress(*this); ConstraintStr += '*'; - return {Addr.getPointer(), Addr.getElementType()}; + return {InputValue.getPointer(*this), Addr.getElementType()}; } std::pair @@ -2701,7 +2701,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { ArgTypes.push_back(DestAddr.getType()); ArgElemTypes.push_back(DestAddr.getElementType()); - Args.push_back(DestAddr.getPointer()); + Args.push_back(DestAddr.emitRawPointer(*this)); Constraints += "=*"; Constraints += OutputConstraint; ReadOnly = ReadNone = false; @@ -3076,8 +3076,8 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) { CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr)); // Initialize variable-length arrays. - LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(), - Ctx.getTagDeclType(RD)); + LValue Base = MakeNaturalAlignRawAddrLValue( + CapturedStmtInfo->getContextValue(), Ctx.getTagDeclType(RD)); for (auto *FD : RD->fields()) { if (FD->hasCapturedVLAType()) { auto *ExprArg = diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index f37ac549d10a827ea0ad5b71fc656d0240d6c03a..e6d504bcdeca5b4e86d7f04974e8dd4713c2d0c0 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -350,7 +350,8 @@ void CodeGenFunction::GenerateOpenMPCapturedVars( LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType()); llvm::Value *SrcAddrVal = EmitScalarConversion( - DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()), + DstAddr.emitRawPointer(*this), + Ctx.getPointerType(Ctx.getUIntPtrType()), Ctx.getPointerType(CurField->getType()), CurCap->getLocation()); LValue SrcLV = MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType()); @@ -364,7 +365,8 @@ void CodeGenFunction::GenerateOpenMPCapturedVars( CapturedVars.push_back(CV); } else { assert(CurCap->capturesVariable() && "Expected capture by reference."); - CapturedVars.push_back(EmitLValue(*I).getAddress(*this).getPointer()); + CapturedVars.push_back( + EmitLValue(*I).getAddress(*this).emitRawPointer(*this)); } } } @@ -375,8 +377,9 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc, ASTContext &Ctx = CGF.getContext(); llvm::Value *CastedPtr = CGF.EmitScalarConversion( - AddrLV.getAddress(CGF).getPointer(), Ctx.getUIntPtrType(), + AddrLV.getAddress(CGF).emitRawPointer(CGF), Ctx.getUIntPtrType(), Ctx.getPointerType(DstType), Loc); + // FIXME: should the pointee type (DstType) be passed? Address TmpAddr = CGF.MakeNaturalAlignAddrLValue(CastedPtr, DstType).getAddress(CGF); return TmpAddr; @@ -702,8 +705,8 @@ void CodeGenFunction::EmitOMPAggregateAssign( llvm::Value *NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr); SrcAddr = SrcAddr.withElementType(DestAddr.getElementType()); - llvm::Value *SrcBegin = SrcAddr.getPointer(); - llvm::Value *DestBegin = DestAddr.getPointer(); + llvm::Value *SrcBegin = SrcAddr.emitRawPointer(*this); + llvm::Value *DestBegin = DestAddr.emitRawPointer(*this); // Cast from pointer to array type to pointer to single element. llvm::Value *DestEnd = Builder.CreateInBoundsGEP(DestAddr.getElementType(), DestBegin, NumElements); @@ -1007,10 +1010,10 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { CopyBegin = createBasicBlock("copyin.not.master"); CopyEnd = createBasicBlock("copyin.not.master.end"); // TODO: Avoid ptrtoint conversion. - auto *MasterAddrInt = - Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy); - auto *PrivateAddrInt = - Builder.CreatePtrToInt(PrivateAddr.getPointer(), CGM.IntPtrTy); + auto *MasterAddrInt = Builder.CreatePtrToInt( + MasterAddr.emitRawPointer(*this), CGM.IntPtrTy); + auto *PrivateAddrInt = Builder.CreatePtrToInt( + PrivateAddr.emitRawPointer(*this), CGM.IntPtrTy); Builder.CreateCondBr( Builder.CreateICmpNE(MasterAddrInt, PrivateAddrInt), CopyBegin, CopyEnd); @@ -1666,7 +1669,7 @@ Address CodeGenFunction::OMPBuilderCBHelpers::getAddrOfThreadPrivate( llvm::Type *VarTy = VDAddr.getElementType(); llvm::Value *Data = - CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.Int8PtrTy); + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy); llvm::ConstantInt *Size = CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)); std::string Suffix = getNameWithSeparators({"cache", ""}); llvm::Twine CacheName = Twine(CGM.getMangledName(VD)).concat(Suffix); @@ -2045,7 +2048,7 @@ void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { ->getParam(0) ->getType() .getNonReferenceType(); - Address CountAddr = CreateMemTemp(LogicalTy, ".count.addr"); + RawAddress CountAddr = CreateMemTemp(LogicalTy, ".count.addr"); emitCapturedStmtCall(*this, DistanceClosure, {CountAddr.getPointer()}); llvm::Value *DistVal = Builder.CreateLoad(CountAddr, ".count"); @@ -2061,7 +2064,7 @@ void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { LValue LCVal = EmitLValue(LoopVarRef); Address LoopVarAddress = LCVal.getAddress(*this); emitCapturedStmtCall(*this, LoopVarClosure, - {LoopVarAddress.getPointer(), IndVar}); + {LoopVarAddress.emitRawPointer(*this), IndVar}); RunCleanupsScope BodyScope(*this); EmitStmt(BodyStmt); @@ -4795,7 +4798,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( ParamTypes.push_back(PrivatesPtr->getType()); for (const Expr *E : Data.PrivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = CGF.CreateMemTemp( + RawAddress PrivatePtr = CGF.CreateMemTemp( CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); CallArgs.push_back(PrivatePtr.getPointer()); @@ -4803,7 +4806,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( } for (const Expr *E : Data.FirstprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".firstpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -4813,7 +4816,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( } for (const Expr *E : Data.LastprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".lastpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -4826,7 +4829,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( Ty = CGF.getContext().getPointerType(Ty); if (isAllocatableDecl(VD)) Ty = CGF.getContext().getPointerType(Ty); - Address PrivatePtr = CGF.CreateMemTemp( + RawAddress PrivatePtr = CGF.CreateMemTemp( CGF.getContext().getPointerType(Ty), ".local.ptr.addr"); auto Result = UntiedLocalVars.insert( std::make_pair(VD, std::make_pair(PrivatePtr, Address::invalid()))); @@ -4859,7 +4862,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( if (auto *DI = CGF.getDebugInfo()) if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo()) (void)DI->EmitDeclareOfAutoVariable( - Pair.first, Pair.second.getPointer(), CGF.Builder, + Pair.first, Pair.second.getBasePointer(), CGF.Builder, /*UsePointerValue*/ true); } // Adjust mapping for internal locals by mapping actual memory instead of @@ -4912,14 +4915,14 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( RedCG, Cnt); Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); - Replacement = - Address(CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, - CGF.getContext().getPointerType( - Data.ReductionCopies[Cnt]->getType()), - Data.ReductionCopies[Cnt]->getExprLoc()), - CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), - Replacement.getAlignment()); + Replacement = Address( + CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF), + CGF.getContext().VoidPtrTy, + CGF.getContext().getPointerType( + Data.ReductionCopies[Cnt]->getType()), + Data.ReductionCopies[Cnt]->getExprLoc()), + CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), + Replacement.getAlignment()); Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement); Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement); } @@ -4970,7 +4973,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); Replacement = Address( CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, + Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy, CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()), InRedPrivs[Cnt]->getExprLoc()), CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()), @@ -5089,7 +5092,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective( // If there is no user-defined mapper, the mapper array will be nullptr. In // this case, we don't need to privatize it. if (!isa_and_nonnull( - InputInfo.MappersArray.getPointer())) { + InputInfo.MappersArray.emitRawPointer(*this))) { MVD = createImplicitFirstprivateForType( getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc()); TargetScope.addPrivate(MVD, InputInfo.MappersArray); @@ -5115,7 +5118,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective( ParamTypes.push_back(PrivatesPtr->getType()); for (const Expr *E : Data.FirstprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".firstpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -5194,14 +5197,14 @@ void CodeGenFunction::processInReduction(const OMPExecutableDirective &S, RedCG, Cnt); Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); - Replacement = - Address(CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, - CGF.getContext().getPointerType( - Data.ReductionCopies[Cnt]->getType()), - Data.ReductionCopies[Cnt]->getExprLoc()), - CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), - Replacement.getAlignment()); + Replacement = Address( + CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF), + CGF.getContext().VoidPtrTy, + CGF.getContext().getPointerType( + Data.ReductionCopies[Cnt]->getType()), + Data.ReductionCopies[Cnt]->getExprLoc()), + CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), + Replacement.getAlignment()); Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement); Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement); } @@ -5247,7 +5250,7 @@ void CodeGenFunction::processInReduction(const OMPExecutableDirective &S, CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); Replacement = Address( CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, + Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy, CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()), InRedPrivs[Cnt]->getExprLoc()), CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()), @@ -5394,7 +5397,7 @@ void CodeGenFunction::EmitOMPDepobjDirective(const OMPDepobjDirective &S) { Dependencies.DepExprs.append(DC->varlist_begin(), DC->varlist_end()); Address DepAddr = CGM.getOpenMPRuntime().emitDepobjDependClause( *this, Dependencies, DC->getBeginLoc()); - EmitStoreOfScalar(DepAddr.getPointer(), DOLVal); + EmitStoreOfScalar(DepAddr.emitRawPointer(*this), DOLVal); return; } if (const auto *DC = S.getSingleClause()) { @@ -6471,21 +6474,21 @@ static void emitOMPAtomicCompareExpr( D->getType()->hasSignedIntegerRepresentation()); llvm::OpenMPIRBuilder::AtomicOpValue XOpVal{ - XAddr.getPointer(), XAddr.getElementType(), + XAddr.emitRawPointer(CGF), XAddr.getElementType(), X->getType()->hasSignedIntegerRepresentation(), X->getType().isVolatileQualified()}; llvm::OpenMPIRBuilder::AtomicOpValue VOpVal, ROpVal; if (V) { LValue LV = CGF.EmitLValue(V); Address Addr = LV.getAddress(CGF); - VOpVal = {Addr.getPointer(), Addr.getElementType(), + VOpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(), V->getType()->hasSignedIntegerRepresentation(), V->getType().isVolatileQualified()}; } if (R) { LValue LV = CGF.EmitLValue(R); Address Addr = LV.getAddress(CGF); - ROpVal = {Addr.getPointer(), Addr.getElementType(), + ROpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(), R->getType()->hasSignedIntegerRepresentation(), R->getType().isVolatileQualified()}; } @@ -7029,7 +7032,7 @@ void CodeGenFunction::EmitOMPInteropDirective(const OMPInteropDirective &S) { std::tie(NumDependences, DependenciesArray) = CGM.getOpenMPRuntime().emitDependClause(*this, Data.Dependences, S.getBeginLoc()); - DependenceList = DependenciesArray.getPointer(); + DependenceList = DependenciesArray.emitRawPointer(*this); } Data.HasNowaitClause = S.hasClausesOfKind(); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 8dee3f74b44b4e66edfc8b2ffd1c41514671496b..862369ae009f4808c73cc0b32cd11101261fd4ba 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -201,14 +201,13 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, // Find the first store of "this", which will be to the alloca associated // with "this". - Address ThisPtr = - Address(&*AI, ConvertTypeForMem(MD->getFunctionObjectParameterType()), - CGM.getClassPointerAlignment(MD->getParent())); + Address ThisPtr = makeNaturalAddressForPointer( + &*AI, MD->getFunctionObjectParameterType(), + CGM.getClassPointerAlignment(MD->getParent())); llvm::BasicBlock *EntryBB = &Fn->front(); llvm::BasicBlock::iterator ThisStore = llvm::find_if(*EntryBB, [&](llvm::Instruction &I) { - return isa(I) && - I.getOperand(0) == ThisPtr.getPointer(); + return isa(I) && I.getOperand(0) == &*AI; }); assert(ThisStore != EntryBB->end() && "Store of this should be in entry block?"); diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h index 1e6f67250583d66fda9c2552d61ce1e9ea629695..cc9ad10ae5969df3c30eac0f9db5234349af9ae6 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -14,12 +14,13 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_CGVALUE_H #define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H +#include "Address.h" +#include "CodeGenTBAA.h" +#include "EHScopeStack.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" -#include "llvm/IR/Value.h" #include "llvm/IR/Type.h" -#include "Address.h" -#include "CodeGenTBAA.h" +#include "llvm/IR/Value.h" namespace llvm { class Constant; @@ -28,57 +29,64 @@ namespace llvm { namespace clang { namespace CodeGen { - class AggValueSlot; - class CodeGenFunction; - struct CGBitFieldInfo; +class AggValueSlot; +class CGBuilderTy; +class CodeGenFunction; +struct CGBitFieldInfo; /// RValue - This trivial value class is used to represent the result of an /// expression that is evaluated. It can be one of three things: either a /// simple LLVM SSA value, a pair of SSA values for complex numbers, or the /// address of an aggregate value in memory. class RValue { - enum Flavor { Scalar, Complex, Aggregate }; + friend struct DominatingValue; - // The shift to make to an aggregate's alignment to make it look - // like a pointer. - enum { AggAlignShift = 4 }; + enum FlavorEnum { Scalar, Complex, Aggregate }; - // Stores first value and flavor. - llvm::PointerIntPair V1; - // Stores second value and volatility. - llvm::PointerIntPair V2; - // Stores element type for aggregate values. - llvm::Type *ElementType; + union { + // Stores first and second value. + struct { + llvm::Value *first; + llvm::Value *second; + } Vals; + + // Stores aggregate address. + Address AggregateAddr; + }; + + unsigned IsVolatile : 1; + unsigned Flavor : 2; public: - bool isScalar() const { return V1.getInt() == Scalar; } - bool isComplex() const { return V1.getInt() == Complex; } - bool isAggregate() const { return V1.getInt() == Aggregate; } + RValue() : Vals{nullptr, nullptr}, Flavor(Scalar) {} + + bool isScalar() const { return Flavor == Scalar; } + bool isComplex() const { return Flavor == Complex; } + bool isAggregate() const { return Flavor == Aggregate; } - bool isVolatileQualified() const { return V2.getInt(); } + bool isVolatileQualified() const { return IsVolatile; } /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); - return V1.getPointer(); + return Vals.first; } /// getComplexVal - Return the real/imag components of this complex value. /// std::pair getComplexVal() const { - return std::make_pair(V1.getPointer(), V2.getPointer()); + return std::make_pair(Vals.first, Vals.second); } /// getAggregateAddr() - Return the Value* of the address of the aggregate. Address getAggregateAddress() const { assert(isAggregate() && "Not an aggregate!"); - auto align = reinterpret_cast(V2.getPointer()) >> AggAlignShift; - return Address( - V1.getPointer(), ElementType, CharUnits::fromQuantity(align)); + return AggregateAddr; } - llvm::Value *getAggregatePointer() const { - assert(isAggregate() && "Not an aggregate!"); - return V1.getPointer(); + + llvm::Value *getAggregatePointer(QualType PointeeType, + CodeGenFunction &CGF) const { + return getAggregateAddress().getBasePointer(); } static RValue getIgnored() { @@ -88,17 +96,19 @@ public: static RValue get(llvm::Value *V) { RValue ER; - ER.V1.setPointer(V); - ER.V1.setInt(Scalar); - ER.V2.setInt(false); + ER.Vals.first = V; + ER.Flavor = Scalar; + ER.IsVolatile = false; return ER; } + static RValue get(Address Addr, CodeGenFunction &CGF) { + return RValue::get(Addr.emitRawPointer(CGF)); + } static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { RValue ER; - ER.V1.setPointer(V1); - ER.V2.setPointer(V2); - ER.V1.setInt(Complex); - ER.V2.setInt(false); + ER.Vals = {V1, V2}; + ER.Flavor = Complex; + ER.IsVolatile = false; return ER; } static RValue getComplex(const std::pair &C) { @@ -107,15 +117,15 @@ public: // FIXME: Aggregate rvalues need to retain information about whether they are // volatile or not. Remove default to find all places that probably get this // wrong. + + /// Convert an Address to an RValue. If the Address is not + /// signed, create an RValue using the unsigned address. Otherwise, resign the + /// address using the provided type. static RValue getAggregate(Address addr, bool isVolatile = false) { RValue ER; - ER.V1.setPointer(addr.getPointer()); - ER.V1.setInt(Aggregate); - ER.ElementType = addr.getElementType(); - - auto align = static_cast(addr.getAlignment().getQuantity()); - ER.V2.setPointer(reinterpret_cast(align << AggAlignShift)); - ER.V2.setInt(isVolatile); + ER.AggregateAddr = addr; + ER.Flavor = Aggregate; + ER.IsVolatile = isVolatile; return ER; } }; @@ -178,8 +188,10 @@ class LValue { MatrixElt // This is a matrix element, use getVector* } LVType; - llvm::Value *V; - llvm::Type *ElementType; + union { + Address Addr = Address::invalid(); + llvm::Value *V; + }; union { // Index into a vector subscript: V[i] @@ -197,10 +209,6 @@ class LValue { // 'const' is unused here Qualifiers Quals; - // The alignment to use when accessing this lvalue. (For vector elements, - // this is the alignment of the whole vector.) - unsigned Alignment; - // objective-c's ivar bool Ivar:1; @@ -234,23 +242,19 @@ class LValue { Expr *BaseIvarExp; private: - void Initialize(QualType Type, Qualifiers Quals, CharUnits Alignment, + void Initialize(QualType Type, Qualifiers Quals, Address Addr, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { - assert((!Alignment.isZero() || Type->isIncompleteType()) && - "initializing l-value with zero alignment!"); - if (isGlobalReg()) - assert(ElementType == nullptr && "Global reg does not store elem type"); - else - assert(ElementType != nullptr && "Must have elem type"); - this->Type = Type; this->Quals = Quals; const unsigned MaxAlign = 1U << 31; - this->Alignment = Alignment.getQuantity() <= MaxAlign - ? Alignment.getQuantity() - : MaxAlign; - assert(this->Alignment == Alignment.getQuantity() && - "Alignment exceeds allowed max!"); + CharUnits Alignment = Addr.getAlignment(); + assert((isGlobalReg() || !Alignment.isZero() || Type->isIncompleteType()) && + "initializing l-value with zero alignment!"); + if (Alignment.getQuantity() > MaxAlign) { + assert(false && "Alignment exceeds allowed max!"); + Alignment = CharUnits::fromQuantity(MaxAlign); + } + this->Addr = Addr; this->BaseInfo = BaseInfo; this->TBAAInfo = TBAAInfo; @@ -259,9 +263,20 @@ private: this->ImpreciseLifetime = false; this->Nontemporal = false; this->ThreadLocalRef = false; + this->IsKnownNonNull = false; this->BaseIvarExp = nullptr; } + void initializeSimpleLValue(Address Addr, QualType Type, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, + ASTContext &Context) { + Qualifiers QS = Type.getQualifiers(); + QS.setObjCGCAttr(Context.getObjCGCAttrKind(Type)); + LVType = Simple; + Initialize(Type, QS, Addr, BaseInfo, TBAAInfo); + assert(Addr.getBasePointer()->getType()->isPointerTy()); + } + public: bool isSimple() const { return LVType == Simple; } bool isVectorElt() const { return LVType == VectorElt; } @@ -328,8 +343,8 @@ public: LangAS getAddressSpace() const { return Quals.getAddressSpace(); } - CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); } - void setAlignment(CharUnits A) { Alignment = A.getQuantity(); } + CharUnits getAlignment() const { return Addr.getAlignment(); } + void setAlignment(CharUnits A) { Addr.setAlignment(A); } LValueBaseInfo getBaseInfo() const { return BaseInfo; } void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; } @@ -345,28 +360,32 @@ public: // simple lvalue llvm::Value *getPointer(CodeGenFunction &CGF) const { assert(isSimple()); - return V; + return Addr.getBasePointer(); } - Address getAddress(CodeGenFunction &CGF) const { - return Address(getPointer(CGF), ElementType, getAlignment(), - isKnownNonNull()); - } - void setAddress(Address address) { + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { assert(isSimple()); - V = address.getPointer(); - ElementType = address.getElementType(); - Alignment = address.getAlignment().getQuantity(); - IsKnownNonNull = address.isKnownNonNull(); + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; } + Address getAddress(CodeGenFunction &CGF) const { + // FIXME: remove parameter. + return Addr; + } + + void setAddress(Address address) { Addr = address; } + // vector elt lvalue Address getVectorAddress() const { - return Address(getVectorPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isVectorElt()); + return Addr; + } + llvm::Value *getRawVectorPointer(CodeGenFunction &CGF) const { + assert(isVectorElt()); + return Addr.emitRawPointer(CGF); } llvm::Value *getVectorPointer() const { assert(isVectorElt()); - return V; + return Addr.getBasePointer(); } llvm::Value *getVectorIdx() const { assert(isVectorElt()); @@ -374,12 +393,12 @@ public: } Address getMatrixAddress() const { - return Address(getMatrixPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isMatrixElt()); + return Addr; } llvm::Value *getMatrixPointer() const { assert(isMatrixElt()); - return V; + return Addr.getBasePointer(); } llvm::Value *getMatrixIdx() const { assert(isMatrixElt()); @@ -388,12 +407,12 @@ public: // extended vector elements. Address getExtVectorAddress() const { - return Address(getExtVectorPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isExtVectorElt()); + return Addr; } - llvm::Value *getExtVectorPointer() const { + llvm::Value *getRawExtVectorPointer(CodeGenFunction &CGF) const { assert(isExtVectorElt()); - return V; + return Addr.emitRawPointer(CGF); } llvm::Constant *getExtVectorElts() const { assert(isExtVectorElt()); @@ -402,10 +421,14 @@ public: // bitfield lvalue Address getBitFieldAddress() const { - return Address(getBitFieldPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isBitField()); + return Addr; + } + llvm::Value *getRawBitFieldPointer(CodeGenFunction &CGF) const { + assert(isBitField()); + return Addr.emitRawPointer(CGF); } - llvm::Value *getBitFieldPointer() const { assert(isBitField()); return V; } + const CGBitFieldInfo &getBitFieldInfo() const { assert(isBitField()); return *BitFieldInfo; @@ -414,18 +437,13 @@ public: // global register lvalue llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; } - static LValue MakeAddr(Address address, QualType type, ASTContext &Context, + static LValue MakeAddr(Address Addr, QualType type, ASTContext &Context, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { - Qualifiers qs = type.getQualifiers(); - qs.setObjCGCAttr(Context.getObjCGCAttrKind(type)); - LValue R; R.LVType = Simple; - assert(address.getPointer()->getType()->isPointerTy()); - R.V = address.getPointer(); - R.ElementType = address.getElementType(); - R.IsKnownNonNull = address.isKnownNonNull(); - R.Initialize(type, qs, address.getAlignment(), BaseInfo, TBAAInfo); + R.initializeSimpleLValue(Addr, type, BaseInfo, TBAAInfo, Context); + R.Addr = Addr; + assert(Addr.getType()->isPointerTy()); return R; } @@ -434,26 +452,18 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = VectorElt; - R.V = vecAddress.getPointer(); - R.ElementType = vecAddress.getElementType(); R.VectorIdx = Idx; - R.IsKnownNonNull = vecAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), vecAddress, BaseInfo, TBAAInfo); return R; } - static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts, + static LValue MakeExtVectorElt(Address Addr, llvm::Constant *Elts, QualType type, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = ExtVectorElt; - R.V = vecAddress.getPointer(); - R.ElementType = vecAddress.getElementType(); R.VectorElts = Elts; - R.IsKnownNonNull = vecAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), Addr, BaseInfo, TBAAInfo); return R; } @@ -468,12 +478,8 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = BitField; - R.V = Addr.getPointer(); - R.ElementType = Addr.getElementType(); R.BitFieldInfo = &Info; - R.IsKnownNonNull = Addr.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo, - TBAAInfo); + R.Initialize(type, type.getQualifiers(), Addr, BaseInfo, TBAAInfo); return R; } @@ -481,11 +487,9 @@ public: QualType type) { LValue R; R.LVType = GlobalReg; - R.V = V; - R.ElementType = nullptr; - R.IsKnownNonNull = true; - R.Initialize(type, type.getQualifiers(), alignment, + R.Initialize(type, type.getQualifiers(), Address::invalid(), LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo()); + R.V = V; return R; } @@ -494,12 +498,8 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = MatrixElt; - R.V = matAddress.getPointer(); - R.ElementType = matAddress.getElementType(); R.VectorIdx = Idx; - R.IsKnownNonNull = matAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), matAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), matAddress, BaseInfo, TBAAInfo); return R; } @@ -643,17 +643,17 @@ public: return NeedsGCBarriers_t(ObjCGCFlag); } - llvm::Value *getPointer() const { - return Addr.getPointer(); + llvm::Value *getPointer(QualType PointeeTy, CodeGenFunction &CGF) const; + + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; } Address getAddress() const { return Addr; } - bool isIgnored() const { - return !Addr.isValid(); - } + bool isIgnored() const { return !Addr.isValid(); } CharUnits getAlignment() const { return Addr.getAlignment(); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index f2ebaf7674523cbb609b5e0a08c40bccede37001..90324de7268ebe901e66b1c8048272064b097f73 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -193,26 +193,35 @@ CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() { CGF.Builder.setDefaultConstrainedRounding(OldRounding); } -LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { +static LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T, + bool ForPointeeType, + CodeGenFunction &CGF) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; - CharUnits Alignment = CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo); - Address Addr(V, ConvertTypeForMem(T), Alignment); - return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, TBAAInfo); + CharUnits Alignment = + CGF.CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, ForPointeeType); + Address Addr = Address(V, CGF.ConvertTypeForMem(T), Alignment); + return CGF.MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); +} + +LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); } -/// Given a value of type T* that may not be to a complete object, -/// construct an l-value with the natural pointee alignment of T. LValue CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) { - LValueBaseInfo BaseInfo; - TBAAAccessInfo TBAAInfo; - CharUnits Align = CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, - /* forPointeeType= */ true); - Address Addr(V, ConvertTypeForMem(T), Align); - return MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); +} + +LValue CodeGenFunction::MakeNaturalAlignRawAddrLValue(llvm::Value *V, + QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); } +LValue CodeGenFunction::MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, + QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); +} llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); @@ -267,6 +276,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { case Type::Record: case Type::ObjCObject: case Type::ObjCInterface: + case Type::ArrayParameter: return TEK_Aggregate; // We operate on atomic values according to their underlying type. @@ -525,7 +535,8 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { ReturnBlock.getBlock()->eraseFromParent(); } if (ReturnValue.isValid()) { - auto *RetAlloca = dyn_cast(ReturnValue.getPointer()); + auto *RetAlloca = + dyn_cast(ReturnValue.emitRawPointer(*this)); if (RetAlloca && RetAlloca->use_empty()) { RetAlloca->eraseFromParent(); ReturnValue = Address::invalid(); @@ -1122,13 +1133,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, auto AI = CurFn->arg_begin(); if (CurFnInfo->getReturnInfo().isSRetAfterThis()) ++AI; - ReturnValue = - Address(&*AI, ConvertType(RetTy), - CurFnInfo->getReturnInfo().getIndirectAlign(), KnownNonNull); + ReturnValue = makeNaturalAddressForPointer( + &*AI, RetTy, CurFnInfo->getReturnInfo().getIndirectAlign(), false, + nullptr, nullptr, KnownNonNull); if (!CurFnInfo->getReturnInfo().getIndirectByVal()) { - ReturnValuePointer = CreateDefaultAlignTempAlloca( - ReturnValue.getPointer()->getType(), "result.ptr"); - Builder.CreateStore(ReturnValue.getPointer(), ReturnValuePointer); + ReturnValuePointer = + CreateDefaultAlignTempAlloca(ReturnValue.getType(), "result.ptr"); + Builder.CreateStore(ReturnValue.emitRawPointer(*this), + ReturnValuePointer); } } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca && !hasScalarEvaluationKind(CurFnInfo->getReturnType())) { @@ -1189,8 +1201,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // or contains the address of the enclosing object). LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { - // If the enclosing object was captured by value, just use its address. - CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); + // If the enclosing object was captured by value, just use its + // address. Sign this pointer. + CXXThisValue = ThisFieldLValue.getPointer(*this); } else { // Load the lvalue pointed to by the field, since '*this' was captured // by reference. @@ -2012,8 +2025,9 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, = llvm::ConstantInt::get(CGF.IntPtrTy, baseSize.getQuantity()); Address begin = dest.withElementType(CGF.Int8Ty); - llvm::Value *end = Builder.CreateInBoundsGEP( - begin.getElementType(), begin.getPointer(), sizeInChars, "vla.end"); + llvm::Value *end = Builder.CreateInBoundsGEP(begin.getElementType(), + begin.emitRawPointer(CGF), + sizeInChars, "vla.end"); llvm::BasicBlock *originBB = CGF.Builder.GetInsertBlock(); llvm::BasicBlock *loopBB = CGF.createBasicBlock("vla-init.loop"); @@ -2024,7 +2038,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, CGF.EmitBlock(loopBB); llvm::PHINode *cur = Builder.CreatePHI(begin.getType(), 2, "vla.cur"); - cur->addIncoming(begin.getPointer(), originBB); + cur->addIncoming(begin.emitRawPointer(CGF), originBB); CharUnits curAlign = dest.getAlignment().alignmentOfArrayElement(baseSize); @@ -2217,10 +2231,10 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, addr = addr.withElementType(baseType); } else { // Create the actual GEP. - addr = Address(Builder.CreateInBoundsGEP( - addr.getElementType(), addr.getPointer(), gepIndices, "array.begin"), - ConvertTypeForMem(eltType), - addr.getAlignment()); + addr = Address(Builder.CreateInBoundsGEP(addr.getElementType(), + addr.emitRawPointer(*this), + gepIndices, "array.begin"), + ConvertTypeForMem(eltType), addr.getAlignment()); } baseType = eltType; @@ -2348,6 +2362,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { type = cast(ty)->getPointeeType(); break; + case Type::ArrayParameter: case Type::ConstantArray: case Type::IncompleteArray: // Losing element qualification here is fine. @@ -2561,7 +2576,7 @@ void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) { Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D, Address Addr) { assert(D->hasAttr() && "no annotate attribute"); - llvm::Value *V = Addr.getPointer(); + llvm::Value *V = Addr.emitRawPointer(*this); llvm::Type *VTy = V->getType(); auto *PTy = dyn_cast(VTy); unsigned AS = PTy ? PTy->getAddressSpace() : 0; diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e8f8aa601ed017b559d2b87548110423e5c78107..e2a7e28c8211ea7fd399aa0063f2cb7e9a0f3073 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -151,6 +151,9 @@ struct DominatingLLVMValue { /// Answer whether the given value needs extra work to be saved. static bool needsSaving(llvm::Value *value) { + if (!value) + return false; + // If it's not an instruction, we don't need to save. if (!isa(value)) return false; @@ -177,21 +180,28 @@ template <> struct DominatingValue
{ typedef Address type; struct saved_type { - DominatingLLVMValue::saved_type SavedValue; + DominatingLLVMValue::saved_type BasePtr; llvm::Type *ElementType; CharUnits Alignment; + DominatingLLVMValue::saved_type Offset; + llvm::PointerType *EffectiveType; }; static bool needsSaving(type value) { - return DominatingLLVMValue::needsSaving(value.getPointer()); + if (DominatingLLVMValue::needsSaving(value.getBasePointer()) || + DominatingLLVMValue::needsSaving(value.getOffset())) + return true; + return false; } static saved_type save(CodeGenFunction &CGF, type value) { - return { DominatingLLVMValue::save(CGF, value.getPointer()), - value.getElementType(), value.getAlignment() }; + return {DominatingLLVMValue::save(CGF, value.getBasePointer()), + value.getElementType(), value.getAlignment(), + DominatingLLVMValue::save(CGF, value.getOffset()), value.getType()}; } static type restore(CodeGenFunction &CGF, saved_type value) { - return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), - value.ElementType, value.Alignment); + return Address(DominatingLLVMValue::restore(CGF, value.BasePtr), + value.ElementType, value.Alignment, + DominatingLLVMValue::restore(CGF, value.Offset)); } }; @@ -201,14 +211,26 @@ template <> struct DominatingValue { class saved_type { enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, AggregateAddress, ComplexAddress }; - - llvm::Value *Value; - llvm::Type *ElementType; + union { + struct { + DominatingLLVMValue::saved_type first, second; + } Vals; + DominatingValue
::saved_type AggregateAddr; + }; LLVM_PREFERRED_TYPE(Kind) unsigned K : 3; - unsigned Align : 29; - saved_type(llvm::Value *v, llvm::Type *e, Kind k, unsigned a = 0) - : Value(v), ElementType(e), K(k), Align(a) {} + unsigned IsVolatile : 1; + + saved_type(DominatingLLVMValue::saved_type Val1, unsigned K) + : Vals{Val1, DominatingLLVMValue::saved_type()}, K(K) {} + + saved_type(DominatingLLVMValue::saved_type Val1, + DominatingLLVMValue::saved_type Val2) + : Vals{Val1, Val2}, K(ComplexAddress) {} + + saved_type(DominatingValue
::saved_type AggregateAddr, + bool IsVolatile, unsigned K) + : AggregateAddr(AggregateAddr), K(K) {} public: static bool needsSaving(RValue value); @@ -659,7 +681,7 @@ public: llvm::Value *Size; public: - CallLifetimeEnd(Address addr, llvm::Value *size) + CallLifetimeEnd(RawAddress addr, llvm::Value *size) : Addr(addr.getPointer()), Size(size) {} void Emit(CodeGenFunction &CGF, Flags flags) override { @@ -684,7 +706,7 @@ public: }; /// i32s containing the indexes of the cleanup destinations. - Address NormalCleanupDest = Address::invalid(); + RawAddress NormalCleanupDest = RawAddress::invalid(); unsigned NextCleanupDestIndex = 1; @@ -819,10 +841,10 @@ public: template void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) { if (!isInConditionalBranch()) - return pushCleanupAfterFullExprWithActiveFlag(Kind, Address::invalid(), - A...); + return pushCleanupAfterFullExprWithActiveFlag( + Kind, RawAddress::invalid(), A...); - Address ActiveFlag = createCleanupActiveFlag(); + RawAddress ActiveFlag = createCleanupActiveFlag(); assert(!DominatingValue
::needsSaving(ActiveFlag) && "cleanup active flag should never need saving"); @@ -835,7 +857,7 @@ public: template void pushCleanupAfterFullExprWithActiveFlag(CleanupKind Kind, - Address ActiveFlag, As... A) { + RawAddress ActiveFlag, As... A) { LifetimeExtendedCleanupHeader Header = {sizeof(T), Kind, ActiveFlag.isValid()}; @@ -850,7 +872,7 @@ public: new (Buffer) LifetimeExtendedCleanupHeader(Header); new (Buffer + sizeof(Header)) T(A...); if (Header.IsConditional) - new (Buffer + sizeof(Header) + sizeof(T)) Address(ActiveFlag); + new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag); } /// Set up the last cleanup that was pushed as a conditional @@ -859,8 +881,8 @@ public: initFullExprCleanupWithFlag(createCleanupActiveFlag()); } - void initFullExprCleanupWithFlag(Address ActiveFlag); - Address createCleanupActiveFlag(); + void initFullExprCleanupWithFlag(RawAddress ActiveFlag); + RawAddress createCleanupActiveFlag(); /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the @@ -1048,7 +1070,7 @@ public: QualType VarTy = LocalVD->getType(); if (VarTy->isReferenceType()) { Address Temp = CGF.CreateMemTemp(VarTy); - CGF.Builder.CreateStore(TempAddr.getPointer(), Temp); + CGF.Builder.CreateStore(TempAddr.emitRawPointer(CGF), Temp); TempAddr = Temp; } SavedTempAddresses.try_emplace(LocalVD, TempAddr); @@ -1243,10 +1265,12 @@ public: /// one branch or the other of a conditional expression. bool isInConditionalBranch() const { return OutermostConditional != nullptr; } - void setBeforeOutermostConditional(llvm::Value *value, Address addr) { + void setBeforeOutermostConditional(llvm::Value *value, Address addr, + CodeGenFunction &CGF) { assert(isInConditionalBranch()); llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); - auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back()); + auto store = + new llvm::StoreInst(value, addr.emitRawPointer(CGF), &block->back()); store->setAlignment(addr.getAlignment().getAsAlign()); } @@ -1601,7 +1625,7 @@ public: /// If \p StepV is null, the default increment is 1. void maybeUpdateMCDCTestVectorBitmap(const Expr *E) { if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) { - PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr); + PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr, *this); PGO.setCurrentStmt(E); } } @@ -1609,7 +1633,7 @@ public: /// Update the MCDC temp value with the condition's evaluated result. void maybeUpdateMCDCCondBitmap(const Expr *E, llvm::Value *Val) { if (isMCDCCoverageEnabled()) { - PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val); + PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val, *this); PGO.setCurrentStmt(E); } } @@ -1704,7 +1728,7 @@ public: : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue), OldCXXThisAlignment(CGF.CXXThisAlignment), SourceLocScope(E, CGF.CurSourceLocExprScope) { - CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer(); + CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getBasePointer(); CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment(); } ~CXXDefaultInitExprScope() { @@ -2090,7 +2114,7 @@ public: llvm::Value *getExceptionFromSlot(); llvm::Value *getSelectorFromSlot(); - Address getNormalCleanupDestSlot(); + RawAddress getNormalCleanupDestSlot(); llvm::BasicBlock *getUnreachableBlock() { if (!UnreachableBlock) { @@ -2579,10 +2603,40 @@ public: // Helpers //===--------------------------------------------------------------------===// + Address mergeAddressesInConditionalExpr(Address LHS, Address RHS, + llvm::BasicBlock *LHSBlock, + llvm::BasicBlock *RHSBlock, + llvm::BasicBlock *MergeBlock, + QualType MergedType) { + Builder.SetInsertPoint(MergeBlock); + llvm::PHINode *PtrPhi = Builder.CreatePHI(LHS.getType(), 2, "cond"); + PtrPhi->addIncoming(LHS.getBasePointer(), LHSBlock); + PtrPhi->addIncoming(RHS.getBasePointer(), RHSBlock); + LHS.replaceBasePointer(PtrPhi); + LHS.setAlignment(std::min(LHS.getAlignment(), RHS.getAlignment())); + return LHS; + } + + /// Construct an address with the natural alignment of T. If a pointer to T + /// is expected to be signed, the pointer passed to this function must have + /// been signed, and the returned Address will have the pointer authentication + /// information needed to authenticate the signed pointer. + Address makeNaturalAddressForPointer( + llvm::Value *Ptr, QualType T, CharUnits Alignment = CharUnits::Zero(), + bool ForPointeeType = false, LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) { + if (Alignment.isZero()) + Alignment = + CGM.getNaturalTypeAlignment(T, BaseInfo, TBAAInfo, ForPointeeType); + return Address(Ptr, ConvertTypeForMem(T), Alignment, nullptr, + IsKnownNonNull); + } + LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source = AlignmentSource::Type) { - return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source), - CGM.getTBAAAccessInfo(T)); + return MakeAddrLValue(Addr, T, LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(T)); } LValue MakeAddrLValue(Address Addr, QualType T, LValueBaseInfo BaseInfo, @@ -2592,6 +2646,14 @@ public: LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, AlignmentSource Source = AlignmentSource::Type) { + return MakeAddrLValue(makeNaturalAddressForPointer(V, T, Alignment), T, + LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T)); + } + + /// Same as MakeAddrLValue above except that the pointer is known to be + /// unsigned. + LValue MakeRawAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, + AlignmentSource Source = AlignmentSource::Type) { Address Addr(V, ConvertTypeForMem(T), Alignment); return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T)); @@ -2604,9 +2666,18 @@ public: TBAAAccessInfo()); } + /// Given a value of type T* that may not be to a complete object, construct + /// an l-value with the natural pointee alignment of T. LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T); + LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); + /// Same as MakeNaturalAlignPointeeAddrLValue except that the pointer is known + /// to be unsigned. + LValue MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, QualType T); + + LValue MakeNaturalAlignRawAddrLValue(llvm::Value *V, QualType T); + Address EmitLoadOfReference(LValue RefLVal, LValueBaseInfo *PointeeBaseInfo = nullptr, TBAAAccessInfo *PointeeTBAAInfo = nullptr); @@ -2655,13 +2726,13 @@ public: /// more efficient if the caller knows that the address will not be exposed. llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp", llvm::Value *ArraySize = nullptr); - Address CreateTempAlloca(llvm::Type *Ty, CharUnits align, - const Twine &Name = "tmp", - llvm::Value *ArraySize = nullptr, - Address *Alloca = nullptr); - Address CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits align, - const Twine &Name = "tmp", - llvm::Value *ArraySize = nullptr); + RawAddress CreateTempAlloca(llvm::Type *Ty, CharUnits align, + const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr, + RawAddress *Alloca = nullptr); + RawAddress CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits align, + const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr); /// CreateDefaultAlignedTempAlloca - This creates an alloca with the /// default ABI alignment of the given LLVM type. @@ -2673,8 +2744,8 @@ public: /// not hand this address off to arbitrary IRGen routines, and especially /// do not pass it as an argument to a function that might expect a /// properly ABI-aligned value. - Address CreateDefaultAlignTempAlloca(llvm::Type *Ty, - const Twine &Name = "tmp"); + RawAddress CreateDefaultAlignTempAlloca(llvm::Type *Ty, + const Twine &Name = "tmp"); /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary @@ -2684,32 +2755,31 @@ public: /// /// That is, this is exactly equivalent to CreateMemTemp, but calling /// ConvertType instead of ConvertTypeForMem. - Address CreateIRTemp(QualType T, const Twine &Name = "tmp"); + RawAddress CreateIRTemp(QualType T, const Twine &Name = "tmp"); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignmen and cast it to the default address space. Returns /// the original alloca instruction by \p Alloca if it is not nullptr. - Address CreateMemTemp(QualType T, const Twine &Name = "tmp", - Address *Alloca = nullptr); - Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp", - Address *Alloca = nullptr); + RawAddress CreateMemTemp(QualType T, const Twine &Name = "tmp", + RawAddress *Alloca = nullptr); + RawAddress CreateMemTemp(QualType T, CharUnits Align, + const Twine &Name = "tmp", + RawAddress *Alloca = nullptr); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignmen without casting it to the default address space. - Address CreateMemTempWithoutCast(QualType T, const Twine &Name = "tmp"); - Address CreateMemTempWithoutCast(QualType T, CharUnits Align, - const Twine &Name = "tmp"); + RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name = "tmp"); + RawAddress CreateMemTempWithoutCast(QualType T, CharUnits Align, + const Twine &Name = "tmp"); /// CreateAggTemp - Create a temporary memory object for the given /// aggregate type. AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp", - Address *Alloca = nullptr) { - return AggValueSlot::forAddr(CreateMemTemp(T, Name, Alloca), - T.getQualifiers(), - AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap); + RawAddress *Alloca = nullptr) { + return AggValueSlot::forAddr( + CreateMemTemp(T, Name, Alloca), T.getQualifiers(), + AggValueSlot::IsNotDestructed, AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap); } /// EvaluateExprAsBool - Perform the usual unary conversions on the specified @@ -3083,6 +3153,25 @@ public: /// calls to EmitTypeCheck can be skipped. bool sanitizePerformTypeCheck() const; + void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, LValue LV, + QualType Type, SanitizerSet SkippedChecks = SanitizerSet(), + llvm::Value *ArraySize = nullptr) { + if (!sanitizePerformTypeCheck()) + return; + EmitTypeCheck(TCK, Loc, LV.emitRawPointer(*this), Type, LV.getAlignment(), + SkippedChecks, ArraySize); + } + + void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, Address Addr, + QualType Type, CharUnits Alignment = CharUnits::Zero(), + SanitizerSet SkippedChecks = SanitizerSet(), + llvm::Value *ArraySize = nullptr) { + if (!sanitizePerformTypeCheck()) + return; + EmitTypeCheck(TCK, Loc, Addr.emitRawPointer(*this), Type, Alignment, + SkippedChecks, ArraySize); + } + /// Emit a check that \p V is the address of storage of the /// appropriate size and alignment for an object of type \p Type /// (or if ArraySize is provided, for an array of that bound). @@ -3183,17 +3272,17 @@ public: /// Address with original alloca instruction. Invalid if the variable was /// emitted as a global constant. - Address AllocaAddr; + RawAddress AllocaAddr; struct Invalid {}; AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()), - AllocaAddr(Address::invalid()) {} + AllocaAddr(RawAddress::invalid()) {} AutoVarEmission(const VarDecl &variable) : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), IsEscapingByRef(false), IsConstantAggregate(false), - SizeForLifetimeMarkers(nullptr), AllocaAddr(Address::invalid()) {} + SizeForLifetimeMarkers(nullptr), AllocaAddr(RawAddress::invalid()) {} bool wasEmittedAsGlobal() const { return !Addr.isValid(); } @@ -3216,7 +3305,7 @@ public: } /// Returns the address for the original alloca instruction. - Address getOriginalAllocatedAddress() const { return AllocaAddr; } + RawAddress getOriginalAllocatedAddress() const { return AllocaAddr; } /// Returns the address of the object within this declaration. /// Note that this does not chase the forwarding pointer for @@ -3246,23 +3335,32 @@ public: llvm::GlobalValue::LinkageTypes Linkage); class ParamValue { - llvm::Value *Value; - llvm::Type *ElementType; - unsigned Alignment; - ParamValue(llvm::Value *V, llvm::Type *T, unsigned A) - : Value(V), ElementType(T), Alignment(A) {} + union { + Address Addr; + llvm::Value *Value; + }; + + bool IsIndirect; + + ParamValue(llvm::Value *V) : Value(V), IsIndirect(false) {} + ParamValue(Address A) : Addr(A), IsIndirect(true) {} + public: static ParamValue forDirect(llvm::Value *value) { - return ParamValue(value, nullptr, 0); + return ParamValue(value); } static ParamValue forIndirect(Address addr) { assert(!addr.getAlignment().isZero()); - return ParamValue(addr.getPointer(), addr.getElementType(), - addr.getAlignment().getQuantity()); + return ParamValue(addr); } - bool isIndirect() const { return Alignment != 0; } - llvm::Value *getAnyValue() const { return Value; } + bool isIndirect() const { return IsIndirect; } + llvm::Value *getAnyValue() const { + if (!isIndirect()) + return Value; + assert(!Addr.hasOffset() && "unexpected offset"); + return Addr.getBasePointer(); + } llvm::Value *getDirectValue() const { assert(!isIndirect()); @@ -3271,8 +3369,7 @@ public: Address getIndirectAddress() const { assert(isIndirect()); - return Address(Value, ElementType, CharUnits::fromQuantity(Alignment), - KnownNonNull); + return Addr; } }; @@ -4182,6 +4279,9 @@ public: const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, const Twine &name = ""); + llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, + ArrayRef
args, + const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, ArrayRef args, const Twine &name = ""); @@ -4208,6 +4308,12 @@ public: CXXDtorType Type, const CXXRecordDecl *RD); + llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) { + return Addr.getBasePointer(); + } + + bool isPointerKnownNonNull(const Expr *E); + // Return the copy constructor name with the prefix "__copy_constructor_" // removed. static std::string getNonTrivialCopyConstructorStr(QualType QT, @@ -4780,6 +4886,11 @@ public: SourceLocation Loc, const Twine &Name = ""); + Address EmitCheckedInBoundsGEP(Address Addr, ArrayRef IdxList, + llvm::Type *elementType, bool SignedIndices, + bool IsSubtraction, SourceLocation Loc, + CharUnits Align, const Twine &Name = ""); + /// Specifies which type of sanitizer check to apply when handling a /// particular builtin. enum BuiltinCheckKind { @@ -4842,6 +4953,10 @@ public: void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, AbstractCallee AC, unsigned ParmNum); + void EmitNonNullArgCheck(Address Addr, QualType ArgType, + SourceLocation ArgLoc, AbstractCallee AC, + unsigned ParmNum); + /// EmitCallArg - Emit a single call argument. void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); @@ -4870,6 +4985,25 @@ public: llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec, unsigned NumElementsDst, const llvm::Twine &Name = ""); + // Adds a convergence_ctrl token to |Input| and emits the required parent + // convergence instructions. + llvm::CallBase *addControlledConvergenceToken(llvm::CallBase *Input); + +private: + // Emits a convergence_loop instruction for the given |BB|, with |ParentToken| + // as it's parent convergence instr. + llvm::IntrinsicInst *emitConvergenceLoopToken(llvm::BasicBlock *BB, + llvm::Value *ParentToken); + // Adds a convergence_ctrl token with |ParentToken| as parent convergence + // instr to the call |Input|. + llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input, + llvm::Value *ParentToken); + // Find the convergence_entry instruction |F|, or emits ones if none exists. + // Returns the convergence instruction. + llvm::IntrinsicInst *getOrEmitConvergenceEntryToken(llvm::Function *F); + // Find the convergence_loop instruction for the loop defined by |LI|, or + // emits one if none exists. Returns the convergence instruction. + llvm::IntrinsicInst *getOrEmitConvergenceLoopToken(const LoopInfo *LI); private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); @@ -5050,7 +5184,7 @@ DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) { CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save"); CGF.Builder.CreateStore(value, alloca); - return saved_type(alloca.getPointer(), true); + return saved_type(alloca.emitRawPointer(CGF), true); } inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index e3ed5e90f2d36b58dee610d1e5f482a39f3b23e2..00b3bfcaa0bc2565862d659b122b1caf18ff0599 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7267,7 +7267,7 @@ void CodeGenFunction::EmitDeclMetadata() { for (auto &I : LocalDeclMap) { const Decl *D = I.first; - llvm::Value *Addr = I.second.getPointer(); + llvm::Value *Addr = I.second.emitRawPointer(*this); if (auto *Alloca = dyn_cast(Addr)) { llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); Alloca->setMetadata( diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 2619edfeb7dc76c3e482b3c2da13dfdca1afc74d..76704c4d7be4a49de647c9f64aac615724215bb7 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -1239,7 +1239,8 @@ void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) { void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr) { + Address MCDCCondBitmapAddr, + CodeGenFunction &CGF) { if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState) return; @@ -1262,7 +1263,7 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, Builder.getInt64(FunctionHash), Builder.getInt32(RegionMCDCState->BitmapBytes), Builder.getInt32(MCDCTestVectorBitmapOffset), - MCDCCondBitmapAddr.getPointer()}; + MCDCCondBitmapAddr.emitRawPointer(CGF)}; Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args); } @@ -1283,7 +1284,8 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S, void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr, - llvm::Value *Val) { + llvm::Value *Val, + CodeGenFunction &CGF) { if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState) return; @@ -1312,7 +1314,7 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy), Builder.getInt64(FunctionHash), Builder.getInt32(Branch.ID), - MCDCCondBitmapAddr.getPointer(), Val}; + MCDCCondBitmapAddr.emitRawPointer(CGF), Val}; Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update), Args); diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h index 036fbf6815a49da500970580c8ed6057bc317847..9d66ffad6f43509e991ca87c3605c94e27ea8833 100644 --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -113,12 +113,14 @@ public: void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S, llvm::Value *StepV); void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr); + Address MCDCCondBitmapAddr, + CodeGenFunction &CGF); void emitMCDCParameters(CGBuilderTy &Builder); void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr); void emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr, llvm::Value *Val); + Address MCDCCondBitmapAddr, llvm::Value *Val, + CodeGenFunction &CGF); /// Return the region count for the counter at the given index. uint64_t getRegionCount(const Stmt *S) { diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index afadc29ab1b02761b79071484419d78f5b2f408f..1568b6e6275b9dee1c65a56f872f2897c24cba0f 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -590,6 +590,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { ResultType = llvm::ArrayType::get(ResultType, 0); break; } + case Type::ArrayParameter: case Type::ConstantArray: { const ConstantArrayType *A = cast(Ty); llvm::Type *EltTy = ConvertTypeForMem(A->getElementType()); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index bdd53a192f828adbe2999a7f54d3d805c4892146..18acf7784f714b4c8d083c086185efd1e45bdec2 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -307,10 +307,6 @@ public: CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, const CXXRecordDecl *NearestVBase); - llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) override; - llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; @@ -646,7 +642,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( // Apply the adjustment and cast back to the original struct type // for consistency. - llvm::Value *This = ThisAddr.getPointer(); + llvm::Value *This = ThisAddr.emitRawPointer(CGF); This = Builder.CreateInBoundsGEP(Builder.getInt8Ty(), This, Adj); ThisPtrForCall = This; @@ -850,7 +846,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress( CGBuilderTy &Builder = CGF.Builder; // Apply the offset, which we assume is non-null. - return Builder.CreateInBoundsGEP(CGF.Int8Ty, Base.getPointer(), MemPtr, + return Builder.CreateInBoundsGEP(CGF.Int8Ty, Base.emitRawPointer(CGF), MemPtr, "memptr.offset"); } @@ -1245,7 +1241,7 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, CGF.getPointerAlign()); // Apply the offset. - llvm::Value *CompletePtr = Ptr.getPointer(); + llvm::Value *CompletePtr = Ptr.emitRawPointer(CGF); CompletePtr = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, CompletePtr, Offset); @@ -1482,7 +1478,8 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall( computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity()); // Emit the call to __dynamic_cast. - llvm::Value *Args[] = {ThisAddr.getPointer(), SrcRTTI, DestRTTI, OffsetHint}; + llvm::Value *Args[] = {ThisAddr.emitRawPointer(CGF), SrcRTTI, DestRTTI, + OffsetHint}; llvm::Value *Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), Args); @@ -1571,7 +1568,7 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast( VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy)); llvm::Value *Success = CGF.Builder.CreateICmpEQ( VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl)); - llvm::Value *Result = ThisAddr.getPointer(); + llvm::Value *Result = ThisAddr.emitRawPointer(CGF); if (!Offset->isZero()) Result = CGF.Builder.CreateInBoundsGEP( CGF.CharTy, Result, @@ -1611,7 +1608,7 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, PtrDiffLTy, OffsetToTop, CGF.getPointerAlign(), "offset.to.top"); } // Finally, add the offset to the pointer. - return CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ThisAddr.getPointer(), + return CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ThisAddr.emitRawPointer(CGF), OffsetToTop); } @@ -1792,8 +1789,8 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF, else Callee = CGCallee::forDirect(CGM.getAddrOfCXXStructor(GD), GD); - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, VTT, VTTTy, - nullptr); + CGF.EmitCXXDestructorCall(GD, Callee, CGF.getAsNaturalPointerTo(This, ThisTy), + ThisTy, VTT, VTTTy, nullptr); } void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, @@ -1952,11 +1949,6 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CGF.getPointerAlign()); } -llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr( - BaseSubobject Base, const CXXRecordDecl *VTableClass) { - return getVTableAddressPoint(Base, VTableClass); -} - llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) { assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets"); @@ -2088,8 +2080,8 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( ThisTy = D->getDestroyedType(); } - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, nullptr, - QualType(), nullptr); + CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, + nullptr, QualType(), nullptr); return nullptr; } @@ -2162,7 +2154,7 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, int64_t VirtualAdjustment, bool IsReturnAdjustment) { if (!NonVirtualAdjustment && !VirtualAdjustment) - return InitialPtr.getPointer(); + return InitialPtr.emitRawPointer(CGF); Address V = InitialPtr.withElementType(CGF.Int8Ty); @@ -2195,10 +2187,10 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, CGF.getPointerAlign()); } // Adjust our pointer. - ResultPtr = CGF.Builder.CreateInBoundsGEP( - V.getElementType(), V.getPointer(), Offset); + ResultPtr = CGF.Builder.CreateInBoundsGEP(V.getElementType(), + V.emitRawPointer(CGF), Offset); } else { - ResultPtr = V.getPointer(); + ResultPtr = V.emitRawPointer(CGF); } // In a derived-to-base conversion, the non-virtual adjustment is @@ -2284,7 +2276,7 @@ Address ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::FunctionType::get(CGM.VoidTy, NumElementsPtr.getType(), false); llvm::FunctionCallee F = CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie"); - CGF.Builder.CreateCall(F, NumElementsPtr.getPointer()); + CGF.Builder.CreateCall(F, NumElementsPtr.emitRawPointer(CGF)); } // Finally, compute a pointer to the actual data buffer by skipping @@ -2315,7 +2307,7 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, llvm::FunctionType::get(CGF.SizeTy, CGF.UnqualPtrTy, false); llvm::FunctionCallee F = CGM.CreateRuntimeFunction(FTy, "__asan_load_cxx_array_cookie"); - return CGF.Builder.CreateCall(F, numElementsPtr.getPointer()); + return CGF.Builder.CreateCall(F, numElementsPtr.emitRawPointer(CGF)); } CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { @@ -2627,7 +2619,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // Call __cxa_guard_release. This cannot throw. CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy), - guardAddr.getPointer()); + guardAddr.emitRawPointer(CGF)); } else if (D.isLocalVarDecl()) { // For local variables, store 1 into the first byte of the guard variable // after the object initialization completes so that initialization is @@ -3120,10 +3112,10 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, LValue LV; if (VD->getType()->isReferenceType()) - LV = CGF.MakeNaturalAlignAddrLValue(CallVal, LValType); + LV = CGF.MakeNaturalAlignRawAddrLValue(CallVal, LValType); else - LV = CGF.MakeAddrLValue(CallVal, LValType, - CGF.getContext().getDeclAlign(VD)); + LV = CGF.MakeRawAddrLValue(CallVal, LValType, + CGF.getContext().getDeclAlign(VD)); // FIXME: need setObjCGCLValueClass? return LV; } @@ -3592,6 +3584,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::Pipe: llvm_unreachable("Pipe types shouldn't get here"); + case Type::ArrayParameter: + llvm_unreachable("Array Parameter types should not get here."); + case Type::Builtin: case Type::BitInt: // GCC treats vector and complex types as fundamental types. @@ -3876,6 +3871,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: // Itanium C++ ABI 2.9.5p5: // abi::__array_type_info adds no data members to std::type_info. break; @@ -4604,7 +4600,7 @@ static void InitCatchParam(CodeGenFunction &CGF, CGF.Builder.CreateStore(Casted, ExnPtrTmp); // Bind the reference to the temporary. - AdjustedExn = ExnPtrTmp.getPointer(); + AdjustedExn = ExnPtrTmp.emitRawPointer(CGF); } } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 172c4c937b97280d30ca5689ec58b600a852a809..d38a26940a3cb613a29557019f92b60b49cb7a9e 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -327,10 +327,6 @@ public: CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, const CXXRecordDecl *NearestVBase) override; - llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) override; - llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; @@ -937,7 +933,7 @@ void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF, } CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam); - CPI->setArgOperand(2, var.getObjectAddress(CGF).getPointer()); + CPI->setArgOperand(2, var.getObjectAddress(CGF).emitRawPointer(CGF)); CGF.EHStack.pushCleanup(NormalCleanup, CPI); CGF.EmitAutoVarCleanups(var); } @@ -974,7 +970,7 @@ MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, llvm::Value *Offset = GetVirtualBaseClassOffset(CGF, Value, SrcDecl, PolymorphicBase); llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP( - Value.getElementType(), Value.getPointer(), Offset); + Value.getElementType(), Value.emitRawPointer(CGF), Offset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Value.getAlignment(), SrcDecl, PolymorphicBase); return std::make_tuple(Address(Ptr, CGF.Int8Ty, VBaseAlign), Offset, @@ -1011,7 +1007,7 @@ llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF, llvm::Type *StdTypeInfoPtrTy) { std::tie(ThisPtr, std::ignore, std::ignore) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy); - llvm::CallBase *Typeid = emitRTtypeidCall(CGF, ThisPtr.getPointer()); + llvm::CallBase *Typeid = emitRTtypeidCall(CGF, ThisPtr.emitRawPointer(CGF)); return CGF.Builder.CreateBitCast(Typeid, StdTypeInfoPtrTy); } @@ -1033,7 +1029,7 @@ llvm::Value *MicrosoftCXXABI::emitDynamicCastCall( llvm::Value *Offset; std::tie(This, Offset, std::ignore) = performBaseAdjustment(CGF, This, SrcRecordTy); - llvm::Value *ThisPtr = This.getPointer(); + llvm::Value *ThisPtr = This.emitRawPointer(CGF); Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty); // PVOID __RTDynamicCast( @@ -1065,7 +1061,7 @@ llvm::Value *MicrosoftCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, llvm::FunctionCallee Function = CGF.CGM.CreateRuntimeFunction( llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false), "__RTCastToVoid"); - llvm::Value *Args[] = {Value.getPointer()}; + llvm::Value *Args[] = {Value.emitRawPointer(CGF)}; return CGF.EmitRuntimeCall(Function, Args); } @@ -1493,7 +1489,7 @@ Address MicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall( llvm::Value *VBaseOffset = GetVirtualBaseClassOffset(CGF, Result, Derived, VBase); llvm::Value *VBasePtr = CGF.Builder.CreateInBoundsGEP( - Result.getElementType(), Result.getPointer(), VBaseOffset); + Result.getElementType(), Result.emitRawPointer(CGF), VBaseOffset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Result.getAlignment(), Derived, VBase); Result = Address(VBasePtr, CGF.Int8Ty, VBaseAlign); @@ -1660,7 +1656,8 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF, llvm::Value *Implicit = getCXXDestructorImplicitParam(CGF, DD, Type, ForVirtualBase, Delegating); // = nullptr - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, + CGF.EmitCXXDestructorCall(GD, Callee, CGF.getAsNaturalPointerTo(This, ThisTy), + ThisTy, /*ImplicitParam=*/Implicit, /*ImplicitParamTy=*/QualType(), nullptr); if (BaseDtorEndBB) { @@ -1791,13 +1788,6 @@ MicrosoftCXXABI::getVTableAddressPoint(BaseSubobject Base, return VFTablesMap[ID]; } -llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr( - BaseSubobject Base, const CXXRecordDecl *VTableClass) { - llvm::Constant *VFTable = getVTableAddressPoint(Base, VTableClass); - assert(VFTable && "Couldn't find a vftable for the given base?"); - return VFTable; -} - llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) { // getAddrOfVTable may return 0 if asked to get an address of a vtable which @@ -2013,8 +2003,9 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( } This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true); - RValue RV = CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, - ImplicitParam, Context.IntTy, CE); + RValue RV = + CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, + ImplicitParam, Context.IntTy, CE); return RV.getScalarVal(); } @@ -2212,13 +2203,13 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, Address This, const ThisAdjustment &TA) { if (TA.isEmpty()) - return This.getPointer(); + return This.emitRawPointer(CGF); This = This.withElementType(CGF.Int8Ty); llvm::Value *V; if (TA.Virtual.isEmpty()) { - V = This.getPointer(); + V = This.emitRawPointer(CGF); } else { assert(TA.Virtual.Microsoft.VtordispOffset < 0); // Adjust the this argument based on the vtordisp value. @@ -2227,7 +2218,7 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, CharUnits::fromQuantity(TA.Virtual.Microsoft.VtordispOffset)); VtorDispPtr = VtorDispPtr.withElementType(CGF.Int32Ty); llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp"); - V = CGF.Builder.CreateGEP(This.getElementType(), This.getPointer(), + V = CGF.Builder.CreateGEP(This.getElementType(), This.emitRawPointer(CGF), CGF.Builder.CreateNeg(VtorDisp)); // Unfortunately, having applied the vtordisp means that we no @@ -2264,11 +2255,11 @@ llvm::Value * MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret, const ReturnAdjustment &RA) { if (RA.isEmpty()) - return Ret.getPointer(); + return Ret.emitRawPointer(CGF); Ret = Ret.withElementType(CGF.Int8Ty); - llvm::Value *V = Ret.getPointer(); + llvm::Value *V = Ret.emitRawPointer(CGF); if (RA.Virtual.Microsoft.VBIndex) { assert(RA.Virtual.Microsoft.VBIndex > 0); int32_t IntSize = CGF.getIntSize().getQuantity(); @@ -2583,7 +2574,7 @@ struct ResetGuardBit final : EHScopeStack::Cleanup { struct CallInitThreadAbort final : EHScopeStack::Cleanup { llvm::Value *Guard; - CallInitThreadAbort(Address Guard) : Guard(Guard.getPointer()) {} + CallInitThreadAbort(RawAddress Guard) : Guard(Guard.getPointer()) {} void Emit(CodeGenFunction &CGF, Flags flags) override { // Calling _Init_thread_abort will reset the guard's state. @@ -3123,8 +3114,8 @@ MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF, llvm::Value **VBPtrOut) { CGBuilderTy &Builder = CGF.Builder; // Load the vbtable pointer from the vbptr in the instance. - llvm::Value *VBPtr = Builder.CreateInBoundsGEP(CGM.Int8Ty, This.getPointer(), - VBPtrOffset, "vbptr"); + llvm::Value *VBPtr = Builder.CreateInBoundsGEP( + CGM.Int8Ty, This.emitRawPointer(CGF), VBPtrOffset, "vbptr"); if (VBPtrOut) *VBPtrOut = VBPtr; @@ -3203,7 +3194,7 @@ llvm::Value *MicrosoftCXXABI::AdjustVirtualBase( Builder.CreateBr(SkipAdjustBB); CGF.EmitBlock(SkipAdjustBB); llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base"); - Phi->addIncoming(Base.getPointer(), OriginalBB); + Phi->addIncoming(Base.emitRawPointer(CGF), OriginalBB); Phi->addIncoming(AdjustedBase, VBaseAdjustBB); return Phi; } @@ -3238,7 +3229,7 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress( Addr = AdjustVirtualBase(CGF, E, RD, Base, VirtualBaseAdjustmentOffset, VBPtrOffset); } else { - Addr = Base.getPointer(); + Addr = Base.emitRawPointer(CGF); } // Apply the offset, which we assume is non-null. @@ -3526,7 +3517,7 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer( ThisPtrForCall = AdjustVirtualBase(CGF, E, RD, This, VirtualBaseAdjustmentOffset, VBPtrOffset); } else { - ThisPtrForCall = This.getPointer(); + ThisPtrForCall = This.emitRawPointer(CGF); } if (NonVirtualBaseAdjustment) @@ -4445,10 +4436,7 @@ void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { llvm::GlobalVariable *TI = getThrowInfo(ThrowType); // Call into the runtime to throw the exception. - llvm::Value *Args[] = { - AI.getPointer(), - TI - }; + llvm::Value *Args[] = {AI.emitRawPointer(CGF), TI}; CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args); } diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 6893b50a3cfe90861432da5f4a8055e534204a36..b1dfe5bf8f274d1b43c7e3f531faf8da526233a7 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -295,6 +295,11 @@ public: /// Get the AST address space for alloca. virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; } + Address performAddrSpaceCast(CodeGen::CodeGenFunction &CGF, Address Addr, + LangAS SrcAddr, LangAS DestAddr, + llvm::Type *DestTy, + bool IsNonNull = false) const; + /// Perform address space cast of an expression of pointer type. /// \param V is the LLVM value to be casted to another address space. /// \param SrcAddr is the language address space of \p V. diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index 8718f1ecf3a7e076b70bc3d18e2d668e0783c93a..7dce5042c3dc203b5fc6e4f16903b90cc9eb1c61 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -85,7 +85,7 @@ private: LValue Src) { llvm::Value *Handle = nullptr; llvm::Constant *C = - llvm::dyn_cast(Src.getAddress(CGF).getPointer()); + llvm::dyn_cast(Src.getAddress(CGF).emitRawPointer(CGF)); // Lookup `addrspacecast` through the constant pointer if any. if (auto *ASC = llvm::dyn_cast_or_null(C)) C = llvm::cast(ASC->getPointerOperand()); diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 00b04723f17dd2e0a2ed392b57aab43300379c1e..174fddabbbdb6b9284ee82890d41619b2715a76b 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -274,7 +274,7 @@ void AIXTargetCodeGenInfo::setTargetAttributes( if (!isa(GV)) return; - auto *GVar = dyn_cast(GV); + auto *GVar = cast(GV); auto GVId = GV->getName(); // Is this a global variable specified by the user as toc-data? @@ -513,9 +513,10 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8); llvm::Value *RegOffset = Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity())); - RegAddr = Address( - Builder.CreateInBoundsGEP(CGF.Int8Ty, RegAddr.getPointer(), RegOffset), - DirectTy, RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); + RegAddr = Address(Builder.CreateInBoundsGEP( + CGF.Int8Ty, RegAddr.emitRawPointer(CGF), RegOffset), + DirectTy, + RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); // Increase the used-register count. NumRegs = @@ -551,7 +552,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, // Round up address of argument to alignment CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > OverflowAreaAlign) { - llvm::Value *Ptr = OverflowArea.getPointer(); + llvm::Value *Ptr = OverflowArea.emitRawPointer(CGF); OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align), OverflowArea.getElementType(), Align); } @@ -560,7 +561,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, // Increase the overflow area. OverflowArea = Builder.CreateConstInBoundsByteGEP(OverflowArea, Size); - Builder.CreateStore(OverflowArea.getPointer(), OverflowAreaAddr); + Builder.CreateStore(OverflowArea.emitRawPointer(CGF), OverflowAreaAddr); CGF.EmitBranch(Cont); } diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index a337a52a94eca940409eb6cb7b5c76bd001668f5..9025a633f328e272901d90ff8effd6222d9842b0 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -326,7 +326,7 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Update VAList. Address NextPtr = Builder.CreateConstInBoundsByteGEP(Addr, Stride, "ap.next"); - Builder.CreateStore(NextPtr.getPointer(), VAListAddr); + Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr); return ArgAddr.withElementType(ArgTy); } diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp index 6eb0c6ef2f7d637bce2093844ea5287c0ee217c2..deaafc85a31576b64379053669cfb678fbfc7cfd 100644 --- a/clang/lib/CodeGen/Targets/SystemZ.cpp +++ b/clang/lib/CodeGen/Targets/SystemZ.cpp @@ -306,7 +306,7 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( - OverflowArgArea.getElementType(), OverflowArgArea.getPointer(), + OverflowArgArea.getElementType(), OverflowArgArea.emitRawPointer(CGF), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); @@ -382,10 +382,9 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, Address MemAddr = RawMemAddr.withElementType(DirectTy); // Update overflow_arg_area_ptr pointer - llvm::Value *NewOverflowArgArea = - CGF.Builder.CreateGEP(OverflowArgArea.getElementType(), - OverflowArgArea.getPointer(), PaddedSizeV, - "overflow_arg_area"); + llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( + OverflowArgArea.getElementType(), OverflowArgArea.emitRawPointer(CGF), + PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); CGF.EmitBranch(ContBlock); diff --git a/clang/lib/CodeGen/Targets/XCore.cpp b/clang/lib/CodeGen/Targets/XCore.cpp index aeb48f851e16936fea7c188e75cdebea3f2df927..88edb781a947b1f4be7efb7b722d034b9be322c7 100644 --- a/clang/lib/CodeGen/Targets/XCore.cpp +++ b/clang/lib/CodeGen/Targets/XCore.cpp @@ -180,7 +180,7 @@ Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Increment the VAList. if (!ArgSize.isZero()) { Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize); - Builder.CreateStore(APN.getPointer(), VAListAddr); + Builder.CreateStore(APN.emitRawPointer(CGF), VAListAddr); } return Val; diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 6e089903a3158a4e79e4cd4f516be2df19d4e6dd..7a62b0f9aec419c2319ec39dfd853c3a059bd1d0 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -471,7 +471,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, // the global setting of tocdata in TOCDataGloballyinEffect. // Those that have the opposite setting to TOCDataGloballyinEffect, are added // to ExplicitlySpecifiedGlobals. - llvm::StringSet<> ExplicitlySpecifiedGlobals; + std::set ExplicitlySpecifiedGlobals; for (const auto Arg : Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) { TOCDataSetting ArgTocDataSetting = @@ -486,7 +486,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, ExplicitlySpecifiedGlobals.erase(Val); } - auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues, + auto buildExceptionList = [](const std::set &ExplicitValues, const char *OptionSpelling) { std::string Option(OptionSpelling); bool IsFirst = true; @@ -495,7 +495,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, Option += ","; IsFirst = false; - Option += E.first(); + Option += E.str(); } return Option; }; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 6b1fbba7abd031574e306805ef2fddceb9503c7f..ace4fb99581e38fa58d4eceb484d4bb4966da42f 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -758,15 +758,15 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC, void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { - const bool IsOSAIX = ToolChain.getTriple().isOSAIX(); - const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN(); + const llvm::Triple &Triple = ToolChain.getTriple(); + const bool IsOSAIX = Triple.isOSAIX(); + const bool IsAMDGCN = Triple.isAMDGCN(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); const Driver &D = ToolChain.getDriver(); const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects); const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto); if (llvm::sys::path::filename(Linker) != "ld.lld" && - llvm::sys::path::stem(Linker) != "ld.lld" && - !ToolChain.getTriple().isOSOpenBSD()) { + llvm::sys::path::stem(Linker) != "ld.lld" && !Triple.isOSOpenBSD()) { // Tell the linker to load the plugin. This has to come before // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to // come before any -plugin-opt/-bplugin_opt that -Wl might forward. @@ -835,7 +835,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, // the plugin. // Handle flags for selecting CPU variants. - std::string CPU = getCPUName(D, Args, ToolChain.getTriple()); + std::string CPU = getCPUName(D, Args, Triple); if (!CPU.empty()) CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU)); @@ -966,10 +966,9 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, false); StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; - if (!IsOSAIX) D.Diag(diag::err_drv_unsupported_opt_for_target) - << OptStr << ToolChain.getTriple().str(); + << OptStr << Triple.str(); if (HasRoptr) { // The data sections option is on by default on AIX. We only need to error @@ -1032,7 +1031,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, } if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, - ToolChain.getTriple().hasDefaultEmulatedTLS())) { + Triple.hasDefaultEmulatedTLS())) { CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + "-emulated-tls")); } diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 05aac9caa7fb296f893318e2f59d9706ab151f6d..1169b5d8c92dd683495736b429809e1dd452f207 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -255,9 +255,7 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, if (!DAL->hasArg(options::OPT_O_Group)) { DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); } - // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and - // shader model 6.2. - // See: https://github.com/llvm/llvm-project/issues/57876 + return DAL; } diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index dc534a33e6d0efe6549e670b8cea660feb8b35d1..fbf2f45b543844827f388bcd24fc88b9e9b6f842 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -79,6 +79,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(std::string("-out:") + Output.getFilename())); + if (Args.hasArg(options::OPT_marm64x)) + CmdArgs.push_back("-machine:arm64x"); + else if (TC.getTriple().isWindowsArm64EC()) + CmdArgs.push_back("-machine:arm64ec"); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); @@ -1017,4 +1022,7 @@ void MSVCToolChain::addClangTargetOptions( if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti, /*Default=*/false)) CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); + + if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x)) + A->ignoreTargetSpecific(); } diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index 22f2c47e1d6a13ce02519177432dd90fcfb2f46a..81797c8c4dc75a21f0ab2d48fd6a03ae974a4008 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1000,6 +1000,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_LValueToRValue: case CK_NoOp: case CK_UserDefinedConversion: + case CK_HLSLArrayRValue: break; case CK_IntegralCast: { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 4c83a7a3a323be59d4c11445665c854a3205f018..b9144cf55452e2d1e13f4852e9e206b47dc4d352 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4827,6 +4827,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } + if (Left.is(tok::identifier) && Right.is(tok::numeric_constant) && + Right.TokenText[0] == '.') { + return false; + } } else if (Style.isProto()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 710bf8d8a8ec700d8323435436f9ea02006acd06..d06c42d5f4c5c5bf93db1c6c734da710a2450086 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -464,10 +464,11 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; - // If PointerAlignment is PAS_Right, keep *s or &s next to the token + // If PointerAlignment is PAS_Right, keep *s or &s next to the token, + // except if the token is equal, then a space is needed. if ((Style.PointerAlignment == FormatStyle::PAS_Right || Style.ReferenceAlignment == FormatStyle::RAS_Right) && - CurrentChange.Spaces != 0) { + CurrentChange.Spaces != 0 && CurrentChange.Tok->isNot(tok::equal)) { const bool ReferenceNotRightAligned = Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 019f847ccbaad0278e1ec9b010ea22beb9a7d22d..6e3baf8386441593bd767ce2260bd1b107be3e6c 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1206,16 +1206,6 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // Note the name of the module we're building. Invocation->getLangOpts().CurrentModule = std::string(ModuleName); - // Make sure that the failed-module structure has been allocated in - // the importing instance, and propagate the pointer to the newly-created - // instance. - PreprocessorOptions &ImportingPPOpts - = ImportingInstance.getInvocation().getPreprocessorOpts(); - if (!ImportingPPOpts.FailedModules) - ImportingPPOpts.FailedModules = - std::make_shared(); - PPOpts.FailedModules = ImportingPPOpts.FailedModules; - // If there is a module map file, build the module using the module map. // Set up the inputs/outputs so that we build the module from its umbrella // header. @@ -1269,6 +1259,13 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, SourceMgr.pushModuleBuildStack(ModuleName, FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + // Make sure that the failed-module structure has been allocated in + // the importing instance, and propagate the pointer to the newly-created + // instance. + if (!ImportingInstance.hasFailedModulesSet()) + ImportingInstance.createFailedModulesSet(); + Instance.setFailedModulesSet(ImportingInstance.getFailedModulesSetPtr()); + // If we're collecting module dependencies, we need to share a collector // between all of the module CompilerInstances. Other than that, we don't // want to produce any dependency output from the module build. @@ -1337,9 +1334,24 @@ static bool compileModule(CompilerInstance &ImportingInstance, // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); bool Result; - if (OptionalFileEntryRef ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { + // We want to use the top-level module map. If we don't, the compiling + // instance may think the containing module map is a top-level one, while + // the importing instance knows it's included from a parent module map via + // the extern directive. This mismatch could bite us later. + SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { + ModuleMapFID = SourceMgr.getFileID(Loc); + Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + } + + OptionalFileEntryRef ModuleMapFile = + SourceMgr.getFileEntryRefForID(ModuleMapFID); + assert(ModuleMapFile && "Top-level module map with no FileID"); + // Canonicalize compilation to start with the public module map. This is // vital for submodules declarations in the private module maps to be // correctly parsed when depending on a top level module in the public one. @@ -1977,10 +1989,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( return nullptr; } - // Check whether we have already attempted to build this module (but - // failed). - if (getPreprocessorOpts().FailedModules && - getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { + // Check whether we have already attempted to build this module (but failed). + if (FailedModules && FailedModules->hasAlreadyFailed(ModuleName)) { getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); return nullptr; @@ -1991,8 +2001,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( ModuleFilename)) { assert(getDiagnostics().hasErrorOccurred() && "undiagnosed error in compileModuleAndReadAST"); - if (getPreprocessorOpts().FailedModules) - getPreprocessorOpts().FailedModules->addFailed(ModuleName); + if (FailedModules) + FailedModules->addFailed(ModuleName); return nullptr; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 7bd91d4791ecf0b9d9657c9937c0d71940b8837e..f1bd3cd66e97dc0836810e44b7d4c80862b5e597 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4284,11 +4284,30 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported) << ShaderModel << T.getOSName() << T.str(); } + // Validate that if fnative-half-type is given, that + // the language standard is at least hlsl2018, and that + // the target shader model is at least 6.2. + if (Args.getLastArg(OPT_fnative_half_type)) { + const LangStandard &Std = + LangStandard::getLangStandardForKind(Opts.LangStd); + if (!(Opts.LangStd >= LangStandard::lang_hlsl2018 && + T.getOSVersion() >= VersionTuple(6, 2))) + Diags.Report(diag::err_drv_hlsl_16bit_types_unsupported) + << "-enable-16bit-types" << true << Std.getName() + << T.getOSVersion().getAsString(); + } } else if (T.isSPIRVLogical()) { if (!T.isVulkanOS() || T.getVulkanVersion() == VersionTuple(0)) { Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported) << VulkanEnv << T.getOSName() << T.str(); } + if (Args.getLastArg(OPT_fnative_half_type)) { + const LangStandard &Std = + LangStandard::getLangStandardForKind(Opts.LangStd); + if (!(Opts.LangStd >= LangStandard::lang_hlsl2018)) + Diags.Report(diag::err_drv_hlsl_16bit_types_unsupported) + << "-fnative-half-type" << false << Std.getName(); + } } else { llvm_unreachable("expected DXIL or SPIR-V target"); } diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b9fd9b8897b7e7187bedd5789de4fbcd769e0295..b7c9967316f0b82ff2b211315d1be87a05d6340c 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -535,8 +535,14 @@ static Module *prepareToBuildModule(CompilerInstance &CI, if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { M->IsInferred = true; - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() - .setInferredModuleAllowedBy(M, *OriginalModuleMap); + auto FileCharacter = + M->IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; + FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( + *OriginalModuleMap, FileCharacter); + CI.getPreprocessor() + .getHeaderSearchInfo() + .getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 3fd1cdd3b4794262979ae19f7baed673e8dbc220..0bc26b694cfc8d477b96f4b33bc087fb717182d1 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -69,7 +69,10 @@ void InitOnlyAction::ExecuteAction() { // Basically PreprocessOnlyAction::ExecuteAction. void ReadPCHAndPreprocessAction::ExecuteAction() { - Preprocessor &PP = getCompilerInstance().getPreprocessor(); + CompilerInstance &CI = getCompilerInstance(); + AdjustCI(CI); + + Preprocessor &PP = CI.getPreprocessor(); // Ignore unknown pragmas. PP.IgnorePragmas(); @@ -1188,6 +1191,8 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { void GetDependenciesByModuleNameAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); + AdjustCI(CI); + Preprocessor &PP = CI.getPreprocessor(); SourceManager &SM = PP.getSourceManager(); FileID MainFileID = SM.getMainFileID(); diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 18472f728eefe00a4c9acd390255d78ad92b708e..9fb6204f90c9a8c7d9980fe506d8b6e0e11f265b 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -243,15 +243,6 @@ float3 ceil(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) float4 ceil(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double ceil(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double2 ceil(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double3 ceil(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double4 ceil(double4); - //===----------------------------------------------------------------------===// // clamp builtins //===----------------------------------------------------------------------===// @@ -585,15 +576,6 @@ float3 floor(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) float4 floor(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double floor(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double2 floor(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double3 floor(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double4 floor(double4); - //===----------------------------------------------------------------------===// // frac builtins //===----------------------------------------------------------------------===// @@ -1147,19 +1129,6 @@ float4 pow(float4, float4); /// \param Val The input value. #ifdef __HLSL_ENABLE_16_BIT -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t reversebits(int16_t); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t2 reversebits(int16_t2); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t3 reversebits(int16_t3); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t4 reversebits(int16_t4); - _HLSL_AVAILABILITY(shadermodel, 6.2) _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint16_t reversebits(uint16_t); @@ -1174,15 +1143,6 @@ _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint16_t4 reversebits(uint16_t4); #endif -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int reversebits(int); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int2 reversebits(int2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int3 reversebits(int3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int4 reversebits(int4); - _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint reversebits(uint); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) @@ -1192,15 +1152,6 @@ uint3 reversebits(uint3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint4 reversebits(uint4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t reversebits(int64_t); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t2 reversebits(int64_t2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t3 reversebits(int64_t3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t4 reversebits(int64_t4); - _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint64_t reversebits(uint64_t); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) @@ -1297,25 +1248,25 @@ float4 rsqrt(float4); /// rounded to the nearest even value. _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half round(half); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half2 round(half2); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half3 round(half3); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half4 round(half4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float round(float); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float2 round(float2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float3 round(float3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float4 round(float4); //===----------------------------------------------------------------------===// @@ -1420,7 +1371,12 @@ float4 trunc(float4); /// true, across all active lanes in the current wave. _HLSL_AVAILABILITY(shadermodel, 6.0) _HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_count_bits) -uint WaveActiveCountBits(bool Val); +__attribute__((convergent)) uint WaveActiveCountBits(bool Val); + +/// \brief Returns the index of the current lane within the current wave. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_get_lane_index) +__attribute__((convergent)) uint WaveGetLaneIndex(); } // namespace hlsl #endif //_HLSL_HLSL_INTRINSICS_H_ diff --git a/clang/lib/InstallAPI/CMakeLists.txt b/clang/lib/InstallAPI/CMakeLists.txt index 894db699578f209a3300cd53fa7527b70d1229bd..e0bc8d969ecb3afc95498d177d2d63c9236f9616 100644 --- a/clang/lib/InstallAPI/CMakeLists.txt +++ b/clang/lib/InstallAPI/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS Support TextAPI + TextAPIBinaryReader Demangle Core ) diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp index ba25e4183a9b8983517a8023dd8a2caac3797bf1..c0eda1d81b9b9839fded64a905d0169ce95cbc5c 100644 --- a/clang/lib/InstallAPI/DylibVerifier.cpp +++ b/clang/lib/InstallAPI/DylibVerifier.cpp @@ -10,6 +10,7 @@ #include "clang/InstallAPI/FrontendRecords.h" #include "clang/InstallAPI/InstallAPIDiagnostic.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/TextAPI/DylibReader.h" using namespace llvm::MachO; @@ -35,6 +36,14 @@ struct DylibVerifier::SymbolContext { bool Inlined = false; }; +struct DylibVerifier::DWARFContext { + // Track whether DSYM parsing has already been attempted to avoid re-parsing. + bool ParsedDSYM{false}; + + // Lookup table for source locations by symbol name. + DylibReader::SymbolToSourceLocMap SourceLocs{}; +}; + static bool isCppMangled(StringRef Name) { // InstallAPI currently only supports itanium manglings. return (Name.starts_with("_Z") || Name.starts_with("__Z") || @@ -511,14 +520,16 @@ DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R, return verifyImpl(R, SymCtx); } -void DylibVerifier::VerifierContext::emitDiag( - llvm::function_ref Report) { +void DylibVerifier::VerifierContext::emitDiag(llvm::function_ref Report, + RecordLoc *Loc) { if (!DiscoveredFirstError) { Diag->Report(diag::warn_target) << (PrintArch ? getArchitectureName(Target.Arch) : getTargetTripleName(Target)); DiscoveredFirstError = true; } + if (Loc && Loc->isValid()) + llvm::errs() << Loc->File << ":" << Loc->Line << ":" << 0 << ": "; Report(); } @@ -561,26 +572,36 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { return; } - // All checks at this point classify as some kind of violation that should be - // reported. + const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); + + // All checks at this point classify as some kind of violation. + // The different verification modes dictate whether they are reported to the + // user. + if (IsLinkerSymbol || (Mode > VerificationMode::ErrorsOnly)) + accumulateSrcLocForDylibSymbols(); + RecordLoc Loc = DWARFCtx->SourceLocs.lookup(SymCtx.SymbolName); // Regardless of verification mode, error out on mismatched special linker // symbols. - if (SymbolName.starts_with("$ld$")) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::err_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + if (IsLinkerSymbol) { + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::err_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Invalid); return; } // Missing declarations for exported symbols are hard errors on Pedantic mode. if (Mode == VerificationMode::Pedantic) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::err_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::err_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Invalid); return; } @@ -588,10 +609,12 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { // Missing declarations for exported symbols are warnings on ErrorsAndWarnings // mode. if (Mode == VerificationMode::ErrorsAndWarnings) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::warn_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::warn_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Ignore); return; } @@ -622,6 +645,18 @@ void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R, visitSymbolInDylib(R, SymCtx); } +void DylibVerifier::accumulateSrcLocForDylibSymbols() { + if (DSYMPath.empty()) + return; + + assert(DWARFCtx != nullptr && "Expected an initialized DWARFContext"); + if (DWARFCtx->ParsedDSYM) + return; + DWARFCtx->ParsedDSYM = true; + DWARFCtx->SourceLocs = + DylibReader::accumulateSourceLocFromDSYM(DSYMPath, Ctx.Target); +} + void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) { if (R.isVerified()) return; @@ -655,6 +690,8 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { return Result::NoVerify; assert(!Dylib.empty() && "No binary to verify against"); + DWARFContext DWARFInfo; + DWARFCtx = &DWARFInfo; Ctx.DiscoveredFirstError = false; Ctx.PrintArch = true; for (std::shared_ptr Slice : Dylib) { diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index f8f5d8d53d5691b0b9657f200d67660add514667..6476c5107cb5cc0c65ead6ccb8c4903bd584b1cb 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -255,7 +255,7 @@ bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) { return true; // Skip methods in CXX RecordDecls. - for (auto P : D->getASTContext().getParents(*M)) { + for (const DynTypedNode &P : D->getASTContext().getParents(*M)) { if (P.get()) return true; } diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp index 1d6b2da087e9fbe40d85111bddc3159199ebd94d..eb2ce9c9fd330200bf10453fff74fb8789fe7b42 100644 --- a/clang/lib/Interpreter/Value.cpp +++ b/clang/lib/Interpreter/Value.cpp @@ -1,4 +1,4 @@ -//===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===// +//===------------ Value.cpp - Definition of interpreter value -------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,8 +22,6 @@ #include #include -using namespace clang; - namespace { // This is internal buffer maintained by Value, used to hold temporaries. @@ -61,7 +59,7 @@ public: void Release() { assert(RefCnt > 0 && "Can't release if reference count is already zero"); if (--RefCnt == 0) { - // We hace a non-trivial dtor. + // We have a non-trivial dtor. if (Dtor && IsAlive()) { assert(Elements && "We at least should have 1 element in Value"); size_t Stride = AllocSize / Elements; @@ -97,6 +95,8 @@ private: }; } // namespace +namespace clang { + static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { if (Ctx.hasSameType(QT, Ctx.VoidTy)) return Value::K_Void; @@ -265,3 +265,5 @@ void Value::print(llvm::raw_ostream &Out) const { assert(OpaqueType != nullptr && "Can't print default Value"); Out << "Not implement yet.\n"; } + +} // namespace clang diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 10c475f617d48549b2b0943bf8b2851c59a70a4c..eed7eca2e73562da5d819410fcde0535b410668d 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -648,8 +648,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - OptionalFileEntryRef UmbrellaModuleMap = - getModuleMapFileForUniquing(UmbrellaModule); + FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between // the directory of the umbrella header and the directory where @@ -1021,7 +1020,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, // If the framework has a parent path from which we're allowed to infer // a framework module, do so. - OptionalFileEntryRef ModuleMapFile; + FileID ModuleMapFID; if (!Parent) { // Determine whether we're allowed to infer a module map. bool canInfer = false; @@ -1060,7 +1059,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive; Attrs.NoUndeclaredIncludes |= inferred->second.Attrs.NoUndeclaredIncludes; - ModuleMapFile = inferred->second.ModuleMapFile; + ModuleMapFID = inferred->second.ModuleMapFID; } } } @@ -1069,7 +1068,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, if (!canInfer) return nullptr; } else { - ModuleMapFile = getModuleMapFileForUniquing(Parent); + ModuleMapFID = getModuleMapFileIDForUniquing(Parent); } // Look for an umbrella header. @@ -1086,7 +1085,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Module *Result = new Module(ModuleName, SourceLocation(), Parent, /*IsFramework=*/true, /*IsExplicit=*/false, NumCreatedModules++); - InferredModuleAllowedBy[Result] = ModuleMapFile; + InferredModuleAllowedBy[Result] = ModuleMapFID; Result->IsInferred = true; if (!Parent) { if (LangOpts.CurrentModule == ModuleName) @@ -1307,28 +1306,34 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header, Cb->moduleMapAddHeader(Header.Entry.getName()); } -OptionalFileEntryRef -ModuleMap::getContainingModuleMapFile(const Module *Module) const { +FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const { if (Module->DefinitionLoc.isInvalid()) - return std::nullopt; + return {}; - return SourceMgr.getFileEntryRefForID( - SourceMgr.getFileID(Module->DefinitionLoc)); + return SourceMgr.getFileID(Module->DefinitionLoc); } OptionalFileEntryRef -ModuleMap::getModuleMapFileForUniquing(const Module *M) const { +ModuleMap::getContainingModuleMapFile(const Module *Module) const { + return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module)); +} + +FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const { if (M->IsInferred) { assert(InferredModuleAllowedBy.count(M) && "missing inferred module map"); return InferredModuleAllowedBy.find(M)->second; } - return getContainingModuleMapFile(M); + return getContainingModuleMapFileID(M); +} + +OptionalFileEntryRef +ModuleMap::getModuleMapFileForUniquing(const Module *M) const { + return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M)); } -void ModuleMap::setInferredModuleAllowedBy(Module *M, - OptionalFileEntryRef ModMap) { +void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) { assert(M->IsInferred && "module not inferred"); - InferredModuleAllowedBy[M] = ModMap; + InferredModuleAllowedBy[M] = ModMapFID; } std::error_code @@ -1517,7 +1522,7 @@ namespace clang { ModuleMap ⤅ /// The current module map file. - FileEntryRef ModuleMapFile; + FileID ModuleMapFID; /// Source location of most recent parsed module declaration SourceLocation CurrModuleDeclLoc; @@ -1585,13 +1590,12 @@ namespace clang { bool parseOptionalAttributes(Attributes &Attrs); public: - explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, - const TargetInfo *Target, DiagnosticsEngine &Diags, - ModuleMap &Map, FileEntryRef ModuleMapFile, - DirectoryEntryRef Directory, bool IsSystem) + ModuleMapParser(Lexer &L, SourceManager &SourceMgr, + const TargetInfo *Target, DiagnosticsEngine &Diags, + ModuleMap &Map, FileID ModuleMapFID, + DirectoryEntryRef Directory, bool IsSystem) : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), - ModuleMapFile(ModuleMapFile), Directory(Directory), - IsSystem(IsSystem) { + ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) { Tok.clear(); consumeToken(); } @@ -2011,11 +2015,13 @@ void ModuleMapParser::parseModuleDecl() { } if (TopLevelModule && - ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) { - assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) && + ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) { + assert(ModuleMapFID != + Map.getModuleMapFileIDForUniquing(TopLevelModule) && "submodule defined in same file as 'module *' that allowed its " "top-level module"); - Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile); + Map.addAdditionalModuleMapFile( + TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID)); } } @@ -2120,7 +2126,8 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; - StringRef MapFileName(ModuleMapFile.getName()); + StringRef MapFileName( + SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName()); if (MapFileName.ends_with("module.private.modulemap") || MapFileName.ends_with("module_private.map")) { ActiveModule->ModuleMapIsPrivate = true; @@ -2906,7 +2913,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { // We'll be inferring framework modules for this directory. Map.InferredDirectories[Directory].InferModules = true; Map.InferredDirectories[Directory].Attrs = Attrs; - Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile; + Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID; // FIXME: Handle the 'framework' keyword. } @@ -3139,8 +3146,7 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem, Buffer->getBufferStart() + (Offset ? *Offset : 0), Buffer->getBufferEnd()); SourceLocation Start = L.getSourceLocation(); - ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, - IsSystem); + ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem); bool Result = Parser.parseModuleMapFile(); ParsedModuleMap[File] = Result; diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 3b1b6df1dbae4e6a8b6d09af637dadda150d3f05..a0cc2b516574c197ea3d2e1eaa0ab993c52a01f5 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -93,16 +93,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir, } Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile); - if (getPreprocessorOpts().DependencyDirectivesForFile && - FID != PredefinesFileID) { - if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) { - if (std::optional> - DepDirectives = - getPreprocessorOpts().DependencyDirectivesForFile(*File)) { + if (DependencyDirectivesForFile && FID != PredefinesFileID) + if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) + if (auto DepDirectives = DependencyDirectivesForFile(*File)) TheLexer->DepDirectives = *DepDirectives; - } - } - } EnterSourceFileWithLexer(TheLexer, CurDir); return false; diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 50e3c39f60919b8d0d7a60c241f9a9f4f1d923a5..07dd2ba0106a4e209debe366879156a50a4b8f17 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" +#include "clang/Sema/SemaOpenACC.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -777,7 +778,7 @@ bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) { SourceLocation ClauseLoc = ConsumeToken(); bool Result = ParseOpenACCClauseParams(DirKind, Kind); - getActions().ActOnOpenACCClause(Kind, ClauseLoc); + getActions().OpenACC().ActOnClause(Kind, ClauseLoc); return Result; } @@ -1151,7 +1152,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { SourceLocation StartLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); - getActions().ActOnOpenACCConstruct(DirKind, StartLoc); + getActions().OpenACC().ActOnConstruct(DirKind, StartLoc); // Once we've parsed the construct/directive name, some have additional // specifiers that need to be taken care of. Atomic has an 'atomic-clause' @@ -1223,12 +1224,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); - if (getActions().ActOnStartOpenACCDeclDirective(DirInfo.DirKind, - DirInfo.StartLoc)) + if (getActions().OpenACC().ActOnStartDeclDirective(DirInfo.DirKind, + DirInfo.StartLoc)) return nullptr; // TODO OpenACC: Do whatever decl parsing is required here. - return DeclGroupPtrTy::make(getActions().ActOnEndOpenACCDeclDirective()); + return DeclGroupPtrTy::make(getActions().OpenACC().ActOnEndDeclDirective()); } // Parse OpenACC Directive on a Statement. @@ -1239,8 +1240,8 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); - if (getActions().ActOnStartOpenACCStmtDirective(DirInfo.DirKind, - DirInfo.StartLoc)) + if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind, + DirInfo.StartLoc)) return StmtError(); StmtResult AssocStmt; @@ -1249,10 +1250,10 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false); ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind)); - AssocStmt = getActions().ActOnOpenACCAssociatedStmt(DirInfo.DirKind, - ParseStatement()); + AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(DirInfo.DirKind, + ParseStatement()); } - return getActions().ActOnEndOpenACCStmtDirective( + return getActions().OpenACC().ActOnEndStmtDirective( DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, AssocStmt); } diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 6722878883be8ed2c27dd023d65fea3f68df747c..ce6211c23218bbd2024bad7aa5dcb690e005ebeb 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/SemaInternal.h" diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b55f433a8be76f61276dd82d23afe311500e6563..b7e4fc0ac9b5b277f8f0bc1ca84c5aa0d2519254 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -43,6 +43,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaOpenACC.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" #include "clang/Sema/TypoCorrection.h" @@ -196,7 +197,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ThreadSafetyDeclCache(nullptr), LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr), - Ident_super(nullptr), + Ident_super(nullptr), OpenACCPtr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()), @@ -653,6 +654,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, case CK_FunctionToPointerDecay: case CK_ToVoid: case CK_NonAtomicToAtomic: + case CK_HLSLArrayRValue: break; } } @@ -2065,8 +2067,11 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } - if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(Ty, Loc, D); + if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType() && FD) { + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(Ty, Loc, D, CallerFeatureMap); + } // Don't allow SVE types in functions without a SVE target. if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 08449581330934d7df93be05fa198820a189ad85..11401b6f56c0ea35a4edcf7555650c580e91cb32 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5541,6 +5541,14 @@ bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { checkDoubleVector); } +bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasUnsignedIntegerRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, + checkAllUnsignedTypes); +} + void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType) { auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); @@ -5628,12 +5636,22 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } // Note these are llvm builtins that we want to catch invalid intrinsic // generation. Normal handling of these builitns will occur elsewhere. + case Builtin::BI__builtin_elementwise_bitreverse: { + if (CheckUnsignedIntRepresentation(this, TheCall)) + return true; + break; + } + case Builtin::BI__builtin_elementwise_ceil: case Builtin::BI__builtin_elementwise_cos: - case Builtin::BI__builtin_elementwise_sin: + case Builtin::BI__builtin_elementwise_exp: + case Builtin::BI__builtin_elementwise_exp2: + case Builtin::BI__builtin_elementwise_floor: case Builtin::BI__builtin_elementwise_log: case Builtin::BI__builtin_elementwise_log2: case Builtin::BI__builtin_elementwise_log10: case Builtin::BI__builtin_elementwise_pow: + case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_sin: case Builtin::BI__builtin_elementwise_sqrt: case Builtin::BI__builtin_elementwise_trunc: { if (CheckFloatOrHalfRepresentations(this, TheCall)) @@ -5760,57 +5778,6 @@ static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall, bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { - // CodeGenFunction can also detect this, but this gives a better error - // message. - bool FeatureMissing = false; - SmallVector ReqFeatures; - StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); - Features.split(ReqFeatures, ',', -1, false); - - // Check if each required feature is included - for (StringRef F : ReqFeatures) { - SmallVector ReqOpFeatures; - F.split(ReqOpFeatures, '|'); - - if (llvm::none_of(ReqOpFeatures, - [&TI](StringRef OF) { return TI.hasFeature(OF); })) { - std::string FeatureStrs; - bool IsExtension = true; - for (StringRef OF : ReqOpFeatures) { - // If the feature is 64bit, alter the string so it will print better in - // the diagnostic. - if (OF == "64bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone"); - OF = "RV64"; - IsExtension = false; - } - if (OF == "32bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone"); - OF = "RV32"; - IsExtension = false; - } - - // Convert features like "zbr" and "experimental-zbr" to "Zbr". - OF.consume_front("experimental-"); - std::string FeatureStr = OF.str(); - FeatureStr[0] = std::toupper(FeatureStr[0]); - // Combine strings. - FeatureStrs += FeatureStrs.empty() ? "" : ", "; - FeatureStrs += "'"; - FeatureStrs += FeatureStr; - FeatureStrs += "'"; - } - // Error message - FeatureMissing = true; - Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) - << IsExtension - << TheCall->getSourceRange() << StringRef(FeatureStrs); - } - } - - if (FeatureMissing) - return true; - // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. switch (BuiltinID) { @@ -6714,36 +6681,35 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, return false; } -void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D) { - const TargetInfo &TI = Context.getTargetInfo(); - +void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap) { ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty->castAs()); unsigned EltSize = Context.getTypeSize(Info.ElementType); unsigned MinElts = Info.EC.getKnownMinValue(); if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) && - !TI.hasFeature("zve64d")) + !FeatureMap.lookup("zve64d")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at // least zve64x else if (((EltSize == 64 && Info.ElementType->isIntegerType()) || MinElts == 1) && - !TI.hasFeature("zve64x")) + !FeatureMap.lookup("zve64x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; - else if (Info.ElementType->isFloat16Type() && !TI.hasFeature("zvfh") && - !TI.hasFeature("zvfhmin")) + else if (Info.ElementType->isFloat16Type() && !FeatureMap.lookup("zvfh") && + !FeatureMap.lookup("zvfhmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfh or zvfhmin"; else if (Info.ElementType->isBFloat16Type() && - !TI.hasFeature("experimental-zvfbfmin")) + !FeatureMap.lookup("experimental-zvfbfmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin"; else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) && - !TI.hasFeature("zve32f")) + !FeatureMap.lookup("zve32f")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; // Given that caller already checked isRVVType() before calling this function, // if we don't have at least zve32x supported, then we need to emit error. - else if (!TI.hasFeature("zve32x")) + else if (!FeatureMap.lookup("zve32x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; } @@ -12480,6 +12446,19 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) { S.Context.getFloatingTypeOrder(From, To) < 0; } +static analyze_format_string::ArgType::MatchKind +handleFormatSignedness(analyze_format_string::ArgType::MatchKind Match, + DiagnosticsEngine &Diags, SourceLocation Loc) { + if (Match == analyze_format_string::ArgType::NoMatchSignedness) { + Match = + Diags.isIgnored( + diag::warn_format_conversion_argument_type_mismatch_signedness, Loc) + ? analyze_format_string::ArgType::Match + : analyze_format_string::ArgType::NoMatch; + } + return Match; +} + bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, @@ -12523,6 +12502,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ArgType::MatchKind ImplicitMatch = ArgType::NoMatch; ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); + ArgType::MatchKind OrigMatch = Match; + + Match = handleFormatSignedness(Match, S.getDiagnostics(), E->getExprLoc()); if (Match == ArgType::Match) return true; @@ -12546,6 +12528,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression ImplicitMatch = AT.matchesType(S.Context, ExprTy); + if (OrigMatch == ArgType::NoMatchSignedness && + ImplicitMatch != ArgType::NoMatchSignedness) + // If the original match was a signedness match this match on the + // implicit cast type also need to be signedness match otherwise we + // might introduce new unexpected warnings from -Wformat-signedness. + return true; + ImplicitMatch = handleFormatSignedness( + ImplicitMatch, S.getDiagnostics(), E->getExprLoc()); if (ImplicitMatch == ArgType::Match) return true; } @@ -12667,6 +12657,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, case ArgType::Match: case ArgType::MatchPromotion: case ArgType::NoMatchPromotionTypeConfusion: + case ArgType::NoMatchSignedness: llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; @@ -12702,8 +12693,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << (S.LangOpts.CPlusPlus ? ">" : ")"); SmallVector Hints; - if (AT.matchesType(S.Context, IntendedTy) != ArgType::Match || - ShouldNotPrintDirectly) + ArgType::MatchKind IntendedMatch = AT.matchesType(S.Context, IntendedTy); + IntendedMatch = handleFormatSignedness(IntendedMatch, S.getDiagnostics(), + E->getExprLoc()); + if ((IntendedMatch != ArgType::Match) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast(E)) { @@ -12772,6 +12765,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, case ArgType::Match: case ArgType::MatchPromotion: case ArgType::NoMatchPromotionTypeConfusion: + case ArgType::NoMatchSignedness: llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; @@ -12983,6 +12977,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( analyze_format_string::ArgType::MatchKind Match = AT.matchesType(S.Context, Ex->getType()); + Match = handleFormatSignedness(Match, S.getDiagnostics(), Ex->getExprLoc()); bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; if (Match == analyze_format_string::ArgType::Match) return true; diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index b6c4d3d540ef50caf52f111859fd291c402b1376..b2986c5012ea2bd45f03c1da9763c2206ea3a064 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1281,6 +1281,8 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, S, InstLocBegin, Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, {InstLocBegin, InstLocEnd}); + if (Inst.isInvalid()) + return true; if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; @@ -1354,6 +1356,8 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { S, CSE->getExprLoc(), Sema::InstantiatingTemplate::ConstraintNormalization{}, D, CSE->getSourceRange()); + if (Inst.isInvalid()) + return std::nullopt; // C++ [temp.constr.normal]p1.1 // [...] // The normal form of an id-expression of the form C, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 66aad2592cb3839f04b0af580be13f2fb5ad56e4..5027deda0d7e0938ce5a90aa20eb9872fda46306 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8962,8 +8962,13 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } } - if (T->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext)); + if (T->isRVVSizelessBuiltinType() && isa(CurContext)) { + const FunctionDecl *FD = cast(CurContext); + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext), + CallerFeatureMap); + } } /// Perform semantic checking on a newly-created variable @@ -9910,7 +9915,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // FIXME: We need a better way to separate C++ standard and clang modules. bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || !NewFD->getOwningModule() || - NewFD->getOwningModule()->isGlobalModule() || + NewFD->isFromExplicitGlobalModule() || NewFD->getOwningModule()->isHeaderLikeModule(); bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -18165,7 +18170,9 @@ CreateNewDecl: cast_or_null(PrevDecl)); } - if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus) + // Only C23 and later allow defining new types in 'offsetof()'. + if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus && + !getLangOpts().C23) Diag(New->getLocation(), diag::ext_type_defined_in_offsetof) << (OOK == OOK_Macro) << New->getSourceRange(); @@ -19424,15 +19431,11 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } else if (Record->isUnion()) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_union_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_union_gnu - : diag::err_flexible_array_union; + : diag::ext_flexible_array_union_gnu; else if (NumNamedMembers < 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_empty_aggregate_gnu - : diag::err_flexible_array_empty_aggregate; + : diag::ext_flexible_array_empty_aggregate_gnu; if (DiagID) Diag(FD->getLocation(), DiagID) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0a62c656d824ffc47d7c28a989dd5dfa4a13e54b..f25f3afd0f4af273cca71e4e6022326ab62aab6e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5271,6 +5271,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { case ParsedAttr::AT_PreserveNone: D->addAttr(::new (S.Context) PreserveNoneAttr(S.Context, AL)); return; + case ParsedAttr::AT_RISCVVectorCC: + D->addAttr(::new (S.Context) RISCVVectorCCAttr(S.Context, AL)); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -5475,6 +5478,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_PreserveNone: CC = CC_PreserveNone; break; + case ParsedAttr::AT_RISCVVectorCC: + CC = CC_RISCVVectorCall; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -9637,6 +9643,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_AMDGPUKernelCall: case ParsedAttr::AT_M68kRTD: case ParsedAttr::AT_PreserveNone: + case ParsedAttr::AT_RISCVVectorCC: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_Suppress: diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e9fecaea84b021fe29e011fa18cb4c926e6d092b..f32ff396f8a54356a898e00415c47b1d1aa82ed7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13589,6 +13589,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, Diag(UsingLoc, diag::err_alias_template_extra_headers) << SourceRange(TemplateParamLists[1]->getTemplateLoc(), TemplateParamLists[TemplateParamLists.size()-1]->getRAngleLoc()); + Invalid = true; } TemplateParameterList *TemplateParams = TemplateParamLists[0]; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 091fc3e4836b63c0a2237f0a39ed6ed8e25fbe33..80b4257d9d83eda83f0fe2dbc34e9083fb210525 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -658,8 +658,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); - // lvalue-to-rvalue conversion cannot be applied to function or array types. - if (T->isFunctionType() || T->isArrayType()) + // lvalue-to-rvalue conversion cannot be applied to types that decay to + // pointers (i.e. function or array types). + if (T->canDecayToPointerType()) return E; // We don't want to throw lvalue-to-rvalue casts on top of @@ -4686,6 +4687,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Decayed: T = cast(Ty)->getPointeeType(); break; + case Type::ArrayParameter: + T = cast(Ty)->getElementType(); + break; case Type::Pointer: T = cast(Ty)->getPointeeType(); break; @@ -12908,6 +12912,8 @@ static ImplicitConversionKind castKindToImplicitConversionKind(CastKind CK) { case CK_IntegralComplexToReal: case CK_IntegralRealToComplex: return ICK_Complex_Real; + case CK_HLSLArrayRValue: + return ICK_HLSL_Array_RValue; } } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 51c8e04bee8c31b8dc66279f71ed5d08d92e8b5c..76bb78aa8b5458fa2e7f9cd994ad9c05599def3f 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4416,6 +4416,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, .get(); break; + case ICK_HLSL_Array_RValue: + FromType = Context.getArrayParameterType(FromType); + From = ImpCastExprToType(From, FromType, CK_HLSLArrayRValue, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, @@ -4793,6 +4800,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: case ICK_Incompatible_Pointer_Conversion: + case ICK_HLSL_Array_RValue: llvm_unreachable("Improper second standard conversion"); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 2b4805d62d07d0dc6c7de0efa85978562fc84548..777f89c70f87c299fd0b6ca27ccbe34f487d16b7 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2329,11 +2329,11 @@ void InitListChecker::CheckStructUnionTypes( break; } - // We've already initialized a member of a union. We're done. + // We've already initialized a member of a union. We can stop entirely. if (InitializedSomething && RD->isUnion()) - break; + return; - // If we've hit the flexible array member at the end, we're done. + // Stop if we've hit a flexible array member. if (Field->getType()->isIncompleteArrayType()) break; @@ -2456,6 +2456,11 @@ void InitListChecker::CheckStructUnionTypes( else CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); + + if (RD->isUnion() && StructuredList) { + // Initialize the first field within the union. + StructuredList->setInitializedFieldInUnion(*Field); + } } /// Expand a field designator that refers to a member of an @@ -6264,7 +6269,10 @@ void InitializationSequence::InitializeFrom(Sema &S, // initializer is a string literal, see 8.5.2. // - Otherwise, if the destination type is an array, the program is // ill-formed. - if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) { + // - Except in HLSL, where non-decaying array parameters behave like + // non-array types for initialization. + if (DestType->isArrayType() && !DestType->isArrayParameterType()) { + const ArrayType *DestAT = Context.getAsArrayType(DestType); if (Initializer && isa(DestAT)) { SetFailed(FK_VariableLengthArrayHasInitializer); return; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index d3a9c7abd0e94465f307691e6ba7b0ed2962de48..38237ee578079db65a94f5af9614cd1d744f0a6f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3243,6 +3243,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Pipe: T = cast(T)->getElementType().getTypePtr(); continue; + + // Array parameter types are treated as fundamental types. + case Type::ArrayParameter: + break; } if (Queue.empty()) diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index d3a602d1c382fa601b7eda1c369402a20bc0fc72..2ac994cac71e199ba08673813f6d4e939f09c43c 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -11,14 +11,15 @@ /// //===----------------------------------------------------------------------===// +#include "clang/AST/StmtOpenACC.h" +#include "clang/Sema/SemaOpenACC.h" #include "clang/Basic/DiagnosticSema.h" -#include "clang/Basic/OpenACCKinds.h" #include "clang/Sema/Sema.h" using namespace clang; namespace { -bool diagnoseConstructAppertainment(Sema &S, OpenACCDirectiveKind K, +bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, SourceLocation StartLoc, bool IsStmt) { switch (K) { default: @@ -30,14 +31,21 @@ bool diagnoseConstructAppertainment(Sema &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: if (!IsStmt) - return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; + return S.SemaRef.Diag(StartLoc, diag::err_acc_construct_appertainment) + << K; break; } return false; } } // namespace -bool Sema::ActOnOpenACCClause(OpenACCClauseKind ClauseKind, +SemaOpenACC::SemaOpenACC(Sema &S) : SemaRef(S) {} + +ASTContext &SemaOpenACC::getASTContext() const { return SemaRef.Context; } +DiagnosticsEngine &SemaOpenACC::getDiagnostics() const { return SemaRef.Diags; } +const LangOptions &SemaOpenACC::getLangOpts() const { return SemaRef.LangOpts; } + +bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc) { if (ClauseKind == OpenACCClauseKind::Invalid) return false; @@ -45,9 +53,10 @@ bool Sema::ActOnOpenACCClause(OpenACCClauseKind ClauseKind, // whatever it can do. This function will eventually need to start returning // some sort of Clause AST type, but for now just return true/false based on // success. - return Diag(StartLoc, diag::warn_acc_clause_unimplemented) << ClauseKind; + return SemaRef.Diag(StartLoc, diag::warn_acc_clause_unimplemented) + << ClauseKind; } -void Sema::ActOnOpenACCConstruct(OpenACCDirectiveKind K, +void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc) { switch (K) { case OpenACCDirectiveKind::Invalid: @@ -63,17 +72,17 @@ void Sema::ActOnOpenACCConstruct(OpenACCDirectiveKind K, // here as these constructs do not take any arguments. break; default: - Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; + SemaRef.Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; break; } } -bool Sema::ActOnStartOpenACCStmtDirective(OpenACCDirectiveKind K, +bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); } -StmtResult Sema::ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, +StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation EndLoc, StmtResult AssocStmt) { @@ -92,7 +101,7 @@ StmtResult Sema::ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, llvm_unreachable("Unhandled case in directive handling?"); } -StmtResult Sema::ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, +StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt) { switch (K) { default: @@ -114,9 +123,9 @@ StmtResult Sema::ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, llvm_unreachable("Invalid associated statement application"); } -bool Sema::ActOnStartOpenACCDeclDirective(OpenACCDirectiveKind K, +bool SemaOpenACC::ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/false); } -DeclGroupRef Sema::ActOnEndOpenACCDeclDirective() { return DeclGroupRef{}; } +DeclGroupRef SemaOpenACC::ActOnEndDeclDirective() { return DeclGroupRef{}; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 51450e486eaeb45b8ea3e913d7a0ecde6ac268f9..16d54c1ffe5fd9f0fa0ada0796181ca306a7a2a8 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -160,6 +160,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { ICR_C_Conversion_Extension, ICR_Conversion, ICR_Conversion, + ICR_Conversion, }; static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds); return Rank[(int)Kind]; @@ -201,6 +202,7 @@ static const char *GetImplicitConversionName(ImplicitConversionKind Kind) { "Incompatible pointer conversion", "Fixed point conversion", "HLSL vector truncation", + "Non-decaying array conversion", }; static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds); return Name[Kind]; @@ -2131,8 +2133,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // A glvalue (3.10) of a non-function, non-array type T can // be converted to a prvalue. bool argIsLValue = From->isGLValue(); - if (argIsLValue && - !FromType->isFunctionType() && !FromType->isArrayType() && + if (argIsLValue && !FromType->canDecayToPointerType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { SCS.First = ICK_Lvalue_To_Rvalue; @@ -2147,6 +2148,19 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // is T (C++ 4.1p1). C++ can't get here with class types; in C, we // just strip the qualifiers because they don't matter. FromType = FromType.getUnqualifiedType(); + } else if (S.getLangOpts().HLSL && FromType->isConstantArrayType() && + ToType->isArrayParameterType()) { + // HLSL constant array parameters do not decay, so if the argument is a + // constant array and the parameter is an ArrayParameterType we have special + // handling here. + FromType = S.Context.getArrayParameterType(FromType); + if (S.Context.getCanonicalType(FromType) != + S.Context.getCanonicalType(ToType)) + return false; + + SCS.First = ICK_HLSL_Array_RValue; + SCS.setAllToTypes(ToType); + return true; } else if (FromType->isArrayType()) { // Array-to-pointer conversion (C++ 4.2) SCS.First = ICK_Array_To_Pointer; @@ -6100,6 +6114,7 @@ static bool CheckConvertedConstantConversions(Sema &S, case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: + case ICK_HLSL_Array_RValue: llvm_unreachable("found a first conversion kind in Second"); case ICK_Function_Conversion: diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 005529a53270c30a25124e94559ed190f32bf86e..1a2d5e9310dbe14ff9a730ac634bb04fddb021f5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1836,7 +1836,27 @@ static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) { // Make sure we get the template parameter list from the most // recent declaration, since that is the only one that is guaranteed to // have all the default template argument information. - return cast(TD->getMostRecentDecl())->getTemplateParameters(); + Decl *D = TD->getMostRecentDecl(); + // C++11 N3337 [temp.param]p12: + // A default template argument shall not be specified in a friend class + // template declaration. + // + // Skip past friend *declarations* because they are not supposed to contain + // default template arguments. Moreover, these declarations may introduce + // template parameters living in different template depths than the + // corresponding template parameters in TD, causing unmatched constraint + // substitution. + // + // FIXME: Diagnose such cases within a class template: + // template + // struct S { + // template friend struct C; + // }; + // template struct S; + while (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None && + D->getPreviousDecl()) + D = D->getPreviousDecl(); + return cast(D)->getTemplateParameters(); } DeclResult Sema::CheckClassTemplate( @@ -2731,6 +2751,8 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) { // Build deduction guides for a type alias template. void DeclareImplicitDeductionGuidesForTypeAlias( Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) { + if (AliasTemplate->isInvalidDecl()) + return; auto &Context = SemaRef.Context; // FIXME: if there is an explicit deduction guide after the first use of the // type alias usage, we will not cover this explicit deduction guide. fix this @@ -2974,7 +2996,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias( if (auto *FPrime = SemaRef.InstantiateFunctionDeclaration( F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(), Sema::CodeSynthesisContext::BuildingDeductionGuides)) { - auto *GG = dyn_cast(FPrime); + auto *GG = cast(FPrime); buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList, GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(), GG->getTypeSourceInfo(), @@ -6876,6 +6898,11 @@ bool UnnamedLocalNoLinkageFinder::VisitBitIntType(const BitIntType *T) { return false; } +bool UnnamedLocalNoLinkageFinder::VisitArrayParameterType( + const ArrayParameterType *T) { + return VisitConstantArrayType(T); +} + bool UnnamedLocalNoLinkageFinder::VisitDependentBitIntType( const DependentBitIntType *T) { return false; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 97f8445bf819c8fa4cb8da6a5a8356afaa35e571..716660244537b81d827b4eb2d82a44bb9da02dd2 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2277,6 +2277,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::DependentTemplateSpecialization: case Type::PackExpansion: case Type::Pipe: + case Type::ArrayParameter: // No template argument deduction for these types return TemplateDeductionResult::Success; @@ -5514,9 +5515,9 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( QualType Obj2Ty; if (TPOC == TPOC_Call) { const FunctionProtoType *Proto1 = - FD1->getType()->getAs(); + FD1->getType()->castAs(); const FunctionProtoType *Proto2 = - FD2->getType()->getAs(); + FD2->getType()->castAs(); // - In the context of a function call, the function parameter types are // used. @@ -6355,11 +6356,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::ConstantArray: case Type::IncompleteArray: + case Type::ArrayParameter: MarkUsedTemplateParameters(Ctx, cast(T)->getElementType(), OnlyDeduced, Depth, Used); break; - case Type::Vector: case Type::ExtVector: MarkUsedTemplateParameters(Ctx, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d7521a5363a3d2c57f4b3dfa313d099973376e44..d88895d35294585b8869691bcc96dde711ac326f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -138,7 +138,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_PreserveMost: \ case ParsedAttr::AT_PreserveAll: \ case ParsedAttr::AT_M68kRTD: \ - case ParsedAttr::AT_PreserveNone + case ParsedAttr::AT_PreserveNone: \ + case ParsedAttr::AT_RISCVVectorCC // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -6504,6 +6505,9 @@ namespace { void VisitDecayedTypeLoc(DecayedTypeLoc TL) { llvm_unreachable("decayed type locs not expected here!"); } + void VisitArrayParameterTypeLoc(ArrayParameterTypeLoc TL) { + llvm_unreachable("array parameter type locs not expected here!"); + } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, State); @@ -7939,6 +7943,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_PreserveNone: return createSimpleAttr(Ctx, Attr); + case ParsedAttr::AT_RISCVVectorCC: + return createSimpleAttr(Ctx, Attr); } llvm_unreachable("unexpected attribute kind!"); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 80a10647ca5d331a1fdd70edf2802eb73bbc7f15..a2568ad0f82cc28b315c6d3f1b30dd1dcc0e25c3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -39,6 +39,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaOpenACC.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include @@ -4000,16 +4001,16 @@ public: SourceLocation BeginLoc, SourceLocation EndLoc, StmtResult StrBlock) { - getSema().ActOnOpenACCConstruct(K, BeginLoc); + getSema().OpenACC().ActOnConstruct(K, BeginLoc); // TODO OpenACC: Include clauses. - if (getSema().ActOnStartOpenACCStmtDirective(K, BeginLoc)) + if (getSema().OpenACC().ActOnStartStmtDirective(K, BeginLoc)) return StmtError(); - StrBlock = getSema().ActOnOpenACCAssociatedStmt(K, StrBlock); + StrBlock = getSema().OpenACC().ActOnAssociatedStmt(K, StrBlock); - return getSema().ActOnEndOpenACCStmtDirective(K, BeginLoc, EndLoc, - StrBlock); + return getSema().OpenACC().ActOnEndStmtDirective(K, BeginLoc, EndLoc, + StrBlock); } private: @@ -5243,6 +5244,23 @@ QualType TreeTransform::TransformDecayedType(TypeLocBuilder &TLB, return Result; } +template +QualType +TreeTransform::TransformArrayParameterType(TypeLocBuilder &TLB, + ArrayParameterTypeLoc TL) { + QualType OriginalType = getDerived().TransformType(TLB, TL.getElementLoc()); + if (OriginalType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + OriginalType != TL.getElementLoc().getType()) + Result = SemaRef.Context.getArrayParameterType(OriginalType); + TLB.push(Result); + // Nothing to set for ArrayParameterTypeLoc. + return Result; +} + template QualType TreeTransform::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 28e8d27fef08c6f955e622c488cc7ae0fba29749..004859ed22bf160a957c5d7058c2c37733a11b88 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6810,6 +6810,10 @@ void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing to do } +void TypeLocReader::VisitArrayParameterTypeLoc(ArrayParameterTypeLoc TL) { + // nothing to do +} + void TypeLocReader::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { TL.setExpansionLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 221409d011a38cc32f553411dda43ca11cb53e7e..a2668e61c51d129651c1e936b0e355f3f91728af 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -193,17 +193,17 @@ std::set GetAffectingModuleMaps(const Preprocessor &PP, const ModuleMap &MM = HS.getModuleMap(); SourceManager &SourceMgr = PP.getSourceManager(); - std::set ModuleMaps{}; - auto CollectIncludingModuleMaps = [&](FileEntryRef F) { + std::set ModuleMaps; + auto CollectIncludingModuleMaps = [&](FileID FID, FileEntryRef F) { if (!ModuleMaps.insert(F).second) return; - FileID FID = SourceMgr.translateFile(F); SourceLocation Loc = SourceMgr.getIncludeLoc(FID); // The include location of inferred module maps can point into the header // file that triggered the inferring. Cut off the walk if that's the case. while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { FID = SourceMgr.getFileID(Loc); - if (!ModuleMaps.insert(*SourceMgr.getFileEntryRefForID(FID)).second) + F = *SourceMgr.getFileEntryRefForID(FID); + if (!ModuleMaps.insert(F).second) break; Loc = SourceMgr.getIncludeLoc(FID); } @@ -216,13 +216,13 @@ std::set GetAffectingModuleMaps(const Preprocessor &PP, break; // The containing module map is affecting, because it's being pointed // into by Module::DefinitionLoc. - if (auto ModuleMapFile = MM.getContainingModuleMapFile(Mod)) - CollectIncludingModuleMaps(*ModuleMapFile); + if (FileID FID = MM.getContainingModuleMapFileID(Mod); FID.isValid()) + CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID)); // For inferred modules, the module map that allowed inferring is not in // the include chain of the virtual containing module map file. It did // affect the compilation, though. - if (auto ModuleMapFile = MM.getModuleMapFileForUniquing(Mod)) - CollectIncludingModuleMaps(*ModuleMapFile); + if (FileID FID = MM.getModuleMapFileIDForUniquing(Mod); FID.isValid()) + CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID)); } }; @@ -318,6 +318,10 @@ void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing to do } +void TypeLocWriter::VisitArrayParameterTypeLoc(ArrayParameterTypeLoc TL) { + // nothing to do +} + void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { addSourceLocation(TL.getCaretLoc()); } @@ -3195,6 +3199,10 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, if (DC->decls_empty()) return 0; + // In reduced BMI, we don't care the declarations in functions. + if (GeneratingReducedBMI && DC->isFunctionOrMethod()) + return 0; + uint64_t Offset = Stream.GetCurrentBitNo(); SmallVector KindDeclPairs; for (const auto *D : DC->decls()) { @@ -4728,7 +4736,6 @@ void ASTWriter::computeNonAffectingInputFiles() { continue; if (!isModuleMap(File.getFileCharacteristic()) || - AffectingModuleMaps.empty() || llvm::is_contained(AffectingModuleMaps, *Cache->OrigEntry)) continue; @@ -4956,38 +4963,12 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, Stream.EmitRecord(METADATA_OLD_FORMAT, Record); } - // Create a lexical update block containing all of the declarations in the - // translation unit that do not come from other AST files. const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - SmallVector NewGlobalKindDeclPairs; - for (const auto *D : TU->noload_decls()) { - if (!D->isFromASTFile()) { - NewGlobalKindDeclPairs.push_back(D->getKind()); - NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); - } - } - - auto Abv = std::make_shared(); - Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); - unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); - { - RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; - Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, - bytes(NewGlobalKindDeclPairs)); - } - - // And a visible updates block for the translation unit. - Abv = std::make_shared(); - Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); - UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(Abv)); - WriteDeclContextVisibleUpdate(TU); - // If we have any extern "C" names, write out a visible update for them. - if (Context.ExternCContext) - WriteDeclContextVisibleUpdate(Context.ExternCContext); + // Force all top level declarations to be emitted. + for (const auto *D : TU->noload_decls()) + if (!D->isFromASTFile()) + GetDeclRef(D); // If the translation unit has an anonymous namespace, and we don't already // have an update block for it, write it as an update block. @@ -5128,6 +5109,14 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, for (auto *D : SemaRef.DeclsToCheckForDeferredDiags) DeclsToCheckForDeferredDiags.push_back(GetDeclRef(D)); + { + auto Abv = std::make_shared(); + Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(Abv)); + } + RecordData DeclUpdatesOffsetsRecord; // Keep writing types, declarations, and declaration update records @@ -5155,6 +5144,35 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, WriteTypeDeclOffsets(); if (!DeclUpdatesOffsetsRecord.empty()) Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); + + // Create a lexical update block containing all of the declarations in the + // translation unit that do not come from other AST files. + { + SmallVector NewGlobalKindDeclPairs; + for (const auto *D : TU->noload_decls()) { + if (!D->isFromASTFile()) { + NewGlobalKindDeclPairs.push_back(D->getKind()); + NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); + } + } + + auto Abv = std::make_shared(); + Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); + + RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; + Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, + bytes(NewGlobalKindDeclPairs)); + } + + // And a visible updates block for the translation unit. + WriteDeclContextVisibleUpdate(TU); + + // If we have any extern "C" names, write out a visible update for them. + if (Context.ExternCContext) + WriteDeclContextVisibleUpdate(Context.ExternCContext); + WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); WriteComments(); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index c3fc56ac30ee9fd01345d42c864a67a63d8161ea..7a900780384a91db8f98b73d7e0ec8ae0207c094 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -330,7 +330,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_ConstructorConversion: case CK_UserDefinedConversion: case CK_FunctionToPointerDecay: - case CK_BuiltinFnToFnPtr: { + case CK_BuiltinFnToFnPtr: + case CK_HLSLArrayRValue: { // Copy the SVal of Ex to CastE. ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 33b43417a6613d8dda6a65d1924960abd86bca11..492b8f1e2b3863dabc02e4fcb34dbd7be11afc32 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -363,20 +363,22 @@ public: PrebuiltModuleVFSMap, ScanInstance.getDiagnostics())) return false; - // Use the dependency scanning optimized file system if requested to do so. - if (DepFS) { - llvm::IntrusiveRefCntPtr LocalDepFS = - DepFS; - ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile = - [LocalDepFS = std::move(LocalDepFS)](FileEntryRef File) - -> std::optional> { - if (llvm::ErrorOr Entry = - LocalDepFS->getOrCreateFileSystemEntry(File.getName())) - if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry)) - return Entry->getDirectiveTokens(); - return std::nullopt; - }; - } + auto AdjustCI = [&](CompilerInstance &CI) { + // Set up the dependency scanning file system callback if requested. + if (DepFS) { + auto GetDependencyDirectives = [LocalDepFS = DepFS](FileEntryRef File) + -> std::optional> { + if (llvm::ErrorOr Entry = + LocalDepFS->getOrCreateFileSystemEntry(File.getName())) + if (LocalDepFS->ensureDirectiveTokensArePopulated(*Entry)) + return Entry->getDirectiveTokens(); + return std::nullopt; + }; + + CI.getPreprocessor().setDependencyDirectivesFn( + std::move(GetDependencyDirectives)); + } + }; // Create the dependency collector that will collect the produced // dependencies. @@ -428,9 +430,11 @@ public: std::unique_ptr Action; if (ModuleName) - Action = std::make_unique(*ModuleName); + Action = std::make_unique( + *ModuleName, std::move(AdjustCI)); else - Action = std::make_unique(); + Action = + std::make_unique(std::move(AdjustCI)); if (ScanInstance.getDiagnostics().hasErrorOccurred()) return false; diff --git a/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes b/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes new file mode 100644 index 0000000000000000000000000000000000000000..14c77afd8c30a1ad4996d489e5ecb4949a1c1de1 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes @@ -0,0 +1,5 @@ +Name: ExportAs +Globals: + - Name: globalInt + Availability: none + AvailabilityMsg: "oh no" diff --git a/clang/test/APINotes/Inputs/Headers/ExportAs.h b/clang/test/APINotes/Inputs/Headers/ExportAs.h new file mode 100644 index 0000000000000000000000000000000000000000..ff490e0964176002686f816ec808d8f477441a60 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/ExportAs.h @@ -0,0 +1 @@ +#include "ExportAsCore.h" diff --git a/clang/test/APINotes/Inputs/Headers/ExportAsCore.h b/clang/test/APINotes/Inputs/Headers/ExportAsCore.h new file mode 100644 index 0000000000000000000000000000000000000000..f7674c19935d64d19a3a5f78655c5a93b898b3a6 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/ExportAsCore.h @@ -0,0 +1 @@ +static int globalInt = 123; diff --git a/clang/test/APINotes/Inputs/Headers/Templates.apinotes b/clang/test/APINotes/Inputs/Headers/Templates.apinotes new file mode 100644 index 0000000000000000000000000000000000000000..b7336484da0c792c38a56a12e097f5bbee1ecfb1 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/Templates.apinotes @@ -0,0 +1,5 @@ +--- +Name: Templates +Tags: +- Name: Box + SwiftImportAs: owned diff --git a/clang/test/APINotes/Inputs/Headers/Templates.h b/clang/test/APINotes/Inputs/Headers/Templates.h new file mode 100644 index 0000000000000000000000000000000000000000..862035fee363f707f3ed1fd1dc14d55baae4c849 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/Templates.h @@ -0,0 +1,9 @@ +template +struct Box { + T value; + + const T& get_value() const { return value; } + const T* get_ptr() const { return &value; } +}; + +using IntBox = Box; diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap index 98b4ee3e96cfe721f92c91717189e478aa8b74e5..d515169184f4f0a5040d8014f4bb525839797095 100644 --- a/clang/test/APINotes/Inputs/Headers/module.modulemap +++ b/clang/test/APINotes/Inputs/Headers/module.modulemap @@ -2,6 +2,16 @@ module ExternCtx { header "ExternCtx.h" } +module ExportAsCore { + header "ExportAsCore.h" + export_as ExportAs +} + +module ExportAs { + header "ExportAs.h" + export * +} + module HeaderLib { header "HeaderLib.h" } @@ -26,6 +36,10 @@ module Namespaces { header "Namespaces.h" } +module Templates { + header "Templates.h" +} + module SwiftImportAs { header "SwiftImportAs.h" } diff --git a/clang/test/APINotes/export-as.c b/clang/test/APINotes/export-as.c new file mode 100644 index 0000000000000000000000000000000000000000..7a8a652ab755754e7b607780005294db6b73d48b --- /dev/null +++ b/clang/test/APINotes/export-as.c @@ -0,0 +1,8 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter globalInt -x c | FileCheck %s + +#include "ExportAs.h" + +// CHECK: Dumping globalInt: +// CHECK: VarDecl {{.+}} imported in ExportAsCore globalInt 'int' +// CHECK: UnavailableAttr {{.+}} <> "oh no" diff --git a/clang/test/APINotes/module-cache.m b/clang/test/APINotes/module-cache.m index 5dcaf1181f9dcfc85ddeb1706e3d1600f84667bf..e5920884ad860f086d3ad1391748ced664c46032 100644 --- a/clang/test/APINotes/module-cache.m +++ b/clang/test/APINotes/module-cache.m @@ -27,6 +27,7 @@ // RUN: FileCheck -check-prefix=CHECK-ONE-ERROR %s < %t/before.log // Change the API notes file, after the module has rebuilt once. +// RUN: chmod u+w %t/APINotes/SomeOtherKit.apinotes // RUN: echo ' - Selector: "methodA"' >> %t/APINotes/SomeOtherKit.apinotes // RUN: echo ' MethodKind: Instance' >> %t/APINotes/SomeOtherKit.apinotes // RUN: echo ' Availability: none' >> %t/APINotes/SomeOtherKit.apinotes diff --git a/clang/test/APINotes/templates.cpp b/clang/test/APINotes/templates.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4dce291615e18ac9d1b4b9bed32a4206f130c7f --- /dev/null +++ b/clang/test/APINotes/templates.cpp @@ -0,0 +1,9 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Tmpl -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -x c++ +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Tmpl -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Box -x c++ | FileCheck -check-prefix=CHECK-BOX %s + +#include "Templates.h" + +// CHECK-BOX: Dumping Box: +// CHECK-BOX-NEXT: ClassTemplateDecl {{.+}} imported in Templates Box +// CHECK-BOX: SwiftAttrAttr {{.+}} <> "import_owned" diff --git a/clang/test/AST/ast-dump-invalid.cpp b/clang/test/AST/ast-dump-invalid.cpp index 0a301dba51d288d08e0f119f261731ebe4431b81..5b6d74194b989d4dbf1a3d2a9a1702ba73d3f78f 100644 --- a/clang/test/AST/ast-dump-invalid.cpp +++ b/clang/test/AST/ast-dump-invalid.cpp @@ -60,3 +60,12 @@ double Str::foo1(double, invalid_type) // CHECK-NEXT: `-ReturnStmt {{.*}} // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'double' // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 45 + +namespace TestAliasTemplateDecl { +template class A; + +template +template using InvalidAlias = A; +// CHECK: TypeAliasTemplateDecl {{.*}} invalid InvalidAlias +// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 T +} diff --git a/clang/test/C/C2x/n2350.c b/clang/test/C/C2x/n2350.c index 2f738488a374270700ceeb9afb5e635ac6579b49..af0ca6d79be5e18315cad84a71e894d657249b41 100644 --- a/clang/test/C/C2x/n2350.c +++ b/clang/test/C/C2x/n2350.c @@ -5,7 +5,7 @@ // RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-comment -std=c99 -verify %s // RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-comment -std=c11 -verify %s // RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-comment -std=c17 -verify %s -// RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-comment -std=c2x -verify %s +// RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-comment -std=c2x -verify=silent %s // silent-no-diagnostics @@ -13,10 +13,10 @@ // https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm int simple(void) { return __builtin_offsetof(struct A // cpp-error {{'A' cannot be defined in a type specifier}} \ - expected-warning {{defining a type within '__builtin_offsetof' is a Clang extension}} + expected-warning {{defining a type within '__builtin_offsetof' is a C23 extension}} { int a; - struct B // expected-warning {{defining a type within '__builtin_offsetof' is a Clang extension}} + struct B // expected-warning {{defining a type within '__builtin_offsetof' is a C23 extension}} { int c; int d; @@ -26,7 +26,7 @@ int simple(void) { int anonymous_struct(void) { return __builtin_offsetof(struct // cpp-error-re {{'(unnamed struct at {{.*}})' cannot be defined in a type specifier}} \ - expected-warning {{defining a type within '__builtin_offsetof' is a Clang extension}} + expected-warning {{defining a type within '__builtin_offsetof' is a C23 extension}} { int a; int b; @@ -47,7 +47,7 @@ int struct_in_second_param(void) { int macro(void) { return offsetof(struct A // cpp-error {{'A' cannot be defined in a type specifier}} \ - expected-warning 2 {{defining a type within 'offsetof' is a Clang extension}} + expected-warning 2 {{defining a type within 'offsetof' is a C23 extension}} { int a; struct B // verifier seems to think the error is emitted by the macro diff --git a/clang/test/C/C99/Inputs/nested-include.h b/clang/test/C/C99/Inputs/nested-include.h new file mode 100644 index 0000000000000000000000000000000000000000..0f64473c0faef539fde8ab39f0a5f25fe355c6ba --- /dev/null +++ b/clang/test/C/C99/Inputs/nested-include.h @@ -0,0 +1,3 @@ +#if __COUNTER__ < 15 +#include __FILE__ +#endif diff --git a/clang/test/C/C99/digraphs.c b/clang/test/C/C99/digraphs.c new file mode 100644 index 0000000000000000000000000000000000000000..870a441118161af9d05f8b868d6555af52c57c08 --- /dev/null +++ b/clang/test/C/C99/digraphs.c @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -verify -ffreestanding %s + +/* WG14 ???: yes + * restricted character set support via digraphs and + * + * NB: I cannot find a definitive document number associated with the feature, + * which was pulled from the editor's report in the C99 front matter. However, + * based on discussion in the C99 rationale document, I believe this is + * referring to features added by AMD1 to support ISO 646 and digraphs. + */ + +// Validate that we provide iso646.h in freestanding mode. +#include + +// Validate that we define all the expected macros and their expected +// expansions (when suitable for a constant expression) as well. +#ifndef and +#error "missing and" +#else +_Static_assert((1 and 1) == (1 && 1), ""); +#endif + +#ifndef and_eq +#error "missing and_eq" +#endif + +#ifndef bitand +#error "missing bitand" +#else +_Static_assert((1 bitand 3) == (1 & 3), ""); +#endif + +#ifndef bitor +#error "missing bitor" +#else +_Static_assert((1 bitor 2) == (1 | 2), ""); +#endif + +#ifndef compl +#error "missing compl" +#else +_Static_assert((compl 0) == (~0), ""); +#endif + +#ifndef not +#error "missing not" +#else +_Static_assert((not 12) == (!12), ""); +#endif + +#ifndef not_eq +#error "missing not_eq" +#else +_Static_assert((0 not_eq 12) == (0 != 12), ""); +#endif + +#ifndef or +#error "missing or" +#else +// This intentionally diagnoses use of '||' only, because the user likely did +// not confuse the operator when using 'or' instead. +_Static_assert((0 or 12) == (0 || 12), ""); // expected-warning {{use of logical '||' with constant operand}} \ + expected-note {{use '|' for a bitwise operation}} +#endif + +#ifndef or_eq +#error "missing or_eq" +#endif + +#ifndef xor +#error "missing xor" +#else +_Static_assert((1 xor 3) == (1 ^ 3), ""); +#endif + +#ifndef xor_eq +#error "missing xor_eq" +#endif + +// Validate that digraphs behave the same as their expected counterparts. The +// definition should match the declaration in every way except spelling. +#define DI_NAME(f, b) f %:%: b +#define STD_NAME(f, b) f ## b +void DI_NAME(foo, bar)(int (*array)<: 0 :>); +void STD_NAME(foo, bar)(int (*array)[0]) {} + +#define DI_STR(f) %:f +#define STD_STR(f) #f +_Static_assert(__builtin_strcmp(DI_STR(testing), STD_STR(testing)) == 0, ""); + diff --git a/clang/test/C/C99/n570.c b/clang/test/C/C99/n570.c new file mode 100644 index 0000000000000000000000000000000000000000..31c09224e618b5ab7f9e24d8a0b1f4c5589d79f3 --- /dev/null +++ b/clang/test/C/C99/n570.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -verify -std=c99 %s +// RUN: %clang_cc1 -E -std=c99 %s | FileCheck %s +// expected-no-diagnostics + +/* WG14 N570: Yes + * Empty macro arguments + * + * NB: the original paper is not available online anywhere, so the test + * coverage is coming from what could be gleaned from the C99 rationale + * document. In C89, it was UB to pass no arguments to a function-like macro, + * and that's now supported in C99. + */ + +#define TEN 10 +#define U u +#define I // expands into no preprocessing tokens +#define L L +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) + +const unsigned u = xglue(TEN, U); +const int i = xglue(TEN, I); +const long l = xglue(TEN, L); + +// CHECK: const unsigned u = 10u; +// CHECK-NEXT: const int i = 10; +// CHECK-NEXT: const long l = 10L; + +_Static_assert(u == 10U, ""); +_Static_assert(i == 10, ""); +_Static_assert(l == 10L, ""); diff --git a/clang/test/C/C99/n590.c b/clang/test/C/C99/n590.c new file mode 100644 index 0000000000000000000000000000000000000000..7302e3c5cebabcc65590cb66079afa36e9868590 --- /dev/null +++ b/clang/test/C/C99/n590.c @@ -0,0 +1,390 @@ +// RUN: %clang_cc1 -verify -Wno-unused -I %S/Inputs %s + +/* WG14 N590: Clang 3.2 + * Increase minimum translation limits + * + * NB: the content of this document is not available, so this is testing + * against the implementation limits in C23, which are the most aggressive + * translation limits we can test against. + */ +// expected-no-diagnostics + +// 15 nesting levels for #included files +// NOTE: this relies on the value of __COUNTER__, so be very careful about +// adding code above this line of the test. +#include "nested-include.h" + +// Helpers for declaring unique variables. +#define CAT_IMPL(x, y) x ## y +#define CAT(x, y) CAT_IMPL(x, y) +#define ONCE(x) CAT(x, __COUNTER__) SEPARATOR +#define REPEAT10(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) +#define REPEAT63(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) ONCE(x) ONCE(x) ONCE(x) +#define REPEAT100(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) +#define REPEAT127(x) REPEAT100(x) REPEAT10(x) REPEAT10(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) +#define REPEAT500(x) REPEAT100(x) REPEAT100(x) REPEAT100(x) REPEAT100(x) REPEAT100(x) +#define REPEAT1000(x) REPEAT500(x) REPEAT500(x) +#define REPEAT1023(x) REPEAT1000(x) REPEAT10(x) REPEAT10(x) ONCE(x) ONCE(x) ONCE(x) +#define REPEAT4095(x) REPEAT1000(x) REPEAT1000(x) REPEAT1000(x) REPEAT1000(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) REPEAT10(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) ONCE(x) + +// Limits taken from C23 5.2.5.2p1. +void func(void) { + // 127 nesting levels of blocks + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ + }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + + // 12 pointer, array, and function declarators (in any combination) modifying + // an arithmetic, structure, union, or void type in a declaration. + void (************fp)(int foo[1][2][3][4][5][6][7][8][9][10][11][12]); + + // 63 nesting levels of parenthesized declarators within a full declarator. + int (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((decl))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + + // 63 significant initial characters in an internal identifier or a macro + // name. + static int aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffggg; + + // 31 significant initial characters in an external identifier. + extern int gggggggggghhhhhhhhhhiiiiiiiiiijjjjjjjjjjkkkkkkkkkkllllllllllmmm; + + // 511 identifiers with block scope declared in one block. + { + #define SEPARATOR ; + REPEAT500(int a) + REPEAT10(int a) + ONCE(int a) + #undef SEPARATOR + } + + // 4095 characters in a logical source line. + (void)0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4; + + // 4095 characters in a string literal (after concatenation) + (void)"0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,\ + 9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,\ + 7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,\ + 5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,\ + 3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,\ + 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4"; + + // 1023 case labels for a switch statement. + switch (aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffggg) { + #define SEPARATOR : + REPEAT1023(case 0x) + #undef SEPARATOR + break; + } +} + +// 32767 bytes in an object. +struct S { + unsigned char mem[32767]; +}; +_Static_assert(sizeof(struct S) >= 32767, ""); + +// 1023 members in a single structure or union +struct T { +#define SEPARATOR ; + REPEAT1023(int mem) +#undef SEPARATOR +}; + +// 1023 enumeration constants in a single enumeration +enum E { +#define SEPARATOR , +REPEAT1023(e) +#undef SEPARATOR +}; + +// 127 parameters in one function definition. +#define SEPARATOR , +// Because the parameters are all separated by commas, we have to add a final +// parameter (without a preceeding comma) to form a valid declaration. +void lots_of_params(REPEAT127(int a) int last) { + // 127 arguments in one function call + lots_of_params(REPEAT127(0x0) 0); +} +#undef SEPARATOR + +// 63 levels of nested structure or union definitions in a single member +// declaration list. +struct U { +#define SEPARATOR ; +REPEAT63(struct { int a) +REPEAT63(} mem) +#undef SEPARATOR +}; + +// 63 nesting levels of conditional inclusion +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 +#if 1 + +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif + +// 63 initial characters in a macro name. +#define AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEEFFFFFFFFFFGGG + +// 4095 external identifiers in one translation unit. +#define SEPARATOR ; +REPEAT4095(extern int val) +#undef SEPARATOR + +// 127 parameters in one macro definition +#define BIG_UN(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, \ + a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, \ + a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, \ + a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, \ + a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, \ + a60, a61, a62, a63, a64, a65, a66, a67, a68, a69, \ + a70, a71, a72, a73, a74, a75, a76, a77, a78, a79, \ + a80, a81, a82, a83, a84, a85, a86, a87, a88, a89, \ + a90, a91, a92, a93, a94, a95, a96, a97, a98, a99, \ + a100, a101, a102, a103, a104, a105, a106, a107, a108, a109, \ + a110, a111, a112, a113, a114, a115, a116, a117, a118, a119, \ + a120, a121, a122, a123, a124, a125, a126) 0 + +// 127 arguments in one macro invocation +int val = BIG_UN(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \ + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \ + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \ + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \ + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \ + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \ + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \ + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, \ + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, \ + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, \ + 120, 121, 122, 123, 124, 125, 126); + +// 4095 macro identifiers simultaneously defined in one preprocessing +// translation unit. Rather than write out 4095 macro definitions, we'll use a +// cheap python script to generate the contents and test that. +// RUN: %python -c "print('\n'.join(['// expected-no-diagnostics'] + [f'#define M{i}\n' for i in range(4096)]))" >%t.inc +// RUN: %clang_cc1 -verify %t.inc diff --git a/clang/test/C/drs/dr4xx.c b/clang/test/C/drs/dr4xx.c index 30145dcfeef16861d746c1d38c64a417f1c8afdf..83d7b94cd67959dfeedf0141dd35b7d22e9049f8 100644 --- a/clang/test/C/drs/dr4xx.c +++ b/clang/test/C/drs/dr4xx.c @@ -1,7 +1,7 @@ -/* RUN: %clang_cc1 -std=c89 -verify=expected,c89only -pedantic -Wno-c11-extensions %s - RUN: %clang_cc1 -std=c99 -verify=expected -pedantic -Wno-c11-extensions %s - RUN: %clang_cc1 -std=c11 -verify=expected -pedantic %s - RUN: %clang_cc1 -std=c17 -verify=expected -pedantic %s +/* RUN: %clang_cc1 -std=c89 -verify=expected,c89only,pre-c23 -pedantic -Wno-c11-extensions %s + RUN: %clang_cc1 -std=c99 -verify=expected,pre-c23 -pedantic -Wno-c11-extensions %s + RUN: %clang_cc1 -std=c11 -verify=expected,pre-c23 -pedantic %s + RUN: %clang_cc1 -std=c17 -verify=expected,pre-c23 -pedantic %s RUN: %clang_cc1 -std=c2x -verify=expected -pedantic %s */ @@ -343,10 +343,13 @@ void dr496(void) { */ /* The DR asked a question about whether defining a new type within offsetof - * is allowed. C2x N2350 made this explicitly undefined behavior, but GCC and - * Clang both support it as an extension. + * is allowed. C23 N2350 had made this explicitly undefined behavior, but this + * was later overturned when C23 DE-137 was accepted, making it well-formed. + * + * Additionally, GCC and Clang both support it as an extension in pre-C23 + * mode. */ - (void)__builtin_offsetof(struct S { int a; }, a); /* expected-warning{{defining a type within '__builtin_offsetof' is a Clang extension}} */ + (void)__builtin_offsetof(struct S { int a; }, a); /* pre-c23-warning{{defining a type within '__builtin_offsetof' is a C23 extension}} */ } /* WG14 DR499: yes diff --git a/clang/test/C/drs/dr5xx.c b/clang/test/C/drs/dr5xx.c index 68bcef78baccd7caca8f0d373ca91bc2c72ab70d..13464f78b6a654a3821e8b587fd3642a6d1a1e0b 100644 --- a/clang/test/C/drs/dr5xx.c +++ b/clang/test/C/drs/dr5xx.c @@ -29,7 +29,7 @@ void dr502(void) { */ struct t { int i; - struct { int a[]; }; /* expected-error {{flexible array member 'a' not allowed in otherwise empty struct}} + struct { int a[]; }; /* expected-warning {{flexible array member 'a' in otherwise empty struct is a GNU extension}} c89only-warning {{flexible array members are a C99 feature}} expected-warning {{'' may not be nested in a struct due to flexible array member}} */ diff --git a/clang/test/ClangScanDeps/modules-extern-unrelated.m b/clang/test/ClangScanDeps/modules-extern-unrelated.m index 442ee90aa1836d48dcd112cd5a1c4f59103e538d..76611c596d3effcc3287cc2f54a0c59e19ea1fb2 100644 --- a/clang/test/ClangScanDeps/modules-extern-unrelated.m +++ b/clang/test/ClangScanDeps/modules-extern-unrelated.m @@ -71,6 +71,7 @@ module second { header "second.h" } // CHECK-NEXT: "context-hash": "{{.*}}", // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/first/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap", // CHECK-NEXT: "[[PREFIX]]/second/second.h", // CHECK-NEXT: "[[PREFIX]]/second/second.modulemap" // CHECK-NEXT: ], diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c index 35d6973818d01c0e4134616a2706869505463711..b303d71304bf3ece9b14905e395618055f66a48a 100644 --- a/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c @@ -2,6 +2,28 @@ // RUN: not %clang_cc1 -triple riscv64 -target-feature +zifencei -target-feature +m -target-feature +a \ // RUN: -emit-llvm %s 2>&1 | FileCheck %s +#include + +void test_builtin() { +// CHECK: error: '__builtin_rvv_vsetvli' needs target feature zve32x + __riscv_vsetvl_e8m8(1); +} + +void test_rvv_i32_type() { +// CHECK: error: RISC-V type 'vint32m1_t' (aka '__rvv_int32m1_t') requires the 'zve32x' extension + vint32m1_t v; +} + +void test_rvv_f32_type() { +// CHECK: error: RISC-V type 'vfloat32m1_t' (aka '__rvv_float32m1_t') requires the 'zve32f' extension + vfloat32m1_t v; +} + +void test_rvv_f64_type() { +// CHECK: error: RISC-V type 'vfloat64m1_t' (aka '__rvv_float64m1_t') requires the 'zve64d' extension + vfloat64m1_t v; +} + // CHECK: error: duplicate 'arch=' in the 'target' attribute string; __attribute__((target("arch=rv64gc;arch=rv64gc_zbb"))) void testMultiArchSelectLast() {} // CHECK: error: duplicate 'cpu=' in the 'target' attribute string; diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c index f216eaf735b4a8546c95008f4bd573225d1ad984..1f8682179ea813886c1a1d9f82dfa134f1f844d9 100644 --- a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c @@ -4,6 +4,8 @@ // RUN: -target-feature -relax -target-feature -zfa \ // RUN: -emit-llvm %s -o - | FileCheck %s +#include + // CHECK-LABEL: define dso_local void @testDefault // CHECK-SAME: () #0 { void testDefault() {} @@ -35,6 +37,34 @@ testAttrFullArchAndAttrCpu() {} // CHECK-SAME: () #8 { __attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} +__attribute__((target("arch=+zve32x"))) +void test_builtin_w_zve32x() { +// CHECK-LABEL: test_builtin_w_zve32x +// CHECK-SAME: #9 + __riscv_vsetvl_e8m8(1); +} + +__attribute__((target("arch=+zve32x"))) +void test_rvv_i32_type_w_zve32x() { +// CHECK-LABEL: test_rvv_i32_type_w_zve32x +// CHECK-SAME: #9 + vint32m1_t v; +} + +__attribute__((target("arch=+zve32f"))) +void test_rvv_f32_type_w_zve32f() { +// CHECK-LABEL: test_rvv_f32_type_w_zve32f +// CHECK-SAME: #11 + vfloat32m1_t v; +} + +__attribute__((target("arch=+zve64d"))) +void test_rvv_f64_type_w_zve64d() { +// CHECK-LABEL: test_rvv_f64_type_w_zve64d +// CHECK-SAME: #12 + vfloat64m1_t v; +} + //. // CHECK: attributes #0 = { {{.*}}"target-features"="+64bit,+a,+m,+save-restore,+zifencei,-relax,-zbb,-zfa" } // CHECK: attributes #1 = { {{.*}}"target-cpu"="rocket-rv64" "target-features"="+64bit,+a,+d,+f,+m,+save-restore,+v,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-relax,-zbb,-zfa" "tune-cpu"="generic-rv64" } @@ -46,3 +76,6 @@ __attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} // CHECK: attributes #6 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+m,+save-restore,+zbb,+zifencei,-relax,-zfa" } // CHECK: attributes #7 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+m,+save-restore,{{(-[[:alnum:]-]+)(,-[[:alnum:]-]+)*}}" } // CHECK: attributes #8 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zicsr,+zifencei,{{(-[[:alnum:]-]+)(,-[[:alnum:]-]+)*}}" } +// CHECK: attributes #9 = { {{.*}}"target-features"="+64bit,+a,+m,+save-restore,+zicsr,+zifencei,+zve32x,+zvl32b,-relax,-zbb,-zfa" } +// CHECK: attributes #11 = { {{.*}}"target-features"="+64bit,+a,+f,+m,+save-restore,+zicsr,+zifencei,+zve32f,+zve32x,+zvl32b,-relax,-zbb,-zfa" } +// CHECK: attributes #12 = { {{.*}}"target-features"="+64bit,+a,+d,+f,+m,+save-restore,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl32b,+zvl64b,-relax,-zbb,-zfa" } diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c new file mode 100644 index 0000000000000000000000000000000000000000..072d8a863d45705b7faacb0fa8f6abecea0655eb --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c @@ -0,0 +1,34 @@ +// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -triple riscv64 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s +// RUN: %clang_cc1 -std=c23 -triple riscv64 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s + +#include + +// CHECK-LLVM: call riscv_vector_cc @bar +vint32m1_t __attribute__((riscv_vector_cc)) bar(vint32m1_t input); +vint32m1_t test_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = bar(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} + +// CHECK-LLVM: call riscv_vector_cc @bar +[[riscv::vector_cc]] vint32m1_t bar(vint32m1_t input); +vint32m1_t test_vector_cc_attr2(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = bar(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} + +// CHECK-LLVM: call @baz +vint32m1_t baz(vint32m1_t input); +vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = baz(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c01aeb21f675714d328f375853671099e1789371 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp @@ -0,0 +1,32 @@ +// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -std=c++11 -triple riscv64 -target-feature +v \ +// RUN: -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s + +#include + +// CHECK-LLVM: call riscv_vector_cc @_Z3baru15__rvv_int32m1_t +vint32m1_t __attribute__((riscv_vector_cc)) bar(vint32m1_t input); +vint32m1_t test_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = bar(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} + +// CHECK-LLVM: call riscv_vector_cc @_Z3baru15__rvv_int32m1_t +[[riscv::vector_cc]] vint32m1_t bar(vint32m1_t input); +vint32m1_t test_vector_cc_attr2(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = bar(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} + +// CHECK-LLVM: call @_Z3bazu15__rvv_int32m1_t +vint32m1_t baz(vint32m1_t input); +vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) { + vint32m1_t val = __riscv_vle32_v_i32m1(base, vl); + vint32m1_t ret = baz(input); + __riscv_vse32_v_i32m1(base, val, vl); + return ret; +} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c new file mode 100644 index 0000000000000000000000000000000000000000..5c35901799b4276b8959003d904d5b210519645f --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -std=c23 -triple riscv64 -target-feature +v -verify + +__attribute__((riscv_vector_cc)) int var; // expected-warning {{'riscv_vector_cc' only applies to function types; type here is 'int'}} + +__attribute__((riscv_vector_cc)) void func(); +__attribute__((riscv_vector_cc(1))) void func_invalid(); // expected-error {{'riscv_vector_cc' attribute takes no arguments}} + +void test_no_attribute(int); // expected-note {{previous declaration is here}} +void __attribute__((riscv_vector_cc)) test_no_attribute(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}} + +[[riscv::vector_cc]] int var2; // expected-warning {{'vector_cc' only applies to function types; type here is 'int'}} + +[[riscv::vector_cc]] void func2(); +[[riscv::vector_cc(1)]] void func_invalid2(); // expected-error {{'vector_cc' attribute takes no arguments}} + +void test_no_attribute2(int); // expected-note {{previous declaration is here}} +[[riscv::vector_cc]] void test_no_attribute2(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}} diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp new file mode 100644 index 0000000000000000000000000000000000000000..264bb7d9ad7c00172a2c3dc9d5dcfa535054fe64 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -triple riscv64 -target-feature +v -verify + +__attribute__((riscv_vector_cc)) int var; // expected-warning {{'riscv_vector_cc' only applies to function types; type here is 'int'}} + +__attribute__((riscv_vector_cc)) void func(); +__attribute__((riscv_vector_cc(1))) void func_invalid(); // expected-error {{'riscv_vector_cc' attribute takes no arguments}} + +void test_no_attribute(int); // expected-note {{previous declaration is here}} +void __attribute__((riscv_vector_cc)) test_no_attribute(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}} + +class test_cc { + __attribute__((riscv_vector_cc)) void member_func(); +}; + +void test_lambda() { + __attribute__((riscv_vector_cc)) auto lambda = []() { // expected-warning {{'riscv_vector_cc' only applies to function types; type here is 'auto'}} + }; +} + +[[riscv::vector_cc]] int var2; // expected-warning {{'vector_cc' only applies to function types; type here is 'int'}} + +[[riscv::vector_cc]] void func2(); +[[riscv::vector_cc(1)]] void func_invalid2(); // expected-error {{'vector_cc' attribute takes no arguments}} + +void test_no_attribute2(int); // expected-note {{previous declaration is here}} +[[riscv::vector_cc]] void test_no_attribute2(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}} + +class test_cc2 { + [[riscv::vector_cc]] void member_func(); +}; + +void test_lambda2() { + [[riscv::vector_cc]] auto lambda = []() { // expected-warning {{'vector_cc' only applies to function types; type here is 'auto'}} + }; +} diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c index ecf090a128aac702d3ea6cb25fc5c4c1ed0827ab..bad68504fab055719a27dc19e6260952a5c67252 100644 --- a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv32-zbb-error.c @@ -1,6 +1,6 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -triple riscv32 -target-feature +zbb -verify %s -o - +// RUN: %clang_cc1 -triple riscv32 -target-feature +zbb -S -verify %s -o - unsigned int orc_b_64(unsigned int a) { - return __builtin_riscv_orc_b_64(a); // expected-error {{builtin requires: 'RV64'}} + return __builtin_riscv_orc_b_64(a); // expected-error {{'__builtin_riscv_orc_b_64' needs target feature zbb,64bit}} } diff --git a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c index d2e3e76043aef16304ff7ad0ad73709182d9a55c..a256bf75b031c6ddc13204bee185d5b087a4b03c 100644 --- a/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c +++ b/clang/test/CodeGen/RISCV/rvb-intrinsics/riscv64-zbkb-error.c @@ -1,14 +1,10 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -triple riscv64 -target-feature +zbkb -verify %s -o - +// RUN: %clang_cc1 -triple riscv64 -target-feature +zbkb -S -verify %s -o - #include -uint32_t zip(uint32_t rs1) +uint32_t zip_unzip(uint32_t rs1) { - return __builtin_riscv_zip_32(rs1); // expected-error {{builtin requires: 'RV32'}} -} - -uint32_t unzip(uint32_t rs1) -{ - return __builtin_riscv_unzip_32(rs1); // expected-error {{builtin requires: 'RV32'}} + (void)__builtin_riscv_zip_32(rs1); // expected-error {{'__builtin_riscv_zip_32' needs target feature zbkb,32bit}} + return __builtin_riscv_unzip_32(rs1); // expected-error {{'__builtin_riscv_unzip_32' needs target feature zbkb,32bit}} } diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c index 6ec9b057997690a919a39da38a85e31372af0ffe..ecb6c5f27025779aafbdbd96606137f34cb2a60f 100644 --- a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c +++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-error.c @@ -11,7 +11,7 @@ // CHECK-RV64V-NEXT: ret i32 [[CONV]] // -// CHECK-RV64-ERR: error: builtin requires at least one of the following extensions: 'Zve32x' +// CHECK-RV64-ERR: error: '__builtin_rvv_vsetvli' needs target feature zve32x int test() { return __builtin_rvv_vsetvli(1, 0, 0); diff --git a/clang/test/CodeGen/aapcs-bitfield-access-unit.c b/clang/test/CodeGen/aapcs-bitfield-access-unit.c new file mode 100644 index 0000000000000000000000000000000000000000..e95dba1c5f50cf63f3f77c582f04b297b903e533 --- /dev/null +++ b/clang/test/CodeGen/aapcs-bitfield-access-unit.c @@ -0,0 +1,231 @@ +// RUN: %clang_cc1 -triple armv8-none-linux-eabi -fno-aapcs-bitfield-width -fdump-record-layouts-simple -emit-llvm -o /dev/null %s | FileCheck %s -check-prefixes=LAYOUT +// RUN: %clang_cc1 -triple armebv8-none-linux-eabi -fno-aapcs-bitfield-width -fdump-record-layouts-simple -emit-llvm -o /dev/null %s | FileCheck %s -check-prefixes=LAYOUT + +// RUN: %clang_cc1 -triple armv8-none-linux-eabi -faapcs-bitfield-width -fdump-record-layouts-simple -emit-llvm -o /dev/null %s | FileCheck %s -check-prefixes=LAYOUT +// RUN: %clang_cc1 -triple armebv8-none-linux-eabi -faapcs-bitfield-width -fdump-record-layouts-simple -emit-llvm -o /dev/null %s | FileCheck %s -check-prefixes=LAYOUT + +struct st0 { + short c : 7; +} st0; +// LAYOUT-LABEL: LLVMType:%struct.st0 = +// LAYOUT-SAME: type { i8, i8 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st1 { + int a : 10; + short c : 6; +} st1; +// LAYOUT-LABEL: LLVMType:%struct.st1 = +// LAYOUT-SAME: type { i16, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st2 { + int a : 10; + short c : 7; +} st2; +// LAYOUT-LABEL: LLVMType:%struct.st2 = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st3 { + volatile short c : 7; +} st3; +// LAYOUT-LABEL: LLVMType:%struct.st3 = +// LAYOUT-SAME: type { i8, i8 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st4 { + int b : 9; + volatile char c : 5; +} st4; +// LAYOUT-LABEL: LLVMType:%struct.st4 = +// LAYOUT-SAME: type { i16, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st5 { + int a : 12; + volatile char c : 5; +} st5; +// LAYOUT-LABEL: LLVMType:%struct.st5 = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st6 { + int a : 12; + char b; + int c : 5; +} st6; +// LAYOUT-LABEL: LLVMType:%struct.st6 = +// LAYOUT-SAME: type { i16, i8, i8 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st7a { + char a; + int b : 5; +} st7a; +// LAYOUT-LABEL: LLVMType:%struct.st7a = +// LAYOUT-SAME: type { i8, i8, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st7b { + char x; + volatile struct st7a y; +} st7b; +// LAYOUT-LABEL: LLVMType:%struct.st7b = +// LAYOUT-SAME: type { i8, [3 x i8], %struct.st7a } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: ]> + +struct st8 { + unsigned f : 16; +} st8; +// LAYOUT-LABEL: LLVMType:%struct.st8 = +// LAYOUT-SAME: type { i16, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st9{ + int f : 8; +} st9; +// LAYOUT-LABEL: LLVMType:%struct.st9 = +// LAYOUT-SAME: type { i8, [3 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st10{ + int e : 1; + int f : 8; +} st10; +// LAYOUT-LABEL: LLVMType:%struct.st10 = +// LAYOUT-SAME: type { i16, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st11{ + char e; + int f : 16; +} st11; +// LAYOUT-LABEL: LLVMType:%struct.st11 = +// LAYOUT-SAME: type <{ i8, i16, i8 }> +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st12{ + int e : 8; + int f : 16; +} st12; +// LAYOUT-LABEL: LLVMType:%struct.st12 = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st13 { + char a : 8; + int b : 32; +} __attribute__((packed)) st13; +// LAYOUT-LABEL: LLVMType:%struct.st13 = +// LAYOUT-SAME: type <{ i8, i32 }> +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st14 { + char a : 8; +} __attribute__((packed)) st14; +// LAYOUT-LABEL: LLVMType:%struct.st14 = +// LAYOUT-SAME: type { i8 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st15 { + short a : 8; +} __attribute__((packed)) st15; +// LAYOUT-LABEL: LLVMType:%struct.st15 = +// LAYOUT-SAME: type { i8 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st16 { + int a : 32; + int b : 16; + int c : 32; + int d : 16; +} st16; +// LAYOUT-LABEL: LLVMType:%struct.st16 = +// LAYOUT-SAME: type { i32, i16, i32, i16 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct st17 { +int b : 32; +char c : 8; +} __attribute__((packed)) st17; +// LAYOUT-LABEL: LLVMType:%struct.st17 = +// LAYOUT-SAME: type <{ i32, i8 }> +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct zero_bitfield { + int a : 8; + char : 0; + int b : 8; +} st18; +// LAYOUT-LABEL: LLVMType:%struct.zero_bitfield = +// LAYOUT-SAME: type { i8, i8, [2 x i8] } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + +struct zero_bitfield_ok { + short a : 8; + char a1 : 8; + long : 0; + int b : 24; +} st19; +// LAYOUT-LABEL: LLVMType:%struct.zero_bitfield_ok = +// LAYOUT-SAME: type { i16, i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + + diff --git a/clang/test/CodeGen/aapcs-bitfield.c b/clang/test/CodeGen/aapcs-bitfield.c index 152ee26e7a3ea94a60be2ccd546c666a2cd49bd9..0df250d4ebc53e45723f76f99a69b0e626a7fd2e 100644 --- a/clang/test/CodeGen/aapcs-bitfield.c +++ b/clang/test/CodeGen/aapcs-bitfield.c @@ -299,77 +299,73 @@ struct st2 { // LE-LABEL: @st2_check_load( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LE-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 1 -// LE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// LE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LE-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 9 +// LE-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// LE-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // LE-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // LE-NEXT: ret i32 [[CONV]] // // BE-LABEL: @st2_check_load( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 1 -// BE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// BE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BE-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BE-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// BE-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // BE-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // BE-NEXT: ret i32 [[CONV]] // // LENUMLOADS-LABEL: @st2_check_load( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 1 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 9 +// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // LENUMLOADS-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // LENUMLOADS-NEXT: ret i32 [[CONV]] // // BENUMLOADS-LABEL: @st2_check_load( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 1 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // BENUMLOADS-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // BENUMLOADS-NEXT: ret i32 [[CONV]] // // LEWIDTH-LABEL: @st2_check_load( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 1 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 9 +// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // LEWIDTH-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // LEWIDTH-NEXT: ret i32 [[CONV]] // // BEWIDTH-LABEL: @st2_check_load( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 1 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // BEWIDTH-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // BEWIDTH-NEXT: ret i32 [[CONV]] // // LEWIDTHNUM-LABEL: @st2_check_load( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 1 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 9 +// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // LEWIDTHNUM-NEXT: ret i32 [[CONV]] // // BEWIDTHNUM-LABEL: @st2_check_load( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 1 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_ASHR]] to i16 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 25 +// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i16 // BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i16 [[BF_CAST]] to i32 // BEWIDTHNUM-NEXT: ret i32 [[CONV]] // @@ -379,74 +375,66 @@ int st2_check_load(struct st2 *m) { // LE-LABEL: @st2_check_store( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -128 -// LE-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LE-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// LE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LE-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -8323073 +// LE-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LE-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // LE-NEXT: ret void // // BE-LABEL: @st2_check_store( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 1 -// BE-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// BE-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// BE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BE-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -65025 +// BE-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 512 +// BE-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @st2_check_store( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -128 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LENUMLOADS-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -8323073 +// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LENUMLOADS-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @st2_check_store( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 1 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// BENUMLOADS-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -65025 +// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 512 +// BENUMLOADS-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @st2_check_store( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -128 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LEWIDTH-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -8323073 +// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LEWIDTH-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @st2_check_store( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 1 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// BEWIDTH-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -65025 +// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 512 +// BEWIDTH-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @st2_check_store( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -128 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LEWIDTHNUM-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -8323073 +// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LEWIDTHNUM-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @st2_check_store( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST2:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[C]], align 2 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 1 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// BEWIDTHNUM-NEXT: store i8 [[BF_SET]], ptr [[C]], align 2 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[M:%.*]], align 4 +// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -65025 +// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 512 +// BEWIDTHNUM-NEXT: store i32 [[BF_SET]], ptr [[M]], align 4 // BEWIDTHNUM-NEXT: ret void // void st2_check_store(struct st2 *m) { @@ -636,8 +624,8 @@ struct st4 { // // LEWIDTH-LABEL: @st4_check_load( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 2 // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // LEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -645,8 +633,8 @@ struct st4 { // // BEWIDTH-LABEL: @st4_check_load( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // BEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -654,8 +642,8 @@ struct st4 { // // LEWIDTHNUM-LABEL: @st4_check_load( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 2 // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -663,8 +651,8 @@ struct st4 { // // BEWIDTHNUM-LABEL: @st4_check_load( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 1 // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -708,38 +696,38 @@ int st4_check_load(struct st4 *m) { // // LEWIDTH-LABEL: @st4_check_store( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -63 // LEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// LEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP1]], align 1 +// LEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 1 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @st4_check_store( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -125 // BEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 4 -// BEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP1]], align 1 +// BEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 1 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @st4_check_store( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -63 // LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 2 -// LEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP1]], align 1 +// LEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 1 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @st4_check_store( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -125 // BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 4 -// BEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP1]], align 1 +// BEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 1 // BEWIDTHNUM-NEXT: ret void // void st4_check_store(struct st4 *m) { @@ -821,42 +809,44 @@ struct st5 { // LE-LABEL: @st5_check_load( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// LE-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 3 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 -// LE-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// LE-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 11 +// LE-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 27 +// LE-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i8 +// LE-NEXT: [[CONV:%.*]] = sext i8 [[BF_CAST]] to i32 // LE-NEXT: ret i32 [[CONV]] // // BE-LABEL: @st5_check_load( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 3 -// BE-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// BE-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BE-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 27 +// BE-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i8 +// BE-NEXT: [[CONV:%.*]] = sext i8 [[BF_CAST]] to i32 // BE-NEXT: ret i32 [[CONV]] // // LENUMLOADS-LABEL: @st5_check_load( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 3 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 -// LENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 11 +// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 27 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i8 +// LENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[BF_CAST]] to i32 // LENUMLOADS-NEXT: ret i32 [[CONV]] // // BENUMLOADS-LABEL: @st5_check_load( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 3 -// BENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 +// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 27 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i32 [[BF_ASHR]] to i8 +// BENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[BF_CAST]] to i32 // BENUMLOADS-NEXT: ret i32 [[CONV]] // // LEWIDTH-LABEL: @st5_check_load( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 3 // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // LEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -864,16 +854,16 @@ struct st5 { // // BEWIDTH-LABEL: @st5_check_load( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 3 // BEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 // BEWIDTH-NEXT: ret i32 [[CONV]] // // LEWIDTHNUM-LABEL: @st5_check_load( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i8 [[BF_LOAD]], 3 // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_SHL]], 3 // LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 @@ -881,8 +871,8 @@ struct st5 { // // BEWIDTHNUM-LABEL: @st5_check_load( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i8 [[BF_LOAD]], 3 // BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[BF_ASHR]] to i32 // BEWIDTHNUM-NEXT: ret i32 [[CONV]] @@ -893,74 +883,70 @@ int st5_check_load(struct st5 *m) { // LE-LABEL: @st5_check_store( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -32 -// LE-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LE-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// LE-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -2031617 +// LE-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LE-NEXT: store volatile i32 [[BF_SET]], ptr [[M]], align 4 // LE-NEXT: ret void // // BE-LABEL: @st5_check_store( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 7 -// BE-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 8 -// BE-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// BE-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -63489 +// BE-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 2048 +// BE-NEXT: store volatile i32 [[BF_SET]], ptr [[M]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @st5_check_store( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -32 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LENUMLOADS-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -2031617 +// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 65536 +// LENUMLOADS-NEXT: store volatile i32 [[BF_SET]], ptr [[M]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @st5_check_store( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 7 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 8 -// BENUMLOADS-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[M:%.*]], align 4 +// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -63489 +// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], 2048 +// BENUMLOADS-NEXT: store volatile i32 [[BF_SET]], ptr [[M]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @st5_check_store( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -32 // LEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// LEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 2 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @st5_check_store( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 7 // BEWIDTH-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 8 -// BEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// BEWIDTH-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 2 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @st5_check_store( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -32 // LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 1 -// LEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// LEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 2 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @st5_check_store( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST5:%.*]], ptr [[M:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 2 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[M:%.*]], i32 2 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP0]], align 2 // BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], 7 // BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i8 [[BF_CLEAR]], 8 -// BEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[C]], align 2 +// BEWIDTHNUM-NEXT: store volatile i8 [[BF_SET]], ptr [[TMP0]], align 2 // BEWIDTHNUM-NEXT: ret void // void st5_check_store(struct st5 *m) { @@ -980,8 +966,8 @@ struct st6 { // LE-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 4 // LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// LE-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// LE-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// LE-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// LE-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // LE-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -997,8 +983,8 @@ struct st6 { // BE-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 4 // BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// BE-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// BE-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// BE-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// BE-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // BE-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1014,8 +1000,8 @@ struct st6 { // LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 4 // LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// LENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// LENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // LENUMLOADS-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1031,8 +1017,8 @@ struct st6 { // BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 4 // BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// BENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// BENUMLOADS-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // BENUMLOADS-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1048,8 +1034,8 @@ struct st6 { // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 4 // LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// LEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// LEWIDTH-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// LEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // LEWIDTH-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1065,8 +1051,8 @@ struct st6 { // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 4 // BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// BEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// BEWIDTH-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// BEWIDTH-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // BEWIDTH-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1082,8 +1068,8 @@ struct st6 { // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 4 // LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // LEWIDTHNUM-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1099,8 +1085,8 @@ struct st6 { // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 4 // BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST6:%.*]], ptr [[M]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = load volatile i8, ptr [[B]], align 2 -// BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[TMP1]] to i32 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = load volatile i8, ptr [[B]], align 2 +// BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 // BEWIDTHNUM-NEXT: [[ADD:%.*]] = add nsw i32 [[BF_CAST]], [[CONV]] // BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST6]], ptr [[M]], i32 0, i32 2 // BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 @@ -1704,9 +1690,9 @@ void store_st9(volatile struct st9 *m) { // LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[M:%.*]], align 4 // LE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// LE-NEXT: store volatile i8 [[TMP1]], ptr [[M]], align 4 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// LE-NEXT: store volatile i8 [[TMP0]], ptr [[M]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_st9( @@ -1714,9 +1700,9 @@ void store_st9(volatile struct st9 *m) { // BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[M:%.*]], align 4 // BE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// BE-NEXT: store volatile i8 [[TMP1]], ptr [[M]], align 4 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// BE-NEXT: store volatile i8 [[TMP0]], ptr [[M]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_st9( @@ -1724,10 +1710,10 @@ void store_st9(volatile struct st9 *m) { // LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[M:%.*]], align 4 // LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[M]], align 4 -// LENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[M]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[M]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_st9( @@ -1735,10 +1721,10 @@ void store_st9(volatile struct st9 *m) { // BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[M:%.*]], align 4 // BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[M]], align 4 -// BENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[M]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[M]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_st9( @@ -1949,9 +1935,9 @@ void store_st10(volatile struct st10 *m) { // LE-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i16 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 // LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[M]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255 +// LE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // LE-NEXT: [[BF_SHL2:%.*]] = shl i16 [[BF_VALUE]], 1 // LE-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD1]], -511 // LE-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL2]] @@ -1968,9 +1954,9 @@ void store_st10(volatile struct st10 *m) { // BE-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i16 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 // BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[M]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255 +// BE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // BE-NEXT: [[BF_SHL2:%.*]] = shl i16 [[BF_VALUE]], 7 // BE-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD1]], -32641 // BE-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL2]] @@ -1987,9 +1973,9 @@ void store_st10(volatile struct st10 *m) { // LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i16 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 // LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[M]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255 +// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // LENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i16 [[BF_VALUE]], 1 // LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD1]], -511 // LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL2]] @@ -2006,9 +1992,9 @@ void store_st10(volatile struct st10 *m) { // BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i16 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 // BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[M]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255 +// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // BENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i16 [[BF_VALUE]], 7 // BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD1]], -32641 // BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL2]] @@ -2767,146 +2753,70 @@ struct st13 { // LE-LABEL: @increment_b_st13( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// LE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // LE-NEXT: ret void // // BE-LABEL: @increment_b_st13( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// BE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_b_st13( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[B]], align 1 +// LENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_b_st13( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[B]], align 1 +// BENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_b_st13( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LEWIDTH-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_b_st13( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BEWIDTH-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_b_st13( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LEWIDTHNUM-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[B]], align 1 +// LEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_b_st13( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BEWIDTHNUM-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST13:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[B]], align 1 +// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[B]], align 1 +// BEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[B]], align 1 // BEWIDTHNUM-NEXT: ret void // void increment_b_st13(volatile struct st13 *s) { @@ -2990,9 +2900,9 @@ struct st15 { // LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // LE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // LE-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 -// LE-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// LE-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 +// LE-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // LE-NEXT: ret void // // BE-LABEL: @increment_a_st15( @@ -3000,9 +2910,9 @@ struct st15 { // BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // BE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // BE-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 -// BE-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// BE-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 +// BE-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_a_st15( @@ -3010,10 +2920,10 @@ struct st15 { // LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // LENUMLOADS-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 // LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 1 -// LENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// LENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_a_st15( @@ -3021,10 +2931,10 @@ struct st15 { // BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // BENUMLOADS-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 // BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 1 -// BENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// BENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_a_st15( @@ -3032,9 +2942,9 @@ struct st15 { // LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // LEWIDTH-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 -// LEWIDTH-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// LEWIDTH-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 +// LEWIDTH-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_a_st15( @@ -3042,9 +2952,9 @@ struct st15 { // BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // BEWIDTH-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 -// BEWIDTH-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// BEWIDTH-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 +// BEWIDTH-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_a_st15( @@ -3052,10 +2962,10 @@ struct st15 { // LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 // LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// LEWIDTHNUM-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_a_st15( @@ -3063,10 +2973,10 @@ struct st15 { // BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 1 // BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i16 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add i16 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = trunc i16 [[INC]] to i8 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i16 [[INC]] to i8 // BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i16 +// BEWIDTHNUM-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 1 +// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i16 // BEWIDTHNUM-NEXT: ret void // void increment_a_st15(volatile struct st15 *s) { @@ -3082,146 +2992,58 @@ struct st16 { // LE-LABEL: @increment_a_st16( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LE-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store i32 [[INC]], ptr [[S]], align 4 // LE-NEXT: ret void // // BE-LABEL: @increment_a_st16( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BE-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store i32 [[INC]], ptr [[S]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_a_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: store i32 [[INC]], ptr [[S]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_a_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: store i32 [[INC]], ptr [[S]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_a_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTH-NEXT: store i32 [[INC]], ptr [[S]], align 4 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_a_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTH-NEXT: store i32 [[INC]], ptr [[S]], align 4 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_a_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTHNUM-NEXT: store i32 [[INC]], ptr [[S]], align 4 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_a_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[S:%.*]], align 4 +// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTHNUM-NEXT: store i32 [[INC]], ptr [[S]], align 4 // BEWIDTHNUM-NEXT: ret void // void increment_a_st16(struct st16 *s) { @@ -3230,154 +3052,90 @@ void increment_a_st16(struct st16 *s) { // LE-LABEL: @increment_b_st16( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LE-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LE-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LE-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_b_st16( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BE-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BE-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BE-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_b_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LENUMLOADS-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_b_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BENUMLOADS-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_b_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LEWIDTH-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LEWIDTH-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_b_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BEWIDTH-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BEWIDTH-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BEWIDTH-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_b_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LEWIDTHNUM-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LEWIDTHNUM-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_b_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[S:%.*]], align 4 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[B]], align 4 +// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BEWIDTHNUM-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BEWIDTHNUM-NEXT: store i16 [[TMP0]], ptr [[B]], align 4 +// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BEWIDTHNUM-NEXT: ret void // void increment_b_st16(struct st16 *s) { @@ -3386,154 +3144,66 @@ void increment_b_st16(struct st16 *s) { // LE-LABEL: @increment_c_st16( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LE-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store i32 [[INC]], ptr [[C]], align 4 // LE-NEXT: ret void // // BE-LABEL: @increment_c_st16( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BE-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BE-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store i32 [[INC]], ptr [[C]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_c_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: store i32 [[INC]], ptr [[C]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_c_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: store i32 [[INC]], ptr [[C]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_c_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTH-NEXT: store i32 [[INC]], ptr [[C]], align 4 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_c_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTH-NEXT: store i32 [[INC]], ptr [[C]], align 4 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_c_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTHNUM-NEXT: store i32 [[INC]], ptr [[C]], align 4 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_c_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[C]], align 4 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[C]], align 4 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[C]], align 4 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[C]], align 4 +// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTHNUM-NEXT: store i32 [[INC]], ptr [[C]], align 4 // BEWIDTHNUM-NEXT: ret void // void increment_c_st16(struct st16 *s) { @@ -3542,162 +3212,90 @@ void increment_c_st16(struct st16 *s) { // LE-LABEL: @increment_d_st16( // LE-NEXT: entry: -// LE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LE-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LE-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LE-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_d_st16( // BE-NEXT: entry: -// BE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BE-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BE-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BE-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_d_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LENUMLOADS-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_d_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BENUMLOADS-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BENUMLOADS-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_d_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LEWIDTH-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LEWIDTH-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LEWIDTH-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_d_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BEWIDTH-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BEWIDTH-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BEWIDTH-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BEWIDTH-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_d_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LEWIDTHNUM-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LEWIDTHNUM-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_d_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i64, ptr [[D]], align 4 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[D]], align 4 +// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load i64, ptr [[D]], align 4 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BEWIDTHNUM-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BEWIDTHNUM-NEXT: store i64 [[BF_SET]], ptr [[D]], align 4 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BEWIDTHNUM-NEXT: store i16 [[TMP0]], ptr [[D]], align 4 +// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BEWIDTHNUM-NEXT: ret void // void increment_d_st16(struct st16 *s) { @@ -3706,74 +3304,32 @@ void increment_d_st16(struct st16 *s) { // LE-LABEL: @increment_v_a_st16( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LE-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 4 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store volatile i32 [[INC]], ptr [[S]], align 4 // LE-NEXT: ret void // // BE-LABEL: @increment_v_a_st16( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BE-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 4 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store volatile i32 [[INC]], ptr [[S]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_a_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 4 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 4 +// LENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[S]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_a_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 4 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 4 +// BENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[S]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_a_st16( @@ -3812,140 +3368,110 @@ void increment_v_a_st16(volatile struct st16 *s) { // LE-LABEL: @increment_v_b_st16( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[B]], align 4 +// LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LE-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LE-NEXT: store volatile i16 [[TMP0]], ptr [[B]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_v_b_st16( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BE-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[B]], align 4 +// BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BE-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BE-NEXT: store volatile i16 [[TMP0]], ptr [[B]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_b_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[B]], align 4 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[B]], align 4 +// LENUMLOADS-NEXT: store volatile i16 [[TMP0]], ptr [[B]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_b_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[S:%.*]], align 4 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BENUMLOADS-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[B]], align 4 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[B]], align 4 +// BENUMLOADS-NEXT: store volatile i16 [[TMP0]], ptr [[B]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_b_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 16 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], -65536 // LEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_v_b_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_LOAD]], 16 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], 65535 // BEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_v_b_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 16 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], -65536 // LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_v_b_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_LOAD]], 16 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], 65535 // BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // BEWIDTHNUM-NEXT: ret void @@ -3956,112 +3482,70 @@ void increment_v_b_st16(volatile struct st16 *s) { // LE-LABEL: @increment_v_c_st16( // LE-NEXT: entry: -// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[C]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[C]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LE-NEXT: store volatile i64 [[BF_SET]], ptr [[C]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // LE-NEXT: ret void // // BE-LABEL: @increment_v_c_st16( // BE-NEXT: entry: -// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[C]], align 4 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[C]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BE-NEXT: store volatile i64 [[BF_SET]], ptr [[C]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_c_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294967296 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_VALUE]] -// LENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[C]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[C]], align 4 +// LENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_c_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL]] -// BENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[C]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[C]], align 4 +// BENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_c_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 2 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 -// LEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_v_c_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 2 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 -// BEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_v_c_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 2 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 -// LEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[C]], align 4 +// LEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_v_c_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 2 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 2 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[C]], align 4 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 -// BEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[C]], align 4 +// BEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[C]], align 4 // BEWIDTHNUM-NEXT: ret void // void increment_v_c_st16(volatile struct st16 *s) { @@ -4070,144 +3554,110 @@ void increment_v_c_st16(volatile struct st16 *s) { // LE-LABEL: @increment_v_d_st16( // LE-NEXT: entry: -// LE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[D]], align 4 -// LE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[D]], align 4 +// LE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[D]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LE-NEXT: store volatile i64 [[BF_SET]], ptr [[D]], align 4 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LE-NEXT: store volatile i16 [[TMP0]], ptr [[D]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_v_d_st16( // BE-NEXT: entry: -// BE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[D]], align 4 -// BE-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BE-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[D]], align 4 +// BE-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[D]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BE-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BE-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BE-NEXT: store volatile i64 [[BF_SET]], ptr [[D]], align 4 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BE-NEXT: store volatile i16 [[TMP0]], ptr [[D]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_d_st16( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 16 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// LENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[D]], align 4 +// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// LENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -281470681743361 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// LENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[D]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[D]], align 4 +// LENUMLOADS-NEXT: store volatile i16 [[TMP0]], ptr [[D]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_d_st16( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 1 -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i64, ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i64 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i64 [[BF_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i64 [[BF_ASHR]] to i32 +// BENUMLOADS-NEXT: [[D:%.*]] = getelementptr inbounds [[STRUCT_ST16:%.*]], ptr [[S:%.*]], i32 0, i32 3 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[D]], align 4 +// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i64 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i64, ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i64 [[TMP1]], 65535 -// BENUMLOADS-NEXT: [[BF_SHL2:%.*]] = shl i64 [[BF_VALUE]], 16 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i64 [[BF_LOAD1]], -4294901761 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i64 [[BF_CLEAR]], [[BF_SHL2]] -// BENUMLOADS-NEXT: store volatile i64 [[BF_SET]], ptr [[D]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i64 [[BF_VALUE]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i64 [[BF_RESULT_SHL]], 48 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i64 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i16 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i16, ptr [[D]], align 4 +// BENUMLOADS-NEXT: store volatile i16 [[TMP0]], ptr [[D]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i16 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_d_st16( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 16 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], -65536 // LEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// LEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_v_d_st16( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_LOAD]], 16 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], 65535 // BEWIDTH-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// BEWIDTH-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_v_d_st16( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_LOAD]], 16 // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_SHL]], 16 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], -65536 // LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// LEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_v_d_st16( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[S:%.*]], i32 3 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i32 [[BF_LOAD]], 16 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_ASHR]], 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 // BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD1]], 65535 // BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i32 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP1]], align 4 +// BEWIDTHNUM-NEXT: store volatile i32 [[BF_SET]], ptr [[TMP0]], align 4 // BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i32 [[BF_VALUE]], 16 // BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i32 [[BF_RESULT_SHL]], 16 // BEWIDTHNUM-NEXT: ret void @@ -4224,146 +3674,62 @@ char c : 8; // LE-LABEL: @increment_v_b_st17( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// LE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// LE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LE-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // LE-NEXT: ret void // // BE-LABEL: @increment_v_b_st17( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// BE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// BE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BE-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_b_st17( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// LENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 1 +// LENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_b_st17( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// BENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 1 +// BENUMLOADS-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_b_st17( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// LEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// LEWIDTH-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTH-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_v_b_st17( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// BEWIDTH-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BEWIDTH-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTH-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// BEWIDTH-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTH-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BEWIDTH-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTH-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTH-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_v_b_st17( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 8 -// LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 8 -// LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// LEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -4294967296 -// LEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// LEWIDTHNUM-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// LEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 1 +// LEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_v_b_st17( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 8 -// BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i32 -// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = zext i32 [[INC]] to i40 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 4294967295 -// BEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTHNUM-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 255 -// BEWIDTHNUM-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// BEWIDTHNUM-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BEWIDTHNUM-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 8 -// BEWIDTHNUM-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 8 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i32 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i32, ptr [[S:%.*]], align 1 +// BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_LOAD]], 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i32, ptr [[S]], align 1 +// BEWIDTHNUM-NEXT: store volatile i32 [[INC]], ptr [[S]], align 1 // BEWIDTHNUM-NEXT: ret void // void increment_v_b_st17(volatile struct st17 *s) { @@ -4372,108 +3738,70 @@ void increment_v_b_st17(volatile struct st17 *s) { // LE-LABEL: @increment_v_c_st17( // LE-NEXT: entry: -// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 32 -// LE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i8 -// LE-NEXT: [[INC:%.*]] = add i8 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = zext i8 [[INC]] to i40 -// LE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 255 -// LE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 4294967295 -// LE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// LE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 32 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i8 +// LE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 +// LE-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// LE-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // LE-NEXT: ret void // // BE-LABEL: @increment_v_c_st17( // BE-NEXT: entry: -// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BE-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 32 -// BE-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 32 -// BE-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i8 -// BE-NEXT: [[INC:%.*]] = add i8 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = zext i8 [[INC]] to i40 -// BE-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BE-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 255 -// BE-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -256 -// BE-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BE-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BE-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// BE-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 32 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i8 +// BE-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 +// BE-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// BE-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_v_c_st17( // LENUMLOADS-NEXT: entry: -// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// LENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_LOAD]], 32 -// LENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i8 -// LENUMLOADS-NEXT: [[INC:%.*]] = add i8 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = zext i8 [[INC]] to i40 -// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 255 -// LENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], 4294967295 -// LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_SHL]] -// LENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// LENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 32 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i8 +// LENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 +// LENUMLOADS-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 +// LENUMLOADS-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_v_c_st17( // BENUMLOADS-NEXT: entry: -// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i40, ptr [[S:%.*]], align 1 -// BENUMLOADS-NEXT: [[BF_SHL:%.*]] = shl i40 [[BF_LOAD]], 32 -// BENUMLOADS-NEXT: [[BF_ASHR:%.*]] = ashr i40 [[BF_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_CAST:%.*]] = trunc i40 [[BF_ASHR]] to i8 -// BENUMLOADS-NEXT: [[INC:%.*]] = add i8 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = zext i8 [[INC]] to i40 -// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i40, ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i40 [[TMP1]], 255 -// BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i40 [[BF_LOAD1]], -256 -// BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i40 [[BF_CLEAR]], [[BF_VALUE]] -// BENUMLOADS-NEXT: store volatile i40 [[BF_SET]], ptr [[S]], align 1 -// BENUMLOADS-NEXT: [[BF_RESULT_SHL:%.*]] = shl i40 [[BF_VALUE]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_ASHR:%.*]] = ashr i40 [[BF_RESULT_SHL]], 32 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = trunc i40 [[BF_RESULT_ASHR]] to i8 +// BENUMLOADS-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 +// BENUMLOADS-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 +// BENUMLOADS-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_v_c_st17( // LEWIDTH-NEXT: entry: -// LEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[S:%.*]], i32 4 -// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 // LEWIDTH-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 -// LEWIDTH-NEXT: store volatile i8 [[INC]], ptr [[TMP1]], align 1 +// LEWIDTH-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_v_c_st17( // BEWIDTH-NEXT: entry: -// BEWIDTH-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[S:%.*]], i32 4 -// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTH-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 // BEWIDTH-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 -// BEWIDTH-NEXT: store volatile i8 [[INC]], ptr [[TMP1]], align 1 +// BEWIDTH-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_v_c_st17( // LEWIDTHNUM-NEXT: entry: -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[S:%.*]], i32 4 -// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// LEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP1]], align 1 -// LEWIDTHNUM-NEXT: store volatile i8 [[INC]], ptr [[TMP1]], align 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 +// LEWIDTHNUM-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_v_c_st17( // BEWIDTHNUM-NEXT: entry: -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[S:%.*]], i32 4 -// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[TMP1]], align 1 +// BEWIDTHNUM-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT_ST17:%.*]], ptr [[S:%.*]], i32 0, i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[C]], align 1 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP1]], align 1 -// BEWIDTHNUM-NEXT: store volatile i8 [[INC]], ptr [[TMP1]], align 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[C]], align 1 +// BEWIDTHNUM-NEXT: store volatile i8 [[INC]], ptr [[C]], align 1 // BEWIDTHNUM-NEXT: ret void // void increment_v_c_st17(volatile struct st17 *s) { @@ -4493,9 +3821,9 @@ struct zero_bitfield { // LE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // LE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// LE-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// LE-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// LE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LE-NEXT: ret void // // BE-LABEL: @increment_a_zero_bitfield( @@ -4503,9 +3831,9 @@ struct zero_bitfield { // BE-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // BE-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BE-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BE-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// BE-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BE-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// BE-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// BE-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BE-NEXT: ret void // // LENUMLOADS-LABEL: @increment_a_zero_bitfield( @@ -4513,10 +3841,10 @@ struct zero_bitfield { // LENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // LENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // LENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 4 -// LENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// LENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LENUMLOADS-NEXT: ret void // // BENUMLOADS-LABEL: @increment_a_zero_bitfield( @@ -4524,10 +3852,10 @@ struct zero_bitfield { // BENUMLOADS-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // BENUMLOADS-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BENUMLOADS-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BENUMLOADS-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // BENUMLOADS-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 4 -// BENUMLOADS-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BENUMLOADS-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// BENUMLOADS-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BENUMLOADS-NEXT: ret void // // LEWIDTH-LABEL: @increment_a_zero_bitfield( @@ -4535,9 +3863,9 @@ struct zero_bitfield { // LEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // LEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTH-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// LEWIDTH-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// LEWIDTH-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// LEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_a_zero_bitfield( @@ -4545,9 +3873,9 @@ struct zero_bitfield { // BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // BEWIDTH-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BEWIDTH-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTH-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 -// BEWIDTH-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BEWIDTH-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 +// BEWIDTH-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// BEWIDTH-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_a_zero_bitfield( @@ -4555,10 +3883,10 @@ struct zero_bitfield { // LEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // LEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // LEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// LEWIDTHNUM-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// LEWIDTHNUM-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// LEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_a_zero_bitfield( @@ -4566,10 +3894,10 @@ struct zero_bitfield { // BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i8, ptr [[S:%.*]], align 4 // BEWIDTHNUM-NEXT: [[BF_CAST:%.*]] = sext i8 [[BF_LOAD]] to i32 // BEWIDTHNUM-NEXT: [[INC:%.*]] = add nsw i32 [[BF_CAST]], 1 -// BEWIDTHNUM-NEXT: [[TMP1:%.*]] = trunc i32 [[INC]] to i8 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = trunc i32 [[INC]] to i8 // BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: store volatile i8 [[TMP1]], ptr [[S]], align 4 -// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP1]] to i32 +// BEWIDTHNUM-NEXT: store volatile i8 [[TMP0]], ptr [[S]], align 4 +// BEWIDTHNUM-NEXT: [[BF_RESULT_CAST:%.*]] = sext i8 [[TMP0]] to i32 // BEWIDTHNUM-NEXT: ret void // void increment_a_zero_bitfield(volatile struct zero_bitfield *s) { @@ -4692,9 +4020,9 @@ struct zero_bitfield_ok { // LE-NEXT: [[CONV3:%.*]] = sext i8 [[BF_CAST]] to i32 // LE-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV3]], [[CONV]] // LE-NEXT: [[CONV4:%.*]] = trunc i32 [[ADD]] to i8 -// LE-NEXT: [[TMP2:%.*]] = zext i8 [[CONV4]] to i16 +// LE-NEXT: [[TMP0:%.*]] = zext i8 [[CONV4]] to i16 // LE-NEXT: [[BF_LOAD5:%.*]] = load volatile i16, ptr [[S]], align 4 -// LE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP2]], 255 +// LE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // LE-NEXT: [[BF_SHL6:%.*]] = shl i16 [[BF_VALUE]], 8 // LE-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD5]], 255 // LE-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL6]] @@ -4716,9 +4044,9 @@ struct zero_bitfield_ok { // BE-NEXT: [[CONV3:%.*]] = sext i8 [[BF_CAST]] to i32 // BE-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV3]], [[CONV]] // BE-NEXT: [[CONV4:%.*]] = trunc i32 [[ADD]] to i8 -// BE-NEXT: [[TMP2:%.*]] = zext i8 [[CONV4]] to i16 +// BE-NEXT: [[TMP0:%.*]] = zext i8 [[CONV4]] to i16 // BE-NEXT: [[BF_LOAD5:%.*]] = load volatile i16, ptr [[S]], align 4 -// BE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP2]], 255 +// BE-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // BE-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD5]], -256 // BE-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]] // BE-NEXT: store volatile i16 [[BF_SET]], ptr [[S]], align 4 @@ -4739,9 +4067,9 @@ struct zero_bitfield_ok { // LENUMLOADS-NEXT: [[CONV3:%.*]] = sext i8 [[BF_CAST]] to i32 // LENUMLOADS-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV3]], [[CONV]] // LENUMLOADS-NEXT: [[CONV4:%.*]] = trunc i32 [[ADD]] to i8 -// LENUMLOADS-NEXT: [[TMP2:%.*]] = zext i8 [[CONV4]] to i16 +// LENUMLOADS-NEXT: [[TMP0:%.*]] = zext i8 [[CONV4]] to i16 // LENUMLOADS-NEXT: [[BF_LOAD5:%.*]] = load volatile i16, ptr [[S]], align 4 -// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP2]], 255 +// LENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // LENUMLOADS-NEXT: [[BF_SHL6:%.*]] = shl i16 [[BF_VALUE]], 8 // LENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD5]], 255 // LENUMLOADS-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_SHL6]] @@ -4763,9 +4091,9 @@ struct zero_bitfield_ok { // BENUMLOADS-NEXT: [[CONV3:%.*]] = sext i8 [[BF_CAST]] to i32 // BENUMLOADS-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV3]], [[CONV]] // BENUMLOADS-NEXT: [[CONV4:%.*]] = trunc i32 [[ADD]] to i8 -// BENUMLOADS-NEXT: [[TMP2:%.*]] = zext i8 [[CONV4]] to i16 +// BENUMLOADS-NEXT: [[TMP0:%.*]] = zext i8 [[CONV4]] to i16 // BENUMLOADS-NEXT: [[BF_LOAD5:%.*]] = load volatile i16, ptr [[S]], align 4 -// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP2]], 255 +// BENUMLOADS-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP0]], 255 // BENUMLOADS-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD5]], -256 // BENUMLOADS-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]] // BENUMLOADS-NEXT: store volatile i16 [[BF_SET]], ptr [[S]], align 4 @@ -4780,12 +4108,12 @@ struct zero_bitfield_ok { // LEWIDTH-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8 // LEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // LEWIDTH-NEXT: [[CONV:%.*]] = sext i16 [[BF_ASHR]] to i32 -// LEWIDTH-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 -// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP2]], align 1 +// LEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 +// LEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTH-NEXT: [[CONV2:%.*]] = sext i8 [[BF_LOAD1]] to i32 // LEWIDTH-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV2]], [[CONV]] // LEWIDTH-NEXT: [[CONV3:%.*]] = trunc i32 [[ADD]] to i8 -// LEWIDTH-NEXT: store volatile i8 [[CONV3]], ptr [[TMP2]], align 1 +// LEWIDTH-NEXT: store volatile i8 [[CONV3]], ptr [[TMP0]], align 1 // LEWIDTH-NEXT: ret void // // BEWIDTH-LABEL: @increment_a_zero_bitfield_ok( @@ -4793,12 +4121,12 @@ struct zero_bitfield_ok { // BEWIDTH-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[S:%.*]], align 4 // BEWIDTH-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 8 // BEWIDTH-NEXT: [[CONV:%.*]] = sext i16 [[BF_ASHR]] to i32 -// BEWIDTH-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 -// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP2]], align 1 +// BEWIDTH-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 +// BEWIDTH-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTH-NEXT: [[CONV2:%.*]] = sext i8 [[BF_LOAD1]] to i32 // BEWIDTH-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV2]], [[CONV]] // BEWIDTH-NEXT: [[CONV3:%.*]] = trunc i32 [[ADD]] to i8 -// BEWIDTH-NEXT: store volatile i8 [[CONV3]], ptr [[TMP2]], align 1 +// BEWIDTH-NEXT: store volatile i8 [[CONV3]], ptr [[TMP0]], align 1 // BEWIDTH-NEXT: ret void // // LEWIDTHNUM-LABEL: @increment_a_zero_bitfield_ok( @@ -4807,13 +4135,13 @@ struct zero_bitfield_ok { // LEWIDTHNUM-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8 // LEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8 // LEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i16 [[BF_ASHR]] to i32 -// LEWIDTHNUM-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 -// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP2]], align 1 +// LEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // LEWIDTHNUM-NEXT: [[CONV2:%.*]] = sext i8 [[BF_LOAD1]] to i32 // LEWIDTHNUM-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV2]], [[CONV]] // LEWIDTHNUM-NEXT: [[CONV3:%.*]] = trunc i32 [[ADD]] to i8 -// LEWIDTHNUM-NEXT: [[BF_LOAD4:%.*]] = load volatile i8, ptr [[TMP2]], align 1 -// LEWIDTHNUM-NEXT: store volatile i8 [[CONV3]], ptr [[TMP2]], align 1 +// LEWIDTHNUM-NEXT: [[BF_LOAD4:%.*]] = load volatile i8, ptr [[TMP0]], align 1 +// LEWIDTHNUM-NEXT: store volatile i8 [[CONV3]], ptr [[TMP0]], align 1 // LEWIDTHNUM-NEXT: ret void // // BEWIDTHNUM-LABEL: @increment_a_zero_bitfield_ok( @@ -4821,13 +4149,13 @@ struct zero_bitfield_ok { // BEWIDTHNUM-NEXT: [[BF_LOAD:%.*]] = load volatile i16, ptr [[S:%.*]], align 4 // BEWIDTHNUM-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_LOAD]], 8 // BEWIDTHNUM-NEXT: [[CONV:%.*]] = sext i16 [[BF_ASHR]] to i32 -// BEWIDTHNUM-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 -// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP2]], align 1 +// BEWIDTHNUM-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[S]], i32 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD1:%.*]] = load volatile i8, ptr [[TMP0]], align 1 // BEWIDTHNUM-NEXT: [[CONV2:%.*]] = sext i8 [[BF_LOAD1]] to i32 // BEWIDTHNUM-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV2]], [[CONV]] // BEWIDTHNUM-NEXT: [[CONV3:%.*]] = trunc i32 [[ADD]] to i8 -// BEWIDTHNUM-NEXT: [[BF_LOAD4:%.*]] = load volatile i8, ptr [[TMP2]], align 1 -// BEWIDTHNUM-NEXT: store volatile i8 [[CONV3]], ptr [[TMP2]], align 1 +// BEWIDTHNUM-NEXT: [[BF_LOAD4:%.*]] = load volatile i8, ptr [[TMP0]], align 1 +// BEWIDTHNUM-NEXT: store volatile i8 [[CONV3]], ptr [[TMP0]], align 1 // BEWIDTHNUM-NEXT: ret void // void increment_a_zero_bitfield_ok(volatile struct zero_bitfield_ok *s) { diff --git a/clang/test/CodeGen/arm-bitfield-alignment.c b/clang/test/CodeGen/arm-bitfield-alignment.c index e34789face5584a663db4271fd23c8be97ea8ad9..5d0967ec70346cd0b83e894595bec002a5060893 100644 --- a/clang/test/CodeGen/arm-bitfield-alignment.c +++ b/clang/test/CodeGen/arm-bitfield-alignment.c @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -triple arm-none-eabi -ffreestanding -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple aarch64 -ffreestanding -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm-none-eabi -fdump-record-layouts-simple -ffreestanding -emit-llvm -o %t %s | FileCheck %s -check-prefixes=LAYOUT,LAYOUT-32 +// RUN: FileCheck %s -check-prefixes=IR,IR-32 <%t +// RUN: %clang_cc1 -triple aarch64 -fdump-record-layouts-simple -ffreestanding -emit-llvm -o %t %s | FileCheck %s -check-prefixes=LAYOUT,LAYOUT-64 +// RUN: FileCheck %s -check-prefixes=IR,IR-64 <%t extern struct T { int b0 : 8; @@ -11,5 +13,18 @@ int func(void) { return g.b1; } -// CHECK: @g = external global %struct.T, align 4 -// CHECK: %{{.*}} = load i64, ptr @g, align 4 +// IR: @g = external global %struct.T, align 4 +// IR-32: %{{.*}} = load i32, ptr @g, align 4 +// IR-64: %{{.*}} = load i64, ptr @g, align 4 + +// LAYOUT-LABEL: LLVMType:%struct.T = +// LAYOUT-32-SAME: type { i32, i8 } +// LAYOUT-64-SAME: type { i64 } +// LAYOUT: BitFields:[ +// LAYOUT-32-NEXT: diff --git a/clang/test/CodeGen/arm64-be-bitfield.c b/clang/test/CodeGen/arm64-be-bitfield.c index 58c318539298475588b8d1520c6b6f9349267a08..57e20b5b62b9ca93407425781109c691eaa32388 100644 --- a/clang/test/CodeGen/arm64-be-bitfield.c +++ b/clang/test/CodeGen/arm64-be-bitfield.c @@ -1,11 +1,25 @@ -// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck --check-prefix IR %s +// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o %t -fdump-record-layouts-simple %s | FileCheck %s --check-prefix=LAYOUT +// RUN: FileCheck %s --check-prefix=IR <%t struct bt3 { signed b2:10; signed b3:10; } b16; // Get the high 32-bits and then shift appropriately for big-endian. signed callee_b0f(struct bt3 bp11) { // IR: callee_b0f(i64 [[ARG:%.*]]) -// IR: store i64 [[ARG]], ptr [[PTR:%.*]], align 8 -// IR: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}, ptr align 8 [[PTR]], i64 4 +// IR: [[BP11:%.*]] = alloca %struct.bt3, align 4 +// IR: [[COERCE_DIVE:%.*]] = getelementptr inbounds %struct.bt3, ptr [[BP11]], i32 0, i32 0 +// IR: [[COERCE_HIGHBITS:%.*]] = lshr i64 [[ARG]], 32 +// IR: [[COERCE_VAL_II:%.*]] = trunc i64 [[COERCE_HIGHBITS]] to i32 +// IR: store i32 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 4 +// IR: [[BF_LOAD:%.*]] = load i32, ptr [[BP11]], align 4 +// IR: [[BF_ASHR:%.*]] = ashr i32 [[BF_LOAD]], 22 +// IR: ret i32 [[BF_ASHR]] return bp11.b2; } + +// LAYOUT-LABEL: LLVMType:%struct.bt3 = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: diff --git a/clang/test/CodeGen/bitfield-2.c b/clang/test/CodeGen/bitfield-2.c index 3e0b30c7a17d8092140f75bac3dcbf1cc181a99c..8688ba6390ddbee311ec840843780df7a383134b 100644 --- a/clang/test/CodeGen/bitfield-2.c +++ b/clang/test/CodeGen/bitfield-2.c @@ -271,11 +271,11 @@ _Bool test_6(void) { // CHECK-RECORD: *** Dumping IRgen Record Layout // CHECK-RECORD: Record: RecordDecl{{.*}}s7 // CHECK-RECORD: Layout: // CHECK-RECORD: IsZeroInitializable:1 // CHECK-RECORD: BitFields:[ -// CHECK-RECORD: + +// This will often be align(1) with -fno-bitfield-type-align +struct P2 { + unsigned a :8; + char :0; + short :0; + unsigned b :8; +} p2; +// CHECK-LABEL: LLVMType:%struct.P2 = +// LAYOUT-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-ARM64-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P3 { + unsigned a :8; + char :0; + short :0; + unsigned :0; + unsigned b :8; +} p3; +// CHECK-LABEL: LLVMType:%struct.P3 = +// LAYOUT-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-ARM64-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P4 { + unsigned a :8; + short :0; + unsigned :0; + unsigned b :8; +} p4; +// CHECK-LABEL: LLVMType:%struct.P4 = +// LAYOUT-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-ARM64-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P5 { + unsigned a :8; + unsigned :0; + unsigned b :8; +} p5; +// CHECK-LABEL: LLVMType:%struct.P5 = +// LAYOUT-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-ARM64-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P6 { + unsigned a :8; + unsigned :0; + short :0; + char :0; + unsigned b :8; +} p6; +// CHECK-LABEL: LLVMType:%struct.P6 = +// LAYOUT-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-ARM64-T-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P7 { + unsigned a : 8; + short : 0; + unsigned char b : 8; +} p7; +// CHECK-LABEL: LLVMType:%struct.P7 = +// LAYOUT-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-ARM64-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +// And with forced alignment for !useZeroLengthBitfieldAlignment machines (eg +// hexagon) +struct __attribute__ ((aligned (2))) P7_align { + unsigned a : 8; + short : 0; + unsigned char b : 8; +} p7_align; +// CHECK-LABEL: LLVMType:%struct.P7_align = +// LAYOUT-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-ARM64-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-NT-SAME: type { i8, i8 } +// LAYOUT-STRICT-NT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P8 { + unsigned a : 7; + short : 0; + unsigned char b : 7; +} p8; +// CHECK-LABEL: LLVMType:%struct.P8 = +// LAYOUT-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-ARM64-T-SAME: type { i8, i8, i8, i8 } +// LAYOUT-NT-SAME: type { i16 } +// LAYOUT-STRICT-NT-SAME: type { i16 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct P9 { + unsigned a : 7; + char : 0; + unsigned short b : 7; +} p9; +// CHECK-LABEL: LLVMType:%struct.P9 = +// LAYOUT-T-SAME: type { i8, i8, [2 x i8] } +// LAYOUT-ARM64-T-SAME: type { i8, i8 } +// LAYOUT-NT-SAME: type { i16 } +// LAYOUT-STRICT-NT-SAME: type { i16 } +// LAYOUT-DWN32-SAME: type { i8, [3 x i8], i8, [3 x i8] } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct __attribute__((aligned(4))) P10 { + unsigned a : 7; + unsigned short b : 7; + unsigned c : 7; + char : 0; +} p10; +// CHECK-LABEL: LLVMType:%struct.P10 = +// LAYOUT-T-SAME: type { i32 } +// LAYOUT-ARM64-T-SAME: type { i32 } +// LAYOUT-NT-SAME: type { i32 } +// LAYOUT-STRICT-NT-SAME: type { i32 } +// LAYOUT-DWN32-SAME: type { i32 } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: + +struct __attribute__((aligned(4))) P11 { + unsigned a : 7; + unsigned short b : 7; + unsigned c : 10; + char : 0; // at a char boundary +} p11; +// CHECK-LABEL: LLVMType:%struct.P11 = +// LAYOUT-T-SAME: type { i32 } +// LAYOUT-ARM64-T-SAME: type { i32 } +// LAYOUT-NT-SAME: type { i32 } +// LAYOUT-STRICT-NT-SAME: type { i32 } +// LAYOUT-DWN32-SAME: type { i32 } +// CHECK: BitFields:[ +// LAYOUT-T-NEXT: diff --git a/clang/test/CodeGen/bitfield-access-unit.c b/clang/test/CodeGen/bitfield-access-unit.c new file mode 100644 index 0000000000000000000000000000000000000000..1aed2e7202fc654f56e4279779c43f1ceb14deb1 --- /dev/null +++ b/clang/test/CodeGen/bitfield-access-unit.c @@ -0,0 +1,302 @@ +// Check arches with 32bit ints. (Not you, AVR & MSP430) + +// Configs that have cheap unaligned access + +// 64-bit Little Endian +// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64-DWN %s +// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64,LAYOUT-64-FLEX %s +// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64,LAYOUT-64-FLEX %s +// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64 %s +// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64 %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64,LAYOUT-64-FLEX %s + +// 64-bit Big Endian +// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64,LAYOUT-64-FLEX %s +// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX64,CHECK-64,LAYOUT-64,LAYOUT-64-FLEX %s + +// 32-bit Little Endian +// RUN: %clang_cc1 -triple=arm-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32,LAYOUT-DWN32-FLEX %s +// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX32 %s +// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX32 %s +// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX32 %s +// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX32 %s + +// 32-bit Big Endian +// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-FLEX,LAYOUT-FLEX32 %s + +// Configs that have expensive unaligned access +// 64-bit Little Endian +// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -target-feature +strict-align -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT,CHECK-64,LAYOUT-64,LAYOUT-64-STRICT %s +// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT,CHECK-64,LAYOUT-64,LAYOUT-64-STRICT %s +// RUN: %clang_cc1 -triple=loongarch64-elf -target-feature -ual %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT,CHECK-64,LAYOUT-64,LAYOUT-64-STRICT %s +// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT,CHECK-64,LAYOUT-64,LAYOUT-64-STRICT %s + +// 64-big Big endian +// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT,CHECK-64,LAYOUT-64,LAYOUT-64-STRICT %s + +// 32-bit Little Endian +// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=arm-apple-darwin %s -target-feature +strict-align -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32,LAYOUT-DWN32-STRICT %s +// RUN: %clang_cc1 -triple=arm-none-eabi %s -target-feature +strict-align -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s + +// 32-bit Big Endian +// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s +// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT-STRICT %s + +// Both le64-elf and m68-elf are strict alignment ISAs with 4-byte aligned +// 64-bit or 2-byte aligned 32-bit integer types. This more compex to describe here. + +// If unaligned access is expensive don't stick these together. +struct A { + char a : 7; + char b : 7; +} a; +// CHECK-LABEL: LLVMType:%struct.A = +// LAYOUT-FLEX-SAME: type { i16 } +// LAYOUT-STRICT-SAME: type { i8, i8 } +// LAYOUT-DWN32-SAME: type { i16 } +// CHECK: BitFields:[ +// LAYOUT-FLEX-NEXT: + +// But do here. +struct __attribute__((aligned(2))) B { + char a : 7; + char b : 7; +} b; +// CHECK-LABEL: LLVMType:%struct.B = +// LAYOUT-SAME: type { i16 } +// LAYOUT-DWN32-SAME: type { i16 } +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +// Not here -- poor alignment within struct +struct C { + int f1; + char f2; + char a : 7; + char b : 7; +} c; +// CHECK-LABEL: LLVMType:%struct.C = +// LAYOUT-FLEX-SAME: type <{ i32, i8, i16, i8 }> +// LAYOUT-STRICT-SAME: type { i32, i8, i8, i8 } +// LAYOUT-DWN32-SAME: type <{ i32, i8, i16, i8 }> +// CHECK: BitFields:[ +// LAYOUT-FLEX-NEXT: + +// Not here, we're packed +struct __attribute__((packed)) D { + int f1; + int a : 8; + int b : 8; + char _; +} d; +// CHECK-LABEL: LLVMType:%struct.D = +// LAYOUT-FLEX-SAME: type <{ i32, i16, i8 }> +// LAYOUT-STRICT-SAME: type <{ i32, i8, i8, i8 }> +// LAYOUT-DWN32-FLEX-SAME: type <{ i32, i16, i8 }> +// LAYOUT-DWN32-STRICT-SAME: type <{ i32, i8, i8, i8 }> +// CHECK: BitFields:[ +// LAYOUT-FLEX-NEXT: + +struct E { + char a : 7; + short b : 13; + unsigned c : 12; +} e; +// CHECK-LABEL: LLVMType:%struct.E = +// LAYOUT-FLEX64-SAME: type { i64 } +// LAYOUT-FLEX32-SAME: type { i32, i16 } +// LAYOUT-STRICT-SAME: type { i32, i16 } +// LAYOUT-DWN32-SAME: type { i32 } +// CHECK: BitFields:[ +// LAYOUT-FLEX64-NEXT: + +struct F { + char a : 7; + short b : 13; + unsigned c : 12; + signed char d : 7; +} f; +// CHECK-LABEL: LLVMType:%struct.F = +// LAYOUT-FLEX64-SAME: type { i64 } +// LAYOUT-FLEX32-SAME: type { i32, i32 } +// LAYOUT-STRICT-SAME: type { i32, i32 } +// LAYOUT-DWN32-SAME: type <{ i32, i8 }> +// CHECK: BitFields:[ +// LAYOUT-FLEX64-NEXT: + +struct G { + char a : 7; + short b : 13; + unsigned c : 12; + signed char d : 7; + signed char e; +} g; +// CHECK-LABEL: LLVMType:%struct.G = +// LAYOUT-SAME: type { i32, i16, i8, i8 } +// LAYOUT-DWN32-SAME: type <{ i32, i8, i8 }> +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +#if _LP64 +struct A64 { + int a : 16; + short b : 8; + long c : 16; + int d : 16; + signed char e : 8; +} a64; +// CHECK-64-LABEL: LLVMType:%struct.A64 = +// LAYOUT-64-SAME: type { i64 } +// LAYOUT-64-DWN-SAME: type { i64 } +// CHECK-64: BitFields:[ +// LAYOUT-64-NEXT: + +struct B64 { + int a : 16; + short b : 8; + long c : 16; + int d : 16; + signed char e; // not a bitfield +} b64; +// CHECK-64-LABEL: LLVMType:%struct.B64 = +// LAYOUT-64-FLEX-SAME: type <{ i16, i8, i32, i8 }> +// LAYOUT-64-STRICT-SAME: type <{ i16, i8, i16, i16, i8 }> +// LAYOUT-64-DWN-SAME: type <{ i16, i8, i32, i8 }> +// CHECK-64: BitFields:[ +// LAYOUT-64-FLEX-NEXT: + +struct C64 { + int a : 15; + short b : 8; + long c : 16; + int d : 15; + signed char e : 7; +} c64; +// CHECK-64-LABEL: LLVMType:%struct.C64 = +// LAYOUT-64-SAME: type { i64 } +// LAYOUT-64-DWN-SAME: type { i64 } +// CHECK-64: BitFields:[ +// LAYOUT-64-NEXT: + +#endif diff --git a/clang/test/CodeGen/debug-info-bitfield-0-struct.c b/clang/test/CodeGen/debug-info-bitfield-0-struct.c index 0535b626771429153456d2cc5c71c437b6d5ffe8..9fadf898e34661856806832d2ed60f8b1da271f5 100644 --- a/clang/test/CodeGen/debug-info-bitfield-0-struct.c +++ b/clang/test/CodeGen/debug-info-bitfield-0-struct.c @@ -101,8 +101,10 @@ struct None_B { int y : 4; }; -struct None_C { - // BOTH-DAG: ![[NONE_C:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "None_C", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 32, elements: ![[NONE_C_ELEMENTS:[0-9]+]]) +// AMDGCN does not do unaligned access cheaply, so the bitfield access units +// would remain single bytes, without the aligned attribure +struct __attribute__((aligned(4))) None_C { + // BOTH-DAG: ![[NONE_C:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "None_C", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 32, align: 32, elements: ![[NONE_C_ELEMENTS:[0-9]+]]) // BOTH-DAG: ![[NONE_C_ELEMENTS]] = !{![[NONE_C_X:[0-9]+]], ![[NONE_C_Y:[0-9]+]], ![[NONE_C_A:[0-9]+]], ![[NONE_C_B:[0-9]+]]} // BOTH-DAG: ![[NONE_C_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[NONE_C]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 8, flags: DIFlagBitField, extraData: i64 0) // BOTH-DAG: ![[NONE_C_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[NONE_C]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 8, offset: 8, flags: DIFlagBitField, extraData: i64 0) diff --git a/clang/test/CodeGen/debug-info-cc.c b/clang/test/CodeGen/debug-info-cc.c index 2664bcd4cb6b2d2fed409ac685c0aa8c31f653f7..2bfb1c28e9353bb7b34f2785c9aaf0f2d6cf1ee7 100644 --- a/clang/test/CodeGen/debug-info-cc.c +++ b/clang/test/CodeGen/debug-info-cc.c @@ -64,11 +64,10 @@ __attribute__((swiftcall)) int add_swiftcall(int a, int b) { return a+b; } -// [FIXME: swiftasynccc] Update debuginfo tag to SwiftAsync once LLVM support lands. // LINUX: !DISubprogram({{.*}}"add_swiftasynccall", {{.*}}type: ![[FTY:[0-9]+]] -// LINUX: ![[FTY]] = !DISubroutineType({{.*}}cc: DW_CC_LLVM_Swift, -__attribute__((swiftasynccall)) int add_swiftasynccall(int a, int b, int c) { - return a+b+c; +// LINUX: ![[FTY]] = !DISubroutineType({{.*}}cc: DW_CC_LLVM_SwiftTail, +__attribute__((swiftasynccall)) int add_swiftasynccall(int a, int b) { + return a+b; } // LINUX: !DISubprogram({{.*}}"add_inteloclbicc", {{.*}}type: ![[FTY:[0-9]+]] diff --git a/clang/test/CodeGen/flexible-array-init.c b/clang/test/CodeGen/flexible-array-init.c index bae926da5feb0701a5a5f5ec0af2009ff6c65b32..15a30c15ac966effae52a0716a5ca4f8e2ccb5b1 100644 --- a/clang/test/CodeGen/flexible-array-init.c +++ b/clang/test/CodeGen/flexible-array-init.c @@ -3,9 +3,15 @@ struct { int x; int y[]; } a = { 1, 7, 11 }; // CHECK: @a ={{.*}} global { i32, [2 x i32] } { i32 1, [2 x i32] [i32 7, i32 11] } +struct { int y[]; } a1 = { 8, 12 }; +// CHECK: @a1 ={{.*}} global { [2 x i32] } { [2 x i32] [i32 8, i32 12] } + struct { int x; int y[]; } b = { 1, { 13, 15 } }; // CHECK: @b ={{.*}} global { i32, [2 x i32] } { i32 1, [2 x i32] [i32 13, i32 15] } +struct { int y[]; } b1 = { { 14, 16 } }; +// CHECK: @b1 ={{.*}} global { [2 x i32] } { [2 x i32] [i32 14, i32 16] } + // sizeof(c) == 8, so this global should be at least 8 bytes. struct { int x; char c; char y[]; } c = { 1, 2, { 13, 15 } }; // CHECK: @c ={{.*}} global { i32, i8, [2 x i8] } { i32 1, i8 2, [2 x i8] c"\0D\0F" } @@ -21,10 +27,79 @@ struct __attribute((packed, aligned(4))) { char a; int x; char z[]; } e = { 1, 2 struct { int x; char y[]; } f = { 1, { 13, 15 } }; // CHECK: @f ={{.*}} global <{ i32, [2 x i8] }> <{ i32 1, [2 x i8] c"\0D\0F" }> -union { - struct { - int a; - char b[]; - } x; -} in_union = {}; -// CHECK: @in_union ={{.*}} global %union.anon zeroinitializer +struct __attribute((packed)) { short a; char z[]; } g = { 2, { 11, 13, 15 } }; +// CHECK: @g ={{.*}} <{ i16, [3 x i8] }> <{ i16 2, [3 x i8] c"\0B\0D\0F" }>, + +// Last member is the potential flexible array, unnamed initializer skips it. +struct { int a; union { int b; short x; }; int c; int d; } h = {1, 2, {}, 3}; +// CHECK: @h = global %struct.anon{{.*}} { i32 1, %union.anon{{.*}} { i32 2 }, i32 0, i32 3 } +struct { int a; union { int b; short x[0]; }; int c; int d; } h0 = {1, 2, {}, 3}; +// CHECK: @h0 = global %struct.anon{{.*}} { i32 1, %union.anon{{.*}} { i32 2 }, i32 0, i32 3 } +struct { int a; union { int b; short x[1]; }; int c; int d; } h1 = {1, 2, {}, 3}; +// CHECK: @h1 = global %struct.anon{{.*}} { i32 1, %union.anon{{.*}} { i32 2 }, i32 0, i32 3 } +struct { + int a; + union { + int b; + struct { + struct { } __ununsed; + short x[]; + }; + }; + int c; + int d; +} hiding = {1, 2, {}, 3}; +// CHECK: @hiding = global %struct.anon{{.*}} { i32 1, %union.anon{{.*}} { i32 2 }, i32 0, i32 3 } +struct { int a; union { int b; short x[]; }; int c; int d; } hf = {1, 2, {}, 3}; +// CHECK: @hf = global %struct.anon{{.*}} { i32 1, %union.anon{{.*}} { i32 2 }, i32 0, i32 3 } + +// First member is the potential flexible array, initialization requires braces. +struct { int a; union { short x; int b; }; int c; int d; } i = {1, 2, {}, 3}; +// CHECK: @i = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] undef }, i32 0, i32 3 } +struct { int a; union { short x[0]; int b; }; int c; int d; } i0 = {1, {}, 2, 3}; +// CHECK: @i0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 2, i32 3 } +struct { int a; union { short x[1]; int b; }; int c; int d; } i1 = {1, {2}, {}, 3}; +// CHECK: @i1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] undef }, i32 0, i32 3 } +struct { int a; union { short x[]; int b; }; int c; int d; } i_f = {4, {}, {}, 6}; +// CHECK: @i_f = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 4, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 0, i32 6 } + +// Named initializers; order doesn't matter. +struct { int a; union { int b; short x; }; int c; int d; } hn = {.a = 1, .x = 2, .c = 3}; +// CHECK: @hn = global { i32, { i16, [2 x i8] }, i32, i32 } { i32 1, { i16, [2 x i8] } { i16 2, [2 x i8] undef }, i32 3, i32 0 } +struct { int a; union { int b; short x[0]; }; int c; int d; } hn0 = {.a = 1, .x = {2}, .c = 3}; +// CHECK: @hn0 = global { i32, { [0 x i16], [4 x i8] }, i32, i32 } { i32 1, { [0 x i16], [4 x i8] } { [0 x i16] zeroinitializer, [4 x i8] undef }, i32 3, i32 0 } +struct { int a; union { int b; short x[1]; }; int c; int d; } hn1 = {.a = 1, .x = {2}, .c = 3}; +// CHECK: @hn1 = global { i32, { [1 x i16], [2 x i8] }, i32, i32 } { i32 1, { [1 x i16], [2 x i8] } { [1 x i16] [i16 2], [2 x i8] undef }, i32 3, i32 0 } + +struct { char a[]; } empty_struct = {}; +// CHECK: @empty_struct ={{.*}} global %struct.anon{{.*}} zeroinitializer, align 1 + +struct { char a[]; } empty_struct0 = {0}; +// CHECK: @empty_struct0 = global { [1 x i8] } zeroinitializer, align 1 + +union { struct { int a; char b[]; }; } struct_in_union = {}; +// CHECK: @struct_in_union = global %union.anon{{.*}} zeroinitializer, align 4 + +union { struct { int a; char b[]; }; } struct_in_union0 = {0}; +// CHECK: @struct_in_union0 = global %union.anon{{.*}} zeroinitializer, align 4 + +union { int a; char b[]; } trailing_in_union = {}; +// CHECK: @trailing_in_union = global %union.anon{{.*}} zeroinitializer, align 4 + +union { int a; char b[]; } trailing_in_union0 = {0}; +// CHECK: @trailing_in_union0 = global %union.anon{{.*}} zeroinitializer, align 4 + +union { char a[]; } only_in_union = {}; +// CHECK: @only_in_union = global %union.anon{{.*}} zeroinitializer, align 1 + +union { char a[]; } only_in_union0 = {0}; +// CHECK: @only_in_union0 = global { [1 x i8] } zeroinitializer, align 1 + +union { char a[]; int b; } first_in_union = {}; +// CHECK: @first_in_union = global { [0 x i8], [4 x i8] } { [0 x i8] zeroinitializer, [4 x i8] undef }, align 4 + +union { char a[]; int b; } first_in_union0 = {0}; +// CHECK: @first_in_union0 = global { [1 x i8], [3 x i8] } { [1 x i8] zeroinitializer, [3 x i8] undef }, align 4 + +union { char a[]; int b; } first_in_union123 = { {1, 2, 3} }; +// CHECK: @first_in_union123 = global { [3 x i8], i8 } { [3 x i8] c"\01\02\03", i8 undef }, align 4 diff --git a/clang/test/CodeGen/flexible-array-init.cpp b/clang/test/CodeGen/flexible-array-init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d067a614e1afe5da1d8d9dc4fb08323cd175f745 --- /dev/null +++ b/clang/test/CodeGen/flexible-array-init.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -x c++ -emit-llvm -o - %s | FileCheck %s + +union _u { char a[]; } u = {}; +union _u0 { char a[]; } u0 = {0}; + +// CHECK: %union._u = type { [0 x i8] } + +// CHECK: @u = global %union._u zeroinitializer, align 1 +// CHECK: @u0 = global { [1 x i8] } zeroinitializer, align 1 + +union { char a[]; } z = {}; +// CHECK: @z = internal global %union.{{.*}} zeroinitializer, align 1 +union { char a[]; } z0 = {0}; +// CHECK: @z0 = internal global { [1 x i8] } zeroinitializer, align 1 + +/* C++ requires global anonymous unions have static storage, so we have to + reference them to keep them in the IR output. */ +char keep(int pick) +{ + if (pick) + return z.a[0]; + else + return z0.a[0]; +} diff --git a/clang/test/CodeGen/no-bitfield-type-align.c b/clang/test/CodeGen/no-bitfield-type-align.c index 53ed5e9ad8f854fa89869974de9bb0c2b1ca8bc5..1861c6886a35b3826b3707cb647eb8637ce721bb 100644 --- a/clang/test/CodeGen/no-bitfield-type-align.c +++ b/clang/test/CodeGen/no-bitfield-type-align.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin -fno-bitfield-type-align -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fno-bitfield-type-align -fdump-record-layouts-simple -emit-llvm -o %t %s | FileCheck %s -check-prefix=LAYOUT +// RUN: FileCheck %s <%t struct S { unsigned short: 0; @@ -7,6 +8,13 @@ struct S { unsigned short f2:15; }; +// LAYOUT-LABEL: LLVMType:%struct.S = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-NEXT: + // CHECK: define{{.*}} void @test_zero_width_bitfield(ptr noundef %[[A:.*]]) // CHECK: %[[BF_LOAD:.*]] = load i32, ptr %[[V1:.*]], align 1 // CHECK: %[[BF_CLEAR:.*]] = and i32 %[[BF_LOAD]], 32767 diff --git a/clang/test/CodeGen/struct-x86-darwin.c b/clang/test/CodeGen/struct-x86-darwin.c index 5191441cabaf040158f0e49fc9ec2e36520fa92e..e79ecefb880dfb9f042de82302e89f6ec92a2144 100644 --- a/clang/test/CodeGen/struct-x86-darwin.c +++ b/clang/test/CodeGen/struct-x86-darwin.c @@ -1,25 +1,70 @@ -// RUN: %clang_cc1 %s -emit-llvm -triple=i686-apple-darwin9 -o - | FileCheck %s -// CHECK: STest1 = type { i32, [4 x i16], double } -// CHECK: STest2 = type { i16, i16, i32, i32 } -// CHECK: STest3 = type { i8, i16, i32 } -// CHECK: STestB1 = type { i8, i8 } -// CHECK: STestB2 = type { i8, i8, i8 } -// CHECK: STestB3 = type { i8, i8 } -// CHECK: STestB4 = type { i8, i8, i8, i8 } -// CHECK: STestB5 = type { i8, i16, i8 } -// CHECK: STestB6 = type { i8, i8, i16 } +// RUN: %clang_cc1 %s -emit-llvm -o /dev/null -triple=i686-apple-darwin9 -fdump-record-layouts-simple | FileCheck %s + // Test struct layout for x86-darwin target struct STest1 {int x; short y[4]; double z; } st1; struct STest2 {short a,b; int c,d; } st2; struct STest3 {char a; short b; int c; } st3; -// Bitfields +// Bitfields struct STestB1 {char a; char b:2; } stb1; struct STestB2 {char a; char b:5; char c:4; } stb2; struct STestB3 {char a; char b:2; } stb3; struct STestB4 {char a; short b:2; char c; } stb4; struct STestB5 {char a; short b:10; char c; } stb5; -struct STestB6 {int a:1; char b; int c:13 } stb6; +struct STestB6 {int a:1; char b; int c:13; } stb6; // Packed struct STestP1 {char a; short b; int c; } __attribute__((__packed__)) stp1; + +// CHECK-LABEL: LLVMType:%struct.STest1 = +// CHECK-SAME: type { i32, [4 x i16], double } +// CHECK: BitFields:[ +// CHECK-NEXT: ]> + +// CHECK-LABEL: LLVMType:%struct.STest2 = +// CHECK-SAME: type { i16, i16, i32, i32 } +// CHECK: BitFields:[ +// CHECK-NEXT: ]> + +// CHECK-LABEL: LLVMType:%struct.STest3 = +// CHECK-SAME: type { i8, i16, i32 } +// CHECK: BitFields:[ +// CHECK-NEXT: ]> + +// CHECK-LABEL: LLVMType:%struct.STestB1 = +// CHECK-SAME: type { i8, i8 } +// CHECK: BitFields:[ +// CHECK-NEXT: + +// CHECK-LABEL: LLVMType:%struct.STestB2 = +// CHECK-SAME: type <{ i8, i16 }> +// CHECK: BitFields:[ +// CHECK-NEXT: + +// CHECK-LABEL: LLVMType:%struct.STestB3 = +// CHECK-SAME: type { i8, i8 } +// CHECK: BitFields:[ +// CHECK-NEXT: + +// CHECK-LABEL: LLVMType:%struct.STestB4 = +// CHECK-SAME: type { i8, i8, i8, i8 } +// CHECK: BitFields:[ +// CHECK-NEXT: + +// CHECK-LABEL: LLVMType:%struct.STestB5 = +// CHECK-SAME: type { i8, i16, i8 } +// CHECK: BitFields:[ +// CHECK-NEXT: + +// CHECK-LABEL: LLVMType:%struct.STestB6 = +// CHECK-SAME: type { i8, i8, i16 } +// CHECK: BitFields:[ +// CHECK-NEXT: diff --git a/clang/test/CodeGen/tbaa-struct.cpp b/clang/test/CodeGen/tbaa-struct.cpp index 9b4b7415142d933be0a89e1a87520dc4d5a726bd..ca076ce5aa27327d91c0265b354e0f0297d6e86c 100644 --- a/clang/test/CodeGen/tbaa-struct.cpp +++ b/clang/test/CodeGen/tbaa-struct.cpp @@ -197,7 +197,7 @@ void copy12(UnionMember2 *a1, UnionMember2 *a2) { // CHECK-OLD: [[TS6]] = !{i64 0, i64 2, [[TAG_CHAR]], i64 2, i64 1, [[TAG_CHAR]], i64 8, i64 8, [[TAG_DOUBLE:!.+]]} // CHECK-OLD: [[TAG_DOUBLE]] = !{[[DOUBLE:!.+]], [[DOUBLE]], i64 0} // CHECK-OLD [[DOUBLE]] = !{!"double", [[CHAR]], i64 0} -// CHECK-OLD: [[TS7]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 1, i64 1, [[TAG_CHAR]], i64 2, i64 1, [[TAG_CHAR]], i64 3, i64 1, [[TAG_CHAR]], i64 4, i64 1, [[TAG_CHAR]], i64 8, i64 8, [[TAG_DOUBLE]], i64 16, i64 1, [[TAG_CHAR]]} +// CHECK-OLD: [[TS7]] = !{i64 0, i64 1, [[TAG_CHAR]], i64 1, i64 1, [[TAG_CHAR]], i64 2, i64 1, [[TAG_CHAR]], i64 3, i64 2, [[TAG_CHAR]], i64 8, i64 8, [[TAG_DOUBLE]], i64 16, i64 1, [[TAG_CHAR]]} // CHECK-OLD: [[TS8]] = !{i64 0, i64 4, [[TAG_CHAR]], i64 8, i64 8, [[TAG_DOUBLE]]} // CHECK-OLD: [[TS9]] = !{i64 0, i64 8, [[TAG_CHAR]], i64 8, i64 4, [[TAG_INT]]} // CHECK-OLD: [[TS10]] = !{i64 0, i64 4, [[TAG_INT]], i64 8, i64 8, [[TAG_CHAR]]} diff --git a/clang/test/CodeGenCXX/bitfield-access-empty.cpp b/clang/test/CodeGenCXX/bitfield-access-empty.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5e6f55ffa6964302ff53b520c4d07d16b08aa0d --- /dev/null +++ b/clang/test/CodeGenCXX/bitfield-access-empty.cpp @@ -0,0 +1,150 @@ +// Check if we can merge bitfields across empty members + +// Configs that have cheap unaligned access +// Little Endian +// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=arm-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32 %s +// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Big Endian +// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Configs that have expensive unaligned access +// Little Endian +// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Big endian +// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +struct Empty {}; + +struct P1 { + unsigned a : 16; + [[no_unique_address]] Empty e; + unsigned b : 16; +} p1; +// CHECK-LABEL: LLVMType:%struct.P1 = +// LAYOUT-SAME: type { i16, i16 } +// LAYOUT-DWN32-SAME: type { i16, i16 } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P1 = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +struct P2 { + unsigned a : 15; + [[no_unique_address]] Empty e; + unsigned b : 15; +} p2; +// CHECK-LABEL: LLVMType:%struct.P2 = +// LAYOUT-SAME: type { i16, i16 } +// LAYOUT-DWN32-SAME: type { i16, i16 } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P2 = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +struct P3 { + unsigned a : 16; + Empty e; + unsigned b : 16; +} p3; +// CHECK-LABEL: LLVMType:%struct.P3 = +// LAYOUT-SAME: type { i16, %struct.Empty, i16, [2 x i8] } +// LAYOUT-DWN32-SAME: type <{ i16, %struct.Empty, i16 }> +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P3 = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +struct P4 { + unsigned : 0; +} p4; +// CHECK-LABEL: LLVMType:%struct.P4 = +// LAYOUT-SAME: type { {{.+}} } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P4 = +// CHECK: BitFields:[ +// CHECK-NEXT: ]> + +struct P5 { + ~P5(); + unsigned : 0; +} p5; +// CHECK-LABEL: LLVMType:%struct.P5 = +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P5.base = type {} +// CHECK: BitFields:[ +// CHECK-NEXT: ]> + +struct P6 { + unsigned a : 16; + unsigned b : 8; + [[no_unique_address]] Empty e; + unsigned c; +} p6; +// CHECK-LABEL: LLVMType:%struct.P6 = +// LAYOUT-SAME: type { i32, i32 } +// LAYOUT-DWN32-SAME: type { i32, i32 } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P6 = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +struct P7 { + unsigned a : 16; + unsigned b : 8; + Empty e; + unsigned c; +} p7; +// CHECK-LABEL: LLVMType:%struct.P7 = +// LAYOUT-SAME: type { i16, i8, %struct.Empty, i32 } +// LAYOUT-DWN32-SAME: type { i16, i8, %struct.Empty, i32 } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.P7 = +// CHECK: BitFields:[ +// LAYOUT-NEXT: diff --git a/clang/test/CodeGenCXX/bitfield-access-tail.cpp b/clang/test/CodeGenCXX/bitfield-access-tail.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68716fdf3b1daa440cb1a110ee07a6784f238f2a --- /dev/null +++ b/clang/test/CodeGenCXX/bitfield-access-tail.cpp @@ -0,0 +1,115 @@ +// Check we use tail padding if it is known to be safe + +// Configs that have cheap unaligned access +// Little Endian +// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=arm-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32 %s +// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Big Endian +// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Configs that have expensive unaligned access +// Little Endian +// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Big endian +// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s + +// Can use tail padding +struct Pod { + int a : 16; + int b : 8; +} P; +// CHECK-LABEL: LLVMType:%struct.Pod = +// LAYOUT-SAME: type { i32 } +// LAYOUT-DWN32-SAME: type <{ i16, i8 }> +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.Pod = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +// No tail padding +struct __attribute__((packed)) PPod { + int a : 16; + int b : 8; +} PP; +// CHECK-LABEL: LLVMType:%struct.PPod = +// LAYOUT-SAME: type <{ i16, i8 }> +// LAYOUT-DWN32-SAME: type <{ i16, i8 }> +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.PPod = +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +// Cannot use tail padding +struct NonPod { + ~NonPod(); + int a : 16; + int b : 8; +} NP; +// CHECK-LABEL: LLVMType:%struct.NonPod = +// LAYOUT-SAME: type <{ i16, i8, i8 }> +// LAYOUT-DWN32-SAME: type <{ i16, i8 }> +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct. +// LAYOUT-SAME: NonPod.base = type <{ i16, i8 }> +// LAYOUT-DWN32-SAME: NonPod = type <{ i16, i8 }> +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +// No tail padding +struct __attribute__((packed)) PNonPod { + ~PNonPod(); + int a : 16; + int b : 8; +} PNP; +// CHECK-LABEL: LLVMType:%struct.PNonPod = +// LAYOUT-SAME: type <{ i16, i8 }> +// LAYOUT-DWN32-SAME: type <{ i16, i8 }> +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.PNonPod = +// CHECK: BitFields:[ +// LAYOUT-NEXT: diff --git a/clang/test/CodeGenCXX/bitfield-ir.cpp b/clang/test/CodeGenCXX/bitfield-ir.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76c144072da686794181e459fbbc43121c441f92 --- /dev/null +++ b/clang/test/CodeGenCXX/bitfield-ir.cpp @@ -0,0 +1,101 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 +// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s + +struct Tail { + ~Tail(); + int a : 16; + int b : 8; +}; + +struct Char { + int a : 16; + int b : 8; + char c; +}; + +struct Int { + int a : 16; + int b : 8; + int c; +}; + + +// CHECK-LABEL: define dso_local void @_Z1AP4Tail +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[P]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add i16 [[BF_LOAD]], 1 +// CHECK-NEXT: store i16 [[INC]], ptr [[P]], align 4 +// CHECK-NEXT: ret void +// +void A (Tail *p) { + p->a++; +} + +// CHECK-LABEL: define dso_local void @_Z1BP4Tail +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 2 +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[B]], align 2 +// CHECK-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// CHECK-NEXT: store i8 [[INC]], ptr [[B]], align 2 +// CHECK-NEXT: ret void +// +void B (Tail *p) { + p->b++; +} + +// CHECK-LABEL: define dso_local void @_Z1AP4Char +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[P]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add i16 [[BF_LOAD]], 1 +// CHECK-NEXT: store i16 [[INC]], ptr [[P]], align 4 +// CHECK-NEXT: ret void +// +void A (Char *p) { + p->a++; +} + +// CHECK-LABEL: define dso_local void @_Z1BP4Char +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 2 +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i8, ptr [[B]], align 2 +// CHECK-NEXT: [[INC:%.*]] = add i8 [[BF_LOAD]], 1 +// CHECK-NEXT: store i8 [[INC]], ptr [[B]], align 2 +// CHECK-NEXT: ret void +// +void B (Char *p) { + p->b++; +} + +// CHECK-LABEL: define dso_local void @_Z1AP3Int +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[P]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add i32 [[BF_LOAD]], 1 +// CHECK-NEXT: [[BF_VALUE:%.*]] = and i32 [[INC]], 65535 +// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -65536 +// CHECK-NEXT: [[BF_SET:%.*]] = or disjoint i32 [[BF_VALUE]], [[BF_CLEAR]] +// CHECK-NEXT: store i32 [[BF_SET]], ptr [[P]], align 4 +// CHECK-NEXT: ret void +// +void A (Int *p) { + p->a++; +} + +// CHECK-LABEL: define dso_local void @_Z1BP3Int +// CHECK-SAME: (ptr nocapture noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[BF_LOAD:%.*]] = load i32, ptr [[P]], align 4 +// CHECK-NEXT: [[BF_VALUE:%.*]] = add i32 [[BF_LOAD]], 65536 +// CHECK-NEXT: [[BF_SHL2:%.*]] = and i32 [[BF_VALUE]], 16711680 +// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i32 [[BF_LOAD]], -16711681 +// CHECK-NEXT: [[BF_SET:%.*]] = or disjoint i32 [[BF_SHL2]], [[BF_CLEAR]] +// CHECK-NEXT: store i32 [[BF_SET]], ptr [[P]], align 4 +// CHECK-NEXT: ret void +// +void B (Int *p) { + p->b++; +} diff --git a/clang/test/CodeGenCXX/bitfield.cpp b/clang/test/CodeGenCXX/bitfield.cpp index a478eb44915e7a3a86ab4c8a91597c615adc3a30..7545e02840e6b2edbdae216b601ff8b448869f6d 100644 --- a/clang/test/CodeGenCXX/bitfield.cpp +++ b/clang/test/CodeGenCXX/bitfield.cpp @@ -1,7 +1,9 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s \ -// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s -// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm -o - %s \ -// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fdump-record-layouts-simple \ +// RUN: -emit-llvm -o %t %s | FileCheck -check-prefixes=LAYOUT,LAYOUT-X86-64 %s +// RUN: FileCheck -check-prefix=CHECK-X86-64 %s <%t +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -fdump-record-layouts-simple\ +// RUN: -emit-llvm -o %t %s | FileCheck -check-prefixes=LAYOUT,LAYOUT-PPC64 %s +// RUN: FileCheck -check-prefix=CHECK-PPC64 %s <%t // // Tests for bitfield access patterns in C++ with special attention to // conformance to C++11 memory model requirements. @@ -19,6 +21,27 @@ namespace N0 { unsigned b70 : 6; unsigned b71 : 2; }; +// LAYOUT-LABEL: LLVMType:%"struct.N0::S" = +// LAYOUT-SAME: type { i64 } +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read00(S* s) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N06read00 // CHECK-X86-64: %[[val:.*]] = load i64, ptr %{{.*}} @@ -149,6 +172,13 @@ namespace N1 { unsigned b : 1; char c; }; +// LAYOUT-LABEL: LLVMType:%"struct.N1::S" = +// LAYOUT-SAME: type { i8, i8, i8, i8 } +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(S* s) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N14read // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}, ptr %{{.*}}, i32 0, i32 1 @@ -193,6 +223,13 @@ namespace N2 { unsigned b : 24; void *p; }; +// LAYOUT-LABEL: LLVMType:%"struct.N2::S" = +// LAYOUT-SAME: type { i32, ptr } +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(S* s) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N24read // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} @@ -230,6 +267,13 @@ namespace N3 { struct S { unsigned b : 24; }; +// LAYOUT-LABEL: LLVMType:%"struct.N3::S" = +// LAYOUT-SAME: type { i32 } +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(S* s) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N34read // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} @@ -276,6 +320,14 @@ namespace N4 { char c; }; #endif +// LAYOUT-LABEL: LLVMType:%"struct.N4::Base" = +// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8] }> +// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N4::Base.base" = type <{ ptr, [3 x i8] }> +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(Base* s) { // FIXME: We should widen this load as long as the function isn't being // instrumented by ThreadSanitizer. @@ -317,6 +369,22 @@ namespace N5 { struct X { unsigned b : 24; char c; } x; struct Y { unsigned b : 24; } y; }; +// LAYOUT-LABEL: LLVMType:%"struct.N5::U::X" = +// LAYOUT-SAME: type { [3 x i8], i8 } +// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N5::U::X" = +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + +// LAYOUT-LABEL: LLVMType:%"struct.N5::U::Y" = +// LAYOUT-SAME: type { i32 } +// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N5::U::Y" = +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(U* u) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N54read // CHECK-X86-64: %[[val:.*]] = load i32, ptr %{{.*}} @@ -360,6 +428,15 @@ namespace N6 { unsigned char : 0; unsigned char b2 : 8; }; +// LAYOUT-LABEL: LLVMType:%"struct.N6::S" = +// LAYOUT-SAME: type { [3 x i8], i8 } +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(S* s) { // CHECK-X86-64-LABEL: define{{.*}} i32 @_ZN2N64read // CHECK-X86-64: %[[val1:.*]] = load i24, ptr %{{.*}} @@ -416,6 +493,22 @@ namespace N7 { char c; }; #endif +// LAYOUT-LABEL: LLVMType:%"struct.N7::B1" = +// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8] }> +// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N7::B1.base" = type <{ ptr, [3 x i8] }> +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + +// LAYOUT-LABEL: LLVMType:%"struct.N7::B2" = +// LAYOUT-SAME: type <{ ptr, [3 x i8], [5 x i8], %"struct.N7::B1.base", [5 x i8] }> +// LAYOUT-NEXT: NonVirtualBaseLLVMType:%"struct.N7::B2.base" = type <{ ptr, [3 x i8] }> +// LAYOUT: BitFields:[ +// LAYOUT-X86-64-NEXT: + unsigned read(B2* s) { // FIXME: We should widen this load as long as the function isn't being // instrumented by ThreadSanitizer. diff --git a/clang/test/CodeGenHLSL/ArrayTemporary.hlsl b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..63a30b61440eb51273a4097a27a62b22c9785bb3 --- /dev/null +++ b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s + +void fn(float x[2]) { } + +// CHECK-LABEL: define void {{.*}}call{{.*}} +// CHECK: [[Arr:%.*]] = alloca [2 x float] +// CHECK: [[Tmp:%.*]] = alloca [2 x float] +// CHECK: call void @llvm.memset.p0.i32(ptr align 4 [[Arr]], i8 0, i32 8, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 8, i1 false) +// CHECK: call void {{.*}}fn{{.*}}(ptr noundef byval([2 x float]) align 4 [[Tmp]]) +void call() { + float Arr[2] = {0, 0}; + fn(Arr); +} + +struct Obj { + float V; + int X; +}; + +void fn2(Obj O[4]) { } + +// CHECK-LABEL: define void {{.*}}call2{{.*}} +// CHECK: [[Arr:%.*]] = alloca [4 x %struct.Obj] +// CHECK: [[Tmp:%.*]] = alloca [4 x %struct.Obj] +// CHECK: call void @llvm.memset.p0.i32(ptr align 4 [[Arr]], i8 0, i32 32, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 32, i1 false) +// CHECK: call void {{.*}}fn2{{.*}}(ptr noundef byval([4 x %struct.Obj]) align 4 [[Tmp]]) +void call2() { + Obj Arr[4] = {}; + fn2(Arr); +} + + +void fn3(float x[2][2]) { } + +// CHECK-LABEL: define void {{.*}}call3{{.*}} +// CHECK: [[Arr:%.*]] = alloca [2 x [2 x float]] +// CHECK: [[Tmp:%.*]] = alloca [2 x [2 x float]] +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{.*}}, i32 16, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 16, i1 false) +// CHECK: call void {{.*}}fn3{{.*}}(ptr noundef byval([2 x [2 x float]]) align 4 [[Tmp]]) +void call3() { + float Arr[2][2] = {{0, 0}, {1,1}}; + fn3(Arr); +} + +// CHECK-LABEL: define void {{.*}}call4{{.*}}(ptr +// CHECK-SAME: noundef byval([2 x [2 x float]]) align 4 [[Arr:%.*]]) +// CHECK: [[Tmp:%.*]] = alloca [2 x [2 x float]] +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 16, i1 false) +// CHECK: call void {{.*}}fn3{{.*}}(ptr noundef byval([2 x [2 x float]]) align 4 [[Tmp]]) + +void call4(float Arr[2][2]) { + fn3(Arr); +} + +// Verify that each template instantiation codegens to a unique and correctly +// mangled function name. + +// CHECK-LABEL: define void {{.*}}template_call{{.*}}(ptr + +// CHECK-SAME: noundef byval([2 x float]) align 4 [[FA2:%[0-9A-Z]+]], +// CHECK-SAME: ptr noundef byval([4 x float]) align 4 [[FA4:%[0-9A-Z]+]], +// CHECK-SAME: ptr noundef byval([3 x i32]) align 4 [[IA3:%[0-9A-Z]+]] + +// CHECK: [[Tmp1:%.*]] = alloca [2 x float] +// CHECK: [[Tmp2:%.*]] = alloca [4 x float] +// CHECK: [[Tmp3:%.*]] = alloca [3 x i32] +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp1]], ptr align 4 [[FA2]], i32 8, i1 false) +// CHECK: call void @"??$template_fn@$$BY01M@@YAXY01M@Z"(ptr noundef byval([2 x float]) align 4 [[Tmp1]]) +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp2]], ptr align 4 [[FA4]], i32 16, i1 false) +// CHECK: call void @"??$template_fn@$$BY03M@@YAXY03M@Z"(ptr noundef byval([4 x float]) align 4 [[Tmp2]]) +// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp3]], ptr align 4 [[IA3]], i32 12, i1 false) +// CHECK: call void @"??$template_fn@$$BY02H@@YAXY02H@Z"(ptr noundef byval([3 x i32]) align 4 [[Tmp3]]) + +template +void template_fn(T Val) {} + +void template_call(float FA2[2], float FA4[4], int IA3[3]) { + template_fn(FA2); + template_fn(FA4); + template_fn(IA3); +} + + +// Verify that Array parameter element access correctly codegens. +// CHECK-LABEL: define void {{.*}}element_access{{.*}}(ptr +// CHECK-SAME: noundef byval([2 x float]) align 4 [[FA2:%[0-9A-Z]+]] + +// CHECK: [[Addr:%.*]] = getelementptr inbounds [2 x float], ptr [[FA2]], i32 0, i32 0 +// CHECK: [[Tmp:%.*]] = load float, ptr [[Addr]] +// CHECK: call void @"??$template_fn@M@@YAXM@Z"(float noundef [[Tmp]]) + +// CHECK: [[Idx0:%.*]] = getelementptr inbounds [2 x float], ptr [[FA2]], i32 0, i32 0 +// CHECK: [[Val0:%.*]] = load float, ptr [[Idx0]] +// CHECK: [[Sum:%.*]] = fadd float [[Val0]], 5.000000e+00 +// CHECK: [[Idx1:%.*]] = getelementptr inbounds [2 x float], ptr [[FA2]], i32 0, i32 1 +// CHECK: store float [[Sum]], ptr [[Idx1]] + +void element_access(float FA2[2]) { + template_fn(FA2[0]); + FA2[1] = FA2[0] + 5; +} diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl index 87002ccd462d3f2c4ed086bcb1d2a7ccbf2e5599..036c9c28ef277908686959f399ad8ee3cddd3af4 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s RWBuffer BufI16; RWBuffer BufU16; diff --git a/clang/test/CodeGenHLSL/builtins/bitreverse.hlsl b/clang/test/CodeGenHLSL/builtins/bitreverse.hlsl deleted file mode 100644 index e7609a2b61e25913ae531fd4c6745ae1694324bd..0000000000000000000000000000000000000000 --- a/clang/test/CodeGenHLSL/builtins/bitreverse.hlsl +++ /dev/null @@ -1,155 +0,0 @@ -// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ -// RUN: dxil-pc-shadermodel6.3-library %s -D__HLSL_ENABLE_16_BIT \ -// RUN: -emit-llvm -disable-llvm-passes -O3 -o - | FileCheck %s - -#ifdef __HLSL_ENABLE_16_BIT -// CHECK: define noundef i16 @ -// CHECK: call i16 @llvm.bitreverse.i16( -int16_t test_bitreverse_short(int16_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i16> @ -// CHECK: call <2 x i16> @llvm.bitreverse.v2i16( -int16_t2 test_bitreverse_short2(int16_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i16> @ -// CHECK: call <3 x i16> @llvm.bitreverse.v3i16 -int16_t3 test_bitreverse_short3(int16_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i16> @ -// CHECK: call <4 x i16> @llvm.bitreverse.v4i16 -int16_t4 test_bitreverse_short4(int16_t4 p0) -{ - return reversebits(p0); -} - -// CHECK: define noundef i16 @ -// CHECK: call i16 @llvm.bitreverse.i16( -uint16_t test_bitreverse_ushort(uint16_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i16> @ -// CHECK: call <2 x i16> @llvm.bitreverse.v2i16 -uint16_t2 test_bitreverse_ushort2(uint16_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i16> @ -// CHECK: call <3 x i16> @llvm.bitreverse.v3i16 -uint16_t3 test_bitreverse_ushort3(uint16_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i16> @ -// CHECK: call <4 x i16> @llvm.bitreverse.v4i16 -uint16_t4 test_bitreverse_ushort4(uint16_t4 p0) -{ - return reversebits(p0); -} -#endif - -// CHECK: define noundef i32 @ -// CHECK: call i32 @llvm.bitreverse.i32( -int test_bitreverse_int(int p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i32> @ -// CHECK: call <2 x i32> @llvm.bitreverse.v2i32 -int2 test_bitreverse_int2(int2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i32> @ -// CHECK: call <3 x i32> @llvm.bitreverse.v3i32 -int3 test_bitreverse_int3(int3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i32> @ -// CHECK: call <4 x i32> @llvm.bitreverse.v4i32 -int4 test_bitreverse_int4(int4 p0) -{ - return reversebits(p0); -} - -// CHECK: define noundef i32 @ -// CHECK: call i32 @llvm.bitreverse.i32( -int test_bitreverse_uint(uint p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i32> @ -// CHECK: call <2 x i32> @llvm.bitreverse.v2i32 -uint2 test_bitreverse_uint2(uint2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i32> @ -// CHECK: call <3 x i32> @llvm.bitreverse.v3i32 -uint3 test_bitreverse_uint3(uint3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i32> @ -// CHECK: call <4 x i32> @llvm.bitreverse.v4i32 -uint4 test_bitreverse_uint4(uint4 p0) -{ - return reversebits(p0); -} - -// CHECK: define noundef i64 @ -// CHECK: call i64 @llvm.bitreverse.i64( -int64_t test_bitreverse_long(int64_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i64> @ -// CHECK: call <2 x i64> @llvm.bitreverse.v2i64 -int64_t2 test_bitreverse_long2(int64_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i64> @ -// CHECK: call <3 x i64> @llvm.bitreverse.v3i64 -int64_t3 test_bitreverse_long3(int64_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i64> @ -// CHECK: call <4 x i64> @llvm.bitreverse.v4i64 -int64_t4 test_bitreverse_long4(int64_t4 p0) -{ - return reversebits(p0); -} - -// CHECK: define noundef i64 @ -// CHECK: call i64 @llvm.bitreverse.i64( -uint64_t test_bitreverse_long(uint64_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i64> @ -// CHECK: call <2 x i64> @llvm.bitreverse.v2i64 -uint64_t2 test_bitreverse_long2(uint64_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i64> @ -// CHECK: call <3 x i64> @llvm.bitreverse.v3i64 -uint64_t3 test_bitreverse_long3(uint64_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i64> @ -// CHECK: call <4 x i64> @llvm.bitreverse.v4i64 -uint64_t4 test_bitreverse_long4(uint64_t4 p0) -{ - return reversebits(p0); -} diff --git a/clang/test/CodeGenHLSL/builtins/ceil.hlsl b/clang/test/CodeGenHLSL/builtins/ceil.hlsl index 06d0d4c2cf546d04557f21a43a24504e3dfb6250..be7725cd4d66c1d1ddb5387a1d2b6173b3c6b1c3 100644 --- a/clang/test/CodeGenHLSL/builtins/ceil.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ceil.hlsl @@ -41,16 +41,3 @@ float3 test_ceil_float3(float3 p0) { return ceil(p0); } // CHECK: define noundef <4 x float> @ // CHECK: call <4 x float> @llvm.ceil.v4f32( float4 test_ceil_float4(float4 p0) { return ceil(p0); } - -// CHECK: define noundef double @ -// CHECK: call double @llvm.ceil.f64( -double test_ceil_double(double p0) { return ceil(p0); } -// CHECK: define noundef <2 x double> @ -// CHECK: call <2 x double> @llvm.ceil.v2f64( -double2 test_ceil_double2(double2 p0) { return ceil(p0); } -// CHECK: define noundef <3 x double> @ -// CHECK: call <3 x double> @llvm.ceil.v3f64( -double3 test_ceil_double3(double3 p0) { return ceil(p0); } -// CHECK: define noundef <4 x double> @ -// CHECK: call <4 x double> @llvm.ceil.v4f64( -double4 test_ceil_double4(double4 p0) { return ceil(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/floor.hlsl b/clang/test/CodeGenHLSL/builtins/floor.hlsl index d2a2f6e52f1ec3d305173769734310eba1b22d57..07803bfae3be68c839651dd65e54a10212ffc1c2 100644 --- a/clang/test/CodeGenHLSL/builtins/floor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/floor.hlsl @@ -41,16 +41,3 @@ float3 test_floor_float3(float3 p0) { return floor(p0); } // CHECK: define noundef <4 x float> @ // CHECK: call <4 x float> @llvm.floor.v4f32( float4 test_floor_float4(float4 p0) { return floor(p0); } - -// CHECK: define noundef double @ -// CHECK: call double @llvm.floor.f64( -double test_floor_double(double p0) { return floor(p0); } -// CHECK: define noundef <2 x double> @ -// CHECK: call <2 x double> @llvm.floor.v2f64( -double2 test_floor_double2(double2 p0) { return floor(p0); } -// CHECK: define noundef <3 x double> @ -// CHECK: call <3 x double> @llvm.floor.v3f64( -double3 test_floor_double3(double3 p0) { return floor(p0); } -// CHECK: define noundef <4 x double> @ -// CHECK: call <4 x double> @llvm.floor.v4f64( -double4 test_floor_double4(double4 p0) { return floor(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/reversebits.hlsl b/clang/test/CodeGenHLSL/builtins/reversebits.hlsl index 6da7d289f82e8044a57e454f05163fa2a38d4a85..a319417e97a436dcf52f8807c7e7e82816722599 100644 --- a/clang/test/CodeGenHLSL/builtins/reversebits.hlsl +++ b/clang/test/CodeGenHLSL/builtins/reversebits.hlsl @@ -3,31 +3,6 @@ // RUN: -emit-llvm -disable-llvm-passes -O3 -o - | FileCheck %s #ifdef __HLSL_ENABLE_16_BIT -// CHECK: define noundef i16 @ -// CHECK: call i16 @llvm.bitreverse.i16( -int16_t test_bitreverse_short(int16_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i16> @ -// CHECK: call <2 x i16> @llvm.bitreverse.v2i16( -int16_t2 test_bitreverse_short2(int16_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i16> @ -// CHECK: call <3 x i16> @llvm.bitreverse.v3i16 -int16_t3 test_bitreverse_short3(int16_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i16> @ -// CHECK: call <4 x i16> @llvm.bitreverse.v4i16 -int16_t4 test_bitreverse_short4(int16_t4 p0) -{ - return reversebits(p0); -} - // CHECK: define noundef i16 @ // CHECK: call i16 @llvm.bitreverse.i16( uint16_t test_bitreverse_ushort(uint16_t p0) @@ -54,31 +29,6 @@ uint16_t4 test_bitreverse_ushort4(uint16_t4 p0) } #endif -// CHECK: define noundef i32 @ -// CHECK: call i32 @llvm.bitreverse.i32( -int test_bitreverse_int(int p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i32> @ -// CHECK: call <2 x i32> @llvm.bitreverse.v2i32 -int2 test_bitreverse_int2(int2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i32> @ -// CHECK: call <3 x i32> @llvm.bitreverse.v3i32 -int3 test_bitreverse_int3(int3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i32> @ -// CHECK: call <4 x i32> @llvm.bitreverse.v4i32 -int4 test_bitreverse_int4(int4 p0) -{ - return reversebits(p0); -} - // CHECK: define noundef i32 @ // CHECK: call i32 @llvm.bitreverse.i32( int test_bitreverse_uint(uint p0) @@ -104,31 +54,6 @@ uint4 test_bitreverse_uint4(uint4 p0) return reversebits(p0); } -// CHECK: define noundef i64 @ -// CHECK: call i64 @llvm.bitreverse.i64( -int64_t test_bitreverse_long(int64_t p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <2 x i64> @ -// CHECK: call <2 x i64> @llvm.bitreverse.v2i64 -int64_t2 test_bitreverse_long2(int64_t2 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <3 x i64> @ -// CHECK: call <3 x i64> @llvm.bitreverse.v3i64 -int64_t3 test_bitreverse_long3(int64_t3 p0) -{ - return reversebits(p0); -} -// CHECK: define noundef <4 x i64> @ -// CHECK: call <4 x i64> @llvm.bitreverse.v4i64 -int64_t4 test_bitreverse_long4(int64_t4 p0) -{ - return reversebits(p0); -} - // CHECK: define noundef i64 @ // CHECK: call i64 @llvm.bitreverse.i64( uint64_t test_bitreverse_long(uint64_t p0) diff --git a/clang/test/CodeGenHLSL/builtins/round.hlsl b/clang/test/CodeGenHLSL/builtins/round.hlsl index b9f35bd3712d18a23afc717ba6be821f93a1262d..33d761dbdfbeaecf10ea0bbd5516bdbf7bacbdfd 100644 --- a/clang/test/CodeGenHLSL/builtins/round.hlsl +++ b/clang/test/CodeGenHLSL/builtins/round.hlsl @@ -7,47 +7,47 @@ // RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF // NATIVE_HALF: define noundef half @ -// NATIVE_HALF: %elt.round = call half @llvm.round.f16( -// NATIVE_HALF: ret half %elt.round +// NATIVE_HALF: %elt.roundeven = call half @llvm.roundeven.f16( +// NATIVE_HALF: ret half %elt.roundeven // NO_HALF: define noundef float @"?test_round_half@@YA$halff@$halff@@Z"( -// NO_HALF: %elt.round = call float @llvm.round.f32( -// NO_HALF: ret float %elt.round +// NO_HALF: %elt.roundeven = call float @llvm.roundeven.f32( +// NO_HALF: ret float %elt.roundeven half test_round_half(half p0) { return round(p0); } // NATIVE_HALF: define noundef <2 x half> @ -// NATIVE_HALF: %elt.round = call <2 x half> @llvm.round.v2f16 -// NATIVE_HALF: ret <2 x half> %elt.round +// NATIVE_HALF: %elt.roundeven = call <2 x half> @llvm.roundeven.v2f16 +// NATIVE_HALF: ret <2 x half> %elt.roundeven // NO_HALF: define noundef <2 x float> @ -// NO_HALF: %elt.round = call <2 x float> @llvm.round.v2f32( -// NO_HALF: ret <2 x float> %elt.round +// NO_HALF: %elt.roundeven = call <2 x float> @llvm.roundeven.v2f32( +// NO_HALF: ret <2 x float> %elt.roundeven half2 test_round_half2(half2 p0) { return round(p0); } // NATIVE_HALF: define noundef <3 x half> @ -// NATIVE_HALF: %elt.round = call <3 x half> @llvm.round.v3f16 -// NATIVE_HALF: ret <3 x half> %elt.round +// NATIVE_HALF: %elt.roundeven = call <3 x half> @llvm.roundeven.v3f16 +// NATIVE_HALF: ret <3 x half> %elt.roundeven // NO_HALF: define noundef <3 x float> @ -// NO_HALF: %elt.round = call <3 x float> @llvm.round.v3f32( -// NO_HALF: ret <3 x float> %elt.round +// NO_HALF: %elt.roundeven = call <3 x float> @llvm.roundeven.v3f32( +// NO_HALF: ret <3 x float> %elt.roundeven half3 test_round_half3(half3 p0) { return round(p0); } // NATIVE_HALF: define noundef <4 x half> @ -// NATIVE_HALF: %elt.round = call <4 x half> @llvm.round.v4f16 -// NATIVE_HALF: ret <4 x half> %elt.round +// NATIVE_HALF: %elt.roundeven = call <4 x half> @llvm.roundeven.v4f16 +// NATIVE_HALF: ret <4 x half> %elt.roundeven // NO_HALF: define noundef <4 x float> @ -// NO_HALF: %elt.round = call <4 x float> @llvm.round.v4f32( -// NO_HALF: ret <4 x float> %elt.round +// NO_HALF: %elt.roundeven = call <4 x float> @llvm.roundeven.v4f32( +// NO_HALF: ret <4 x float> %elt.roundeven half4 test_round_half4(half4 p0) { return round(p0); } // CHECK: define noundef float @ -// CHECK: %elt.round = call float @llvm.round.f32( -// CHECK: ret float %elt.round +// CHECK: %elt.roundeven = call float @llvm.roundeven.f32( +// CHECK: ret float %elt.roundeven float test_round_float(float p0) { return round(p0); } // CHECK: define noundef <2 x float> @ -// CHECK: %elt.round = call <2 x float> @llvm.round.v2f32 -// CHECK: ret <2 x float> %elt.round +// CHECK: %elt.roundeven = call <2 x float> @llvm.roundeven.v2f32 +// CHECK: ret <2 x float> %elt.roundeven float2 test_round_float2(float2 p0) { return round(p0); } // CHECK: define noundef <3 x float> @ -// CHECK: %elt.round = call <3 x float> @llvm.round.v3f32 -// CHECK: ret <3 x float> %elt.round +// CHECK: %elt.roundeven = call <3 x float> @llvm.roundeven.v3f32 +// CHECK: ret <3 x float> %elt.roundeven float3 test_round_float3(float3 p0) { return round(p0); } // CHECK: define noundef <4 x float> @ -// CHECK: %elt.round = call <4 x float> @llvm.round.v4f32 -// CHECK: ret <4 x float> %elt.round +// CHECK: %elt.roundeven = call <4 x float> @llvm.roundeven.v4f32 +// CHECK: ret <4 x float> %elt.roundeven float4 test_round_float4(float4 p0) { return round(p0); } diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..9481b0d60a27237d2f98d13bbafd0b33b65e3986 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s + +// CHECK: define spir_func void @main() [[A0:#[0-9]+]] { +void main() { +// CHECK: entry: +// CHECK: %[[CT_ENTRY:[0-9]+]] = call token @llvm.experimental.convergence.entry() +// CHECK: br label %[[LABEL_WHILE_COND:.+]] + int cond = 0; + +// CHECK: [[LABEL_WHILE_COND]]: +// CHECK: %[[CT_LOOP:[0-9]+]] = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %[[CT_ENTRY]]) ] +// CHECK: br label %[[LABEL_WHILE_BODY:.+]] + while (true) { + +// CHECK: [[LABEL_WHILE_BODY]]: +// CHECK: br i1 {{%.+}}, label %[[LABEL_IF_THEN:.+]], label %[[LABEL_IF_END:.+]] + +// CHECK: [[LABEL_IF_THEN]]: +// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CT_LOOP]]) ] +// CHECK: br label %[[LABEL_WHILE_END:.+]] + if (cond == 2) { + uint index = WaveGetLaneIndex(); + break; + } + +// CHECK: [[LABEL_IF_END]]: +// CHECK: br label %[[LABEL_WHILE_COND]] + cond++; + } + +// CHECK: [[LABEL_WHILE_END]]: +// CHECK: ret void +} + +// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]] + +// CHECK-DAG: attributes [[A0]] = {{{.*}}convergent{{.*}}} +// CHECK-DAG: attributes [[A1]] = {{{.*}}convergent{{.*}}} + diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..8f52d81091c180ee80d7f95d7f8cf1ce3fb140d7 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_simple.hlsl @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s + +// CHECK: define spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] { +// CHECK: %[[CI:[0-9]+]] = call token @llvm.experimental.convergence.entry() +// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ] +uint test_1() { + return WaveGetLaneIndex(); +} + +// CHECK: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]] + +// CHECK-DAG: attributes [[A0]] = { {{.*}}convergent{{.*}} } +// CHECK-DAG: attributes [[A1]] = { {{.*}}convergent{{.*}} } diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..379c8f118f52f31b59bbe7f4028c9710b6f9e4de --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_subcall.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s + +// CHECK: define spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] { +// CHECK: %[[C1:[0-9]+]] = call token @llvm.experimental.convergence.entry() +// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ] +uint test_1() { + return WaveGetLaneIndex(); +} + +// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]] + +// CHECK: define spir_func noundef i32 @_Z6test_2v() [[A0]] { +// CHECK: %[[C2:[0-9]+]] = call token @llvm.experimental.convergence.entry() +// CHECK: call spir_func noundef i32 @_Z6test_1v() [ "convergencectrl"(token %[[C2]]) ] +uint test_2() { + return test_1(); +} + +// CHECK-DAG: attributes [[A0]] = {{{.*}}convergent{{.*}}} +// CHECK-DAG: attributes [[A1]] = {{{.*}}convergent{{.*}}} diff --git a/clang/test/Driver/cl-outputs.c b/clang/test/Driver/cl-outputs.c index 07ff43642a62be0c353b6619bdcdcf1113914104..4d58f0fb548b5793de03e7de76e5deec422f60ee 100644 --- a/clang/test/Driver/cl-outputs.c +++ b/clang/test/Driver/cl-outputs.c @@ -301,5 +301,8 @@ // RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Foa.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1 %s // RELATIVE_OBJPATH1: "-object-file-name=a.obj" +// RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Fo:a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH1_COLON %s +// RELATIVE_OBJPATH1_COLON: "-object-file-name=a.obj" + // RUN: %clang_cl -fdebug-compilation-dir=. /Z7 /Fofoo/a.obj -### -- %s 2>&1 | FileCheck -check-prefix=RELATIVE_OBJPATH2 %s // RELATIVE_OBJPATH2: "-object-file-name=foo\\a.obj" diff --git a/clang/test/Driver/darwin-ld-reexports.c b/clang/test/Driver/darwin-ld-reexports.c new file mode 100644 index 0000000000000000000000000000000000000000..2e96db49a8a3871902f7dd55a16f4ea2d9d273ce --- /dev/null +++ b/clang/test/Driver/darwin-ld-reexports.c @@ -0,0 +1,21 @@ +// RUN: touch %t.o +// RUN: %clang -target arm64-apple-darwin13 -### \ +// RUN: -reexport_framework Foo -reexport-lBar -reexport_library Baz %t.o 2> %t.log + +// Check older spellings also work. +// RUN: %clang -target arm64-apple-darwin13 -### \ +// RUN: -Xlinker -reexport_framework -Xlinker Forest \ +// RUN: -Xlinker -reexport-lBranch \ +// RUN: -Xlinker -reexport_library -Xlinker Flower %t.o 2>> %t.log +// RUN: FileCheck -check-prefix=LINK_REEXPORT %s < %t.log + +// LINK_REEXPORT: {{ld(.exe)?"}} +// LINK_REEXPORT: "-reexport_framework" "Foo" +// LINK_REEXPORT: "-reexport-lBar" +// LINK_REEXPORT: "-reexport_library" "Baz" +// LINK_REEXPORT: "-reexport_framework" "Forest" +// LINK_REEXPORT: "-reexport-lBranch" +// LINK_REEXPORT: "-reexport_library" "Flower" + +// Make sure arguments are not repeated. +// LINK_REEXPORT-NOT: "-reexport diff --git a/clang/test/Driver/linker-wrapper-image.c b/clang/test/Driver/linker-wrapper-image.c index 7547526413522475e5f47de5b0700b344e4e1230..d01445e3aed04ee3e35c59a69a598a724cc3a259 100644 --- a/clang/test/Driver/linker-wrapper-image.c +++ b/clang/test/Driver/linker-wrapper-image.c @@ -26,11 +26,11 @@ // OPENMP: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8 // OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr inbounds ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr getelementptr inbounds ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }] // OPENMP-NEXT: @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries } -// OPENMP-NEXT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.omp_offloading.descriptor_reg, ptr null }] -// OPENMP-NEXT: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.omp_offloading.descriptor_unreg, ptr null }] +// OPENMP-NEXT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.omp_offloading.descriptor_reg, ptr null }] // OPENMP: define internal void @.omp_offloading.descriptor_reg() section ".text.startup" { // OPENMP-NEXT: entry: +// OPENMP-NEXT: %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg) // OPENMP-NEXT: call void @__tgt_register_lib(ptr @.omp_offloading.descriptor) // OPENMP-NEXT: ret void // OPENMP-NEXT: } @@ -62,7 +62,7 @@ // CUDA-NEXT: @.fatbin_wrapper = internal constant %fatbin_wrapper { i32 1180844977, i32 1, ptr @.fatbin_image, ptr null }, section ".nvFatBinSegment", align 8 // CUDA-NEXT: @.cuda.binary_handle = internal global ptr null -// CUDA: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.cuda.fatbin_reg, ptr null }] +// CUDA: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.cuda.fatbin_reg, ptr null }] // CUDA: define internal void @.cuda.fatbin_reg() section ".text.startup" { // CUDA-NEXT: entry: @@ -162,7 +162,7 @@ // HIP-NEXT: @.fatbin_wrapper = internal constant %fatbin_wrapper { i32 1212764230, i32 1, ptr @.fatbin_image, ptr null }, section ".hipFatBinSegment", align 8 // HIP-NEXT: @.hip.binary_handle = internal global ptr null -// HIP: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.hip.fatbin_reg, ptr null }] +// HIP: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.hip.fatbin_reg, ptr null }] // HIP: define internal void @.hip.fatbin_reg() section ".text.startup" { // HIP-NEXT: entry: diff --git a/clang/test/Driver/msvc-link.c b/clang/test/Driver/msvc-link.c index 64e099ea63042f4b598121fd4f59eaff68ae093a..b5c32b173785220943e52fabc9809b5767c00873 100644 --- a/clang/test/Driver/msvc-link.c +++ b/clang/test/Driver/msvc-link.c @@ -36,3 +36,23 @@ // VFSOVERLAY: "--vfsoverlay" // VFSOVERLAY: lld-link // VFSOVERLAY: "/vfsoverlay:{{.*}}" "{{.*}}.obj" + +// RUN: %clang -target arm64ec-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | FileCheck --check-prefix=ARM64EC %s +// RUN: %clang_cl -target arm64ec-pc-windows-msvc -fuse-ld=link -### -- %s 2>&1 | FileCheck --check-prefix=ARM64EC %s +// RUN: %clang_cl -arm64EC -fuse-ld=link -### -- %s 2>&1 | FileCheck --check-prefix=ARM64EC %s +// ARM64EC: "-machine:arm64ec" + +// RUN: %clang -target arm64ec-pc-windows-msvc -fuse-ld=link -marm64x -### %s 2>&1 | \ +// RUN: FileCheck --check-prefix=ARM64X %s +// RUN: %clang -target aarch64-pc-windows-msvc -fuse-ld=link -marm64x -### %s 2>&1 | \ +// RUN: FileCheck --check-prefix=ARM64X %s +// RUN: %clang_cl -marm64x -fuse-ld=link -### -- %s 2>&1 | FileCheck --check-prefix=ARM64X %s +// RUN: %clang_cl -arm64EC -marm64x -fuse-ld=link -### -- %s 2>&1 | FileCheck --check-prefix=ARM64X %s +// ARM64X: "-machine:arm64x" + +// RUN: not %clang -target x86_64-linux-gnu -marm64x -### %s 2>&1 | FileCheck --check-prefix=HYBRID-ERR %s +// HYBRID-ERR: error: unsupported option '-marm64x' for target 'x86_64-linux-gnu' + +// RUN: %clang -c -marm64x -target arm64ec-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | \ +// RUN: FileCheck --check-prefix=HYBRID-WARN %s +// HYBRID-WARN: warning: argument unused during compilation: '-marm64x' [-Wunused-command-line-argument] diff --git a/clang/test/Driver/toc-conf.c b/clang/test/Driver/toc-conf.c index 80d92ee1a90b4bcb29312613b20601e019ff229a..7b2d5122ebc6ce4648c035f34e270c7652070052 100644 --- a/clang/test/Driver/toc-conf.c +++ b/clang/test/Driver/toc-conf.c @@ -23,7 +23,7 @@ void func() { // CHECK-CONF1-NOT: warning: // CHECK-CONF1: "-cc1"{{.*}}" "-mno-tocdata" -// CHECK-CONF1: "-mtocdata=g2,g1" +// CHECK-CONF1: "-mtocdata=g1,g2" // CHECK-CONF2-NOT: warning: // CHECK-CONF2: "-cc1"{{.*}}" "-mtocdata" diff --git a/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/AAA.h b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/AAA.h new file mode 100644 index 0000000000000000000000000000000000000000..993d5d4abadb8e685a2e171701ae6845623ea98b --- /dev/null +++ b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/AAA.h @@ -0,0 +1,3 @@ +#ifndef PUBLIC_UMBRELLA_HEADER_FIRST +#error "Public umbrella header was not included first!" +#endif diff --git a/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/SpecialUmbrella.h b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/SpecialUmbrella.h new file mode 100644 index 0000000000000000000000000000000000000000..2599ff14ae1723b0bf67790519089714c35a2a76 --- /dev/null +++ b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/Headers/SpecialUmbrella.h @@ -0,0 +1 @@ +#define PUBLIC_UMBRELLA_HEADER_FIRST diff --git a/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/AAA_Private.h b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/AAA_Private.h new file mode 100644 index 0000000000000000000000000000000000000000..557209bfeb86993e591de3587497cf4358432ca4 --- /dev/null +++ b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/AAA_Private.h @@ -0,0 +1,3 @@ +#ifndef PRIVATE_UMBRELLA_HEADER_FIRST +#error "Private umbrella header was not included first!" +#endif diff --git a/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h new file mode 100644 index 0000000000000000000000000000000000000000..fd5b49b943161a7d088a88b39f71a77d04453b74 --- /dev/null +++ b/clang/test/InstallAPI/Inputs/Umbrella/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h @@ -0,0 +1 @@ +#define PRIVATE_UMBRELLA_HEADER_FIRST diff --git a/clang/test/InstallAPI/diagnostics-dsym.test b/clang/test/InstallAPI/diagnostics-dsym.test new file mode 100644 index 0000000000000000000000000000000000000000..8a1b394f2f8683ed8eb46810866f14b9d05caf4e --- /dev/null +++ b/clang/test/InstallAPI/diagnostics-dsym.test @@ -0,0 +1,39 @@ +; REQUIRES: 86_64-darwin + +; RUN: rm -rf %t +; RUN: split-file %s %t + +// Build a simple dylib with debug info. +; RUN: %clang --target=x86_64-apple-macos10.15 -g -dynamiclib %t/foo.c \ +; RUN: -current_version 1 -compatibility_version 1 -L%t/usr/lib \ +; RUN: -save-temps \ +; RUN: -o %t/foo.dylib -install_name %t/foo.dylib +; RUN: dsymutil %t/foo.dylib -o %t/foo.dSYM + +; RUN: not clang-installapi -x c++ --target=x86_64-apple-macos10.15 \ +; RUN: -install_name %t/foo.dylib \ +; RUN: -current_version 1 -compatibility_version 1 \ +; RUN: -o %t/output.tbd \ +; RUN: --verify-against=%t/foo.dylib --dsym=%t/foo.dSYM \ +; RUN: --verify-mode=Pedantic 2>&1 | FileCheck %s + +; CHECK: violations found for x86_64 +; CHECK: foo.c:5:0: error: no declaration found for exported symbol 'bar' in dynamic library +; CHECK: foo.c:1:0: error: no declaration found for exported symbol 'foo' in dynamic library + +;--- foo.c +int foo(void) { + return 1; +} +extern char bar; +char bar = 'a'; + +;--- usr/lib/libSystem.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ x86_64-macos ] +install-name: '/usr/lib/libSystem.B.dylib' +exports: + - targets: [ x86_64-macos ] + symbols: [ dyld_stub_binder ] +... diff --git a/clang/test/InstallAPI/umbrella-headers-unix.test b/clang/test/InstallAPI/umbrella-headers-unix.test new file mode 100644 index 0000000000000000000000000000000000000000..46118779896cf1492a3522213d3fba93d7ded826 --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers-unix.test @@ -0,0 +1,40 @@ +// UNSUPPORTED: system-windows + +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json +; RUN: mkdir %t/Frameworks/ +; RUN: cp -r %S/Inputs/Umbrella/Umbrella.framework %t/Frameworks/ + +// Only validate path based input that rely on regex matching on unix based file systems. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-NOT: warning + +;--- inputs.json.in +{ + "headers": [ { + "path" : "DSTROOT/Frameworks/Umbrella.framework/Headers/AAA.h", + "type" : "public" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/Headers/SpecialUmbrella.h", + "type" : "public" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/PrivateHeaders/AAA_Private.h", + "type" : "private" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h", + "type" : "private" + }], + "version": "3" +} diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 0000000000000000000000000000000000000000..ce9c50608c41194b648a29f1f987dfe28f6b9134 --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,48 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json +; RUN: cp -r %S/Inputs/Umbrella/Umbrella.framework %t/Frameworks/ + +// Check base filename matches. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella.framework/Versions/A/Umbrella \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=SpecialUmbrella.h \ +; RUN: --private-umbrella-header=SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +// Try missing umbrella header argument. +; RUN: not clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella.framework/Versions/A/Umbrella \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=Ignore.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck %s -check-prefix=ERR + +; ERR: error: public umbrella header file not found in input: 'Ignore.h' + +; CHECK-NOT: error +; CHECK-NOT: warning + +;--- Frameworks/Umbrella.framework/Headers/Ignore.h +#error "This header should be ignored" + +;--- inputs.json.in +{ + "headers": [ { + "path" : "DSTROOT/Frameworks/Umbrella.framework/Headers/AAA.h", + "type" : "public" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/Headers/SpecialUmbrella.h", + "type" : "public" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/PrivateHeaders/AAA_Private.h", + "type" : "private" + }, + { + "path" : "DSTROOT/Frameworks/Umbrella.framework/PrivateHeaders/SpecialPrivateUmbrella.h", + "type" : "private" + }], + "version": "3" +} diff --git a/clang/test/Modules/language-linkage.cppm b/clang/test/Modules/language-linkage.cppm index bf7982cd9207d630918ab40e56bb075678eb7ba8..a5db9e9ebc07ec58e67549342ad44e47a5a05492 100644 --- a/clang/test/Modules/language-linkage.cppm +++ b/clang/test/Modules/language-linkage.cppm @@ -14,5 +14,5 @@ void foo() {} extern "C" void bar() {} -// CHECK: define {{.*}}@bar( // CHECK: define {{.*}}@_Z3foov( +// CHECK: define {{.*}}@bar( diff --git a/clang/test/Modules/no-local-decl-in-reduced-bmi.cppm b/clang/test/Modules/no-local-decl-in-reduced-bmi.cppm new file mode 100644 index 0000000000000000000000000000000000000000..41ae2bf0dec8098252d3f43f29dfe2270b7eff7b --- /dev/null +++ b/clang/test/Modules/no-local-decl-in-reduced-bmi.cppm @@ -0,0 +1,33 @@ +// Test that we won't record local declarations by default in reduced BMI. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm +// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/a.pcm > %t/a.dump +// RUN: cat %t/a.dump | FileCheck %t/a.cppm +// +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-reduced-module-interface -o %t/b.pcm +// RUN: llvm-bcanalyzer --dump --disable-histogram --show-binary-blobs %t/b.pcm > %t/b.dump +// RUN: cat %t/b.dump | FileCheck %t/b.cppm + +//--- a.cppm +export module a; +export int func() { + int v = 43; + return 43; +} + +// Test that the variable declaration is not recorded completely. +// CHECK-NOT: &1 | FileCheck -check-prefix=both_invalid %s +// RUN: not %clang_dxc -enable-16bit-types -T lib_6_4 -HV 2017 %s 2>&1 | FileCheck -check-prefix=HV_invalid_2017 %s +// RUN: not %clang_dxc -enable-16bit-types -T cs_6_0 /HV 2021 %s 2>&1 | FileCheck -check-prefix=TP_invalid %s +// RUN: %clang_dxc -enable-16bit-types -T lib_6_4 /HV 2018 %s 2>&1 -### | FileCheck -check-prefix=valid_2018 %s +// RUN: %clang_dxc -enable-16bit-types -T lib_6_4 /HV 2021 %s 2>&1 -### | FileCheck -check-prefix=valid_2021 %s + + +// both_invalid: error: '-enable-16bit-types' option requires target HLSL Version >= 2018 and shader model >= 6.2, but HLSL Version is 'hlsl2016' and shader model is '6.0' +// HV_invalid_2017: error: '-enable-16bit-types' option requires target HLSL Version >= 2018 and shader model >= 6.2, but HLSL Version is 'hlsl2017' and shader model is '6.4' +// TP_invalid: error: '-enable-16bit-types' option requires target HLSL Version >= 2018 and shader model >= 6.2, but HLSL Version is 'hlsl2021' and shader model is '6.0' + +// valid_2021: "dxil-unknown-shadermodel6.4-library" +// valid_2021-SAME: "-std=hlsl2021" +// valid_2021-SAME: "-fnative-half-type" + +// valid_2018: "dxil-unknown-shadermodel6.4-library" +// valid_2018-SAME: "-std=hlsl2018" +// valid_2018-SAME: "-fnative-half-type" + +[numthreads(1,1,1)] +void main() +{ + return; +} + diff --git a/clang/test/Options/enable_16bit_types_validation_spirv.hlsl b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..a9700ef87a27c3fc205148339e4da2cadb86a1a4 --- /dev/null +++ b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl @@ -0,0 +1,14 @@ +// RUN: not %clang_cc1 -internal-isystem D:\llvm-project\build\x64-Release\lib\clang\19\include -nostdsysteminc -triple spirv-vulkan-library -x hlsl -std=hlsl2016 -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s 2>&1 | FileCheck %s --check-prefix=SPIRV +// RUN: %clang_cc1 -internal-isystem D:\llvm-project\build\x64-Release\lib\clang\19\include -nostdsysteminc -triple spirv-vulkan-library -x hlsl -std=hlsl2021 -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s 2>&1 | FileCheck %s --check-prefix=valid + +// SPIRV: error: '-fnative-half-type' option requires target HLSL Version >= 2018, but HLSL Version is 'hlsl2016' + +// valid: "spirv-unknown-vulkan-library" +// valid: define spir_func void @main() #0 { + +[numthreads(1,1,1)] +void main() +{ + return; +} + diff --git a/clang/test/Sema/constant-builtins-all-args-evaluated.cpp b/clang/test/Sema/constant-builtins-all-args-evaluated.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db55e24cecda7a4c2704827c17421fdb3be9fedb --- /dev/null +++ b/clang/test/Sema/constant-builtins-all-args-evaluated.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +constexpr int test_clzg_0() { + int x = 0; + (void)__builtin_clzg(0U, ++x); + return x; +} + +static_assert(test_clzg_0() == 1); + +constexpr int test_clzg_1() { + int x = 0; + (void)__builtin_clzg(1U, ++x); + return x; +} + +static_assert(test_clzg_1() == 1); + +constexpr int test_ctzg_0() { + int x = 0; + (void)__builtin_ctzg(0U, ++x); + return x; +} + +static_assert(test_ctzg_0() == 1); + +constexpr int test_ctzg_1() { + int x = 0; + (void)__builtin_ctzg(1U, ++x); + return x; +} + +static_assert(test_ctzg_1() == 1); diff --git a/clang/test/Sema/flexible-array-in-union.c b/clang/test/Sema/flexible-array-in-union.c index 5fabfbe0b1eaabfd6d73b5b8ab242dea45341880..dd5e8069665feabe88c56db27b6747d35fd6d4c1 100644 --- a/clang/test/Sema/flexible-array-in-union.c +++ b/clang/test/Sema/flexible-array-in-union.c @@ -1,13 +1,188 @@ -// RUN: %clang_cc1 %s -verify=c -fsyntax-only -// RUN: %clang_cc1 %s -verify -fsyntax-only -x c++ -// RUN: %clang_cc1 %s -verify -fsyntax-only -fms-compatibility -// RUN: %clang_cc1 %s -verify -fsyntax-only -fms-compatibility -x c++ +// RUN: %clang_cc1 %s -verify=stock,c -fsyntax-only +// RUN: %clang_cc1 %s -verify=stock,cpp -fsyntax-only -x c++ +// RUN: %clang_cc1 %s -verify=stock,cpp -fsyntax-only -fms-compatibility -x c++ +// RUN: %clang_cc1 %s -verify=stock,c,gnu -fsyntax-only -Wgnu-flexible-array-union-member -Wgnu-empty-struct +// RUN: %clang_cc1 %s -verify=stock,c,microsoft -fsyntax-only -fms-compatibility -Wmicrosoft // The test checks that an attempt to initialize union with flexible array // member with an initializer list doesn't crash clang. -union { char x[]; } r = {0}; // c-error {{flexible array member 'x' in a union is not allowed}} +union { char x[]; } r = {0}; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ +struct _name1 { + int a; + union { + int b; + char x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + }; +} name1 = { + 10, + 42, /* initializes "b" */ +}; -// expected-no-diagnostics +struct _name1i { + int a; + union { + int b; + char x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + }; +} name1i = { + .a = 10, + .b = 42, +}; + +/* Initialization of flexible array in a union is never allowed. */ +struct _name2 { + int a; + union { + int b; + char x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + }; +} name2 = { + 12, + 13, + { 'c' }, /* c-warning {{excess elements in struct initializer}} + cpp-error {{excess elements in struct initializer}} + */ +}; + +/* Initialization of flexible array in a union is never allowed. */ +struct _name2i { + int a; + union { + int b; + char x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + stock-note {{initialized flexible array member 'x' is here}} + */ + }; +} name2i = { + .a = 12, + .b = 13, /* stock-note {{previous initialization is here}} */ + .x = { 'c' }, /* stock-error {{initialization of flexible array member is not allowed}} + c-warning {{initializer overrides prior initialization of this subobject}} + cpp-error {{initializer partially overrides prior initialization of this subobject}} + */ +}; + +/* Flexible array initialization always allowed when not in a union, + and when struct has another member. + */ +struct _okay { + int a; + char x[]; +} okay = { + 22, + { 'x', 'y', 'z' }, +}; + +struct _okayi { + int a; + char x[]; +} okayi = { + .a = 22, + .x = { 'x', 'y', 'z' }, +}; + +struct _okay0 { + int a; + char x[]; +} okay0 = { }; + +struct _flex_extension { + char x[]; /* gnu-warning {{flexible array member 'x' in otherwise empty struct is a GNU extension}} + microsoft-warning {{flexible array member 'x' in otherwise empty struct is a Microsoft extension}} + */ +} flex_extension = { + { 'x', 'y', 'z' }, +}; + +struct _flex_extensioni { + char x[]; /* gnu-warning {{flexible array member 'x' in otherwise empty struct is a GNU extension}} + microsoft-warning {{flexible array member 'x' in otherwise empty struct is a Microsoft extension}} + */ +} flex_extensioni = { + .x = { 'x', 'y', 'z' }, +}; + +struct already_hidden { + int a; + union { + int b; + struct { + struct { } __empty; // gnu-warning {{empty struct is a GNU extension}} + char x[]; + }; + }; +}; +struct still_zero_sized { + struct { } __unused; // gnu-warning {{empty struct is a GNU extension}} + int x[]; +}; + +struct warn1 { + int a; + union { + int b; + char x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + }; +}; + +struct warn2 { + int x[]; /* gnu-warning {{flexible array member 'x' in otherwise empty struct is a GNU extension}} + microsoft-warning {{flexible array member 'x' in otherwise empty struct is a Microsoft extension}} + */ +}; + +union warn3 { + short x[]; /* gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ +}; + +struct quiet1 { + int a; + short x[]; +}; + +struct _not_at_end { + union { short x[]; }; /* stock-warning-re {{field '' with variable sized type '{{.*}}' not at the end of a struct or class is a GNU extension}} + gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + int y; +} not_at_end = {{}, 3}; + +struct _not_at_end_s { + struct { int a; short x[]; }; /* stock-warning-re {{field '' with variable sized type '{{.*}}' not at the end of a struct or class is a GNU extension}} */ + int y; +} not_at_end_s = {{}, 3}; + +struct { + int a; + union { /* stock-warning-re {{field '' with variable sized type '{{.*}}' not at the end of a struct or class is a GNU extension}} */ + short x[]; /* stock-note {{initialized flexible array member 'x' is here}} + gnu-warning {{flexible array member 'x' in a union is a GNU extension}} + microsoft-warning {{flexible array member 'x' in a union is a Microsoft extension}} + */ + int b; + }; + int c; + int d; +} i_f = { 4, + {5}, /* stock-error {{initialization of flexible array member is not allowed}} */ + {}, + 6}; + +// expected-no-diagnostics diff --git a/clang/test/Sema/format-strings-signedness-fixit.c b/clang/test/Sema/format-strings-signedness-fixit.c new file mode 100644 index 0000000000000000000000000000000000000000..b4e6e975657aaed4f1b5b3e439f610d4215cfec5 --- /dev/null +++ b/clang/test/Sema/format-strings-signedness-fixit.c @@ -0,0 +1,98 @@ +// RUN: cp %s %t +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -Wformat -Wformat-signedness -fixit %t +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -Wformat -Wformat-signedness -Werror %t +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -E -o - %t | FileCheck %s + +#include + +int printf(const char *restrict format, ...); + +void test_printf_int(int x) +{ + printf("%u", x); +} + +void test_printf_unsigned(unsigned x) +{ + printf("%d", x); +} + +void test_printf_long(long x) +{ + printf("%lu", x); +} + +void test_printf_unsigned_long(unsigned long x) +{ + printf("%ld", x); +} + +void test_printf_long_long(long long x) +{ + printf("%llu", x); +} + +void test_printf_unsigned_long_long(unsigned long long x) +{ + printf("%lld", x); +} + +enum enum_int { + minus_1 = -1 +}; + +void test_printf_enum_int(enum enum_int x) +{ + printf("%u", x); +} + +enum enum_unsigned { + zero = 0 +}; + +void test_printf_enum_unsigned(enum enum_unsigned x) +{ + printf("%d", x); +} + +enum enum_long { + minus_one = -1, + int_val = INT_MAX, + unsigned_val = (unsigned)INT_MIN +}; + +void test_printf_enum_long(enum enum_long x) +{ + printf("%lu", x); +} + +enum enum_unsigned_long { + uint_max_plus = (unsigned long)UINT_MAX+1, +}; + +void test_printf_enum_unsigned_long(enum enum_unsigned_long x) +{ + printf("%ld", x); +} + +// Validate the fixes. +// CHECK: void test_printf_int(int x) +// CHECK: printf("%d", x); +// CHECK: void test_printf_unsigned(unsigned x) +// CHECK: printf("%u", x); +// CHECK: void test_printf_long(long x) +// CHECK: printf("%ld", x); +// CHECK: void test_printf_unsigned_long(unsigned long x) +// CHECK: printf("%lu", x); +// CHECK: void test_printf_long_long(long long x) +// CHECK: printf("%lld", x); +// CHECK: void test_printf_unsigned_long_long(unsigned long long x) +// CHECK: printf("%llu", x); +// CHECK: void test_printf_enum_int(enum enum_int x) +// CHECK: printf("%d", x); +// CHECK: void test_printf_enum_unsigned(enum enum_unsigned x) +// CHECK: printf("%u", x); +// CHECK: void test_printf_enum_long(enum enum_long x) +// CHECK: printf("%ld", x); +// CHECK: void test_printf_enum_unsigned_long(enum enum_unsigned_long x) +// CHECK: printf("%lu", x); diff --git a/clang/test/Sema/format-strings-signedness.c b/clang/test/Sema/format-strings-signedness.c new file mode 100644 index 0000000000000000000000000000000000000000..d5a8140d9ef8a084ea6c8dd7b58f578bea474178 --- /dev/null +++ b/clang/test/Sema/format-strings-signedness.c @@ -0,0 +1,222 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -verify -Wformat -Wformat-signedness %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -std=c11 -fsyntax-only -verify -Wformat -Wformat-signedness %s + +// Verify that -Wformat-signedness alone (without -Wformat) trigger the +// warnings. Note in gcc this will not trigger the signedness warnings as +// -Wformat is default off in gcc. +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -verify -Wformat-signedness %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -std=c11 -fsyntax-only -verify -Wformat-signedness %s + +// Verify that -Wformat-signedness warnings are not reported with only -Wformat +// (gcc compat). +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wformat -verify=okay %s + +// Verify that -Wformat-signedness with -Wno-format are not reported (gcc compat). +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wformat-signedness -Wno-format -verify=okay %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -std=c11 -fsyntax-only -Wno-format -Wformat-signedness -verify=okay %s +// okay-no-diagnostics + +int printf(const char *restrict format, ...); +int scanf(const char * restrict, ...); + +void test_printf_bool(_Bool x) +{ + printf("%d", x); // no-warning + printf("%u", x); // no-warning + printf("%x", x); // no-warning +} + +void test_printf_char(char x) +{ + printf("%c", x); // no-warning +} + +void test_printf_unsigned_char(unsigned char x) +{ + printf("%c", x); // no-warning +} + +void test_printf_int(int x) +{ + printf("%d", x); // no-warning + printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}} + printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'int'}} +} + +void test_printf_unsigned(unsigned x) +{ + printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned int'}} + printf("%u", x); // no-warning + printf("%x", x); // no-warning +} + +void test_printf_long(long x) +{ + printf("%ld", x); // no-warning + printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}} + printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has type 'long'}} +} + +void test_printf_unsigned_long(unsigned long x) +{ + printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has type 'unsigned long'}} + printf("%lu", x); // no-warning + printf("%lx", x); // no-warning +} + +void test_printf_long_long(long long x) +{ + printf("%lld", x); // no-warning + printf("%llu", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}} + printf("%llx", x); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'long long'}} +} + +void test_printf_unsigned_long_long(unsigned long long x) +{ + printf("%lld", x); // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned long long'}} + printf("%llu", x); // no-warning + printf("%llx", x); // no-warning +} + +enum enum_int { + minus_1 = -1 +}; + +void test_printf_enum_int(enum enum_int x) +{ + printf("%d", x); // no-warning + printf("%u", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}} + printf("%x", x); // expected-warning{{format specifies type 'unsigned int' but the argument has underlying type 'int'}} +} + +#ifndef _WIN32 // Disabled due to enums have different underlying type on _WIN32 +enum enum_unsigned { + zero = 0 +}; + +void test_printf_enum_unsigned(enum enum_unsigned x) +{ + printf("%d", x); // expected-warning{{format specifies type 'int' but the argument has underlying type 'unsigned int'}} + printf("%u", x); // no-warning + printf("%x", x); // no-warning +} + +enum enum_long { + minus_one = -1, + int_val = __INT_MAX__, // INT_MAX + unsigned_val = (unsigned)(-__INT_MAX__ -1) // (unsigned)INT_MIN +}; + +void test_printf_enum_long(enum enum_long x) +{ + printf("%ld", x); // no-warning + printf("%lu", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}} + printf("%lx", x); // expected-warning{{format specifies type 'unsigned long' but the argument has underlying type 'long'}} +} + +enum enum_unsigned_long { + uint_max_plus = (unsigned long)(__INT_MAX__ *2U +1U)+1, // (unsigned long)UINT_MAX+1 +}; + +void test_printf_enum_unsigned_long(enum enum_unsigned_long x) +{ + printf("%ld", x); // expected-warning{{format specifies type 'long' but the argument has underlying type 'unsigned long'}} + printf("%lu", x); // no-warning + printf("%lx", x); // no-warning +} +#endif + +void test_scanf_char(char *y) { + scanf("%c", y); // no-warning +} + +void test_scanf_unsigned_char(unsigned char *y) { + scanf("%c", y); // no-warning +} + +void test_scanf_int(int *x) { + scanf("%d", x); // no-warning + scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *'}} + scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'int *'}} +} + +void test_scanf_unsigned(unsigned *x) { + scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'unsigned int *'}} + scanf("%u", x); // no-warning + scanf("%x", x); // no-warning +} + +void test_scanf_long(long *x) { + scanf("%ld", x); // no-warning + scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *'}} + scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'long *'}} +} + +void test_scanf_unsigned_long(unsigned long *x) { + scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'unsigned long *'}} + scanf("%lu", x); // no-warning + scanf("%lx", x); // no-warning +} + +void test_scanf_longlong(long long *x) { + scanf("%lld", x); // no-warning + scanf("%llu", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *'}} + scanf("%llx", x); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'long long *'}} +} + +void test_scanf_unsigned_longlong(unsigned long long *x) { + scanf("%lld", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'unsigned long long *'}} + scanf("%llu", x); // no-warning + scanf("%llx", x); // no-warning +} + +void test_scanf_enum_int(enum enum_int *x) { + scanf("%d", x); // no-warning + scanf("%u", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *'}} + scanf("%x", x); // expected-warning{{format specifies type 'unsigned int *' but the argument has type 'enum enum_int *'}} +} + +#ifndef _WIN32 // Disabled due to enums have different underlying type on _WIN32 +void test_scanf_enum_unsigned(enum enum_unsigned *x) { + scanf("%d", x); // expected-warning{{format specifies type 'int *' but the argument has type 'enum enum_unsigned *'}} + scanf("%u", x); // no-warning + scanf("%x", x); // no-warning +} + +void test_scanf_enum_long(enum enum_long *x) { + scanf("%ld", x); // no-warning + scanf("%lu", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *'}} + scanf("%lx", x); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum enum_long *'}} +} + +void test_scanf_enum_unsigned_long(enum enum_unsigned_long *x) { + scanf("%ld", x); // expected-warning{{format specifies type 'long *' but the argument has type 'enum enum_unsigned_long *'}} + scanf("%lu", x); // no-warning + scanf("%lx", x); // no-warning +} +#endif + +// Verify that we get no warnings from + +typedef short int int16_t; +typedef unsigned short int uint16_t; + +void test_printf_priX16(int16_t x) { + printf("PRId16: %" "d" /*PRId16*/ "\n", x); // no-warning + printf("PRIi16: %" "i" /*PRIi16*/ "\n", x); // no-warning +} + +void test_printf_unsigned_priX16(uint16_t x) { + printf("PRIo16: %" "o" /*PRIo16*/ "\n", x); // no-warning + printf("PRIu16: %" "u" /*PRIu16*/ "\n", x); // no-warning + printf("PRIx16: %" "x" /*PRIx16*/ "\n", x); // no-warning + printf("PRIX16: %" "X" /*PRIX16*/ "\n", x); // no-warning +} + +// Verify that we can suppress a -Wformat-signedness warning by ignoring +// -Wformat (gcc compat). +void test_suppress(int x) +{ +#pragma GCC diagnostic ignored "-Wformat" + printf("%u", x); +} diff --git a/clang/test/Sema/transparent-union.c b/clang/test/Sema/transparent-union.c index c134a7a9b1c4d0077d592c7a7c73eb52917604c7..f02c2298b51ce1433fecfa5709f5fad15359ee9c 100644 --- a/clang/test/Sema/transparent-union.c +++ b/clang/test/Sema/transparent-union.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wgnu-flexible-array-union-member %s typedef union { int *ip; float *fp; @@ -131,7 +131,7 @@ union pr15134v2 { union pr30520v { void b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'void'}} -union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-error {{flexible array member 'b' in a union is not allowed}} +union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-warning {{flexible array member 'b' in a union is a GNU extension}} // expected-note@+1 2 {{forward declaration of 'struct stb'}} union pr30520s { struct stb b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'struct stb'}} diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 3ce26c8fcd984ec8cd5407d08b6b55b7cd7380c9..ce403285b0f5314c36d3f0aaf3b4617f7aab30c4 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -247,3 +247,15 @@ using Bar = Foo; // expected-note {{could not match 'Foo' Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}} } // namespace test18 + +// GH85406, verify no crash on invalid alias templates. +namespace test19 { +template +class Foo {}; + +template +template +using Bar2 = Foo; // expected-error {{extraneous template parameter list in alias template declaration}} + +Bar2 b = 1; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}} +} // namespace test19 diff --git a/clang/test/SemaHLSL/ArrayParams.hlsl b/clang/test/SemaHLSL/ArrayParams.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..75af9d775206e6a48eaf8c0ddbe072f67bc6a18c --- /dev/null +++ b/clang/test/SemaHLSL/ArrayParams.hlsl @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -verify + +void fn(int I[5]); // #fn +void fn2(int I[3][3]); // #fn2 + +void call() { + float F[5]; + double D[4]; + int Long[9]; + int Short[4]; + int Same[5]; + + fn(F); // expected-error{{no matching function for call to 'fn'}} + // expected-note@#fn{{candidate function not viable: no known conversion from 'float[5]' to 'int[5]' for 1st argument}} + + fn(D); // expected-error{{no matching function for call to 'fn'}} + // expected-note@#fn{{candidate function not viable: no known conversion from 'double[4]' to 'int[5]' for 1st argument}} + + fn(Long); // expected-error{{no matching function for call to 'fn'}} + // expected-note@#fn{{candidate function not viable: no known conversion from 'int[9]' to 'int[5]' for 1st argument}} + + fn(Short); // expected-error{{no matching function for call to 'fn'}} + // expected-note@#fn{{candidate function not viable: no known conversion from 'int[4]' to 'int[5]' for 1st argument}} + + fn(Same); // totally fine, nothing to see here. + + fn2(Long); // expected-error{{no matching function for call to 'fn2'}} + // expected-note@#fn2{{candidate function not viable: no known conversion from 'int[9]' to 'int[3][3]' for 1st argument}} +} diff --git a/clang/test/SemaHLSL/ArrayTemporary.hlsl b/clang/test/SemaHLSL/ArrayTemporary.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..dff9aff7d9b2998cc7ddb86b6e3d85f8d886e7f9 --- /dev/null +++ b/clang/test/SemaHLSL/ArrayTemporary.hlsl @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump %s | FileCheck %s + +void fn(float x[2]) { } + +// CHECK: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float[2])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (float[2])' lvalue Function {{.*}} 'fn' 'void (float[2])' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[2]' + +void call() { + float Arr[2] = {0, 0}; + fn(Arr); +} + +struct Obj { + float V; + int X; +}; + +void fn2(Obj O[4]) { } + +// CHECK: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(Obj[4])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (Obj[4])' lvalue Function {{.*}} 'fn2' 'void (Obj[4])' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'Obj[4]' + +void call2() { + Obj Arr[4] = {}; + fn2(Arr); +} + + +void fn3(float x[2][2]) { } + +// CHECK: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float[2][2])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (float[2][2])' lvalue Function {{.*}} 'fn3' 'void (float[2][2])' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[2][2]' + +void call3() { + float Arr[2][2] = {{0, 0}, {1,1}}; + fn3(Arr); +} + +// This template function should be instantiated 3 times for the different array +// types and lengths. + +// CHECK: FunctionTemplateDecl {{.*}} template_fn +// CHECK-NEXT: TemplateTypeParmDecl {{.*}} referenced typename depth 0 index 0 T +// CHECK-NEXT: FunctionDecl {{.*}} template_fn 'void (T)' +// CHECK-NEXT: ParmVarDecl {{.*}} Val 'T' + +// CHECK: FunctionDecl {{.*}} used template_fn 'void (float[2])' implicit_instantiation +// CHECK-NEXT: TemplateArgument type 'float[2]' +// CHECK-NEXT: ArrayParameterType {{.*}} 'float[2]' 2 +// CHECK-NEXT: BuiltinType {{.*}} 'float' +// CHECK-NEXT: ParmVarDecl {{.*}} Val 'float[2]' + +// CHECK: FunctionDecl {{.*}} used template_fn 'void (float[4])' implicit_instantiation +// CHECK-NEXT: TemplateArgument type 'float[4]' +// CHECK-NEXT: ArrayParameterType {{.*}} 'float[4]' 4 +// CHECK-NEXT: BuiltinType {{.*}} 'float' +// CHECK-NEXT: ParmVarDecl {{.*}} Val 'float[4]' + +// CHECK: FunctionDecl {{.*}} used template_fn 'void (int[3])' implicit_instantiation +// CHECK-NEXT: TemplateArgument type 'int[3]' +// CHECK-NEXT: ArrayParameterType {{.*}} 'int[3]' 3 +// CHECK-NEXT: BuiltinType {{.*}} 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} Val 'int[3]' + +template +void template_fn(T Val) {} + +// CHECK: FunctionDecl {{.*}} call 'void (float[2], float[4], int[3])' +// CHECK: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float[2])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (float[2])' lvalue Function {{.*}} 'template_fn' 'void (float[2])' (FunctionTemplate {{.*}} 'template_fn') +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[2]' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float[2]' lvalue ParmVar {{.*}} 'FA2' 'float[2]' +// CHECK-NEXT: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float[4])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (float[4])' lvalue Function {{.*}} 'template_fn' 'void (float[4])' (FunctionTemplate {{.*}} 'template_fn') +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[4]' +// CHECK-NEXT: DeclRefExpr {{.*}} 'float[4]' lvalue ParmVar {{.*}} 'FA4' 'float[4]' +// CHECK-NEXT: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int[3])' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int[3])' lvalue Function {{.*}} 'template_fn' 'void (int[3])' (FunctionTemplate {{.*}} 'template_fn') +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int[3]' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int[3]' lvalue ParmVar {{.*}} 'IA3' 'int[3]' + +void call(float FA2[2], float FA4[4], int IA3[3]) { + template_fn(FA2); + template_fn(FA4); + template_fn(IA3); +} diff --git a/clang/test/SemaHLSL/ArrayTemporary.ll b/clang/test/SemaHLSL/ArrayTemporary.ll new file mode 100644 index 0000000000000000000000000000000000000000..5eec0094865bae8b862c68062cf9c06e4da2d67d --- /dev/null +++ b/clang/test/SemaHLSL/ArrayTemporary.ll @@ -0,0 +1,76 @@ +; ModuleID = '/Users/cbieneman/dev/llvm-project/clang/test/SemaHLSL/ArrayTemporary.hlsl' +source_filename = "/Users/cbieneman/dev/llvm-project/clang/test/SemaHLSL/ArrayTemporary.hlsl" +target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-pc-shadermodel6.3-library" + +%struct.Obj = type { float, i32 } + +@"__const.?call3@@YAXXZ.Arr" = private unnamed_addr constant [2 x [2 x float]] [[2 x float] zeroinitializer, [2 x float] [float 1.000000e+00, float 1.000000e+00]], align 4 + +; Function Attrs: noinline nounwind optnone +define void @"?fn@@YAXY01M@Z"(ptr noundef byval([2 x float]) align 4 %x) #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone +define void @"?call@@YAXXZ"() #0 { +entry: + %Arr = alloca [2 x float], align 4 + %agg.tmp = alloca [2 x float], align 4 + call void @llvm.memset.p0.i32(ptr align 4 %Arr, i8 0, i32 8, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.tmp, ptr align 4 %Arr, i32 8, i1 false) + call void @"?fn@@YAXY01M@Z"(ptr noundef byval([2 x float]) align 4 %agg.tmp) + ret void +} + +; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) +declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #1 + +; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) +declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg) #2 + +; Function Attrs: noinline nounwind optnone +define void @"?fn2@@YAXY03UObj@@@Z"(ptr noundef byval([4 x %struct.Obj]) align 4 %O) #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone +define void @"?call2@@YAXXZ"() #0 { +entry: + %Arr = alloca [4 x %struct.Obj], align 4 + %agg.tmp = alloca [4 x %struct.Obj], align 4 + call void @llvm.memset.p0.i32(ptr align 4 %Arr, i8 0, i32 32, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.tmp, ptr align 4 %Arr, i32 32, i1 false) + call void @"?fn2@@YAXY03UObj@@@Z"(ptr noundef byval([4 x %struct.Obj]) align 4 %agg.tmp) + ret void +} + +; Function Attrs: noinline nounwind optnone +define void @"?fn3@@YAXY111M@Z"(ptr noundef byval([2 x [2 x float]]) align 4 %x) #0 { +entry: + ret void +} + +; Function Attrs: noinline nounwind optnone +define void @"?call3@@YAXXZ"() #0 { +entry: + %Arr = alloca [2 x [2 x float]], align 4 + %agg.tmp = alloca [2 x [2 x float]], align 4 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %Arr, ptr align 4 @"__const.?call3@@YAXXZ.Arr", i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %agg.tmp, ptr align 4 %Arr, i32 16, i1 false) + call void @"?fn3@@YAXY111M@Z"(ptr noundef byval([2 x [2 x float]]) align 4 %agg.tmp) + ret void +} + +attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: write) } +attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 4, !"dx.disable_optimizations", i32 1} +!2 = !{!"clang version 19.0.0git (git@github.com:llvm/llvm-project.git 64e1c15c520cf11114ef2ddd887e76560903db2b)"} diff --git a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl index 92dd06d5a3309524616c21d549ad060ba33fe1db..98c02c38675f4e13989e3fef87bf6168641abe68 100644 --- a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl @@ -1,12 +1,16 @@ -// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_cos -// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_sin +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_ceil +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_cos +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_exp +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_exp2 +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_floor // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_log // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_log2 // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_log10 +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_sin // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_sqrt +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_roundeven // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_trunc - double2 test_double_builtin(double2 p0) { return TEST_FUNC(p0); // expected-error@-1 {{passing 'double2' (aka 'vector') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}} diff --git a/clang/test/SemaHLSL/BuiltIns/reversebits-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/reversebits-errors.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..6e66db6d1cca9e2f110980cbd88ba47d3d375e14 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/reversebits-errors.hlsl @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify + + +double2 test_int_builtin(double2 p0) { + return __builtin_elementwise_bitreverse(p0); + // expected-error@-1 {{1st argument must be a vector of integers (was 'double2' (aka 'vector'))}} +} + +int2 test_int_builtin(int2 p0) { + return __builtin_elementwise_bitreverse(p0); + // expected-error@-1 {{passing 'int2' (aka 'vector') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values)}} +} diff --git a/clang/test/SemaTemplate/concepts-GH86757.cpp b/clang/test/SemaTemplate/concepts-GH86757.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3122381b20359e3d9dd25306214af48171c5edde --- /dev/null +++ b/clang/test/SemaTemplate/concepts-GH86757.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++20 -Wfatal-errors -verify %s + +template int a; +template concept c = a; +template concept e = c<>; + +// must be a fatal error to trigger the crash +undefined; // expected-error {{a type specifier is required for all declarations}} + +template concept g = e; +template struct h +template +struct h; diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp index 255b0858917fb6fdad51b7b50dde446e2e3b01a7..91b797034ed6cf040b2fdbba066a36112d4a4ab8 100644 --- a/clang/test/SemaTemplate/concepts-friends.cpp +++ b/clang/test/SemaTemplate/concepts-friends.cpp @@ -478,3 +478,29 @@ template class Foo { }; } // namespace FriendOfFriend + +namespace GH86769 { + +template +concept X = true; + +template struct Y { + Y(T) {} + template friend struct Y; + template friend struct Y; + template friend struct Y; +}; + +template +struct Z { + // FIXME: This is ill-formed per C++11 N3337 [temp.param]p12: + // A default template argument shall not be specified in a friend class + // template declaration. + template friend struct Y; +}; + +template struct Y; +template struct Z; +Y y(1); + +} diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp index 388ed7d4cced18fb1a698d20983335d18481253b..ec144d4f44ba8c3b71c5609d8be79ab785efeaff 100644 --- a/clang/test/SemaTemplate/ctad.cpp +++ b/clang/test/SemaTemplate/ctad.cpp @@ -53,4 +53,4 @@ X x; template struct Y { Y(T); }; template struct Y ; Y y(1); -}; +} diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 16c7083df29d0c81275bea5221a6db906911a69f..0caef78fedbfd9c9a849025115e4332ba3615468 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -239,3 +239,12 @@ F s(0); // CHECK: |-InjectedClassNameType {{.*}} 'F<>' dependent // CHECK: | `-CXXRecord {{.*}} 'F' // CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1 + +template +struct G { T t; }; + +G g = {1}; +// CHECK-LABEL: Dumping : +// CHECK: FunctionTemplateDecl +// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit 'auto (T) -> G' aggregate +// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit used 'auto (int) -> G' implicit_instantiation aggregate diff --git a/clang/tools/clang-format/clang-format-diff.py b/clang/tools/clang-format/clang-format-diff.py index 0a2c24743678d0d9928f2a020942901720061372..3a74b90e731578cad6796b9895db563a6512728e 100755 --- a/clang/tools/clang-format/clang-format-diff.py +++ b/clang/tools/clang-format/clang-format-diff.py @@ -138,6 +138,7 @@ def main(): ) # Reformat files containing changes in place. + has_diff = False for filename, lines in lines_by_file.items(): if args.i and args.verbose: print("Formatting {}".format(filename)) @@ -169,7 +170,7 @@ def main(): stdout, stderr = p.communicate() if p.returncode != 0: - sys.exit(p.returncode) + return p.returncode if not args.i: with open(filename) as f: @@ -185,9 +186,12 @@ def main(): ) diff_string = "".join(diff) if len(diff_string) > 0: + has_diff = True sys.stdout.write(diff_string) - sys.exit(1) + + if has_diff: + return 1 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/clang/tools/clang-installapi/InstallAPIOpts.td b/clang/tools/clang-installapi/InstallAPIOpts.td index ab9e1fe7f2f949af6abd190dfea7ea7627f4f25f..010f2507a1d1f38557ff64f2383b0bd54980c625 100644 --- a/clang/tools/clang-installapi/InstallAPIOpts.td +++ b/clang/tools/clang-installapi/InstallAPIOpts.td @@ -29,6 +29,8 @@ def verify_mode_EQ : Joined<["--"], "verify-mode=">, HelpText<"Specify the severity and extend of the validation. Valid modes are ErrorsOnly, ErrorsAndWarnings, and Pedantic.">; def demangle : Flag<["--", "-"], "demangle">, HelpText<"Demangle symbols when printing warnings and errors">; +def dsym: Joined<["--"], "dsym=">, + MetaVarName<"">, HelpText<"Specify dSYM path for enriched diagnostics.">; // Additional input options. def extra_project_header : Separate<["-"], "extra-project-header">, @@ -61,3 +63,15 @@ def exclude_private_header : Separate<["-"], "exclude-private-header">, HelpText<"Exclude private header from parsing">; def exclude_private_header_EQ : Joined<["--"], "exclude-private-header=">, Alias; +def public_umbrella_header : Separate<["-"], "public-umbrella-header">, + MetaVarName<"">, HelpText<"Specify the public umbrella header location">; +def public_umbrella_header_EQ : Joined<["--"], "public-umbrella-header=">, + Alias; +def private_umbrella_header : Separate<["-"], "private-umbrella-header">, + MetaVarName<"">, HelpText<"Specify the private umbrella header location">; +def private_umbrella_header_EQ : Joined<["--"], "private-umbrella-header=">, + Alias; +def project_umbrella_header : Separate<["-"], "project-umbrella-header">, + MetaVarName<"">, HelpText<"Specify the project umbrella header location">; +def project_umbrella_header_EQ : Joined<["--"], "project-umbrella-header=">, + Alias; diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp index 4f79c62724a62d58763e56463bde61343f477d67..c4f39b7c841742df0a3b85f342187963bdc011ff 100644 --- a/clang/tools/clang-installapi/Options.cpp +++ b/clang/tools/clang-installapi/Options.cpp @@ -241,6 +241,9 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef Args) { if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_against)) DriverOpts.DylibToVerify = A->getValue(); + if (const Arg *A = ParsedArgs.getLastArg(OPT_dsym)) + DriverOpts.DSYMPath = A->getValue(); + // Handle exclude & extra header directories or files. auto handleAdditionalInputArgs = [&](PathSeq &Headers, clang::installapi::ID OptID) { @@ -270,6 +273,16 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef Args) { OPT_exclude_project_header)) return {}; + // Handle umbrella headers. + if (const Arg *A = ParsedArgs.getLastArg(OPT_public_umbrella_header)) + DriverOpts.PublicUmbrellaHeader = A->getValue(); + + if (const Arg *A = ParsedArgs.getLastArg(OPT_private_umbrella_header)) + DriverOpts.PrivateUmbrellaHeader = A->getValue(); + + if (const Arg *A = ParsedArgs.getLastArg(OPT_project_umbrella_header)) + DriverOpts.ProjectUmbrellaHeader = A->getValue(); + /// Any unclaimed arguments should be forwarded to the clang driver. std::vector ClangDriverArgs(ParsedArgs.size()); for (const Arg *A : ParsedArgs) { @@ -323,6 +336,15 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM, } } +static const Regex Rule("(.+)/(.+)\\.framework/"); +static StringRef getFrameworkNameFromInstallName(StringRef InstallName) { + SmallVector Match; + Rule.match(InstallName, &Match); + if (Match.empty()) + return ""; + return Match.back(); +} + InstallAPIContext Options::createContext() { InstallAPIContext Ctx; Ctx.FM = FM; @@ -339,6 +361,11 @@ InstallAPIContext Options::createContext() { Ctx.OutputLoc = DriverOpts.OutputPath; Ctx.LangMode = FEOpts.LangMode; + // Attempt to find umbrella headers by capturing framework name. + StringRef FrameworkName; + if (!LinkerOpts.IsDylib) + FrameworkName = getFrameworkNameFromInstallName(LinkerOpts.InstallName); + // Process inputs. for (const std::string &ListPath : DriverOpts.FileLists) { auto Buffer = FM->getBufferForFile(ListPath); @@ -357,8 +384,7 @@ InstallAPIContext Options::createContext() { assert(Type != HeaderType::Unknown && "Missing header type."); for (const StringRef Path : Headers) { if (!FM->getOptionalFileRef(Path)) { - Diags->Report(diag::err_no_such_header_file) - << Path << (unsigned)Type - 1; + Diags->Report(diag::err_no_such_header_file) << Path << (unsigned)Type; return false; } SmallString FullPath(Path); @@ -382,6 +408,7 @@ InstallAPIContext Options::createContext() { std::vector> ExcludedHeaderGlobs; std::set ExcludedHeaderFiles; auto ParseGlobs = [&](const PathSeq &Paths, HeaderType Type) { + assert(Type != HeaderType::Unknown && "Missing header type."); for (const StringRef Path : Paths) { auto Glob = HeaderGlob::create(Path, Type); if (Glob) @@ -424,6 +451,57 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](llvm::Regex &Regex, + HeaderType Type) -> bool { + auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); + }); + + if (It == Ctx.InputHeaders.end()) + return false; + It->setUmbrellaHeader(); + + // Because there can be an umbrella header per header type, + // find the first non umbrella header to swap position with. + auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); + }); + if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); + return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { + assert(Type != HeaderType::Unknown && "Missing header type."); + if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { + Diags->Report(diag::err_no_such_umbrella_header_file) + << HeaderPath << (unsigned)Type; + return false; + } + } else if (!FrameworkName.empty() && (Type != HeaderType::Project)) { + auto UmbrellaName = "/" + Regex::escape(FrameworkName); + if (Type == HeaderType::Public) + UmbrellaName += "\\.h"; + else + UmbrellaName += "[_]?Private\\.h"; + Regex UmbrellaRegex(UmbrellaName); + MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type); + } + return true; + }; + if (!FindUmbrellaHeader(DriverOpts.PublicUmbrellaHeader, + HeaderType::Public) || + !FindUmbrellaHeader(DriverOpts.PrivateUmbrellaHeader, + HeaderType::Private) || + !FindUmbrellaHeader(DriverOpts.ProjectUmbrellaHeader, + HeaderType::Project)) + return Ctx; + // Parse binary dylib and initialize verifier. if (DriverOpts.DylibToVerify.empty()) { Ctx.Verifier = std::make_unique(); @@ -447,7 +525,8 @@ InstallAPIContext Options::createContext() { } Ctx.Verifier = std::make_unique( - std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle); + std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle, + DriverOpts.DSYMPath); return Ctx; } diff --git a/clang/tools/clang-installapi/Options.h b/clang/tools/clang-installapi/Options.h index c18309f693701eacbab9180f3387ee44a36ed4aa..82e04b49d125962a8ba7de0d8ee73d38ab8f7147 100644 --- a/clang/tools/clang-installapi/Options.h +++ b/clang/tools/clang-installapi/Options.h @@ -31,6 +31,15 @@ struct DriverOptions { /// \brief Path to input file lists (JSON). llvm::MachO::PathSeq FileLists; + /// \brief Path to public umbrella header. + std::string PublicUmbrellaHeader; + + /// \brief Path to private umbrella header. + std::string PrivateUmbrellaHeader; + + /// \brief Path to project umbrella header. + std::string ProjectUmbrellaHeader; + /// \brief Paths of extra public headers. PathSeq ExtraPublicHeaders; @@ -58,6 +67,9 @@ struct DriverOptions { /// \brief Output path. std::string OutputPath; + /// \brief DSYM path. + std::string DSYMPath; + /// \brief File encoding to print. FileType OutFT = FileType::TBD_V5; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 454ee1e42aed1d79814934468981784cc46ecfeb..00ddc4f24500fd4f05868199db1de88eef270829 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1923,6 +1923,7 @@ DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType) DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType) DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType) DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType) +DEFAULT_TYPELOC_IMPL(ArrayParameter, ConstantArrayType) DEFAULT_TYPELOC_IMPL(DependentAddressSpace, Type) DEFAULT_TYPELOC_IMPL(DependentVector, Type) DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type) diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index 292d524f00abd697bf1aec0822965a1c2ec00b0f..991767dc4c49c67e91e27ae474e9f6ce956c93a0 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -680,6 +680,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { TCALLINGCONV(PreserveAll); TCALLINGCONV(M68kRTD); TCALLINGCONV(PreserveNone); + TCALLINGCONV(RISCVVectorCall); case CC_SpirFunction: return CXCallingConv_Unexposed; case CC_AMDGPUKernelCall: return CXCallingConv_Unexposed; case CC_OpenCLKernel: return CXCallingConv_Unexposed; diff --git a/clang/unittests/AST/DeclPrinterTest.cpp b/clang/unittests/AST/DeclPrinterTest.cpp index 8a29d0544a04bfb0d3677f555290c72de16005bf..f2b027a25621ce9d2a131bd5f7ecae642cbe43c9 100644 --- a/clang/unittests/AST/DeclPrinterTest.cpp +++ b/clang/unittests/AST/DeclPrinterTest.cpp @@ -1387,34 +1387,38 @@ TEST(DeclPrinter, TestTemplateArgumentList16) { } TEST(DeclPrinter, TestCXXRecordDecl17) { - ASSERT_TRUE(PrintedDeclCXX98Matches("template struct Z {};" - "struct X {};" - "Z A;", - "A", "Z A")); - (void)[](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; }; + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template struct Z {};" + "struct X {};" + "Z A;", + "A", "Z A", + [](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; })); } TEST(DeclPrinter, TestCXXRecordDecl18) { - ASSERT_TRUE(PrintedDeclCXX98Matches("template struct Z {};" - "struct X {};" - "Z A;" - "template " - "struct Y{};" - "Y, 2> B;", - "B", "Y, 2> B")); - (void)[](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; }; + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template struct Z {};" + "struct X {};" + "Z A;" + "template " + "struct Y{};" + "Y, 2> B;", + "B", "Y, 2> B", + [](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; })); } TEST(DeclPrinter, TestCXXRecordDecl19) { - ASSERT_TRUE(PrintedDeclCXX98Matches("template struct Z {};" - "struct X {};" - "Z A;" - "template " - "struct Y{};" - "Y, 2> B;", - "B", "Y, 2> B")); - (void)[](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = true; }; + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template struct Z {};" + "struct X {};" + "Z A;" + "template " + "struct Y{};" + "Y, 2> B;", + "B", "Y, 2> B", + [](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = true; })); } + TEST(DeclPrinter, TestCXXRecordDecl20) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template class Inner;" @@ -1431,8 +1435,8 @@ TEST(DeclPrinter, TestCXXRecordDecl20) { "};" "Outer, 5>::NestedStruct nestedInstance(100);", "nestedInstance", - "Outer, 5>::NestedStruct nestedInstance(100)")); - (void)[](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; }; + "Outer, 5>::NestedStruct nestedInstance(100)", + [](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = false; })); } TEST(DeclPrinter, TestCXXRecordDecl21) { @@ -1451,8 +1455,8 @@ TEST(DeclPrinter, TestCXXRecordDecl21) { "};" "Outer, 5>::NestedStruct nestedInstance(100);", "nestedInstance", - "Outer, 5>::NestedStruct nestedInstance(100)")); - (void)[](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = true; }; + "Outer, 5>::NestedStruct nestedInstance(100)", + [](PrintingPolicy &Policy) { Policy.SuppressTagKeyword = true; })); } TEST(DeclPrinter, TestFunctionParamUglified) { diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp index cef0f8711416b699f8decc04d4402e0b68731683..2530ce74eb6a37623e4d71bda419e8a3c1ae0acb 100644 --- a/clang/unittests/AST/DeclTest.cpp +++ b/clang/unittests/AST/DeclTest.cpp @@ -429,7 +429,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator new"), Ctx)); ASSERT_TRUE(SizedOperatorNew->getOwningModule()); - EXPECT_TRUE(SizedOperatorNew->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(SizedOperatorNew->isFromExplicitGlobalModule()); // void* operator new(std::size_t, std::align_val_t); auto *SizedAlignedOperatorNew = selectFirst( @@ -441,7 +441,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator new"), Ctx)); ASSERT_TRUE(SizedAlignedOperatorNew->getOwningModule()); - EXPECT_TRUE(SizedAlignedOperatorNew->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(SizedAlignedOperatorNew->isFromExplicitGlobalModule()); // void* operator new[](std::size_t); auto *SizedArrayOperatorNew = selectFirst( @@ -451,7 +451,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator new[]"), Ctx)); ASSERT_TRUE(SizedArrayOperatorNew->getOwningModule()); - EXPECT_TRUE(SizedArrayOperatorNew->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(SizedArrayOperatorNew->isFromExplicitGlobalModule()); // void* operator new[](std::size_t, std::align_val_t); auto *SizedAlignedArrayOperatorNew = selectFirst( @@ -464,7 +464,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { Ctx)); ASSERT_TRUE(SizedAlignedArrayOperatorNew->getOwningModule()); EXPECT_TRUE( - SizedAlignedArrayOperatorNew->getOwningModule()->isGlobalModule()); + SizedAlignedArrayOperatorNew->isFromExplicitGlobalModule()); // void operator delete(void*) noexcept; auto *Delete = selectFirst( @@ -475,7 +475,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator delete"), Ctx)); ASSERT_TRUE(Delete->getOwningModule()); - EXPECT_TRUE(Delete->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(Delete->isFromExplicitGlobalModule()); // void operator delete(void*, std::align_val_t) noexcept; auto *AlignedDelete = selectFirst( @@ -487,7 +487,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator delete"), Ctx)); ASSERT_TRUE(AlignedDelete->getOwningModule()); - EXPECT_TRUE(AlignedDelete->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(AlignedDelete->isFromExplicitGlobalModule()); // Sized deallocation is not enabled by default. So we skip it here. @@ -500,7 +500,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator delete[]"), Ctx)); ASSERT_TRUE(ArrayDelete->getOwningModule()); - EXPECT_TRUE(ArrayDelete->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(ArrayDelete->isFromExplicitGlobalModule()); // void operator delete[](void*, std::align_val_t) noexcept; auto *AlignedArrayDelete = selectFirst( @@ -512,7 +512,7 @@ TEST(Decl, ImplicitlyDeclaredAllocationFunctionsInModules) { .bind("operator delete[]"), Ctx)); ASSERT_TRUE(AlignedArrayDelete->getOwningModule()); - EXPECT_TRUE(AlignedArrayDelete->getOwningModule()->isGlobalModule()); + EXPECT_TRUE(AlignedArrayDelete->isFromExplicitGlobalModule()); } TEST(Decl, TemplateArgumentDefaulted) { diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp index 9430730004dbd2e1f3f8c5da33bcf8be81a0eb21..f16472ef17141cfea492cf2b302bf8b2e9c37c83 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -2798,6 +2798,59 @@ TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) { )"); } +TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) { + ExpectDiagnosticsFor( + R"( + #include "unchecked_optional_access_test.h" + + using OptionalInt = $ns::$optional; + + void target($ns::$optional opt) { + if (!opt) return; + + // Accessing the outer optional is OK now. + *opt; + + // But accessing the nested optional is still unsafe because we haven't + // checked it. + **opt; // [[unsafe]] + + *opt = 1; + + // Accessing the nested optional is safe after assigning a value to it. + **opt; + } + )"); +} + +TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) { + ExpectDiagnosticsFor( + R"( + #include "unchecked_optional_access_test.h" + + using OptionalInt = $ns::$optional; + + void target($ns::$optional opt) { + if (!opt) return; + + // Accessing the outer optional is OK now. + *opt; + + // But accessing the nested optional is still unsafe because we haven't + // checked it. + **opt; // [[unsafe]] + + // Assign from `optional` so that we trigger conversion assignment + // instead of move assignment. + *opt = $ns::$optional(); + + // Accessing the nested optional is still unsafe after assigning an empty + // optional to it. + **opt; // [[unsafe]] + } + )"); +} + // Tests that structs can be nested. We use an optional field because its easy // to use in a test, but the type of the field shouldn't matter. TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) { @@ -3443,6 +3496,22 @@ TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) { ast_matchers::hasName("Method")); } +TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) { + ExpectDiagnosticsFor(R"( + #include "unchecked_optional_access_test.h" + + struct Derived : public $ns::$optional { + Derived(int); + }; + + void target(Derived opt) { + *opt; // [[unsafe]] + opt = 1; + *opt; + } + )"); +} + // FIXME: Add support for: // - constructors (copy, move) // - assignment operators (default, copy, move) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 03005384a6f667e10d0c2164abfe90d5994b1c5d..33dec7dae319f050388bd0cfa343cbab9e243641 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12075,6 +12075,7 @@ TEST_F(FormatTest, UnderstandsSquareAttributes) { verifyFormat("SomeType s [[gnu::unused]] (InitValue);"); verifyFormat("SomeType s [[using gnu: unused]] (InitValue);"); verifyFormat("[[gsl::suppress(\"clang-tidy-check-name\")]] void f() {}"); + verifyFormat("[[suppress(type.5)]] int uninitialized_on_purpose;"); verifyFormat("void f() [[deprecated(\"so sorry\")]];"); verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" " [[unused]] aaaaaaaaaaaaaaaaaaaaaaa(int i);"); @@ -19066,6 +19067,11 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { verifyFormat("int a(int x);\n" "double b();", Alignment); + verifyFormat("int a(const Test & = Test());\n" + "int a1(int &foo, const Test & = Test());\n" + "int a2(int &foo, const Test &name = Test());\n" + "double b();", + Alignment); verifyFormat("struct Test {\n" " Test(const Test &) = default;\n" " ~Test() = default;\n" @@ -19102,6 +19108,13 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { " int x,\n" " bool y);", Alignment); + // Set ColumnLimit low so that we break the argument list in multiple lines. + Alignment.ColumnLimit = 35; + verifyFormat("int a3(SomeTypeName1 &x,\n" + " SomeTypeName2 &y,\n" + " const Test & = Test());\n" + "double b();", + Alignment); Alignment.ColumnLimit = OldColumnLimit; // Ensure function pointers don't screw up recursive alignment verifyFormat("int a(int x, void (*fp)(int y));\n" @@ -19287,6 +19300,10 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { "int foobar;", AlignmentLeft); + verifyFormat("int a(SomeType& foo, const Test& = Test());\n" + "double b();", + AlignmentLeft); + // PAS_Middle FormatStyle AlignmentMiddle = Alignment; AlignmentMiddle.PointerAlignment = FormatStyle::PAS_Middle; @@ -19347,6 +19364,10 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { "int foobar;", AlignmentMiddle); + verifyFormat("int a(SomeType & foo, const Test & = Test());\n" + "double b();", + AlignmentMiddle); + Alignment.AlignConsecutiveAssignments.Enabled = false; Alignment.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; verifyFormat("#define A \\\n" diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp index 6ff87f720a559fd6276fd79eb3a2414efbed5cda..0c396720ece66d552436f15a311533f4764cd317 100644 --- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp +++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp @@ -117,11 +117,6 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { }; auto PPOpts = std::make_shared(); - PPOpts->DependencyDirectivesForFile = [&](FileEntryRef File) - -> std::optional> { - return getDependencyDirectives(File); - }; - TrivialModuleLoader ModLoader; HeaderSearch HeaderInfo(std::make_shared(), SourceMgr, Diags, LangOpts, Target.get()); @@ -130,6 +125,12 @@ TEST_F(PPDependencyDirectivesTest, MacroGuard) { /*OwnsHeaderSearch =*/false); PP.Initialize(*Target); + PP.setDependencyDirectivesFn( + [&](FileEntryRef File) + -> std::optional> { + return getDependencyDirectives(File); + }); + SmallVector IncludedFiles; PP.addPPCallbacks(std::make_unique(PP, IncludedFiles)); PP.EnterMainSourceFile(); diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp index 3a90eee5f1c92108387b01a04bc9d8e82f4b6056..aa20c758d84a60d90160d1c995e6647c02c4044f 100644 --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -575,7 +575,7 @@ public: // Emit code to generate this result as a Value *. std::string asValue() override { if (AddressType) - return "(" + varname() + ".getPointer())"; + return "(" + varname() + ".emitRawPointer(*this))"; return Result::asValue(); } bool hasIntegerValue() const override { return Immediate; } diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp index 8513174c88bfc3242635774806bc1fcc37293523..5e41ef9f9d2684037988014b79d87755847959d7 100644 --- a/clang/utils/TableGen/RISCVVEmitter.cpp +++ b/clang/utils/TableGen/RISCVVEmitter.cpp @@ -334,10 +334,6 @@ void RVVEmitter::createHeader(raw_ostream &OS) { OS << "#include \n"; OS << "#include \n\n"; - OS << "#ifndef __riscv_vector\n"; - OS << "#error \"Vector intrinsics require the vector extension.\"\n"; - OS << "#endif\n\n"; - OS << "#ifdef __cplusplus\n"; OS << "extern \"C\" {\n"; OS << "#endif\n\n"; diff --git a/clang/www/c_status.html b/clang/www/c_status.html index 60f48aba2788e0820fe5f5fa9d942324b85074ec..123897593e5d84e5d69a68f5d767fcf2cbc50935 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -105,7 +105,7 @@ conformance.

restricted character set support via digraphs and <iso646.h> Unknown - Unknown + Yes more precise aliasing rules via effective type @@ -132,11 +132,6 @@ conformance.

Unknown Yes - - more precise aliasing rules via effective type - Unknown - Unknown - complex and imaginary support in <complex.h> @@ -173,7 +168,7 @@ conformance.

increase minimum translation limits N590 - Unknown + Clang 3.2 additional floating-point characteristics in <float.h> @@ -305,7 +300,7 @@ conformance.

empty macro arguments N570 - Unknown + Yes new structure type compatibility (tag compatibility) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 911f48fa13816c00d20457f3b7ae85f4848af23e..46a6fdf8728ff8fcdb8ef103dcfb918d8560a410 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -235,9 +235,9 @@ set(COMPILER_RT_SUPPORTED_ARCH) # Try to compile a very simple source file to ensure we can target the given # platform. We use the results of these tests to build only the various target # runtime libraries supported by our current compilers cross-compiling -# abilities. Avoids using libc as that may not be available yet. +# abilities. set(SIMPLE_SOURCE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/simple.cc) -file(WRITE ${SIMPLE_SOURCE} "int main(void) { return 0; }\n") +file(WRITE ${SIMPLE_SOURCE} "#include \n#include \nint main(void) { printf(\"hello, world\"); }\n") # Detect whether the current target platform is 32-bit or 64-bit, and setup # the correct commandline flags needed to attempt to target 32-bit and 64-bit. diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index a04175ba1e4b56939122785fd3169764c2c46e66..a638e66eccee58f13c5d052f1d8f11c588290d66 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -479,6 +479,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { switch (*(u8*)address) { case 0x90: // 90 : nop + case 0xC3: // C3 : ret (for small/empty function interception + case 0xCC: // CC : int 3 i.e. registering weak functions) return 1; case 0x50: // push eax / rax @@ -502,7 +504,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { // Cannot overwrite control-instruction. Return 0 to indicate failure. case 0xE9: // E9 XX XX XX XX : jmp