From d38d0a0d1bd219555f130dd63e2599f5126e1bdd Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 29 May 2024 20:32:34 -0700 Subject: [PATCH 001/243] Revert "[ELF] Simplify getSectionRank" This reverts commit f639b57f7993cadb82ee9c36f04703ae4430ed85. The premerge bot is still broken with failing bolt test. --- lld/ELF/Writer.cpp | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index c498153f3348..d2cc6d8ff5f2 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -618,6 +618,7 @@ enum RankFlags { RF_NOT_ADDR_SET = 1 << 27, RF_NOT_ALLOC = 1 << 26, RF_PARTITION = 1 << 18, // Partition number (8 bits) + RF_NOT_SPECIAL = 1 << 17, RF_LARGE_ALT = 1 << 15, RF_WRITE = 1 << 14, RF_EXEC_WRITE = 1 << 13, @@ -643,6 +644,24 @@ unsigned elf::getSectionRank(OutputSection &osec) { if (!(osec.flags & SHF_ALLOC)) return rank | RF_NOT_ALLOC; + if (osec.type == SHT_LLVM_PART_EHDR) + return rank; + if (osec.type == SHT_LLVM_PART_PHDR) + return rank | 1; + + // Put .interp first because some loaders want to see that section + // on the first page of the executable file when loaded into memory. + if (osec.name == ".interp") + return rank | 2; + + // Put .note sections at the beginning so that they are likely to be included + // in a truncate core file. In particular, .note.gnu.build-id, if available, + // can identify the object file. + if (osec.type == SHT_NOTE) + return rank | 3; + + rank |= RF_NOT_SPECIAL; + // Sort sections based on their access permission in the following // order: R, RX, RXW, RW(RELRO), RW(non-RELRO). // @@ -658,6 +677,11 @@ unsigned elf::getSectionRank(OutputSection &osec) { bool isWrite = osec.flags & SHF_WRITE; if (!isWrite && !isExec) { + // Make PROGBITS sections (e.g .rodata .eh_frame) closer to .text to + // alleviate relocation overflow pressure. Large special sections such as + // .dynstr and .dynsym can be away from .text. + if (osec.type == SHT_PROGBITS) + rank |= RF_RODATA; // Among PROGBITS sections, place .lrodata further from .text. // For -z lrodata-after-bss, place .lrodata after .lbss like GNU ld. This // layout has one extra PT_LOAD, but alleviates relocation overflow @@ -667,25 +691,6 @@ unsigned elf::getSectionRank(OutputSection &osec) { rank |= config->zLrodataAfterBss ? RF_LARGE_ALT : 0; else rank |= config->zLrodataAfterBss ? 0 : RF_LARGE; - - if (osec.type == SHT_LLVM_PART_EHDR) - ; - else if (osec.type == SHT_LLVM_PART_PHDR) - rank |= 1; - else if (osec.name == ".interp") - rank |= 2; - // Put .note sections at the beginning so that they are likely to be - // included in a truncate core file. In particular, .note.gnu.build-id, if - // available, can identify the object file. - else if (osec.type == SHT_NOTE) - rank |= 3; - // Make PROGBITS sections (e.g .rodata .eh_frame) closer to .text to - // alleviate relocation overflow pressure. Large special sections such as - // .dynstr and .dynsym can be away from .text. - else if (osec.type != SHT_PROGBITS) - rank |= 4; - else - rank |= RF_RODATA; } else if (isExec) { rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC; } else { -- GitLab From 815250b219a04966e4ea5de3a09965bea4d4cc41 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Wed, 29 May 2024 20:56:05 -0700 Subject: [PATCH 002/243] [compiler-rt] Don't rely on automatic codesigning with Apple's linker (#91681) In https://github.com/llvm/llvm-project/pull/88323, I changed the logic within `add_compiler_rt_runtime` to only explicitly code sign the resulting library if an older version of Apple's ld64 was in use. This was based on the assumption that newer versions of ld64 and the new Apple linker always ad-hoc sign their output binaries. This is true in most cases, but not when using Apple's new linker with the `-darwin-target-variant` flag to build Mac binaries that are compatible with Catalyst. Rather than adding increasingly complicated logic to detect the exact scenarios that require explicit code signing, I've opted to always explicitly code sign when using any Apple linker. We instead detect and use the 'linker-signed' codesigning option when possible to match the signatures that the linker would otherwise create. This avoids having non-'linker-signed' ad-hoc signatures which was the underlying problem that https://github.com/llvm/llvm-project/pull/88323 was intended to address. Co-authored-by: Mark Rowe --- compiler-rt/cmake/Modules/AddCompilerRT.cmake | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler-rt/cmake/Modules/AddCompilerRT.cmake b/compiler-rt/cmake/Modules/AddCompilerRT.cmake index 75b34c8e27e0..9ec2eecf801b 100644 --- a/compiler-rt/cmake/Modules/AddCompilerRT.cmake +++ b/compiler-rt/cmake/Modules/AddCompilerRT.cmake @@ -387,35 +387,35 @@ function(add_compiler_rt_runtime name type) set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib") endif() if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*") - # Ad-hoc sign the dylibs when using Xcode versions older than 12. - # Xcode 12 shipped with ld64-609. - # FIXME: Remove whole conditional block once everything uses Xcode 12+. - set(LD_V_OUTPUT) + # Apple's linker signs the resulting dylib with an ad-hoc code signature in + # most situations, except: + # 1. Versions of ld64 prior to ld64-609 in Xcode 12 predate this behavior. + # 2. Apple's new linker does not when building with `-darwin-target-variant` + # to support macOS Catalyst. + # + # Explicitly re-signing the dylib works around both of these issues. The + # signature is marked as `linker-signed` when that is supported so that it + # behaves as expected when processed by subsequent tooling. + # + # Detect whether `codesign` supports `-o linker-signed` by passing it as an + # argument and looking for `invalid argument "linker-signed"` in its output. + # FIXME: Remove this once all supported toolchains support `-o linker-signed`. execute_process( - COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1" - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LD_V_OUTPUT + COMMAND sh -c "codesign -f -s - -o linker-signed this-does-not-exist 2>&1 | grep -q linker-signed" + RESULT_VARIABLE CODESIGN_SUPPORTS_LINKER_SIGNED ) - if (HAD_ERROR) - message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}") - endif() - set(NEED_EXPLICIT_ADHOC_CODESIGN 0) - # Apple introduced a new linker by default in Xcode 15. This linker reports itself as ld - # rather than ld64 and does not match this version regex. That's ok since it never needs - # the explicit ad-hoc code signature. - if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*") - string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) - if (HOST_LINK_VERSION VERSION_LESS 609) - set(NEED_EXPLICIT_ADHOC_CODESIGN 1) - endif() - endif() - if (NEED_EXPLICIT_ADHOC_CODESIGN) - add_custom_command(TARGET ${libname} - POST_BUILD - COMMAND codesign --sign - $ - WORKING_DIRECTORY ${COMPILER_RT_OUTPUT_LIBRARY_DIR} - ) + + set(EXTRA_CODESIGN_ARGUMENTS) + if (CODESIGN_SUPPORTS_LINKER_SIGNED) + list(APPEND EXTRA_CODESIGN_ARGUMENTS -o linker-signed) endif() + + add_custom_command(TARGET ${libname} + POST_BUILD + COMMAND codesign --sign - ${EXTRA_CODESIGN_ARGUMENTS} $ + WORKING_DIRECTORY ${COMPILER_RT_OUTPUT_LIBRARY_DIR} + COMMAND_EXPAND_LISTS + ) endif() endif() -- GitLab From 17940465364e0ad66fa364c5bef8abec4e34ac5b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 29 May 2024 21:01:28 -0700 Subject: [PATCH 003/243] [VPlan] Move verifier to class to reduce need to pass via args. (NFC) Move VPlan verification functions to avoid the need to pass VPDT across multiple calls. This also allows easier extensions in the future. --- .../Transforms/Vectorize/VPlanVerifier.cpp | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp index 7ebdb914fb85..2fe487f972bb 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp @@ -23,10 +23,41 @@ using namespace llvm; -// Verify that phi-like recipes are at the beginning of \p VPBB, with no -// other recipes in between. Also check that only header blocks contain -// VPHeaderPHIRecipes. -static bool verifyPhiRecipes(const VPBasicBlock *VPBB) { +namespace { +class VPlanVerifier { + const VPDominatorTree &VPDT; + + // Verify that phi-like recipes are at the beginning of \p VPBB, with no + // other recipes in between. Also check that only header blocks contain + // VPHeaderPHIRecipes. + bool verifyPhiRecipes(const VPBasicBlock *VPBB); + + bool verifyVPBasicBlock(const VPBasicBlock *VPBB); + + bool verifyBlock(const VPBlockBase *VPB); + + /// Helper function that verifies the CFG invariants of the VPBlockBases + /// within + /// \p Region. Checks in this function are generic for VPBlockBases. They are + /// not specific for VPBasicBlocks or VPRegionBlocks. + bool verifyBlocksInRegion(const VPRegionBlock *Region); + + /// Verify the CFG invariants of VPRegionBlock \p Region and its nested + /// VPBlockBases. Do not recurse inside nested VPRegionBlocks. + bool verifyRegion(const VPRegionBlock *Region); + + /// Verify the CFG invariants of VPRegionBlock \p Region and its nested + /// VPBlockBases. Recurse inside nested VPRegionBlocks. + bool verifyRegionRec(const VPRegionBlock *Region); + +public: + VPlanVerifier(VPDominatorTree &VPDT) : VPDT(VPDT) {} + + bool verify(const VPlan &Plan); +}; +} // namespace + +bool VPlanVerifier::verifyPhiRecipes(const VPBasicBlock *VPBB) { auto RecipeI = VPBB->begin(); auto End = VPBB->end(); unsigned NumActiveLaneMaskPhiRecipes = 0; @@ -80,8 +111,7 @@ static bool verifyPhiRecipes(const VPBasicBlock *VPBB) { return true; } -static bool verifyVPBasicBlock(const VPBasicBlock *VPBB, - const VPDominatorTree &VPDT) { +bool VPlanVerifier::verifyVPBasicBlock(const VPBasicBlock *VPBB) { if (!verifyPhiRecipes(VPBB)) return false; @@ -133,7 +163,7 @@ static bool hasDuplicates(const SmallVectorImpl &VPBlockVec) { return false; } -static bool verifyBlock(const VPBlockBase *VPB, const VPDominatorTree &VPDT) { +bool VPlanVerifier::verifyBlock(const VPBlockBase *VPB) { auto *VPBB = dyn_cast(VPB); // Check block's condition bit. if (VPB->getNumSuccessors() > 1 || @@ -193,14 +223,10 @@ static bool verifyBlock(const VPBlockBase *VPB, const VPDominatorTree &VPDT) { return false; } } - return !VPBB || verifyVPBasicBlock(VPBB, VPDT); + return !VPBB || verifyVPBasicBlock(VPBB); } -/// Helper function that verifies the CFG invariants of the VPBlockBases within -/// \p Region. Checks in this function are generic for VPBlockBases. They are -/// not specific for VPBasicBlocks or VPRegionBlocks. -static bool verifyBlocksInRegion(const VPRegionBlock *Region, - const VPDominatorTree &VPDT) { +bool VPlanVerifier::verifyBlocksInRegion(const VPRegionBlock *Region) { for (const VPBlockBase *VPB : vp_depth_first_shallow(Region->getEntry())) { // Check block's parent. if (VPB->getParent() != Region) { @@ -208,16 +234,13 @@ static bool verifyBlocksInRegion(const VPRegionBlock *Region, return false; } - if (!verifyBlock(VPB, VPDT)) + if (!verifyBlock(VPB)) return false; } return true; } -/// Verify the CFG invariants of VPRegionBlock \p Region and its nested -/// VPBlockBases. Do not recurse inside nested VPRegionBlocks. -static bool verifyRegion(const VPRegionBlock *Region, - const VPDominatorTree &VPDT) { +bool VPlanVerifier::verifyRegion(const VPRegionBlock *Region) { const VPBlockBase *Entry = Region->getEntry(); const VPBlockBase *Exiting = Region->getExiting(); @@ -231,33 +254,26 @@ static bool verifyRegion(const VPRegionBlock *Region, return false; } - return verifyBlocksInRegion(Region, VPDT); + return verifyBlocksInRegion(Region); } -/// Verify the CFG invariants of VPRegionBlock \p Region and its nested -/// VPBlockBases. Recurse inside nested VPRegionBlocks. -static bool verifyRegionRec(const VPRegionBlock *Region, - const VPDominatorTree &VPDT) { +bool VPlanVerifier::verifyRegionRec(const VPRegionBlock *Region) { // Recurse inside nested regions and check all blocks inside the region. - return verifyRegion(Region, VPDT) && + return verifyRegion(Region) && all_of(vp_depth_first_shallow(Region->getEntry()), - [&VPDT](const VPBlockBase *VPB) { + [this](const VPBlockBase *VPB) { const auto *SubRegion = dyn_cast(VPB); - return !SubRegion || verifyRegionRec(SubRegion, VPDT); + return !SubRegion || verifyRegionRec(SubRegion); }); } -bool llvm::verifyVPlanIsValid(const VPlan &Plan) { - VPDominatorTree VPDT; - VPDT.recalculate(const_cast(Plan)); - - if (any_of( - vp_depth_first_shallow(Plan.getEntry()), - [&VPDT](const VPBlockBase *VPB) { return !verifyBlock(VPB, VPDT); })) +bool VPlanVerifier::verify(const VPlan &Plan) { + if (any_of(vp_depth_first_shallow(Plan.getEntry()), + [this](const VPBlockBase *VPB) { return !verifyBlock(VPB); })) return false; const VPRegionBlock *TopRegion = Plan.getVectorLoopRegion(); - if (!verifyRegionRec(TopRegion, VPDT)) + if (!verifyRegionRec(TopRegion)) return false; if (TopRegion->getParent()) { @@ -305,3 +321,10 @@ bool llvm::verifyVPlanIsValid(const VPlan &Plan) { return true; } + +bool llvm::verifyVPlanIsValid(const VPlan &Plan) { + VPDominatorTree VPDT; + VPDT.recalculate(const_cast(Plan)); + VPlanVerifier Verifier(VPDT); + return Verifier.verify(Plan); +} -- GitLab From 3db1f3110e714ad24f7d72114b3a2c14f6c63651 Mon Sep 17 00:00:00 2001 From: Owen Pan Date: Wed, 29 May 2024 21:05:32 -0700 Subject: [PATCH 004/243] [clang-format] Fix a regression in annotating class decl braces (#93657) Fixes #93604. --- clang/lib/Format/UnwrappedLineParser.cpp | 3 +++ clang/unittests/Format/TokenAnnotatorTest.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index b6f7567adc14..bf89def05bb2 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -4026,6 +4026,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { if (AngleNestingLevel == 0) { if (FormatTok->is(tok::colon)) { IsDerived = true; + } else if (FormatTok->is(tok::identifier) && + FormatTok->Previous->is(tok::coloncolon)) { + ClassName = FormatTok; } else if (FormatTok->is(tok::l_paren) && IsNonMacroIdentifier(FormatTok->Previous)) { break; diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 6ea9c4a241dc..3339a749df3a 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2914,6 +2914,11 @@ TEST_F(TokenAnnotatorTest, BraceKind) { EXPECT_BRACE_KIND(Tokens[5], BK_Block); EXPECT_BRACE_KIND(Tokens[6], BK_Block); + Tokens = annotate("struct Foo::Bar {};"); + ASSERT_EQ(Tokens.size(), 11u) << Tokens; + EXPECT_BRACE_KIND(Tokens[7], BK_Block); + EXPECT_BRACE_KIND(Tokens[8], BK_Block); + Tokens = annotate("struct Foo : Base {};"); ASSERT_EQ(Tokens.size(), 11u) << Tokens; EXPECT_BRACE_KIND(Tokens[7], BK_Block); -- GitLab From 32f1f5ee39985bbd0c8f21bf264a45cd5d4335f6 Mon Sep 17 00:00:00 2001 From: Pavel Samolysov Date: Thu, 30 May 2024 07:10:26 +0300 Subject: [PATCH 005/243] [PGO] Add tests for modules with only globals and function declarations (#93764) When a module contains globals and/or function declarations only, the '__llvm_profile_raw_version' variable should not be generated because the module was not instrumented at all. NFC --- .../available_externally_functions.ll | 17 +++++++++++++++++ .../Transforms/PGOProfile/declarations_only.ll | 13 +++++++++++++ .../PGOProfile/global_variables_only.ll | 9 +++++++++ 3 files changed, 39 insertions(+) create mode 100644 llvm/test/Transforms/PGOProfile/available_externally_functions.ll create mode 100644 llvm/test/Transforms/PGOProfile/declarations_only.ll create mode 100644 llvm/test/Transforms/PGOProfile/global_variables_only.ll diff --git a/llvm/test/Transforms/PGOProfile/available_externally_functions.ll b/llvm/test/Transforms/PGOProfile/available_externally_functions.ll new file mode 100644 index 000000000000..f455ca066aa7 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/available_externally_functions.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -passes=pgo-instr-gen -S | FileCheck %s --check-prefix=GEN --check-prefix=GEN-COMDAT + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; GEN-COMDAT: $__llvm_profile_raw_version = comdat any +; GEN-COMDAT: @__llvm_profile_raw_version = hidden constant i64 {{[0-9]+}}, comdat +; GEN: @__profn_foo = linkonce_odr hidden constant [3 x i8] c"foo" +; GEN: @__profn_bar = linkonce_odr hidden constant [3 x i8] c"bar" + +define available_externally hidden void @foo() { + ret void +} + +define available_externally i32 @bar() { + ret i32 42 +} diff --git a/llvm/test/Transforms/PGOProfile/declarations_only.ll b/llvm/test/Transforms/PGOProfile/declarations_only.ll new file mode 100644 index 000000000000..e7208fc264c7 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/declarations_only.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -passes=pgo-instr-gen -S | FileCheck %s --check-prefix=GEN --check-prefix=GEN-COMDAT + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; GEN-COMDAT: $__llvm_profile_raw_version = comdat any +; GEN-COMDAT: @__llvm_profile_raw_version = hidden constant i64 {{[0-9]+}}, comdat +; GEN-NOT: @__profn_test_1 = private constant [6 x i8] c"test_1" +; GEN-NOT: @__profn_test_2 = private constant [6 x i8] c"test_2" + +declare i32 @test_1(i32 %i) + +declare i32 @test_2(i32 %i) diff --git a/llvm/test/Transforms/PGOProfile/global_variables_only.ll b/llvm/test/Transforms/PGOProfile/global_variables_only.ll new file mode 100644 index 000000000000..3bfa29af5d34 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/global_variables_only.ll @@ -0,0 +1,9 @@ +; RUN: opt < %s -passes=pgo-instr-gen -S | FileCheck %s --check-prefix=GEN-COMDAT + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; GEN-COMDAT: $__llvm_profile_raw_version = comdat any +; GEN-COMDAT: @__llvm_profile_raw_version = hidden constant i64 {{[0-9]+}}, comdat + +@var = internal unnamed_addr global [35 x ptr] zeroinitializer, align 16 -- GitLab From 02c6845c762dfd0a19d4a2f997990e160f392dae Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 29 May 2024 22:48:15 -0600 Subject: [PATCH 006/243] Revert "[DebugInfo] Add flag to only emit referenced member functions" (#93767) Reverts llvm/llvm-project#87018 MacOS and Windows bots are broken. --- clang/include/clang/Basic/DebugOptions.def | 2 -- clang/include/clang/Driver/Options.td | 4 ---- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- clang/lib/Driver/ToolChains/Clang.cpp | 15 --------------- .../CodeGenCXX/debug-info-incomplete-types.cpp | 12 ------------ clang/test/Driver/debug-options.c | 8 -------- 6 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 clang/test/CodeGenCXX/debug-info-incomplete-types.cpp diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def index bc96d5dfdf89..b94f6aef9ac6 100644 --- a/clang/include/clang/Basic/DebugOptions.def +++ b/clang/include/clang/Basic/DebugOptions.def @@ -68,8 +68,6 @@ BENIGN_DEBUGOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain ///< inline line tables. DEBUGOPT(DebugStrictDwarf, 1, 1) ///< Whether or not to use strict DWARF info. -DEBUGOPT(DebugOmitUnreferencedMethods, 1, 0) ///< Omit unreferenced member - ///< functions in type debug info. /// Control the Assignment Tracking debug info feature. BENIGN_ENUM_DEBUGOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index f64d7c60783e..4119e69c8554 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4345,10 +4345,6 @@ defm strict_dwarf : BoolOption<"g", "strict-dwarf", "the specified version, avoiding features from later versions.">, NegFlag, BothFlags<[], [ClangOption, CLOption, DXCOption]>>, Group; -defm omit_unreferenced_methods : BoolGOption<"omit-unreferenced-methods", - CodeGenOpts<"DebugOmitUnreferencedMethods">, DefaultFalse, - NegFlag, - PosFlag, BothFlags<[], [ClangOption, CLOption, DXCOption]>>; defm column_info : BoolOption<"g", "column-info", CodeGenOpts<"DebugColumnInfo">, DefaultTrue, NegFlag, diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 5f6f911c7a6d..9d7107abf8a6 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2836,7 +2836,7 @@ CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { // Collect data fields (including static variables and any initializers). CollectRecordFields(RD, DefUnit, EltTys, FwdDecl); - if (CXXDecl && !CGM.getCodeGenOpts().DebugOmitUnreferencedMethods) + if (CXXDecl) CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl); LexicalBlockStack.pop_back(); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 4e1c52462e58..97e451cfe2ac 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -45,7 +45,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" -#include "llvm/Frontend/Debug/Options.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" @@ -4643,7 +4642,6 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame, options::OPT_fno_force_dwarf_frame); - bool EnableTypeUnits = false; if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { if (!(T.isOSBinFormatELF() || T.isOSBinFormatWasm())) { @@ -4654,24 +4652,11 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, } else if (checkDebugInfoOption( Args.getLastArg(options::OPT_fdebug_types_section), Args, D, TC)) { - EnableTypeUnits = true; CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-generate-type-units"); } } - if (const Arg *A = - Args.getLastArg(options::OPT_gomit_unreferenced_methods, - options::OPT_gno_omit_unreferenced_methods)) - (void)checkDebugInfoOption(A, Args, D, TC); - if (Args.hasFlag(options::OPT_gomit_unreferenced_methods, - options::OPT_gno_omit_unreferenced_methods, false) && - (DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor || - DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo) && - !EnableTypeUnits) { - CmdArgs.push_back("-gomit-unreferenced-methods"); - } - // To avoid join/split of directory+filename, the integrated assembler prefers // the directory form of .file on all DWARF versions. GNU as doesn't allow the // form before DWARF v5. diff --git a/clang/test/CodeGenCXX/debug-info-incomplete-types.cpp b/clang/test/CodeGenCXX/debug-info-incomplete-types.cpp deleted file mode 100644 index 0bf59233b4e2..000000000000 --- a/clang/test/CodeGenCXX/debug-info-incomplete-types.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cc1 -debug-info-kind=limited -gomit-unreferenced-methods %s -emit-llvm -o - | FileCheck %s - -struct t1 { - void f1(); - void f2(); -}; - -void t1::f1() { } - -// CHECK: distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1" -// CHECK-SAME: elements: [[ELEMENTS:![0-9]+]] -// CHECK: [[ELEMENTS]] = !{} diff --git a/clang/test/Driver/debug-options.c b/clang/test/Driver/debug-options.c index b09238d7b6bb..7d061410a229 100644 --- a/clang/test/Driver/debug-options.c +++ b/clang/test/Driver/debug-options.c @@ -242,11 +242,6 @@ // RUN: %clang -### -c %s 2>&1 | FileCheck -check-prefix=NORNGBSE %s // RUN: %clang -### -c -fdebug-ranges-base-address -fno-debug-ranges-base-address %s 2>&1 | FileCheck -check-prefix=NORNGBSE %s // -// RUN: %clang -### -c -gomit-unreferenced-methods %s 2>&1 | FileCheck -check-prefix=INCTYPES %s -// RUN: %clang -### -c %s 2>&1 | FileCheck -check-prefix=NOINCTYPES %s -// RUN: %clang -### -c -gomit-unreferenced-methods -fdebug-types-section %s 2>&1 | FileCheck -check-prefix=NOINCTYPES %s -// RUN: %clang -### -c -gomit-unreferenced-methods -fstandalone-debug %s 2>&1 | FileCheck -check-prefix=NOINCTYPES %s -// // RUN: %clang -### -c -glldb %s 2>&1 | FileCheck -check-prefix=NOPUB %s // RUN: %clang -### -c -glldb -gno-pubnames %s 2>&1 | FileCheck -check-prefix=NOPUB %s // @@ -386,9 +381,6 @@ // RNGBSE: -fdebug-ranges-base-address // NORNGBSE-NOT: -fdebug-ranges-base-address // -// INCTYPES: -gomit-unreferenced-methods -// NOINCTYPES-NOT: -gomit-unreferenced-methods -// // GARANGE-DAG: -generate-arange-section // // FDTS: "-mllvm" "-generate-type-units" -- GitLab From 8890209ead2246461985f49c4c9c01cc2371ac09 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 29 May 2024 21:52:20 -0700 Subject: [PATCH 007/243] [HLSL] Default and Relaxed Availability Diagnostics (#92704) Implements HLSL availability diagnostics' default and relaxed mode. HLSL availability diagnostics emits errors or warning when unavailable shader APIs are used. Unavailable shader APIs are APIs that are exposed in HLSL code but are not available in the target shader stage or shader model version. In the default mode the compiler emits an error when an unavailable API is found in a code that is reachable from the shader entry point function. In the future this check will also extended to exported library functions (#92073). The relaxed diagnostic mode is the same except the compiler emits a warning. This mode is enabled by ``-Wno-error=hlsl-availability``. See HLSL Availability Diagnostics design doc [here](https://github.com/llvm/llvm-project/blob/main/clang/docs/HLSL/AvailabilityDiagnostics.rst) for more details. Fixes #90095 --- clang/include/clang/Basic/Attr.td | 45 ++- clang/include/clang/Basic/DiagnosticGroups.td | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 7 + clang/include/clang/Sema/SemaHLSL.h | 1 + clang/lib/AST/DeclBase.cpp | 3 +- clang/lib/Sema/Sema.cpp | 4 + clang/lib/Sema/SemaAvailability.cpp | 24 +- clang/lib/Sema/SemaHLSL.cpp | 297 ++++++++++++++++++ .../attr-availability-compute.hlsl | 19 +- .../Availability/attr-availability-mesh.hlsl | 19 +- .../Availability/attr-availability-pixel.hlsl | 6 +- .../avail-diag-default-compute.hlsl | 119 +++++++ .../Availability/avail-diag-default-lib.hlsl | 130 ++++++++ .../avail-diag-relaxed-compute.hlsl | 119 +++++++ .../Availability/avail-diag-relaxed-lib.hlsl | 130 ++++++++ .../avail-lib-multiple-stages.hlsl | 57 ++++ .../SemaHLSL/WaveBuiltinAvailability.hlsl | 9 +- 17 files changed, 941 insertions(+), 51 deletions(-) create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl create mode 100644 clang/test/SemaHLSL/Availability/avail-lib-multiple-stages.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ef9df1e9d8b4..2665b7353ca4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1060,18 +1060,10 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { .Case("ShaderModel", "shadermodel") .Default(Platform); } -static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) { - return llvm::StringSwitch(Environment) - .Case("pixel", "pixel shader") - .Case("vertex", "vertex shader") - .Case("geometry", "geometry shader") - .Case("hull", "hull shader") - .Case("domain", "domain shader") - .Case("compute", "compute shader") - .Case("mesh", "mesh shader") - .Case("amplification", "amplification shader") - .Case("library", "shader library") - .Default(Environment); +static llvm::StringRef getPrettyEnviromentName(llvm::Triple::EnvironmentType EnvironmentType) { + if (EnvironmentType >= llvm::Triple::Pixel && EnvironmentType <= llvm::Triple::Amplification) + return llvm::Triple::getEnvironmentTypeName(EnvironmentType); + return ""; } static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) { return llvm::StringSwitch(Environment) @@ -1081,6 +1073,12 @@ static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environm .Case("hull", llvm::Triple::Hull) .Case("domain", llvm::Triple::Domain) .Case("compute", llvm::Triple::Compute) + .Case("raygeneration", llvm::Triple::RayGeneration) + .Case("intersection", llvm::Triple::Intersection) + .Case("anyhit", llvm::Triple::AnyHit) + .Case("closesthit", llvm::Triple::ClosestHit) + .Case("miss", llvm::Triple::Miss) + .Case("callable", llvm::Triple::Callable) .Case("mesh", llvm::Triple::Mesh) .Case("amplification", llvm::Triple::Amplification) .Case("library", llvm::Triple::Library) @@ -4480,6 +4478,29 @@ def HLSLShader : InheritableAttr { "Miss", "Callable", "Mesh", "Amplification"]> ]; let Documentation = [HLSLSV_ShaderTypeAttrDocs]; + let AdditionalMembers = +[{ + static const unsigned ShaderTypeMaxValue = (unsigned)HLSLShaderAttr::Amplification; + + static llvm::Triple::EnvironmentType getTypeAsEnvironment(HLSLShaderAttr::ShaderType ShaderType) { + switch (ShaderType) { + case HLSLShaderAttr::Pixel: return llvm::Triple::Pixel; + case HLSLShaderAttr::Vertex: return llvm::Triple::Vertex; + case HLSLShaderAttr::Geometry: return llvm::Triple::Geometry; + case HLSLShaderAttr::Hull: return llvm::Triple::Hull; + case HLSLShaderAttr::Domain: return llvm::Triple::Domain; + case HLSLShaderAttr::Compute: return llvm::Triple::Compute; + case HLSLShaderAttr::RayGeneration: return llvm::Triple::RayGeneration; + case HLSLShaderAttr::Intersection: return llvm::Triple::Intersection; + case HLSLShaderAttr::AnyHit: return llvm::Triple::AnyHit; + case HLSLShaderAttr::ClosestHit: return llvm::Triple::ClosestHit; + case HLSLShaderAttr::Miss: return llvm::Triple::Miss; + case HLSLShaderAttr::Callable: return llvm::Triple::Callable; + case HLSLShaderAttr::Mesh: return llvm::Triple::Mesh; + case HLSLShaderAttr::Amplification: return llvm::Triple::Amplification; + } + } +}]; } def HLSLResource : InheritableAttr { diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 6b595a356793..7d5ba7869ec3 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1517,6 +1517,9 @@ def HLSLMixPackOffset : DiagGroup<"mix-packoffset">; // Warnings for DXIL validation def DXILValidation : DiagGroup<"dxil-validation">; +// Warning for HLSL API availability +def HLSLAvailability : DiagGroup<"hlsl-availability">; + // Warnings and notes related to const_var_decl_type attribute checks def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f15cba63624e..e34eb692941b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12239,6 +12239,13 @@ def err_hlsl_param_qualifier_mismatch : def warn_hlsl_impcast_vector_truncation : Warning< "implicit conversion truncates vector: %0 to %1">, InGroup; +def warn_hlsl_availability : Warning< + "%0 is only available %select{|in %4 environment }3on %1 %2 or newer">, + InGroup, DefaultError; +def warn_hlsl_availability_unavailable : + Warning, + InGroup, DefaultError; + // Layout randomization diagnostics. def err_non_designated_init_used : Error< "a randomized struct can only be initialized with a designated initializer">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 34acaf19517f..eac1f7c07c85 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -49,6 +49,7 @@ public: void DiagnoseAttrStageMismatch( const Attr *A, HLSLShaderAttr::ShaderType Stage, std::initializer_list AllowedStages); + void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); }; } // namespace clang diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 65d5eeb6354e..ffb22194bce5 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -669,7 +669,8 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, IdentifierInfo *IIEnv = A->getEnvironment(); StringRef TargetEnv = Context.getTargetInfo().getTriple().getEnvironmentName(); - StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(TargetEnv); + StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName( + Context.getTargetInfo().getTriple().getEnvironment()); // Matching environment or no environment on attribute if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) { if (Message) { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d1fb21bb1ae1..39a9a431728f 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1357,6 +1357,10 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteExternalDeclaration(D); } + if (LangOpts.HLSL) + HLSL().DiagnoseAvailabilityViolations( + getASTContext().getTranslationUnitDecl()); + // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 22f5a2f66347..330cd602297d 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -15,6 +15,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DelayedDiagnostic.h" @@ -228,8 +229,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); break; case llvm::Triple::ShaderModel: - // Always enable availability diagnostics for shader models. - return true; + // FIXME: This will be updated when HLSL strict diagnostic mode + // is implemented (issue #90096) + return false; default: // New targets should always warn about availability. return Triple.getVendor() == llvm::Triple::Apple; @@ -409,10 +411,11 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, std::string PlatformName( AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( - TI.getTriple().getEnvironmentName())); + TI.getTriple().getEnvironment())); llvm::StringRef AttrEnvironment = AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName( - AA->getEnvironment()->getName()) + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) : ""; bool UseEnvironment = (!AttrEnvironment.empty() && !TargetEnvironment.empty()); @@ -438,6 +441,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, << S.Context.getTargetInfo().getPlatformMinVersion().getAsString() << UseEnvironment << AttrEnvironment << TargetEnvironment; + // Do not offer to silence the warning or fixits for HLSL + if (S.getLangOpts().HLSL) + return; + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { if (const auto *TD = dyn_cast(Enclosing)) if (TD->getDeclName().isEmpty()) { @@ -839,10 +846,11 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( std::string PlatformName( AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName( - TI.getTriple().getEnvironmentName())); + TI.getTriple().getEnvironment())); llvm::StringRef AttrEnvironment = AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName( - AA->getEnvironment()->getName()) + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) : ""; bool UseEnvironment = (!AttrEnvironment.empty() && !TargetEnvironment.empty()); @@ -865,6 +873,10 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() << UseEnvironment << AttrEnvironment << TargetEnvironment; + // Do not offer to silence the warning or fixits for HLSL + if (SemaRef.getLangOpts().HLSL) + return; + auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) << Range << D diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 6a12c417e2f3..9e614ae99f37 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -9,6 +9,9 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaHLSL.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetInfo.h" @@ -16,6 +19,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TargetParser/Triple.h" #include @@ -290,3 +294,296 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) << (AllowedStages.size() != 1) << join(StageStrings, ", "); } + +namespace { + +/// This class implements HLSL availability diagnostics for default +/// and relaxed mode +/// +/// The goal of this diagnostic is to emit an error or warning when an +/// unavailable API is found in code that is reachable from the shader +/// entry function or from an exported function (when compiling a shader +/// library). +/// +/// This is done by traversing the AST of all shader entry point functions +/// and of all exported functions, and any functions that are refrenced +/// from this AST. In other words, any functions that are reachable from +/// the entry points. +class DiagnoseHLSLAvailability + : public RecursiveASTVisitor { + + Sema &SemaRef; + + // Stack of functions to be scaned + llvm::SmallVector DeclsToScan; + + // Tracks which environments functions have been scanned in. + // + // Maps FunctionDecl to an unsigned number that represents the set of shader + // environments the function has been scanned for. + // Since HLSLShaderAttr::ShaderType enum is generated from Attr.td and is + // defined without any assigned values, it is guaranteed to be numbered + // sequentially from 0 up and we can use it to 'index' individual bits + // in the set. + // The N'th bit in the set will be set if the function has been scanned + // in shader environment whose ShaderType integer value equals N. + // For example, if a function has been scanned in compute and pixel stage + // environment, the value will be 0x21 (100001 binary) because + // (int)HLSLShaderAttr::ShaderType::Pixel == 1 and + // (int)HLSLShaderAttr::ShaderType::Compute == 5. + // A FunctionDecl is mapped to 0 (or not included in the map) if it has not + // been scanned in any environment. + llvm::DenseMap ScannedDecls; + + // Do not access these directly, use the get/set methods below to make + // sure the values are in sync + llvm::Triple::EnvironmentType CurrentShaderEnvironment; + unsigned CurrentShaderStageBit; + + // True if scanning a function that was already scanned in a different + // shader stage context, and therefore we should not report issues that + // depend only on shader model version because they would be duplicate. + bool ReportOnlyShaderStageIssues; + + // Helper methods for dealing with current stage context / environment + void SetShaderStageContext(HLSLShaderAttr::ShaderType ShaderType) { + static_assert(sizeof(unsigned) >= 4); + assert((unsigned)ShaderType < 31); // 31 is reserved for "unknown" + + CurrentShaderEnvironment = HLSLShaderAttr::getTypeAsEnvironment(ShaderType); + CurrentShaderStageBit = (1 << ShaderType); + } + + void SetUnknownShaderStageContext() { + CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment; + CurrentShaderStageBit = (1 << 31); + } + + llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const { + return CurrentShaderEnvironment; + } + + bool InUnknownShaderStageContext() const { + return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment; + } + + // Helper methods for dealing with shader stage bitmap + void AddToScannedFunctions(const FunctionDecl *FD) { + unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD); + ScannedStages |= CurrentShaderStageBit; + } + + unsigned GetScannedStages(const FunctionDecl *FD) { + return ScannedDecls.getOrInsertDefault(FD); + } + + bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) { + return WasAlreadyScannedInCurrentStage(GetScannedStages(FD)); + } + + bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) { + return ScannerStages & CurrentShaderStageBit; + } + + static bool NeverBeenScanned(unsigned ScannedStages) { + return ScannedStages == 0; + } + + // Scanning methods + void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr); + void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA, + SourceRange Range); + const AvailabilityAttr *FindAvailabilityAttr(const Decl *D); + bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA); + +public: + DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {} + + // AST traversal methods + void RunOnTranslationUnit(const TranslationUnitDecl *TU); + void RunOnFunction(const FunctionDecl *FD); + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + FunctionDecl *FD = llvm::dyn_cast(DRE->getDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, DRE); + return true; + } + + bool VisitMemberExpr(MemberExpr *ME) { + FunctionDecl *FD = llvm::dyn_cast(ME->getMemberDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, ME); + return true; + } +}; + +void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD, + Expr *RefExpr) { + assert((isa(RefExpr) || isa(RefExpr)) && + "expected DeclRefExpr or MemberExpr"); + + // has a definition -> add to stack to be scanned + const FunctionDecl *FDWithBody = nullptr; + if (FD->hasBody(FDWithBody)) { + if (!WasAlreadyScannedInCurrentStage(FDWithBody)) + DeclsToScan.push_back(FDWithBody); + return; + } + + // no body -> diagnose availability + const AvailabilityAttr *AA = FindAvailabilityAttr(FD); + if (AA) + CheckDeclAvailability( + FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc())); +} + +void DiagnoseHLSLAvailability::RunOnTranslationUnit( + const TranslationUnitDecl *TU) { + // Iterate over all shader entry functions and library exports, and for those + // that have a body (definiton), run diag scan on each, setting appropriate + // shader environment context based on whether it is a shader entry function + // or an exported function. + for (auto &D : TU->decls()) { + const FunctionDecl *FD = llvm::dyn_cast(D); + if (!FD || !FD->isThisDeclarationADefinition()) + continue; + + // shader entry point + auto ShaderAttr = FD->getAttr(); + if (ShaderAttr) { + SetShaderStageContext(ShaderAttr->getType()); + RunOnFunction(FD); + continue; + } + // exported library function with definition + // FIXME: tracking issue #92073 +#if 0 + if (FD->getFormalLinkage() == Linkage::External) { + SetUnknownShaderStageContext(); + RunOnFunction(FD); + } +#endif + } +} + +void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) { + assert(DeclsToScan.empty() && "DeclsToScan should be empty"); + DeclsToScan.push_back(FD); + + while (!DeclsToScan.empty()) { + // Take one decl from the stack and check it by traversing its AST. + // For any CallExpr found during the traversal add it's callee to the top of + // the stack to be processed next. Functions already processed are stored in + // ScannedDecls. + const FunctionDecl *FD = DeclsToScan.back(); + DeclsToScan.pop_back(); + + // Decl was already scanned + const unsigned ScannedStages = GetScannedStages(FD); + if (WasAlreadyScannedInCurrentStage(ScannedStages)) + continue; + + ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages); + + AddToScannedFunctions(FD); + TraverseStmt(FD->getBody()); + } +} + +bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone( + const AvailabilityAttr *AA) { + IdentifierInfo *IIEnvironment = AA->getEnvironment(); + if (!IIEnvironment) + return true; + + llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment(); + if (CurrentEnv == llvm::Triple::UnknownEnvironment) + return false; + + llvm::Triple::EnvironmentType AttrEnv = + AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); + + return CurrentEnv == AttrEnv; +} + +const AvailabilityAttr * +DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) { + AvailabilityAttr const *PartialMatch = nullptr; + // Check each AvailabilityAttr to find the one for this platform. + // For multiple attributes with the same platform try to find one for this + // environment. + for (const auto *A : D->attrs()) { + if (const auto *Avail = dyn_cast(A)) { + StringRef AttrPlatform = Avail->getPlatform()->getName(); + StringRef TargetPlatform = + SemaRef.getASTContext().getTargetInfo().getPlatformName(); + + // Match the platform name. + if (AttrPlatform == TargetPlatform) { + // Find the best matching attribute for this environment + if (HasMatchingEnvironmentOrNone(Avail)) + return Avail; + PartialMatch = Avail; + } + } + } + return PartialMatch; +} + +// Check availability against target shader model version and current shader +// stage and emit diagnostic +void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D, + const AvailabilityAttr *AA, + SourceRange Range) { + if (ReportOnlyShaderStageIssues && !AA->getEnvironment()) + return; + + bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA); + VersionTuple Introduced = AA->getIntroduced(); + VersionTuple TargetVersion = + SemaRef.Context.getTargetInfo().getPlatformMinVersion(); + + if (TargetVersion >= Introduced && EnvironmentMatches) + return; + + // Do not diagnose shade-stage-specific availability when the shader stage + // context is unknown + if (InUnknownShaderStageContext() && AA->getEnvironment() != nullptr) + return; + + // Emit diagnostic message + const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); + llvm::StringRef PlatformName( + AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); + + llvm::StringRef CurrentEnvStr = + AvailabilityAttr::getPrettyEnviromentName(GetCurrentShaderEnvironment()); + + llvm::StringRef AttrEnvStr = AA->getEnvironment() + ? AvailabilityAttr::getPrettyEnviromentName( + AvailabilityAttr::getEnvironmentType( + AA->getEnvironment()->getName())) + : ""; + bool UseEnvironment = !AttrEnvStr.empty(); + + if (EnvironmentMatches) { + SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability) + << Range << D << PlatformName << Introduced.getAsString() + << UseEnvironment << CurrentEnvStr; + } else { + SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable) + << Range << D; + } + + SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here) + << D << PlatformName << Introduced.getAsString() + << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() + << UseEnvironment << AttrEnvStr << CurrentEnvStr; +} + +} // namespace + +void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) { + DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU); +} diff --git a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl index 8fa696ea1164..2f488a8d7c35 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl @@ -38,33 +38,28 @@ unsigned f8(); [numthreads(4,1,1)] int main() { - // expected-warning@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} + // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f1_call {{enclose 'f1' in a __builtin_available check to silence this warning}} unsigned A = f1(); // #f1_call - // expected-warning@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} + // expected-error@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} // expected-note@#f2 {{'f2' has been marked as being introduced in Shader Model 5.1 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f2_call {{enclose 'f2' in a __builtin_available check to silence this warning}} unsigned B = f2(); // #f2_call unsigned C = f3(); - // expected-warning@#f4_call {{'f4' is only available on Shader Model 6.0 or newer}} + // expected-error@#f4_call {{'f4' is only available on Shader Model 6.0 or newer}} // expected-note@#f4 {{'f4' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f4_call {{enclose 'f4' in a __builtin_available check to silence this warning}} unsigned D = f4(); // #f4_call unsigned E = f5(); - // expected-warning@#f6_call {{'f6' is only available in compute shader environment on Shader Model 6.0 or newer}} - // expected-note@#f6 {{'f6' has been marked as being introduced in Shader Model 6.0 in compute shader environment here, but the deployment target is Shader Model 5.0}} - // expected-note@#f6_call {{enclose 'f6' in a __builtin_available check to silence this warning}} + // expected-error@#f6_call {{'f6' is only available in compute environment on Shader Model 6.0 or newer}} + // expected-note@#f6 {{'f6' has been marked as being introduced in Shader Model 6.0 in compute environment here, but the deployment target is Shader Model 5.0}} unsigned F = f6(); // #f6_call - // expected-warning@#f7_call {{'f7' is unavailable}} - // expected-note@#f7 {{'f7' has been marked as being introduced in Shader Model 6.0 in mesh shader environment here, but the deployment target is Shader Model 5.0 compute shader environment}} - // expected-note@#f7_call {{enclose 'f7' in a __builtin_available check to silence this warning}} + // expected-error@#f7_call {{'f7' is unavailable}} + // expected-note@#f7 {{'f7' has been marked as being introduced in Shader Model 6.0 in mesh environment here, but the deployment target is Shader Model 5.0 compute environment}} unsigned G = f7(); // #f7_call unsigned H = f8(); diff --git a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl index 40a7ddbb1de9..07da116d403c 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl @@ -38,35 +38,30 @@ unsigned f8(); // #f8 [numthreads(4,1,1)] int main() { - // expected-warning@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} + // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f1_call {{enclose 'f1' in a __builtin_available check to silence this warning}} unsigned A = f1(); // #f1_call - // expected-warning@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} + // expected-error@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} // expected-note@#f2 {{'f2' has been marked as being introduced in Shader Model 5.1 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f2_call {{enclose 'f2' in a __builtin_available check to silence this warning}} unsigned B = f2(); // #f2_call unsigned C = f3(); - // expected-warning@#f4_call {{'f4' is only available on Shader Model 6.0 or newer}} + // expected-error@#f4_call {{'f4' is only available on Shader Model 6.0 or newer}} // expected-note@#f4 {{'f4' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f4_call {{enclose 'f4' in a __builtin_available check to silence this warning}} unsigned D = f4(); // #f4_call unsigned E = f5(); // #f5_call unsigned F = f6(); // #f6_call - // expected-warning@#f7_call {{'f7' is only available in mesh shader environment on Shader Model 6.0 or newer}} - // expected-note@#f7 {{'f7' has been marked as being introduced in Shader Model 6.0 in mesh shader environment here, but the deployment target is Shader Model 5.0 mesh shader environment}} - // expected-note@#f7_call {{enclose 'f7' in a __builtin_available check to silence this warning}} + // expected-error@#f7_call {{'f7' is only available in mesh environment on Shader Model 6.0 or newer}} + // expected-note@#f7 {{'f7' has been marked as being introduced in Shader Model 6.0 in mesh environment here, but the deployment target is Shader Model 5.0 mesh environment}} unsigned G = f7(); // #f7_call - // expected-warning@#f8_call {{'f8' is only available in mesh shader environment on Shader Model 6.0 or newer}} - // expected-note@#f8 {{'f8' has been marked as being introduced in Shader Model 6.0 in mesh shader environment here, but the deployment target is Shader Model 5.0 mesh shader environment}} - // expected-note@#f8_call {{enclose 'f8' in a __builtin_available check to silence this warning}} + // expected-error@#f8_call {{'f8' is only available in mesh environment on Shader Model 6.0 or newer}} + // expected-note@#f8 {{'f8' has been marked as being introduced in Shader Model 6.0 in mesh environment here, but the deployment target is Shader Model 5.0 mesh environment}} unsigned H = f8(); // #f8_call return 0; diff --git a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl index 59d09a9cd276..7cd13e653ed5 100644 --- a/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl +++ b/clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl @@ -37,14 +37,12 @@ __attribute__((availability(shadermodel, introduced = 6.0, environment = mesh))) unsigned f8(); int main() { - // expected-warning@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} + // expected-error@#f1_call {{'f1' is only available on Shader Model 6.0 or newer}} // expected-note@#f1 {{'f1' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f1_call {{enclose 'f1' in a __builtin_available check to silence this warning}} unsigned A = f1(); // #f1_call - // expected-warning@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} + // expected-error@#f2_call {{'f2' is only available on Shader Model 5.1 or newer}} // expected-note@#f2 {{'f2' has been marked as being introduced in Shader Model 5.1 here, but the deployment target is Shader Model 5.0}} - // expected-note@#f2_call {{enclose 'f2' in a __builtin_available check to silence this warning}} unsigned B = f2(); // #f2_call unsigned C = f3(); diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl new file mode 100644 index 000000000000..764b9e843f7f --- /dev/null +++ b/clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute \ +// RUN: -fsyntax-only -verify %s + +__attribute__((availability(shadermodel, introduced = 6.5))) +float fx(float); // #fx + +__attribute__((availability(shadermodel, introduced = 6.6))) +half fx(half); // #fx_half + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = compute))) +float fy(float); // #fy + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh))) +float fz(float); // #fz + +float also_alive(float f) { + // expected-error@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #also_alive_fx_call + // expected-error@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #also_alive_fy_call + // expected-error@#also_alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #also_alive_fz_call + return 0; +} + +float alive(float f) { + // expected-error@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #alive_fx_call + // expected-error@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #alive_fy_call + // expected-error@#alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #alive_fz_call + + return also_alive(f); +} + +float also_dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return 0; +} + +float dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + + return also_dead(f); +} + +template +T aliveTemp(T f) { + // expected-error@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #aliveTemp_fx_call + // expected-error@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #aliveTemp_fy_call + // expected-error@#aliveTemp_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #aliveTemp_fz_call + return 0; +} + +template T aliveTemp2(T f) { + // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}} + // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}} + // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + return fx(f); // #aliveTemp2_fx_call +} + +half test(half x) { + return aliveTemp2(x); +} + +float test(float x) { + return aliveTemp2(x); +} + +class MyClass +{ + float F; + float makeF() { + // expected-error@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(F); // #MyClass_makeF_fx_call + // expected-error@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(F); // #MyClass_makeF_fy_call + // expected-error@#MyClass_makeF_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(F); // #MyClass_makeF_fz_call + return 0; + } +}; + +[numthreads(4,1,1)] +float main() { + float f = 3; + MyClass C = { 1.0f }; + float a = alive(f); + float b = aliveTemp(f); // #aliveTemp_inst + float c = C.makeF(); + float d = test((float)1.0); + float e = test((half)1.0); + return a * b * c; +} diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl new file mode 100644 index 000000000000..515e4c5f9df0 --- /dev/null +++ b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library \ +// RUN: -fsyntax-only -verify %s + +__attribute__((availability(shadermodel, introduced = 6.5))) +float fx(float); // #fx + +__attribute__((availability(shadermodel, introduced = 6.6))) +half fx(half); // #fx_half + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = compute))) +float fy(float); // #fy + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh))) +float fz(float); // #fz + +float also_alive(float f) { + // expected-error@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #also_alive_fx_call + + // expected-error@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #also_alive_fy_call + + // expected-error@#also_alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #also_alive_fz_call + + return 0; +} + +float alive(float f) { + // expected-error@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #alive_fx_call + + // expected-error@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #alive_fy_call + + // expected-error@#alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #alive_fz_call + + return also_alive(f); +} + +float also_dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return 0; +} + +float dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return also_dead(f); +} + +template +T aliveTemp(T f) { + // expected-error@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #aliveTemp_fx_call + // expected-error@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #aliveTemp_fy_call + // expected-error@#aliveTemp_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #aliveTemp_fz_call + return 0; +} + +template T aliveTemp2(T f) { + // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}} + // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}} + // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + return fx(f); // #aliveTemp2_fx_call +} + +half test(half x) { + return aliveTemp2(x); +} + +float test(float x) { + return aliveTemp2(x); +} + +class MyClass +{ + float F; + float makeF() { + // expected-error@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(F); // #MyClass_makeF_fx_call + // expected-error@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(F); // #MyClass_makeF_fy_call + // expected-error@#MyClass_makeF_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(F); // #MyClass_makeF_fz_call + return 0; + } +}; + +// Shader entry point without body +[shader("compute")] +[numthreads(4,1,1)] +float main(); + +// Shader entry point with body +[shader("compute")] +[numthreads(4,1,1)] +float main() { + float f = 3; + MyClass C = { 1.0f }; + float a = alive(f); + float b = aliveTemp(f); // #aliveTemp_inst + float c = C.makeF(); + float d = test((float)1.0); + float e = test((half)1.0); + return a * b * c; +} diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl new file mode 100644 index 000000000000..65836c55821d --- /dev/null +++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute \ +// RUN: -fsyntax-only -Wno-error=hlsl-availability -verify %s + +__attribute__((availability(shadermodel, introduced = 6.5))) +float fx(float); // #fx + +__attribute__((availability(shadermodel, introduced = 6.6))) +half fx(half); // #fx_half + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = compute))) +float fy(float); // #fy + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh))) +float fz(float); // #fz + +float also_alive(float f) { + // expected-warning@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #also_alive_fx_call + // expected-warning@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #also_alive_fy_call + // expected-warning@#also_alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #also_alive_fz_call + return 0; +} + +float alive(float f) { + // expected-warning@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #alive_fx_call + // expected-warning@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #alive_fy_call + // expected-warning@#alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #alive_fz_call + + return also_alive(f); +} + +float also_dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return 0; +} + +float dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + + return also_dead(f); +} + +template +T aliveTemp(T f) { + // expected-warning@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #aliveTemp_fx_call + // expected-warning@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #aliveTemp_fy_call + // expected-warning@#aliveTemp_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #aliveTemp_fz_call + return 0; +} + +template T aliveTemp2(T f) { + // expected-warning@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}} + // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}} + // expected-warning@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + return fx(f); // #aliveTemp2_fx_call +} + +half test(half x) { + return aliveTemp2(x); +} + +float test(float x) { + return aliveTemp2(x); +} + +class MyClass +{ + float F; + float makeF() { + // expected-warning@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(F); // #MyClass_makeF_fx_call + // expected-warning@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(F); // #MyClass_makeF_fy_call + // expected-warning@#MyClass_makeF_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(F); // #MyClass_makeF_fz_call + return 0; + } +}; + +[numthreads(4,1,1)] +float main() { + float f = 3; + MyClass C = { 1.0f }; + float a = alive(f); + float b = aliveTemp(f); // #aliveTemp_inst + float c = C.makeF(); + float d = test((float)1.0); + float e = test((half)1.0); + return a * b * c; +} diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl new file mode 100644 index 000000000000..6bd20450f8bf --- /dev/null +++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library \ +// RUN: -fsyntax-only -Wno-error=hlsl-availability -verify %s + +__attribute__((availability(shadermodel, introduced = 6.5))) +float fx(float); // #fx + +__attribute__((availability(shadermodel, introduced = 6.6))) +half fx(half); // #fx_half + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = compute))) +float fy(float); // #fy + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh))) +float fz(float); // #fz + +float also_alive(float f) { + // expected-warning@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #also_alive_fx_call + + // expected-warning@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #also_alive_fy_call + + // expected-warning@#also_alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #also_alive_fz_call + + return 0; +} + +float alive(float f) { + // expected-warning@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #alive_fx_call + + // expected-warning@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #alive_fy_call + + // expected-warning@#alive_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #alive_fz_call + + return also_alive(f); +} + +float also_dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return 0; +} + +float dead(float f) { + // unreachable code - no errors expected + float A = fx(f); + float B = fy(f); + float C = fz(f); + return also_dead(f); +} + +template +T aliveTemp(T f) { + // expected-warning@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #aliveTemp_fx_call + // expected-warning@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #aliveTemp_fy_call + // expected-warning@#aliveTemp_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(f); // #aliveTemp_fz_call + return 0; +} + +template T aliveTemp2(T f) { + // expected-warning@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}} + // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}} + // expected-warning@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + return fx(f); // #aliveTemp2_fx_call +} + +half test(half x) { + return aliveTemp2(x); +} + +float test(float x) { + return aliveTemp2(x); +} + +class MyClass +{ + float F; + float makeF() { + // expected-warning@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(F); // #MyClass_makeF_fx_call + // expected-warning@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(F); // #MyClass_makeF_fy_call + // expected-warning@#MyClass_makeF_fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}} + float C = fz(F); // #MyClass_makeF_fz_call + return 0; + } +}; + +// Shader entry point without body +[shader("compute")] +[numthreads(4,1,1)] +float main(); + +// Shader entry point with body +[shader("compute")] +[numthreads(4,1,1)] +float main() { + float f = 3; + MyClass C = { 1.0f }; + float a = alive(f); + float b = aliveTemp(f); // #aliveTemp_inst + float c = C.makeF(); + float d = test((float)1.0); + float e = test((half)1.0); + return a * b * c; +} diff --git a/clang/test/SemaHLSL/Availability/avail-lib-multiple-stages.hlsl b/clang/test/SemaHLSL/Availability/avail-lib-multiple-stages.hlsl new file mode 100644 index 000000000000..b56ab8fe4526 --- /dev/null +++ b/clang/test/SemaHLSL/Availability/avail-lib-multiple-stages.hlsl @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library \ +// RUN: -fsyntax-only -verify %s + +__attribute__((availability(shadermodel, introduced = 6.5))) +float fx(float); // #fx + +__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel))) +__attribute__((availability(shadermodel, introduced = 6.5, environment = compute))) +float fy(float); // #fy + +__attribute__((availability(shadermodel, introduced = 5.0, environment = compute))) +float fz(float); // #fz + + +void F(float f) { + // Make sure we only get this error once, even though this function is scanned twice - once + // in compute shader context and once in pixel shader context. + // expected-error@#fx_call {{'fx' is only available on Shader Model 6.5 or newer}} + // expected-note@#fx {{fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}} + float A = fx(f); // #fx_call + + // expected-error@#fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}} + // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}} + float B = fy(f); // #fy_call + + // expected-error@#fz_call {{'fz' is unavailable}} + // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 5.0 in compute environment here, but the deployment target is Shader Model 6.0 pixel environment}} + float X = fz(f); // #fz_call +} + +void deadCode(float f) { + // no diagnostics expected under default diagnostic mode + float A = fx(f); + float B = fy(f); + float X = fz(f); +} + +// Pixel shader +[shader("pixel")] +void mainPixel() { + F(1.0); +} + +// First Compute shader +[shader("compute")] +[numthreads(4,1,1)] +void mainCompute1() { + F(2.0); +} + +// Second compute shader to make sure we do not get duplicate messages if F is called +// from multiple entry points. +[shader("compute")] +[numthreads(4,1,1)] +void mainCompute2() { + F(3.0); +} diff --git a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl index 185b79be37be..6333c6356932 100644 --- a/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl +++ b/clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl @@ -1,9 +1,10 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel5.0-library -verify %s // WaveActiveCountBits is unavailable before ShaderModel 6.0. -unsigned foo(bool b) { - // expected-warning@#site {{'WaveActiveCountBits' is only available on Shader Model 6.0 or newer}} +[shader("compute")] +[numthreads(8,8,1)] +unsigned foo() { + // expected-error@#site {{'WaveActiveCountBits' is only available on Shader Model 6.0 or newer}} // expected-note@hlsl/hlsl_intrinsics.h:* {{'WaveActiveCountBits' has been marked as being introduced in Shader Model 6.0 here, but the deployment target is Shader Model 5.0}} - // expected-note@#site {{enclose 'WaveActiveCountBits' in a __builtin_available check to silence this warning}} - return hlsl::WaveActiveCountBits(b); // #site + return hlsl::WaveActiveCountBits(1); // #site } -- GitLab From 7d4a45d98275e669bda40410f064891beb3480ce Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 29 May 2024 21:55:39 -0700 Subject: [PATCH 008/243] Revert "Add option to generate additional debug info for expression dereferencing pointer to pointers. (#81545)" This reverts commit aeccfee348c717165541d8d895b9b0cdfe31415c, and dependents: Revert "[NFC] Fix PPC buildbot failure https://lab.llvm.org/buildbot/#/builders/230/builds/29066" This reverts commit 2b1d1c51f6e321267cc86e9db7808298c59caf0e. Revert "Fix test - remove unnecessary/incorrect `-S`, in favor of `-emit-llvm`" This reverts commit ea1ecb50fa831583241fc531153bd2c072955d29. The test is failing on MacOs and Windows --- clang/lib/CodeGen/CGDebugInfo.cpp | 84 ------------ clang/lib/CodeGen/CGDebugInfo.h | 6 - clang/lib/CodeGen/CGExprScalar.cpp | 21 +-- .../test/CodeGenCXX/debug-info-ptr-to-ptr.cpp | 120 ------------------ 4 files changed, 1 insertion(+), 230 deletions(-) delete mode 100644 clang/test/CodeGenCXX/debug-info-ptr-to-ptr.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 9d7107abf8a6..fac278f0e20a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -5737,90 +5737,6 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, Var->addDebugInfo(GVE); } -void CGDebugInfo::EmitPseudoVariable(CGBuilderTy &Builder, - llvm::Instruction *Value, QualType Ty) { - // Only when -g2 or above is specified, debug info for variables will be - // generated. - if (CGM.getCodeGenOpts().getDebugInfo() <= - llvm::codegenoptions::DebugLineTablesOnly) - return; - - llvm::DebugLoc SaveDebugLoc = Builder.getCurrentDebugLocation(); - if (!SaveDebugLoc.get()) - return; - - llvm::DIFile *Unit = SaveDebugLoc->getFile(); - llvm::DIType *Type = getOrCreateType(Ty, Unit); - - // Check if Value is already a declared variable and has debug info, in this - // case we have nothing to do. Clang emits declared variable as alloca, and - // it is loaded upon use, so we identify such pattern here. - if (llvm::LoadInst *Load = dyn_cast(Value)) { - llvm::Value *Var = Load->getPointerOperand(); - if (llvm::Metadata *MDValue = llvm::ValueAsMetadata::getIfExists(Var)) { - if (llvm::Value *DbgValue = llvm::MetadataAsValue::getIfExists( - CGM.getLLVMContext(), MDValue)) { - for (llvm::User *U : DbgValue->users()) { - if (llvm::CallInst *DbgDeclare = dyn_cast(U)) { - if (DbgDeclare->getCalledFunction()->getIntrinsicID() == - llvm::Intrinsic::dbg_declare && - DbgDeclare->getArgOperand(0) == DbgValue) { - // There can be implicit type cast applied on a variable if it is - // an opaque ptr, in this case its debug info may not match the - // actual type of object being used as in the next instruction, so - // we will need to emit a pseudo variable for type-casted value. - llvm::DILocalVariable *MDNode = cast( - cast(DbgDeclare->getOperand(1)) - ->getMetadata()); - if (MDNode->getType() == Type) - return; - } - } - } - } - } - } - - // Find the correct location to insert a sequence of instructions to - // materialize Value on the stack. - auto SaveInsertionPoint = Builder.saveIP(); - if (llvm::InvokeInst *Invoke = dyn_cast(Value)) - Builder.SetInsertPoint(Invoke->getNormalDest()->begin()); - else if (llvm::Instruction *Next = Value->getIterator()->getNextNode()) - Builder.SetInsertPoint(Next); - else - Builder.SetInsertPoint(Value->getParent()); - llvm::DebugLoc DL = Value->getDebugLoc(); - if (DL.get()) - Builder.SetCurrentDebugLocation(DL); - else if (!Builder.getCurrentDebugLocation().get()) - Builder.SetCurrentDebugLocation(SaveDebugLoc); - - llvm::AllocaInst *PseudoVar = Builder.CreateAlloca(Value->getType()); - Address PseudoVarAddr(PseudoVar, Value->getType(), - CharUnits::fromQuantity(PseudoVar->getAlign())); - llvm::LoadInst *Load = Builder.CreateLoad(PseudoVarAddr); - Value->replaceAllUsesWith(Load); - Builder.SetInsertPoint(Load); - Builder.CreateStore(Value, PseudoVarAddr); - - // Emit debug info for materialized Value. - unsigned Line = Builder.getCurrentDebugLocation().getLine(); - unsigned Column = Builder.getCurrentDebugLocation().getCol(); - llvm::DILocalVariable *D = DBuilder.createAutoVariable( - LexicalBlockStack.back(), "", nullptr, 0, Type, false, - llvm::DINode::FlagArtificial); - llvm::DILocation *DIL = - llvm::DILocation::get(CGM.getLLVMContext(), Line, Column, - LexicalBlockStack.back(), CurInlinedAt); - SmallVector Expr; - DBuilder.insertDeclare(PseudoVar, D, DBuilder.createExpression(Expr), DIL, - Load); - - Builder.restoreIP(SaveInsertionPoint); - Builder.SetCurrentDebugLocation(SaveDebugLoc); -} - void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl GD) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 614316f3fc7f..d6db4d711366 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -529,12 +529,6 @@ public: /// Emit information about an external variable. void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); - /// Emit a pseudo variable and debug info for an intermediate value if it does - /// not correspond to a variable in the source code, so that a profiler can - /// track more accurate usage of certain instructions of interest. - void EmitPseudoVariable(CGBuilderTy &Builder, llvm::Instruction *Value, - QualType Ty); - /// Emit information about global variable alias. void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 58f0a3113b4f..1b144c178ce9 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1937,26 +1937,7 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { } } - llvm::Value *Result = EmitLoadOfLValue(E); - - // If -fdebug-info-for-profiling is specified, emit a pseudo variable and its - // debug info for the pointer, even if there is no variable associated with - // the pointer's expression. - if (CGF.CGM.getCodeGenOpts().DebugInfoForProfiling && CGF.getDebugInfo()) { - if (llvm::LoadInst *Load = dyn_cast(Result)) { - if (llvm::GetElementPtrInst *GEP = - dyn_cast(Load->getPointerOperand())) { - if (llvm::Instruction *Pointer = - dyn_cast(GEP->getPointerOperand())) { - QualType Ty = E->getBase()->getType(); - if (!E->isArrow()) - Ty = CGF.getContext().getPointerType(Ty); - CGF.getDebugInfo()->EmitPseudoVariable(Builder, Pointer, Ty); - } - } - } - } - return Result; + return EmitLoadOfLValue(E); } Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { diff --git a/clang/test/CodeGenCXX/debug-info-ptr-to-ptr.cpp b/clang/test/CodeGenCXX/debug-info-ptr-to-ptr.cpp deleted file mode 100644 index 9f2a3f9e6919..000000000000 --- a/clang/test/CodeGenCXX/debug-info-ptr-to-ptr.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Test debug info for intermediate value of a chained pointer deferencing -// expression when the flag -fdebug-info-for-pointer-type is enabled. -// RUN: %clang_cc1 %s -fdebug-info-for-profiling -debug-info-kind=constructor -emit-llvm -o - | FileCheck %s - -class A { -public: - int i; - char c; - void *p; - int arr[3]; -}; - -class B { -public: - A* a; -}; - -class C { -public: - B* b; - A* a; - A arr[10]; -}; - -// CHECK-LABEL: define dso_local noundef{{.*}}i32 @{{.*}}func1{{.*}}( -// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds %class.B, ptr {{%.*}}, i32 0, i32 0, !dbg [[DBG1:![0-9]+]] -// CHECK-NEXT: [[A:%.*]] = load ptr, ptr [[A_ADDR]], align {{.*}}, !dbg [[DBG1]] -// CHECK-NEXT: [[PSEUDO1:%.*]] = alloca ptr, align {{.*}}, !dbg [[DBG1]] -// CHECK-NEXT: store ptr [[A]], ptr [[PSEUDO1]], align {{.*}}, !dbg [[DBG1]] -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[PSEUDO1]], metadata [[META1:![0-9]+]], metadata !DIExpression()), !dbg [[DBG1]] -// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PSEUDO1]], align {{.*}}, !dbg [[DBG1]] -// CHECK-NEXT: {{%.*}} = getelementptr inbounds %class.A, ptr [[TMP1]], i32 0, i32 0, -int func1(B *b) { - return b->a->i; -} - -// Should generate a pseudo variable when pointer is type-casted. -// CHECK-LABEL: define dso_local noundef ptr @{{.*}}func2{{.*}}( -// CHECK: call void @llvm.dbg.declare(metadata ptr [[B_ADDR:%.*]], metadata [[META2:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: [[B:%.*]] = load ptr, ptr [[B_ADDR]], -// CHECK-NEXT: [[PSEUDO1:%.*]] = alloca ptr, -// CHECK-NEXT: store ptr [[B]], ptr [[PSEUDO1]], -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[PSEUDO1]], metadata [[META3:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PSEUDO1]], -// CHECK-NEXT: {{%.*}} = getelementptr inbounds %class.B, ptr [[TMP1]], i32 0, -A* func2(void *b) { - return ((B*)b)->a; -} - -// Should not generate pseudo variable in this case. -// CHECK-LABEL: define dso_local noundef{{.*}}i32 @{{.*}}func3{{.*}}( -// CHECK: call void @llvm.dbg.declare(metadata ptr [[B_ADDR:%.*]], metadata [[META4:![0-9]+]], metadata !DIExpression()) -// CHECK: call void @llvm.dbg.declare(metadata ptr [[LOCAL1:%.*]], metadata [[META5:![0-9]+]], metadata !DIExpression()) -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr -int func3(B *b) { - A *local1 = b->a; - return local1->i; -} - -// CHECK-LABEL: define dso_local noundef signext i8 @{{.*}}func4{{.*}}( -// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds %class.C, ptr {{%.*}}, i32 0, i32 1 -// CHECK-NEXT: [[A:%.*]] = load ptr, ptr [[A_ADDR]], -// CHECK-NEXT: [[PSEUDO1:%.*]] = alloca ptr, -// CHECK-NEXT: store ptr [[A]], ptr [[PSEUDO1]], -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[PSEUDO1]], metadata [[META6:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PSEUDO1]], -// CHECK-NEXT: {{%.*}} = getelementptr inbounds %class.A, ptr [[TMP1]], i32 0, i32 0, -// CHECK: [[CALL:%.*]] = call noundef ptr @{{.*}}foo{{.*}}( -// CHECK-NEXT: [[PSEUDO2:%.*]] = alloca ptr, -// CHECK-NEXT: store ptr [[CALL]], ptr [[PSEUDO2]] -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[PSEUDO2]], metadata [[META6]], metadata !DIExpression()) -// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PSEUDO2]] -// CHECK-NEXT: [[I1:%.*]] = getelementptr inbounds %class.A, ptr [[TMP2]], i32 0, i32 1 -char func4(C *c) { - extern A* foo(int x); - return foo(c->a->i)->c; -} - -// CHECK-LABEL: define dso_local noundef signext i8 @{{.*}}func5{{.*}}( -// CHECK: call void @llvm.dbg.declare(metadata ptr {{%.*}}, metadata [[META7:![0-9]+]], metadata !DIExpression()) -// CHECK: call void @llvm.dbg.declare(metadata ptr {{%.*}}, metadata [[META8:![0-9]+]], metadata !DIExpression()) -// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds %class.A, ptr {{%.*}}, i64 {{%.*}}, -// CHECK-NEXT: [[PSEUDO1:%.*]] = alloca ptr, -// CHECK-NEXT: store ptr [[A_ADDR]], ptr [[PSEUDO1]], -// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[PSEUDO1]], metadata [[META9:![0-9]+]], metadata !DIExpression()) -// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PSEUDO1]], -// CHECK-NEXT: {{%.*}} = getelementptr inbounds %class.A, ptr [[TMP1]], i32 0, i32 1, -char func5(void *arr, int n) { - return ((A*)arr)[n].c; -} - -// CHECK-LABEL: define dso_local noundef{{.*}}i32 @{{.*}}func6{{.*}}( -// CHECK: call void @llvm.dbg.declare(metadata ptr {{%.*}}, metadata [[META10:![0-9]+]], metadata !DIExpression()) -// CHECK: call void @llvm.dbg.declare(metadata ptr {{%.*}}, metadata [[META11:![0-9]+]], metadata !DIExpression()) -int func6(B &b) { - return reinterpret_cast(b).i; -} - -// CHECK-DAG: [[META_A:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", -// CHECK-DAG: [[META_AP:![0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META_A]], -// CHECK-DAG: [[META_B:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "B", -// CHECK-DAG: [[META_BP:![0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META_B]], -// CHECK-DAG: [[META_C:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", -// CHECK-DAG: [[META_CP:![0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META_C]], -// CHECK-DAG: [[META_VP:![0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, -// CHECK-DAG: [[META_I32:![0-9]+]] = !DIBasicType(name: "int", size: 32, -// CHECK-DAG: [[META_BR:![0-9]+]] = !DIDerivedType(tag: DW_TAG_reference_type, baseType: [[META_B]], - -// CHECK-DAG: [[DBG1]] = !DILocation(line: 34, column: 13, -// CHECK-DAG: [[META1]] = !DILocalVariable(scope: {{.*}}, type: [[META_AP]], flags: DIFlagArtificial) -// CHECK-DAG: [[META2]] = !DILocalVariable(name: "b", arg: 1, scope: {{.*}}, file: {{.*}}, line: 46, type: [[META_VP]]) -// CHECK-DAG: [[META3]] = !DILocalVariable(scope: {{.*}}, type: [[META_BP]], flags: DIFlagArtificial) -// CHECK-DAG: [[META4]] = !DILocalVariable(name: "b", arg: 1, scope: {{.*}}, file: {{.*}}, line: 55, type: [[META_BP]]) -// CHECK-DAG: [[META5]] = !DILocalVariable(name: "local1", scope: {{.*}}, file: {{.*}}, line: 56, type: [[META_AP]]) -// CHECK-DAG: [[META6]] = !DILocalVariable(scope: {{.*}}, type: [[META_AP]], flags: DIFlagArtificial) -// CHECK-DAG: [[META7]] = !DILocalVariable(name: "arr", arg: 1, scope: {{.*}}, file: {{.*}}, line: 88, type: [[META_VP]]) -// CHECK-DAG: [[META8]] = !DILocalVariable(name: "n", arg: 2, scope: {{.*}}, file: {{.*}}, line: 88, type: [[META_I32]]) -// CHECK-DAG: [[META9]] = !DILocalVariable(scope: {{.*}}, type: [[META_AP]], flags: DIFlagArtificial) -// CHECK-DAG: [[META10]] = !DILocalVariable(name: "b", arg: 1, scope: {{.*}}, file: {{.*}}, line: 95, type: [[META_BR]]) -// CHECK-DAG: [[META11]] = !DILocalVariable(scope: {{.*}}, type: [[META_AP]], flags: DIFlagArtificial) -- GitLab From 89801c74c3e25f5a1eaa3999863be398f6a82abb Mon Sep 17 00:00:00 2001 From: Bimo Date: Thu, 30 May 2024 13:01:40 +0800 Subject: [PATCH 009/243] [MLIR][Python] add ctype python binding support for bf16 (#92489) Since bf16 is supported by mlir, similar to complex128/complex64/float16, we need an implementation of bf16 ctype in Python binding. Furthermore, to resolve the absence of bf16 support in NumPy, a third-party package [ml_dtypes ](https://github.com/jax-ml/ml_dtypes) is introduced to add bf16 extension, and the same approach was used in `torch-mlir` project. See motivation and discussion in: https://discourse.llvm.org/t/how-to-run-executionengine-with-bf16-dtype-in-mlir-python-bindings/79025 --- mlir/python/mlir/runtime/np_to_memref.py | 19 +++++++++++ mlir/python/requirements.txt | 3 +- mlir/test/python/execution_engine.py | 40 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mlir/python/mlir/runtime/np_to_memref.py b/mlir/python/mlir/runtime/np_to_memref.py index f6b706f9bc8a..882b2751921b 100644 --- a/mlir/python/mlir/runtime/np_to_memref.py +++ b/mlir/python/mlir/runtime/np_to_memref.py @@ -7,6 +7,12 @@ import numpy as np import ctypes +try: + import ml_dtypes +except ModuleNotFoundError: + # The third-party ml_dtypes provides some optional low precision data-types for NumPy. + ml_dtypes = None + class C128(ctypes.Structure): """A ctype representation for MLIR's Double Complex.""" @@ -26,6 +32,12 @@ class F16(ctypes.Structure): _fields_ = [("f16", ctypes.c_int16)] +class BF16(ctypes.Structure): + """A ctype representation for MLIR's BFloat16.""" + + _fields_ = [("bf16", ctypes.c_int16)] + + # https://stackoverflow.com/questions/26921836/correct-way-to-test-for-numpy-dtype def as_ctype(dtp): """Converts dtype to ctype.""" @@ -35,6 +47,8 @@ def as_ctype(dtp): return C64 if dtp == np.dtype(np.float16): return F16 + if ml_dtypes is not None and dtp == ml_dtypes.bfloat16: + return BF16 return np.ctypeslib.as_ctypes_type(dtp) @@ -46,6 +60,11 @@ def to_numpy(array): return array.view("complex64") if array.dtype == F16: return array.view("float16") + assert not ( + array.dtype == BF16 and ml_dtypes is None + ), f"bfloat16 requires the ml_dtypes package, please run:\n\npip install ml_dtypes\n" + if array.dtype == BF16: + return array.view("bfloat16") return array diff --git a/mlir/python/requirements.txt b/mlir/python/requirements.txt index acd6dbb25eda..6ec63e43adf8 100644 --- a/mlir/python/requirements.txt +++ b/mlir/python/requirements.txt @@ -1,3 +1,4 @@ numpy>=1.19.5, <=1.26 pybind11>=2.9.0, <=2.10.3 -PyYAML>=5.3.1, <=6.0.1 \ No newline at end of file +PyYAML>=5.3.1, <=6.0.1 +ml_dtypes # provides several NumPy dtype extensions, including the bf16 \ No newline at end of file diff --git a/mlir/test/python/execution_engine.py b/mlir/test/python/execution_engine.py index e8b47007a890..8125bf3fb8fc 100644 --- a/mlir/test/python/execution_engine.py +++ b/mlir/test/python/execution_engine.py @@ -5,6 +5,7 @@ from mlir.ir import * from mlir.passmanager import * from mlir.execution_engine import * from mlir.runtime import * +from ml_dtypes import bfloat16 # Log everything to stderr and flush so that we have a unified stream to match @@ -521,6 +522,45 @@ def testComplexUnrankedMemrefAdd(): run(testComplexUnrankedMemrefAdd) +# Test bf16 memrefs +# CHECK-LABEL: TEST: testBF16Memref +def testBF16Memref(): + with Context(): + module = Module.parse( + """ + module { + func.func @main(%arg0: memref<1xbf16>, + %arg1: memref<1xbf16>) attributes { llvm.emit_c_interface } { + %0 = arith.constant 0 : index + %1 = memref.load %arg0[%0] : memref<1xbf16> + memref.store %1, %arg1[%0] : memref<1xbf16> + return + } + } """ + ) + + arg1 = np.array([0.5]).astype(bfloat16) + arg2 = np.array([0.0]).astype(bfloat16) + + arg1_memref_ptr = ctypes.pointer( + ctypes.pointer(get_ranked_memref_descriptor(arg1)) + ) + arg2_memref_ptr = ctypes.pointer( + ctypes.pointer(get_ranked_memref_descriptor(arg2)) + ) + + execution_engine = ExecutionEngine(lowerToLLVM(module)) + execution_engine.invoke("main", arg1_memref_ptr, arg2_memref_ptr) + + # test to-numpy utility + # CHECK: [0.5] + npout = ranked_memref_to_numpy(arg2_memref_ptr[0]) + log(npout) + + +run(testBF16Memref) + + # Test addition of two 2d_memref # CHECK-LABEL: TEST: testDynamicMemrefAdd2D def testDynamicMemrefAdd2D(): -- GitLab From 49ef21d7674fa8267d674879e21b69d9ca4e6203 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 29 May 2024 22:02:02 -0700 Subject: [PATCH 010/243] Remove debug print from CI generation script (NFC) --- .ci/generate-buildkite-pipeline-premerge | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index bb7d2117e277..033ab804b165 100755 --- a/.ci/generate-buildkite-pipeline-premerge +++ b/.ci/generate-buildkite-pipeline-premerge @@ -56,7 +56,6 @@ function compute-projects-to-test() { isForWindows=$1 shift projects=${@} - echo "isForWindows : $isForWindows ; projects: $projects " >&2 for project in ${projects}; do echo "${project}" case ${project} in -- GitLab From e6821dd8c8cdd0279000f9a8eb57caf7977d68db Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Wed, 29 May 2024 23:21:04 -0600 Subject: [PATCH 011/243] Revert "[MLIR][Python] add ctype python binding support for bf16" (#93771) Reverts llvm/llvm-project#92489 This broke the bots. --- mlir/python/mlir/runtime/np_to_memref.py | 19 ----------- mlir/python/requirements.txt | 3 +- mlir/test/python/execution_engine.py | 40 ------------------------ 3 files changed, 1 insertion(+), 61 deletions(-) diff --git a/mlir/python/mlir/runtime/np_to_memref.py b/mlir/python/mlir/runtime/np_to_memref.py index 882b2751921b..f6b706f9bc8a 100644 --- a/mlir/python/mlir/runtime/np_to_memref.py +++ b/mlir/python/mlir/runtime/np_to_memref.py @@ -7,12 +7,6 @@ import numpy as np import ctypes -try: - import ml_dtypes -except ModuleNotFoundError: - # The third-party ml_dtypes provides some optional low precision data-types for NumPy. - ml_dtypes = None - class C128(ctypes.Structure): """A ctype representation for MLIR's Double Complex.""" @@ -32,12 +26,6 @@ class F16(ctypes.Structure): _fields_ = [("f16", ctypes.c_int16)] -class BF16(ctypes.Structure): - """A ctype representation for MLIR's BFloat16.""" - - _fields_ = [("bf16", ctypes.c_int16)] - - # https://stackoverflow.com/questions/26921836/correct-way-to-test-for-numpy-dtype def as_ctype(dtp): """Converts dtype to ctype.""" @@ -47,8 +35,6 @@ def as_ctype(dtp): return C64 if dtp == np.dtype(np.float16): return F16 - if ml_dtypes is not None and dtp == ml_dtypes.bfloat16: - return BF16 return np.ctypeslib.as_ctypes_type(dtp) @@ -60,11 +46,6 @@ def to_numpy(array): return array.view("complex64") if array.dtype == F16: return array.view("float16") - assert not ( - array.dtype == BF16 and ml_dtypes is None - ), f"bfloat16 requires the ml_dtypes package, please run:\n\npip install ml_dtypes\n" - if array.dtype == BF16: - return array.view("bfloat16") return array diff --git a/mlir/python/requirements.txt b/mlir/python/requirements.txt index 6ec63e43adf8..acd6dbb25eda 100644 --- a/mlir/python/requirements.txt +++ b/mlir/python/requirements.txt @@ -1,4 +1,3 @@ numpy>=1.19.5, <=1.26 pybind11>=2.9.0, <=2.10.3 -PyYAML>=5.3.1, <=6.0.1 -ml_dtypes # provides several NumPy dtype extensions, including the bf16 \ No newline at end of file +PyYAML>=5.3.1, <=6.0.1 \ No newline at end of file diff --git a/mlir/test/python/execution_engine.py b/mlir/test/python/execution_engine.py index 8125bf3fb8fc..e8b47007a890 100644 --- a/mlir/test/python/execution_engine.py +++ b/mlir/test/python/execution_engine.py @@ -5,7 +5,6 @@ from mlir.ir import * from mlir.passmanager import * from mlir.execution_engine import * from mlir.runtime import * -from ml_dtypes import bfloat16 # Log everything to stderr and flush so that we have a unified stream to match @@ -522,45 +521,6 @@ def testComplexUnrankedMemrefAdd(): run(testComplexUnrankedMemrefAdd) -# Test bf16 memrefs -# CHECK-LABEL: TEST: testBF16Memref -def testBF16Memref(): - with Context(): - module = Module.parse( - """ - module { - func.func @main(%arg0: memref<1xbf16>, - %arg1: memref<1xbf16>) attributes { llvm.emit_c_interface } { - %0 = arith.constant 0 : index - %1 = memref.load %arg0[%0] : memref<1xbf16> - memref.store %1, %arg1[%0] : memref<1xbf16> - return - } - } """ - ) - - arg1 = np.array([0.5]).astype(bfloat16) - arg2 = np.array([0.0]).astype(bfloat16) - - arg1_memref_ptr = ctypes.pointer( - ctypes.pointer(get_ranked_memref_descriptor(arg1)) - ) - arg2_memref_ptr = ctypes.pointer( - ctypes.pointer(get_ranked_memref_descriptor(arg2)) - ) - - execution_engine = ExecutionEngine(lowerToLLVM(module)) - execution_engine.invoke("main", arg1_memref_ptr, arg2_memref_ptr) - - # test to-numpy utility - # CHECK: [0.5] - npout = ranked_memref_to_numpy(arg2_memref_ptr[0]) - log(npout) - - -run(testBF16Memref) - - # Test addition of two 2d_memref # CHECK-LABEL: TEST: testDynamicMemrefAdd2D def testDynamicMemrefAdd2D(): -- GitLab From 3e023d87d8e9a7bcf0a2feb2cee9b9ca47643a7e Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 30 May 2024 07:48:59 +0200 Subject: [PATCH 012/243] [lldb] Remove DWARFDebugInfo DIERef footguns (#92894) DWARFDebugInfo doesn't know how to resolve the "file_index" component of a DIERef. This patch removes GetUnit (in favor of existing GetUnitContainingDIEOffset) and changes GetDIE to take only the components it actually uses. --- .../Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp | 11 +++-------- lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 3 +-- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 7 ++++--- .../Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index d28da728728e..c37cc91e08ed 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -222,10 +222,6 @@ DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, return result; } -DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { - return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset()); -} - DWARFUnit * DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset) { @@ -253,9 +249,8 @@ bool DWARFDebugInfo::ContainsTypeUnits() { // // Get the DIE (Debug Information Entry) with the specified offset. DWARFDIE -DWARFDebugInfo::GetDIE(const DIERef &die_ref) { - DWARFUnit *cu = GetUnit(die_ref); - if (cu) - return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); +DWARFDebugInfo::GetDIE(DIERef::Section section, dw_offset_t die_offset) { + if (DWARFUnit *cu = GetUnitContainingDIEOffset(section, die_offset)) + return cu->GetNonSkeletonUnit().GetDIE(die_offset); return DWARFDIE(); // Not found } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 456ebd908ccb..4706b55d38ea 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -38,11 +38,10 @@ public: uint32_t *idx_ptr = nullptr); DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset); - DWARFUnit *GetUnit(const DIERef &die_ref); DWARFUnit *GetSkeletonUnit(DWARFUnit *dwo_unit); DWARFTypeUnit *GetTypeUnitForHash(uint64_t hash); bool ContainsTypeUnits(); - DWARFDIE GetDIE(const DIERef &die_ref); + DWARFDIE GetDIE(DIERef::Section section, dw_offset_t die_offset); enum { eDumpFlag_Verbose = (1 << 0), // Verbose dumping diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index bc489e5b8ad4..661e4a78a021 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1761,7 +1761,8 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) { symbol_file = debug_map->GetSymbolFileByOSOIndex(*file_index); // OSO case if (symbol_file) - return symbol_file->DebugInfo().GetDIE(die_ref); + return symbol_file->DebugInfo().GetDIE(die_ref.section(), + die_ref.die_offset()); return DWARFDIE(); } @@ -1778,7 +1779,7 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { if (symbol_file) return symbol_file->GetDIE(die_ref); - return DebugInfo().GetDIE(die_ref); + return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset()); } /// Return the DW_AT_(GNU_)dwo_id. @@ -3786,7 +3787,7 @@ SymbolFileDWARF::FindBlockContainingSpecification( // Give the concrete function die specified by "func_die_offset", find the // concrete block whose DW_AT_specification or DW_AT_abstract_origin points // to "spec_block_die_offset" - return FindBlockContainingSpecification(DebugInfo().GetDIE(func_die_ref), + return FindBlockContainingSpecification(GetDIE(func_die_ref), spec_block_die_offset); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 8fd369c65f86..e4db39cabf6f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -145,7 +145,7 @@ SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { DWARFDIE SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) { if (die_ref.file_index() == GetFileIndex()) - return DebugInfo().GetDIE(die_ref); + return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset()); return GetBaseSymbolFile().GetDIE(die_ref); } -- GitLab From 498da62088b22ef1d4e90d6021a80ae7bab6abae Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Thu, 1 Feb 2024 02:07:16 -0300 Subject: [PATCH 013/243] [NFC] [clang] add tests for merging of UsingShadowDecl --- clang/test/Modules/cxx20-decls.cppm | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 clang/test/Modules/cxx20-decls.cppm diff --git a/clang/test/Modules/cxx20-decls.cppm b/clang/test/Modules/cxx20-decls.cppm new file mode 100644 index 000000000000..9f0c40685b68 --- /dev/null +++ b/clang/test/Modules/cxx20-decls.cppm @@ -0,0 +1,35 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 -I %t %t/A.cppm -emit-module-interface -o %t/A.pcm -verify +// RUN: %clang_cc1 -std=c++20 -I %t %t/B.cpp -fmodule-file=A=%t/A.pcm -fsyntax-only -verify -ast-dump-all -ast-dump-filter baz | FileCheck %s + +//--- foo.h +namespace baz { + using foo = char; + using baz::foo; +} + +//--- A.cppm +// expected-no-diagnostics +module; +#include "foo.h" +export module A; + +//--- B.cpp +// expected-no-diagnostics +#include "foo.h" +import A; +// Since modules are loaded lazily, force loading by performing a lookup. +using xxx = baz::foo; + +// CHECK-LABEL: Dumping baz: +// CHECK-NEXT: NamespaceDecl 0x[[BAZ_REDECL_ADDR:[^ ]*]] prev 0x[[BAZ_ADDR:[^ ]*]] +// CHECK: TypeAliasDecl 0x[[ALIAS_REDECL_ADDR:[^ ]*]] prev 0x[[ALIAS_ADDR:[^ ]*]] +// FIXME: UsingShadowDecl should have been merged +// CHECK: UsingShadowDecl 0x{{[^ ]*}} <{{.*}}> col:{{.*}} imported in A. hidden implicit TypeAlias 0x[[ALIAS_REDECL_ADDR]] 'foo' + +// CHECK-LABEL: Dumping baz: +// CHECK-NEXT: NamespaceDecl 0x[[BAZ_ADDR]] <{{.*}}> line:{{.*}} baz +// CHECK: UsingShadowDecl 0x[[SHADOW_ADDR:[^ ]*]] <{{.*}}> col:{{.*}} implicit TypeAlias 0x[[ALIAS_ADDR]] 'foo' -- GitLab From 6a3982f8b7e37987659706cb3e6427c54c9bc7ce Mon Sep 17 00:00:00 2001 From: Christian Ulmann Date: Thu, 30 May 2024 07:58:13 +0200 Subject: [PATCH 014/243] [MLIR][LLVM] Relax the LLVM dialect's inliner assuming UCF (#93514) This commit changes the LLVM dialect's inliner interface to stop assuming that the inlined function only contained unstructured control flow. This is not necessarily true, and it lead to not properly propagating the noalias information. --- mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp | 23 ++++---- .../Dialect/LLVMIR/inlining-alias-scopes.mlir | 59 +++++++++++++++---- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp index 4a6154ea6d30..5552dc5e244b 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp @@ -187,7 +187,7 @@ deepCloneAliasScopes(iterator_range inlinedBlocks) { }; for (Block &block : inlinedBlocks) { - for (Operation &op : block) { + block.walk([&](Operation *op) { if (auto aliasInterface = dyn_cast(op)) { aliasInterface.setAliasScopes( convertScopeList(aliasInterface.getAliasScopesOrNull())); @@ -202,7 +202,7 @@ deepCloneAliasScopes(iterator_range inlinedBlocks) { noAliasScope.setScopeAttr(cast( mapping.lookup(noAliasScope.getScopeAttr()))); } - } + }); } } @@ -357,9 +357,7 @@ static void createNewAliasScopesFromNoAliasParameter( // Go through every instruction and attempt to find which noalias parameters // it is definitely based on and definitely not based on. for (Block &inlinedBlock : inlinedBlocks) { - for (auto aliasInterface : - inlinedBlock.getOps()) { - + inlinedBlock.walk([&](LLVM::AliasAnalysisOpInterface aliasInterface) { // Collect the pointer arguments affected by the alias scopes. SmallVector pointerArgs = aliasInterface.getAccessedOperands(); @@ -395,7 +393,7 @@ static void createNewAliasScopesFromNoAliasParameter( } return true; })) - continue; + return; // Add all noalias parameter scopes to the noalias scope list that we are // not based on. @@ -438,7 +436,7 @@ static void createNewAliasScopesFromNoAliasParameter( // arguments. if (aliasesOtherKnownObject || isa(aliasInterface.getOperation())) - continue; + return; SmallVector aliasScopes; for (LLVM::SSACopyOp noAlias : noAliasParams) @@ -449,7 +447,7 @@ static void createNewAliasScopesFromNoAliasParameter( aliasInterface.setAliasScopes( concatArrayAttr(aliasInterface.getAliasScopesOrNull(), ArrayAttr::get(call->getContext(), aliasScopes))); - } + }); } } @@ -472,7 +470,7 @@ appendCallOpAliasScopes(Operation *call, // Simply append the call op's alias and noalias scopes to any operation // implementing AliasAnalysisOpInterface. for (Block &block : inlinedBlocks) { - for (auto aliasInterface : block.getOps()) { + block.walk([&](LLVM::AliasAnalysisOpInterface aliasInterface) { if (aliasScopes) aliasInterface.setAliasScopes(concatArrayAttr( aliasInterface.getAliasScopesOrNull(), aliasScopes)); @@ -480,7 +478,7 @@ appendCallOpAliasScopes(Operation *call, if (noAliasScopes) aliasInterface.setNoAliasScopes(concatArrayAttr( aliasInterface.getNoAliasScopesOrNull(), noAliasScopes)); - } + }); } } @@ -667,7 +665,7 @@ struct LLVMInlinerInterface : public DialectInlinerInterface { LLVM_DEBUG(llvm::dbgs() << "Cannot inline: callable is variadic\n"); return false; } - // TODO: Generate aliasing metadata from noalias argument/result attributes. + // TODO: Generate aliasing metadata from noalias result attributes. if (auto attrs = funcOp.getArgAttrs()) { for (DictionaryAttr attrDict : attrs->getAsRange()) { if (attrDict.contains(LLVM::LLVMDialect::getInAllocaAttrName())) { @@ -755,8 +753,7 @@ struct LLVMInlinerInterface : public DialectInlinerInterface { return handleByValArgument(builder, callable, argument, elementType, requestedAlignment); } - if ([[maybe_unused]] std::optional attr = - argumentAttrs.getNamed(LLVM::LLVMDialect::getNoAliasAttrName())) { + if (argumentAttrs.contains(LLVM::LLVMDialect::getNoAliasAttrName())) { if (argument.use_empty()) return argument; diff --git a/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir b/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir index 29450833bee5..0b8b60e963bb 100644 --- a/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir +++ b/mlir/test/Dialect/LLVMIR/inlining-alias-scopes.mlir @@ -24,12 +24,15 @@ llvm.func @foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr) { %0 = llvm.mlir.constant(5 : i64) : i64 llvm.intr.experimental.noalias.scope.decl #alias_scope %2 = llvm.load %arg1 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : !llvm.ptr -> f32 - %3 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32 - llvm.store %2, %3 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr + "test.one_region_op"() ({ + %3 = llvm.getelementptr inbounds %arg0[%0] : (!llvm.ptr, i64) -> !llvm.ptr, f32 + llvm.store %2, %3 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr + "test.terminator"() : () -> () + }) : () -> () llvm.return } -// CHECK-LABEL: llvm.func @bar +// CHECK-LABEL: llvm.func @clone_alias_scopes // CHECK: llvm.intr.experimental.noalias.scope.decl #[[$BAR_LOAD]] // CHECK: llvm.load // CHECK-SAME: alias_scopes = [#[[$BAR_LOAD]]] @@ -37,8 +40,8 @@ llvm.func @foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr) { // CHECK: llvm.store // CHECK-SAME: alias_scopes = [#[[$BAR_STORE]]] // CHECK-SAME: noalias_scopes = [#[[$BAR_LOAD]]] -llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) { - llvm.call @foo(%arg0, %arg2) : (!llvm.ptr, !llvm.ptr) -> () +llvm.func @clone_alias_scopes(%arg0: !llvm.ptr, %arg1: !llvm.ptr) { + llvm.call @foo(%arg0, %arg1) : (!llvm.ptr, !llvm.ptr) -> () llvm.return } @@ -87,9 +90,12 @@ llvm.func @callee_with_metadata(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm llvm.store %3, %4 {alias_scopes = [#alias_scope], alignment = 4 : i64, noalias_scopes = [#alias_scope1]} : f32, !llvm.ptr %5 = llvm.getelementptr inbounds %arg1[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32 llvm.store %3, %5 {alias_scopes = [#alias_scope1], alignment = 4 : i64, noalias_scopes = [#alias_scope]} : f32, !llvm.ptr - %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32 - %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32 - llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr + "test.one_region_op"() ({ + %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32 + %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32 + llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr + "test.terminator"() : () -> () + }) : () -> () llvm.return } @@ -105,9 +111,13 @@ llvm.func @callee_without_metadata(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !l llvm.store %3, %4 {alignment = 4 : i64} : f32, !llvm.ptr %5 = llvm.getelementptr inbounds %arg1[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32 llvm.store %3, %5 {alignment = 4 : i64} : f32, !llvm.ptr - %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32 - %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32 - llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr + "test.one_region_op"() ({ + %6 = llvm.load %arg2 {alignment = 4 : i64} : !llvm.ptr -> f32 + %7 = llvm.getelementptr inbounds %arg0[%2] : (!llvm.ptr, i64) -> !llvm.ptr, f32 + llvm.store %6, %7 {alignment = 4 : i64} : f32, !llvm.ptr + "test.terminator"() : () -> () + }) : () -> () + llvm.return } @@ -394,3 +404,30 @@ llvm.func @bar(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) { llvm.call @supported_operations(%arg0, %arg2) : (!llvm.ptr, !llvm.ptr) -> () llvm.return } + +// ----- + +// CHECK-DAG: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<{{.*}}> +// CHECK-DAG: #[[$ARG_SCOPE:.*]] = #llvm.alias_scope + +llvm.func @foo(%arg: i32) + +llvm.func @region(%arg0: !llvm.ptr {llvm.noalias}) { + "test.one_region_op"() ({ + %1 = llvm.load %arg0 : !llvm.ptr -> i32 + llvm.call @foo(%1) : (i32) -> () + "test.terminator"() : () -> () + }) : () -> () + llvm.return +} + +// CHECK-LABEL: llvm.func @noalias_with_region +// CHECK: llvm.load +// CHECK-SAME: alias_scopes = [#[[$ARG_SCOPE]]] +// CHECK: llvm.call +// CHECK-NOT: alias_scopes +// CHECK-SAME: noalias_scopes = [#[[$ARG_SCOPE]]] +llvm.func @noalias_with_region(%arg0: !llvm.ptr) { + llvm.call @region(%arg0) : (!llvm.ptr) -> () + llvm.return +} -- GitLab From 4bce270157f9a81bd7e38dc589a2970a445d1e96 Mon Sep 17 00:00:00 2001 From: Guy David <49722543+guy-david@users.noreply.github.com> Date: Thu, 30 May 2024 09:21:08 +0300 Subject: [PATCH 015/243] [mlir][llvm] Implement ConstantLike for ZeroOp, UndefOp, PoisonOp (#93690) These act as constants and should be propagated whenever possible. It is safe to do so for mlir.undef and mlir.poison because they remain "dirty" through out their lifetime and can be duplicated, merged, etc. per the LangRef. Signed-off-by: Guy David --- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 21 +++ mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 9 +- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 38 +++++- .../Dialect/GPU/dynamic-shared-memory.mlir | 126 +++++++++--------- .../test/Dialect/LLVMIR/constant-folding.mlir | 68 ++++++++++ .../test/Dialect/SparseTensor/conversion.mlir | 2 +- .../SparseTensor/sparse_fill_zero.mlir | 4 +- .../SparseTensor/specifier_to_llvm.mlir | 12 +- mlir/test/Examples/transform/ChH/full.mlir | 12 +- 9 files changed, 210 insertions(+), 82 deletions(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 535cf8dfd2ce..bfcfbd64ae02 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -1037,4 +1037,25 @@ def LLVM_TargetFeaturesAttr : LLVM_Attr<"TargetFeatures", "target_features"> let genVerifyDecl = 1; } +//===----------------------------------------------------------------------===// +// UndefAttr +//===----------------------------------------------------------------------===// + +/// Folded into from LLVM::UndefOp. +def LLVM_UndefAttr : LLVM_Attr<"Undef", "undef">; + +//===----------------------------------------------------------------------===// +// PoisonAttr +//===----------------------------------------------------------------------===// + +/// Folded into from LLVM::PoisonOp. +def LLVM_PoisonAttr : LLVM_Attr<"Poison", "poison">; + +//===----------------------------------------------------------------------===// +// ZeroAttr +//===----------------------------------------------------------------------===// + +/// Folded into from LLVM::ZeroOp. +def LLVM_ZeroAttr : LLVM_Attr<"Zero", "zero">; + #endif // LLVMIR_ATTRDEFS diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 84e67d2c11db..f6f907f39a4b 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1522,7 +1522,7 @@ def LLVM_NoneTokenOp let assemblyFormat = "attr-dict `:` type($res)"; } -def LLVM_UndefOp : LLVM_Op<"mlir.undef", [Pure]>, +def LLVM_UndefOp : LLVM_Op<"mlir.undef", [Pure, ConstantLike]>, LLVM_Builder<"$res = llvm::UndefValue::get($_resultType);"> { let summary = "Creates an undefined value of LLVM dialect type."; let description = [{ @@ -1541,9 +1541,10 @@ def LLVM_UndefOp : LLVM_Op<"mlir.undef", [Pure]>, let results = (outs LLVM_Type:$res); let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = "attr-dict `:` type($res)"; + let hasFolder = 1; } -def LLVM_PoisonOp : LLVM_Op<"mlir.poison", [Pure]>, +def LLVM_PoisonOp : LLVM_Op<"mlir.poison", [Pure, ConstantLike]>, LLVM_Builder<"$res = llvm::PoisonValue::get($_resultType);"> { let summary = "Creates a poison value of LLVM dialect type."; let description = [{ @@ -1563,10 +1564,11 @@ def LLVM_PoisonOp : LLVM_Op<"mlir.poison", [Pure]>, let results = (outs LLVM_Type:$res); let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = "attr-dict `:` type($res)"; + let hasFolder = 1; } def LLVM_ZeroOp - : LLVM_Op<"mlir.zero", [Pure]>, + : LLVM_Op<"mlir.zero", [Pure, ConstantLike]>, LLVM_Builder<"$res = llvm::Constant::getNullValue($_resultType);"> { let summary = "Creates a zero-initialized value of LLVM dialect type."; @@ -1588,6 +1590,7 @@ def LLVM_ZeroOp let builders = [LLVM_OneResultOpBuilder]; let assemblyFormat = "attr-dict `:` type($res)"; let hasVerifier = 1; + let hasFolder = 1; } def LLVM_ConstantOp diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index dcf3f3b52a60..60b911948d4a 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2555,6 +2555,24 @@ Region *LLVMFuncOp::getCallableRegion() { return &getBody(); } +//===----------------------------------------------------------------------===// +// UndefOp. +//===----------------------------------------------------------------------===// + +/// Fold an undef operation to a dedicated undef attribute. +OpFoldResult LLVM::UndefOp::fold(FoldAdaptor) { + return LLVM::UndefAttr::get(getContext()); +} + +//===----------------------------------------------------------------------===// +// PoisonOp. +//===----------------------------------------------------------------------===// + +/// Fold a poison operation to a dedicated poison attribute. +OpFoldResult LLVM::PoisonOp::fold(FoldAdaptor) { + return LLVM::PoisonAttr::get(getContext()); +} + //===----------------------------------------------------------------------===// // ZeroOp. //===----------------------------------------------------------------------===// @@ -2568,6 +2586,15 @@ LogicalResult LLVM::ZeroOp::verify() { return success(); } +/// Fold a zero operation to a builtin zero attribute when possible and fall +/// back to a dedicated zero attribute. +OpFoldResult LLVM::ZeroOp::fold(FoldAdaptor) { + OpFoldResult result = Builder(getContext()).getZeroAttr(getType()); + if (result) + return result; + return LLVM::ZeroAttr::get(getContext()); +} + //===----------------------------------------------------------------------===// // ConstantOp. //===----------------------------------------------------------------------===// @@ -3271,11 +3298,18 @@ LogicalResult LLVMDialect::verifyRegionResultAttribute(Operation *op, Operation *LLVMDialect::materializeConstant(OpBuilder &builder, Attribute value, Type type, Location loc) { - // If this was folded from an llvm.mlir.addressof operation, it should be - // materialized as such. + // If this was folded from an operation other than llvm.mlir.constant, it + // should be materialized as such. Note that an llvm.mlir.zero may fold into + // a builtin zero attribute and thus will materialize as a llvm.mlir.constant. if (auto symbol = dyn_cast(value)) if (isa(type)) return builder.create(loc, type, symbol); + if (isa(value)) + return builder.create(loc, type); + if (isa(value)) + return builder.create(loc, type); + if (isa(value)) + return builder.create(loc, type); // Otherwise try materializing it as a regular llvm.mlir.constant op. return LLVM::ConstantOp::materialize(builder, value, type, loc); } diff --git a/mlir/test/Dialect/GPU/dynamic-shared-memory.mlir b/mlir/test/Dialect/GPU/dynamic-shared-memory.mlir index fb45faaa712f..d73125fd763e 100644 --- a/mlir/test/Dialect/GPU/dynamic-shared-memory.mlir +++ b/mlir/test/Dialect/GPU/dynamic-shared-memory.mlir @@ -3,11 +3,11 @@ gpu.module @modules { // CHECK: llvm.mlir.global internal @__dynamic_shmem__3() {addr_space = 3 : i32, alignment = 16 : i64} : !llvm.array<0 x i8> llvm.mlir.global internal @__dynamic_shmem__0() {addr_space = 3 : i32, alignment = 4 : i64} : !llvm.array<0 x i8> - llvm.mlir.global internal @__dynamic_shmem__1() {addr_space = 3 : i32, alignment = 4 : i64} : !llvm.array<0 x i8> - llvm.mlir.global internal @__dynamic_shmem__2() {alignment = 16 : i64} : !llvm.array<0 x i8> + llvm.mlir.global internal @__dynamic_shmem__1() {addr_space = 3 : i32, alignment = 4 : i64} : !llvm.array<0 x i8> + llvm.mlir.global internal @__dynamic_shmem__2() {alignment = 16 : i64} : !llvm.array<0 x i8> // CHECK-LABEL: llvm.func @dynamic_shared_memory_kernel( // CHECK-SAME: %[[arg0:.+]]: i64) - gpu.func @dynamic_shared_memory_kernel(%d : index) kernel attributes {gpu.known_block_size = array, gpu.known_grid_size = array} { + gpu.func @dynamic_shared_memory_kernel(%d : index) kernel attributes {gpu.known_block_size = array, gpu.known_grid_size = array} { %c1 = arith.constant 1 : index %c8192 = arith.constant 8192 : index %c16384 = arith.constant 16384 : index @@ -19,83 +19,83 @@ gpu.module @modules { %1 = memref.view %shmem[%c16384][] : memref> to memref<32x64xf32, #gpu.address_space> "test.use.shared.memory"(%1) : (memref<32x64xf32, #gpu.address_space>) -> () - -// CHECK: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 -// CHECK: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 -// CHECK: %[[S2:.+]] = llvm.mlir.constant(1 : index) : i64 -// CHECK: %[[S3:.+]] = llvm.mlir.constant(0 : index) : i64 -// CHECK: %[[S4:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> -// CHECK: %[[S5:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S4]], %[[S5]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S4]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 -// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S3]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S2]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %[[S13]] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> -// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () -// CHECK: %[[S15:.+]] = llvm.getelementptr %4[16384] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 -// CHECK: %[[S16:.+]] = llvm.insertvalue %[[S15]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S17:.+]] = llvm.insertvalue %[[S3]], %[[S16]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S18:.+]] = llvm.insertvalue %[[S1]], %[[S17]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S19:.+]] = llvm.insertvalue %[[S2]], %[[S18]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S20:.+]] = llvm.insertvalue %[[S0]], %[[S19]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S21:.+]] = llvm.insertvalue %[[S1]], %[[S20]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S22:.+]] = builtin.unrealized_conversion_cast %[[S21]] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> -// CHECK: "test.use.shared.memory"(%[[S22]]) : (memref<32x64xf32, #gpu.address_space>) -> () + +// CHECK-DAG: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 +// CHECK-DAG: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 +// CHECK-DAG: %[[S2:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK-DAG: %[[S3:.+]] = llvm.mlir.constant(1 : index) : i64 +// CHECK-DAG: %[[S4:.+]] = llvm.mlir.constant(0 : index) : i64 +// CHECK-DAG: %[[S5:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> +// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S5]], %[[S2]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S5]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 +// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S4]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S3]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %[[S13]] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> +// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () +// CHECK: %[[S15:.+]] = llvm.getelementptr %[[S5]][16384] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 +// CHECK: %[[S16:.+]] = llvm.insertvalue %[[S15]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S17:.+]] = llvm.insertvalue %[[S4]], %[[S16]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S18:.+]] = llvm.insertvalue %[[S1]], %[[S17]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S19:.+]] = llvm.insertvalue %[[S3]], %[[S18]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S20:.+]] = llvm.insertvalue %[[S0]], %[[S19]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S21:.+]] = llvm.insertvalue %[[S1]], %[[S20]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S22:.+]] = builtin.unrealized_conversion_cast %[[S21]] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> +// CHECK: "test.use.shared.memory"(%[[S22]]) : (memref<32x64xf32, #gpu.address_space>) -> () gpu.return } // CHECK-LABEL: llvm.func @gpu_device_function - gpu.func @gpu_device_function() { + gpu.func @gpu_device_function() { %c8192 = arith.constant 8192 : index %shmem = gpu.dynamic_shared_memory : memref> %0 = memref.view %shmem[%c8192][] : memref> to memref<32x64xf32, #gpu.address_space> "test.use.shared.memory"(%0) : (memref<32x64xf32, #gpu.address_space>) -> () -// CHECK: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 -// CHECK: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 -// CHECK: %[[S2:.+]] = llvm.mlir.constant(1 : index) : i64 -// CHECK: %[[S3:.+]] = llvm.mlir.constant(0 : index) : i64 -// CHECK: %[[S4:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> -// CHECK: %[[S5:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S4]], %[[S5]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S4]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 -// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S3]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S2]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %13 : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> -// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () +// CHECK-DAG: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 +// CHECK-DAG: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 +// CHECK-DAG: %[[S2:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK-DAG: %[[S3:.+]] = llvm.mlir.constant(1 : index) : i64 +// CHECK-DAG: %[[S4:.+]] = llvm.mlir.constant(0 : index) : i64 +// CHECK-DAG: %[[S5:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> +// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S5]], %[[S2]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S5]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 +// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S4]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S3]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %13 : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> +// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () gpu.return } // CHECK-LABEL: llvm.func @func_device_function - func.func @func_device_function() { + func.func @func_device_function() { %c8192 = arith.constant 8192 : index %shmem = gpu.dynamic_shared_memory : memref> %0 = memref.view %shmem[%c8192][] : memref> to memref<32x64xf32, #gpu.address_space> "test.use.shared.memory"(%0) : (memref<32x64xf32, #gpu.address_space>) -> () -// CHECK: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 -// CHECK: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 -// CHECK: %[[S2:.+]] = llvm.mlir.constant(1 : index) : i64 -// CHECK: %[[S3:.+]] = llvm.mlir.constant(0 : index) : i64 -// CHECK: %[[S4:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> -// CHECK: %[[S5:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S4]], %[[S5]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S4]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 -// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S3]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S2]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> -// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %13 : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> -// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () +// CHECK-DAG: %[[S0:.+]] = llvm.mlir.constant(32 : index) : i64 +// CHECK-DAG: %[[S1:.+]] = llvm.mlir.constant(64 : index) : i64 +// CHECK-DAG: %[[S2:.+]] = llvm.mlir.undef : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK-DAG: %[[S3:.+]] = llvm.mlir.constant(1 : index) : i64 +// CHECK-DAG: %[[S4:.+]] = llvm.mlir.constant(0 : index) : i64 +// CHECK-DAG: %[[S5:.+]] = llvm.mlir.addressof @__dynamic_shmem__3 : !llvm.ptr<3> +// CHECK: %[[S6:.+]] = llvm.insertvalue %[[S5]], %[[S2]][0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S7:.+]] = llvm.getelementptr %[[S5]][8192] : (!llvm.ptr<3>) -> !llvm.ptr<3>, i8 +// CHECK: %[[S8:.+]] = llvm.insertvalue %[[S7]], %[[S6]][1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S9:.+]] = llvm.insertvalue %[[S4]], %[[S8]][2] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S10:.+]] = llvm.insertvalue %[[S1]], %[[S9]][3, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S11:.+]] = llvm.insertvalue %[[S3]], %[[S10]][4, 1] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S12:.+]] = llvm.insertvalue %[[S0]], %[[S11]][3, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S13:.+]] = llvm.insertvalue %[[S1]], %[[S12]][4, 0] : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> +// CHECK: %[[S14:.+]] = builtin.unrealized_conversion_cast %13 : !llvm.struct<(ptr<3>, ptr<3>, i64, array<2 x i64>, array<2 x i64>)> to memref<32x64xf32, #gpu.address_space> +// CHECK: "test.use.shared.memory"(%[[S14]]) : (memref<32x64xf32, #gpu.address_space>) -> () func.return } diff --git a/mlir/test/Dialect/LLVMIR/constant-folding.mlir b/mlir/test/Dialect/LLVMIR/constant-folding.mlir index 454126321eb9..497d679a12a0 100644 --- a/mlir/test/Dialect/LLVMIR/constant-folding.mlir +++ b/mlir/test/Dialect/LLVMIR/constant-folding.mlir @@ -101,3 +101,71 @@ llvm.func @addressof_blocks(%arg: i1) -> !llvm.ptr { } llvm.mlir.global constant @foo() : i32 + +// ----- + +// CHECK-LABEL: llvm.func @undef +llvm.func @undef() { + // CHECK-NEXT: %[[UNDEF:.+]] = llvm.mlir.undef : i32 + %undef1 = llvm.mlir.undef : i32 + %undef2 = llvm.mlir.undef : i32 + // CHECK-NEXT: llvm.call @foo(%[[UNDEF]], %[[UNDEF]]) + llvm.call @foo(%undef1, %undef2) : (i32, i32) -> () + // CHECK-NEXT: llvm.return + llvm.return +} + +llvm.func @foo(i32, i32) + +// ----- + +// CHECK-LABEL: llvm.func @poison +llvm.func @poison() { + // CHECK-NEXT: %[[POISON:.+]] = llvm.mlir.poison : i32 + %poison1 = llvm.mlir.poison : i32 + %poison2 = llvm.mlir.poison : i32 + // CHECK-NEXT: llvm.call @foo(%[[POISON]], %[[POISON]]) + llvm.call @foo(%poison1, %poison2) : (i32, i32) -> () + // CHECK-NEXT: llvm.return + llvm.return +} + +llvm.func @foo(i32, i32) + +// ----- + +llvm.func @foo(!llvm.ptr, !llvm.ptr) + +// CHECK-LABEL: llvm.func @null_pointer +llvm.func @null_pointer() { + // CHECK-NEXT: %[[NULLPTR:.+]] = llvm.mlir.zero : !llvm.ptr + %nullptr1 = llvm.mlir.zero : !llvm.ptr + %nullptr2 = llvm.mlir.zero : !llvm.ptr + // CHECK-NEXT: llvm.call @foo(%[[NULLPTR]], %[[NULLPTR]]) + llvm.call @foo(%nullptr1, %nullptr2) : (!llvm.ptr, !llvm.ptr) -> () + // CHECK-NEXT: llvm.return + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @zero_integer +llvm.func @zero_integer() -> i64 { + // CHECK-NEXT: %[[ZERO:.+]] = llvm.mlir.constant(0 : i64) : i64 + %zero = llvm.mlir.zero : i32 + %zero_extended = llvm.zext %zero : i32 to i64 + // CHECK-NEXT: llvm.return %[[ZERO]] + llvm.return %zero_extended : i64 +} + +// ----- + +// CHECK-LABEL: llvm.func @null_pointer_select +llvm.func @null_pointer_select(%cond: i1) -> !llvm.ptr { + // CHECK-NEXT: %[[NULLPTR:.+]] = llvm.mlir.zero : !llvm.ptr + %nullptr1 = llvm.mlir.zero : !llvm.ptr + %nullptr2 = llvm.mlir.zero : !llvm.ptr + %result = arith.select %cond, %nullptr1, %nullptr2 : !llvm.ptr + // CHECK-NEXT: llvm.return %[[NULLPTR]] + llvm.return %result : !llvm.ptr +} diff --git a/mlir/test/Dialect/SparseTensor/conversion.mlir b/mlir/test/Dialect/SparseTensor/conversion.mlir index f23f6ac4f181..ff0fb22431d6 100644 --- a/mlir/test/Dialect/SparseTensor/conversion.mlir +++ b/mlir/test/Dialect/SparseTensor/conversion.mlir @@ -144,7 +144,7 @@ func.func @sparse_new3d(%arg0: !llvm.ptr) -> tensor { // CHECK-DAG: %[[Iota:.*]] = memref.cast %[[Iota0]] : memref<2xindex> to memref // CHECK-DAG: memref.store %[[I]], %[[Sizes0]][%[[C0]]] : memref<2xindex> // CHECK-DAG: memref.store %[[J]], %[[Sizes0]][%[[C1]]] : memref<2xindex> -// CHECK: %[[NP:.*]] = llvm.mlir.zero : !llvm.ptr +// CHECK-DAG: %[[NP:.*]] = llvm.mlir.zero : !llvm.ptr // CHECK: %[[T:.*]] = call @newSparseTensor(%[[Sizes]], %[[Sizes]], %[[LvlTypes]], %[[Iota]], %[[Iota]], %{{.*}}, %{{.*}}, %{{.*}}, %[[Empty]], %[[NP]]) // CHECK: return %[[T]] : !llvm.ptr func.func @sparse_init(%arg0: index, %arg1: index) -> tensor { diff --git a/mlir/test/Dialect/SparseTensor/sparse_fill_zero.mlir b/mlir/test/Dialect/SparseTensor/sparse_fill_zero.mlir index 6e8a26762d90..df3e4b0ed60c 100644 --- a/mlir/test/Dialect/SparseTensor/sparse_fill_zero.mlir +++ b/mlir/test/Dialect/SparseTensor/sparse_fill_zero.mlir @@ -6,6 +6,7 @@ // CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr, // CHECK-SAME: %[[VAL_1:.*]]: !llvm.ptr) -> !llvm.ptr { // CHECK-DAG: %[[VAL_2:.*]] = arith.constant 0.000000e+00 : f64 +// CHECK-DAG: %[[ZERO:.*]] = llvm.mlir.zero : !llvm.ptr // CHECK-DAG: %[[VAL_3:.*]] = arith.constant 1 : i32 // CHECK-DAG: %[[VAL_4:.*]] = arith.constant 0 : i32 // CHECK-DAG: %[[VAL_5:.*]] = arith.constant 0 : index @@ -27,8 +28,7 @@ // CHECK: %[[VAL_17:.*]] = memref.cast %[[VAL_16]] : memref<2xindex> to memref // CHECK: memref.store %[[VAL_5]], %[[VAL_16]]{{\[}}%[[VAL_5]]] : memref<2xindex> // CHECK: memref.store %[[VAL_6]], %[[VAL_16]]{{\[}}%[[VAL_6]]] : memref<2xindex> -// CHECK: %[[VAL_18:.*]] = llvm.mlir.zero : !llvm.ptr -// CHECK: %[[VAL_19:.*]] = call @newSparseTensor(%[[VAL_15]], %[[VAL_15]], %[[VAL_13]], %[[VAL_17]], %[[VAL_17]], %[[VAL_4]], %[[VAL_4]], %[[VAL_3]], %[[VAL_4]], %[[VAL_18]]) : (memref, memref, memref, memref, memref, i32, i32, i32, i32, !llvm.ptr) -> !llvm.ptr +// CHECK: %[[VAL_19:.*]] = call @newSparseTensor(%[[VAL_15]], %[[VAL_15]], %[[VAL_13]], %[[VAL_17]], %[[VAL_17]], %[[VAL_4]], %[[VAL_4]], %[[VAL_3]], %[[VAL_4]], %[[ZERO]]) : (memref, memref, memref, memref, memref, i32, i32, i32, i32, !llvm.ptr) -> !llvm.ptr // CHECK: %[[VAL_20:.*]] = memref.alloc() : memref<300xf64> // CHECK: %[[VAL_21:.*]] = memref.cast %[[VAL_20]] : memref<300xf64> to memref // CHECK: %[[VAL_22:.*]] = memref.alloc() : memref<300xi1> diff --git a/mlir/test/Dialect/SparseTensor/specifier_to_llvm.mlir b/mlir/test/Dialect/SparseTensor/specifier_to_llvm.mlir index b647fe0cdeed..00ff29125fb5 100644 --- a/mlir/test/Dialect/SparseTensor/specifier_to_llvm.mlir +++ b/mlir/test/Dialect/SparseTensor/specifier_to_llvm.mlir @@ -3,12 +3,12 @@ #CSR = #sparse_tensor.encoding<{map = (d0, d1) -> (d0 : dense, d1 : compressed)}> // CHECK-LABEL: func.func @sparse_metadata_init() -> !llvm.struct<(array<2 x i64>, array<3 x i64>)> { -// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64 -// CHECK: %[[VAL_1:.*]] = llvm.mlir.undef : !llvm.struct<(array<2 x i64>, array<3 x i64>)> -// CHECK: %[[VAL_2:.*]] = llvm.insertvalue %[[VAL_0]], %[[VAL_1]][1, 0] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> -// CHECK: %[[VAL_3:.*]] = llvm.insertvalue %[[VAL_0]], %[[VAL_2]][1, 1] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> -// CHECK: %[[VAL_4:.*]] = llvm.insertvalue %[[VAL_0]], %[[VAL_3]][1, 2] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> -// CHECK: return %[[VAL_4]] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> +// CHECK-DAG: %[[STRUCT:.*]] = llvm.mlir.undef : !llvm.struct<(array<2 x i64>, array<3 x i64>)> +// CHECK-DAG: %[[CST0:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_1:.*]] = llvm.insertvalue %[[CST0]], %[[STRUCT]][1, 0] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> +// CHECK: %[[VAL_2:.*]] = llvm.insertvalue %[[CST0]], %[[VAL_1]][1, 1] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> +// CHECK: %[[VAL_3:.*]] = llvm.insertvalue %[[CST0]], %[[VAL_2]][1, 2] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> +// CHECK: return %[[VAL_3]] : !llvm.struct<(array<2 x i64>, array<3 x i64>)> // CHECK: } func.func @sparse_metadata_init() -> !sparse_tensor.storage_specifier<#CSR> { %0 = sparse_tensor.storage_specifier.init : !sparse_tensor.storage_specifier<#CSR> diff --git a/mlir/test/Examples/transform/ChH/full.mlir b/mlir/test/Examples/transform/ChH/full.mlir index f8d910370bc2..259475ebdbf4 100644 --- a/mlir/test/Examples/transform/ChH/full.mlir +++ b/mlir/test/Examples/transform/ChH/full.mlir @@ -380,27 +380,29 @@ module attributes { transform.with_named_sequence } { // immediately adjacent fma on vector<64xf32>. // CHECK: %[[R0:.+]] = llvm.mlir.undef : !llvm.array<5 x vector<64xf32>> -// CHECK-NEXT: %[[LINE0:.+]] = llvm.extractvalue %[[V:.+]][0] : !llvm.array<5 x vector<64xf32>> + +// CHECK: %[[V:.+]] = llvm.load %{{.*}} : !llvm.ptr -> !llvm.array<5 x vector<64xf32>> +// CHECK-NEXT: %[[LINE0:.+]] = llvm.extractvalue %[[V]][0] : !llvm.array<5 x vector<64xf32>> // CHECK-NEXT: %[[FMA0:.+]] = llvm.intr.fma(%{{.*}}, %{{.*}}, %[[LINE0]]) // CHECK-SAME: -> vector<64xf32> // CHECK-NEXT: %[[R1:.+]] = llvm.insertvalue %[[FMA0]], %[[R0]][0] -// CHECK-NEXT: %[[LINE1:.+]] = llvm.extractvalue %[[V:.+]][1] : !llvm.array<5 x vector<64xf32>> +// CHECK-NEXT: %[[LINE1:.+]] = llvm.extractvalue %[[V]][1] : !llvm.array<5 x vector<64xf32>> // CHECK-NEXT: %[[FMA1:.+]] = llvm.intr.fma(%{{.*}}, %{{.*}}, %[[LINE1]]) // CHECK-SAME: -> vector<64xf32> // CHECK-NEXT: %[[R2:.+]] = llvm.insertvalue %[[FMA1]], %[[R1]][1] -// CHECK-NEXT: %[[LINE2:.+]] = llvm.extractvalue %[[V:.+]][2] : !llvm.array<5 x vector<64xf32>> +// CHECK-NEXT: %[[LINE2:.+]] = llvm.extractvalue %[[V]][2] : !llvm.array<5 x vector<64xf32>> // CHECK-NEXT: %[[FMA2:.+]] = llvm.intr.fma(%{{.*}}, %{{.*}}, %[[LINE2]]) // CHECK-SAME: -> vector<64xf32> // CHECK-NEXT: %[[R3:.+]] = llvm.insertvalue %[[FMA2]], %[[R2]][2] -// CHECK-NEXT: %[[LINE3:.+]] = llvm.extractvalue %[[V:.+]][3] : !llvm.array<5 x vector<64xf32>> +// CHECK-NEXT: %[[LINE3:.+]] = llvm.extractvalue %[[V]][3] : !llvm.array<5 x vector<64xf32>> // CHECK-NEXT: %[[FMA3:.+]] = llvm.intr.fma(%{{.*}}, %{{.*}}, %[[LINE3]]) // CHECK-SAME: -> vector<64xf32> // CHECK-NEXT: %[[R4:.+]] = llvm.insertvalue %[[FMA3]], %[[R3]][3] -// CHECK-NEXT: %[[LINE4:.+]] = llvm.extractvalue %[[V:.+]][4] : !llvm.array<5 x vector<64xf32>> +// CHECK-NEXT: %[[LINE4:.+]] = llvm.extractvalue %[[V]][4] : !llvm.array<5 x vector<64xf32>> // CHECK-NEXT: %[[FMA4:.+]] = llvm.intr.fma(%{{.*}}, %{{.*}}, %[[LINE4]]) // CHECK-SAME: -> vector<64xf32> // CHECK-NEXT: %[[R5:.+]] = llvm.insertvalue %[[FMA4]], %[[R4]][4] -- GitLab From d10b76552f919ddb84347ab03908a55804ea6b8a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 30 May 2024 08:36:44 +0200 Subject: [PATCH 016/243] [ConstantFold] Remove notional over-indexing fold (#93697) The data-layout independent constant folding currently has some rather gnarly code for canonicalizing GEP indices to reduce "notional overindexing", and then infers inbounds based on that canonicalization. Now that we canonicalize to i8 GEPs, this canonicalization is essentially useless, as we'll discard it as soon as the GEP hits the data-layout aware constant folder anyway. As such, I'd like to remove this code entirely. This shouldn't have any impact on optimization capabilities. --- clang/test/CodeGen/object-size.c | 2 +- ...initializer-stdinitializerlist-pr12086.cpp | 8 +- clang/test/CodeGenHLSL/cbuf.hlsl | 4 +- clang/test/Driver/linker-wrapper-image.c | 2 +- ...anitizer_coverage_allowlist_ignorelist.cpp | 4 +- llvm/lib/IR/ConstantFold.cpp | 196 ------------------ llvm/test/Assembler/ConstantExprFold.ll | 4 +- llvm/test/Assembler/getelementptr.ll | 15 +- llvm/test/Assembler/getelementptr_vec_ce.ll | 2 +- llvm/test/CodeGen/AMDGPU/opencl-printf.ll | 8 +- llvm/test/Linker/comdat-largest.ll | 2 +- .../gather-scatter-opt-inseltpoison.ll | 2 +- .../AArch64/gather-scatter-opt.ll | 2 +- .../X86/gather-scatter-opt-inseltpoison.ll | 2 +- .../CodeGenPrepare/X86/gather-scatter-opt.ll | 2 +- .../GlobalOpt/globalsra-opaque-ptr.ll | 10 +- llvm/test/Transforms/GlobalSplit/basic.ll | 4 +- .../AMDGPU/infer-address-space.ll | 2 +- .../AMDGPU/infer-getelementptr.ll | 8 +- .../old-pass-regressions-inseltpoison.ll | 2 +- .../AMDGPU/old-pass-regressions.ll | 2 +- .../InferAddressSpaces/NVPTX/bug31948.ll | 4 +- .../Transforms/InferAlignment/gep-array.ll | 8 +- .../test/Transforms/InstCombine/gep-vector.ll | 6 +- .../InstSimplify/ConstProp/vectorgep-crash.ll | 2 +- .../Transforms/InstSimplify/vector_gep.ll | 2 +- .../NewGVN/2007-07-26-InterlockingLoops.ll | 2 +- ...arget-constant-indexing-device-region.mlir | 2 +- ...target-fortran-allocatable-types-host.mlir | 8 +- 29 files changed, 58 insertions(+), 259 deletions(-) diff --git a/clang/test/CodeGen/object-size.c b/clang/test/CodeGen/object-size.c index b39b15fcc65b..58561a5470f7 100644 --- a/clang/test/CodeGen/object-size.c +++ b/clang/test/CodeGen/object-size.c @@ -34,7 +34,7 @@ void test2(void) { // CHECK-LABEL: define{{.*}} void @test3 void test3(void) { - // CHECK: = call ptr @__strcpy_chk(ptr getelementptr inbounds ([63 x i8], ptr @gbuf, i64 1, i64 37), ptr @.str, i64 0) + // CHECK: = call ptr @__strcpy_chk(ptr getelementptr inbounds ([63 x i8], ptr @gbuf, i64 0, i64 100), ptr @.str, i64 0) strcpy(&gbuf[100], "Hi there"); } diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp index c15a6183d15d..6fbe4c7fd17a 100644 --- a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp +++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp @@ -112,21 +112,21 @@ std::initializer_list> nested = { // CHECK-DYNAMIC-BE: store i32 {{.*}}, ptr getelementptr inbounds (i32, ptr @_ZGR6nested0_, i64 1) // CHECK-DYNAMIC-BE: store ptr @_ZGR6nested0_, // CHECK-DYNAMIC-BE: ptr @_ZGR6nested_, align 8 -// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested0_, i64 1, i64 0), +// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested0_, i64 0, i64 2), // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @_ZGR6nested_, i32 0, i32 1), align 8 // CHECK-DYNAMIC-BE: store i32 3, ptr @_ZGR6nested1_ // CHECK-DYNAMIC-BE: store i32 {{.*}}, ptr getelementptr inbounds (i32, ptr @_ZGR6nested1_, i64 1) // CHECK-DYNAMIC-BE: store ptr @_ZGR6nested1_, // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @_ZGR6nested_, i64 1), align 8 -// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested1_, i64 1, i64 0), +// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested1_, i64 0, i64 2), // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @_ZGR6nested_, i64 1, i32 1), align 8 // CHECK-DYNAMIC-BE: store i32 5, ptr @_ZGR6nested2_ // CHECK-DYNAMIC-BE: store i32 {{.*}}, ptr getelementptr inbounds (i32, ptr @_ZGR6nested2_, i64 1) // CHECK-DYNAMIC-BE: store ptr @_ZGR6nested2_, // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @_ZGR6nested_, i64 2), align 8 -// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested2_, i64 1, i64 0), +// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([2 x i32], ptr @_ZGR6nested2_, i64 0, i64 2), // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @_ZGR6nested_, i64 2, i32 1), align 8 // CHECK-DYNAMIC-BE: store ptr @_ZGR6nested_, // CHECK-DYNAMIC-BE: ptr @nested, align 8 -// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([3 x {{.*}}], ptr @_ZGR6nested_, i64 1, i64 0), +// CHECK-DYNAMIC-BE: store ptr getelementptr inbounds ([3 x {{.*}}], ptr @_ZGR6nested_, i64 0, i64 3), // CHECK-DYNAMIC-BE: ptr getelementptr inbounds ({{.*}}, ptr @nested, i32 0, i32 1), align 8 diff --git a/clang/test/CodeGenHLSL/cbuf.hlsl b/clang/test/CodeGenHLSL/cbuf.hlsl index dc2a6aaa8f43..78d9768b22fc 100644 --- a/clang/test/CodeGenHLSL/cbuf.hlsl +++ b/clang/test/CodeGenHLSL/cbuf.hlsl @@ -16,9 +16,9 @@ tbuffer A : register(t2, space1) { float foo() { // CHECK: load float, ptr @[[CB]], align 4 -// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr @[[CB]], i32 0, i32 1), align 8 +// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[CB]], i32 0, i32 1), align 8 // CHECK: load float, ptr @[[TB]], align 4 -// CHECK: load double, ptr getelementptr inbounds ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8 +// CHECK: load double, ptr getelementptr ({ float, double }, ptr @[[TB]], i32 0, i32 1), align 8 return a + b + c*d; } diff --git a/clang/test/Driver/linker-wrapper-image.c b/clang/test/Driver/linker-wrapper-image.c index 5d5d62805e17..161402124c4c 100644 --- a/clang/test/Driver/linker-wrapper-image.c +++ b/clang/test/Driver/linker-wrapper-image.c @@ -24,7 +24,7 @@ // OPENMP-REL: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading.relocatable", align 8 // 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.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 144), ptr getelementptr ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 0, i64 144), 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 101, ptr @.omp_offloading.descriptor_reg, ptr null }] diff --git a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_allowlist_ignorelist.cpp b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_allowlist_ignorelist.cpp index 8e1c02c6dee6..2fbace52696a 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_allowlist_ignorelist.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_allowlist_ignorelist.cpp @@ -27,8 +27,8 @@ // RUN: echo 'section "__sancov_cntrs"' > patterns.txt // RUN: echo '%[0-9]\+ = load i8, ptr @__sancov_gen_' >> patterns.txt // RUN: echo 'store i8 %[0-9]\+, ptr @__sancov_gen_' >> patterns.txt -// RUN: echo '%[0-9]\+ = load i8, ptr getelementptr inbounds (\[[0-9]\+ x i8\], ptr @__sancov_gen_' >> patterns.txt -// RUN: echo 'store i8 %[0-9]\+, ptr getelementptr inbounds (\[[0-9]\+ x i8\], ptr @__sancov_gen_' >> patterns.txt +// RUN: echo '%[0-9]\+ = load i8, ptr getelementptr (\[[0-9]\+ x i8\], ptr @__sancov_gen_' >> patterns.txt +// RUN: echo 'store i8 %[0-9]\+, ptr getelementptr (\[[0-9]\+ x i8\], ptr @__sancov_gen_' >> patterns.txt // Check indirect-calls // RUN: echo 'call void @__sanitizer_cov_trace_pc_indir' >> patterns.txt diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index 8fce782f47a9..9a7d437e6da6 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -1417,50 +1417,6 @@ Constant *llvm::ConstantFoldCompareInstruction(CmpInst::Predicate Predicate, return nullptr; } -/// Test whether the given sequence of *normalized* indices is "inbounds". -template -static bool isInBoundsIndices(ArrayRef Idxs) { - // No indices means nothing that could be out of bounds. - if (Idxs.empty()) return true; - - // If the first index is zero, it's in bounds. - if (cast(Idxs[0])->isNullValue()) return true; - - // If the first index is one and all the rest are zero, it's in bounds, - // by the one-past-the-end rule. - if (auto *CI = dyn_cast(Idxs[0])) { - if (!CI->isOne()) - return false; - } else { - auto *CV = cast(Idxs[0]); - CI = dyn_cast_or_null(CV->getSplatValue()); - if (!CI || !CI->isOne()) - return false; - } - - for (unsigned i = 1, e = Idxs.size(); i != e; ++i) - if (!cast(Idxs[i])->isNullValue()) - return false; - return true; -} - -/// Test whether a given ConstantInt is in-range for a SequentialType. -static bool isIndexInRangeOfArrayType(uint64_t NumElements, - const ConstantInt *CI) { - // We cannot bounds check the index if it doesn't fit in an int64_t. - if (CI->getValue().getSignificantBits() > 64) - return false; - - // A negative index or an index past the end of our sequential type is - // considered out-of-range. - int64_t IndexVal = CI->getSExtValue(); - if (IndexVal < 0 || (IndexVal != 0 && (uint64_t)IndexVal >= NumElements)) - return false; - - // Otherwise, it is in-range. - return true; -} - // Combine Indices - If the source pointer to this getelementptr instruction // is a getelementptr instruction, combine the indices of the two // getelementptr instructions into a single instruction. @@ -1572,157 +1528,5 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C, if (Constant *C = foldGEPOfGEP(GEP, PointeeTy, InBounds, Idxs)) return C; - // Check to see if any array indices are not within the corresponding - // notional array or vector bounds. If so, try to determine if they can be - // factored out into preceding dimensions. - SmallVector NewIdxs; - Type *Ty = PointeeTy; - Type *Prev = C->getType(); - auto GEPIter = gep_type_begin(PointeeTy, Idxs); - bool Unknown = - !isa(Idxs[0]) && !isa(Idxs[0]); - for (unsigned i = 1, e = Idxs.size(); i != e; - Prev = Ty, Ty = (++GEPIter).getIndexedType(), ++i) { - if (!isa(Idxs[i]) && !isa(Idxs[i])) { - // We don't know if it's in range or not. - Unknown = true; - continue; - } - if (!isa(Idxs[i - 1]) && !isa(Idxs[i - 1])) - // Skip if the type of the previous index is not supported. - continue; - if (isa(Ty)) { - // The verify makes sure that GEPs into a struct are in range. - continue; - } - if (isa(Ty)) { - // There can be awkward padding in after a non-power of two vector. - Unknown = true; - continue; - } - auto *STy = cast(Ty); - if (ConstantInt *CI = dyn_cast(Idxs[i])) { - if (isIndexInRangeOfArrayType(STy->getNumElements(), CI)) - // It's in range, skip to the next index. - continue; - if (CI->isNegative()) { - // It's out of range and negative, don't try to factor it. - Unknown = true; - continue; - } - } else { - auto *CV = cast(Idxs[i]); - bool IsInRange = true; - for (unsigned I = 0, E = CV->getNumElements(); I != E; ++I) { - auto *CI = cast(CV->getElementAsConstant(I)); - IsInRange &= isIndexInRangeOfArrayType(STy->getNumElements(), CI); - if (CI->isNegative()) { - Unknown = true; - break; - } - } - if (IsInRange || Unknown) - // It's in range, skip to the next index. - // It's out of range and negative, don't try to factor it. - continue; - } - if (isa(Prev)) { - // It's out of range, but the prior dimension is a struct - // so we can't do anything about it. - Unknown = true; - continue; - } - - // Determine the number of elements in our sequential type. - uint64_t NumElements = STy->getArrayNumElements(); - if (!NumElements) { - Unknown = true; - continue; - } - - // It's out of range, but we can factor it into the prior - // dimension. - NewIdxs.resize(Idxs.size()); - - // Expand the current index or the previous index to a vector from a scalar - // if necessary. - Constant *CurrIdx = cast(Idxs[i]); - auto *PrevIdx = - NewIdxs[i - 1] ? NewIdxs[i - 1] : cast(Idxs[i - 1]); - bool IsCurrIdxVector = CurrIdx->getType()->isVectorTy(); - bool IsPrevIdxVector = PrevIdx->getType()->isVectorTy(); - bool UseVector = IsCurrIdxVector || IsPrevIdxVector; - - if (!IsCurrIdxVector && IsPrevIdxVector) - CurrIdx = ConstantDataVector::getSplat( - cast(PrevIdx->getType())->getNumElements(), CurrIdx); - - if (!IsPrevIdxVector && IsCurrIdxVector) - PrevIdx = ConstantDataVector::getSplat( - cast(CurrIdx->getType())->getNumElements(), PrevIdx); - - Constant *Factor = - ConstantInt::get(CurrIdx->getType()->getScalarType(), NumElements); - if (UseVector) - Factor = ConstantDataVector::getSplat( - IsPrevIdxVector - ? cast(PrevIdx->getType())->getNumElements() - : cast(CurrIdx->getType())->getNumElements(), - Factor); - - NewIdxs[i] = - ConstantFoldBinaryInstruction(Instruction::SRem, CurrIdx, Factor); - - Constant *Div = - ConstantFoldBinaryInstruction(Instruction::SDiv, CurrIdx, Factor); - - // We're working on either ConstantInt or vectors of ConstantInt, - // so these should always fold. - assert(NewIdxs[i] != nullptr && Div != nullptr && "Should have folded"); - - unsigned CommonExtendedWidth = - std::max(PrevIdx->getType()->getScalarSizeInBits(), - Div->getType()->getScalarSizeInBits()); - CommonExtendedWidth = std::max(CommonExtendedWidth, 64U); - - // Before adding, extend both operands to i64 to avoid - // overflow trouble. - Type *ExtendedTy = Type::getIntNTy(Div->getContext(), CommonExtendedWidth); - if (UseVector) - ExtendedTy = FixedVectorType::get( - ExtendedTy, - IsPrevIdxVector - ? cast(PrevIdx->getType())->getNumElements() - : cast(CurrIdx->getType())->getNumElements()); - - if (!PrevIdx->getType()->isIntOrIntVectorTy(CommonExtendedWidth)) - PrevIdx = - ConstantFoldCastInstruction(Instruction::SExt, PrevIdx, ExtendedTy); - - if (!Div->getType()->isIntOrIntVectorTy(CommonExtendedWidth)) - Div = ConstantFoldCastInstruction(Instruction::SExt, Div, ExtendedTy); - - assert(PrevIdx && Div && "Should have folded"); - NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div); - } - - // If we did any factoring, start over with the adjusted indices. - if (!NewIdxs.empty()) { - for (unsigned i = 0, e = Idxs.size(); i != e; ++i) - if (!NewIdxs[i]) NewIdxs[i] = cast(Idxs[i]); - return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs, InBounds, - InRange); - } - - // If all indices are known integers and normalized, we can do a simple - // check for the "inbounds" property. - if (!Unknown && !InBounds) - if (auto *GV = dyn_cast(C)) - if (!GV->hasExternalWeakLinkage() && GV->getValueType() == PointeeTy && - isInBoundsIndices(Idxs)) - // TODO(gep_nowrap): Can also set NUW here. - return ConstantExpr::getGetElementPtr( - PointeeTy, C, Idxs, GEPNoWrapFlags::inBounds(), InRange); - return nullptr; } diff --git a/llvm/test/Assembler/ConstantExprFold.ll b/llvm/test/Assembler/ConstantExprFold.ll index ab7e767d767b..adef90fce7ca 100644 --- a/llvm/test/Assembler/ConstantExprFold.ll +++ b/llvm/test/Assembler/ConstantExprFold.ll @@ -43,9 +43,9 @@ ; CHECK: @mul = global ptr null ; CHECK: @xor = global ptr @A ; CHECK: @B = external global %Ty -; CHECK: @icmp_ult1 = global i1 icmp ugt (ptr getelementptr inbounds (i64, ptr @A, i64 1), ptr @A) +; CHECK: @icmp_ult1 = global i1 icmp ugt (ptr getelementptr (i64, ptr @A, i64 1), ptr @A) ; CHECK: @icmp_slt = global i1 false -; CHECK: @icmp_ult2 = global i1 icmp ugt (ptr getelementptr inbounds (%Ty, ptr @B, i64 0, i32 1), ptr @B) +; CHECK: @icmp_ult2 = global i1 icmp ugt (ptr getelementptr (%Ty, ptr @B, i64 0, i32 1), ptr @B) ; CHECK: @cons = weak global i32 0, align 8 ; CHECK: @gep1 = global <2 x ptr> undef ; CHECK: @gep2 = global <2 x ptr> undef diff --git a/llvm/test/Assembler/getelementptr.ll b/llvm/test/Assembler/getelementptr.ll index 45c6a2d00cc3..a58af2f7a9b3 100644 --- a/llvm/test/Assembler/getelementptr.ll +++ b/llvm/test/Assembler/getelementptr.ll @@ -1,18 +1,17 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; Verify that over-indexed getelementptrs are folded. @A = external global [2 x [3 x [5 x [7 x i32]]]] @B = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 0, i64 0, i64 2, i64 1, i64 7523) -; CHECK: @B = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 36, i64 0, i64 1, i64 0, i64 5) +; CHECK: @B = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 0, i64 0, i64 2, i64 1, i64 7523) @C = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 3, i64 2, i64 0, i64 0, i64 7523) -; CHECK: @C = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 39, i64 1, i64 1, i64 4, i64 5) +; CHECK: @C = global ptr getelementptr ([2 x [3 x [5 x [7 x i32]]]], ptr @A, i64 3, i64 2, i64 0, i64 0, i64 7523) ; Verify that constant expression GEPs work with i84 indices. @D = external global [1 x i32] @E = global ptr getelementptr inbounds ([1 x i32], ptr @D, i84 0, i64 1) -; CHECK: @E = global ptr getelementptr inbounds ([1 x i32], ptr @D, i84 1, i64 0) +; CHECK: @E = global ptr getelementptr inbounds ([1 x i32], ptr @D, i84 0, i64 1) ; Verify that i16 indices work. @x = external global {i32, i32} @@ -23,16 +22,12 @@ @PR23753_b = global ptr getelementptr (i8, ptr @PR23753_a, i64 ptrtoint (ptr @PR23753_a to i64)) ; CHECK: @PR23753_b = global ptr getelementptr (i8, ptr @PR23753_a, i64 ptrtoint (ptr @PR23753_a to i64)) -; Verify that inrange doesn't inhibit over-indexed getelementptr folding, -; but does inhibit combining two GEPs where the inner one has inrange (this -; will be done when DataLayout is available instead). - @nestedarray = global [2 x [4 x ptr]] zeroinitializer -; CHECK: @nestedarray.1 = alias ptr, getelementptr inbounds inrange(-32, 32) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i64 1, i32 0) +; CHECK: @nestedarray.1 = alias ptr, getelementptr inbounds inrange(-32, 32) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i32 0, i32 4) @nestedarray.1 = alias ptr, getelementptr inbounds inrange(-32, 32) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i32 0, i32 4) -; CHECK: @nestedarray.2 = alias ptr, getelementptr inbounds inrange(0, 1) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i64 1, i32 0) +; CHECK: @nestedarray.2 = alias ptr, getelementptr inbounds inrange(0, 1) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i32 0, i32 4) @nestedarray.2 = alias ptr, getelementptr inbounds inrange(0, 1) ([2 x [4 x ptr]], ptr @nestedarray, i32 0, i32 0, i32 4) ; CHECK: @nestedarray.3 = alias ptr, getelementptr inbounds inrange(0, 4) ([4 x ptr], ptr @nestedarray, i32 0, i32 0) diff --git a/llvm/test/Assembler/getelementptr_vec_ce.ll b/llvm/test/Assembler/getelementptr_vec_ce.ll index 2b0d462fec9b..045f8b672edf 100644 --- a/llvm/test/Assembler/getelementptr_vec_ce.ll +++ b/llvm/test/Assembler/getelementptr_vec_ce.ll @@ -3,7 +3,7 @@ @G = global [4 x i32] zeroinitializer ; CHECK-LABEL: @foo -; CHECK: ret <4 x ptr> getelementptr inbounds ([4 x i32], ptr @G, <4 x i32> zeroinitializer, <4 x i32> ) +; CHECK: ret <4 x ptr> getelementptr ([4 x i32], ptr @G, <4 x i32> zeroinitializer, <4 x i32> ) define <4 x ptr> @foo() { ret <4 x ptr> getelementptr ([4 x i32], ptr @G, i32 0, <4 x i32> ) } diff --git a/llvm/test/CodeGen/AMDGPU/opencl-printf.ll b/llvm/test/CodeGen/AMDGPU/opencl-printf.ll index ee5f82f538ef..24a6ab1d6c9b 100644 --- a/llvm/test/CodeGen/AMDGPU/opencl-printf.ll +++ b/llvm/test/CodeGen/AMDGPU/opencl-printf.ll @@ -555,7 +555,7 @@ entry: define amdgpu_kernel void @test_indexed_format_str(i32 %n) { ; R600-LABEL: @test_indexed_format_str( ; R600-NEXT: entry: -; R600-NEXT: [[CALL1:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) getelementptr inbounds ([11 x i8], ptr addrspace(4) @indexed.format.str, i64 0, i32 7), i32 [[N:%.*]]) +; R600-NEXT: [[CALL1:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) getelementptr ([11 x i8], ptr addrspace(4) @indexed.format.str, i64 0, i32 7), i32 [[N:%.*]]) ; R600-NEXT: ret void ; ; GCN-LABEL: @test_indexed_format_str( @@ -583,7 +583,7 @@ entry: define amdgpu_kernel void @test_indexed_format_str_oob(i32 %n) { ; R600-LABEL: @test_indexed_format_str_oob( ; R600-NEXT: entry: -; R600-NEXT: [[CALL1:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) getelementptr inbounds ([11 x i8], ptr addrspace(4) @indexed.format.str, i64 1, i64 0), i32 [[N:%.*]]) +; R600-NEXT: [[CALL1:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) getelementptr ([11 x i8], ptr addrspace(4) @indexed.format.str, i64 0, i64 11), i32 [[N:%.*]]) ; R600-NEXT: ret void ; ; GCN-LABEL: @test_indexed_format_str_oob( @@ -1864,7 +1864,7 @@ entry: define amdgpu_kernel void @test_print_string_indexed(i32 %n) { ; R600-LABEL: @test_print_string_indexed( ; R600-NEXT: entry: -; R600-NEXT: [[PRINTF:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) @.str, ptr addrspace(4) getelementptr inbounds ([32 x i8], ptr addrspace(4) @printed.str.size32, i64 0, i64 15), i32 [[N:%.*]]) +; R600-NEXT: [[PRINTF:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) @.str, ptr addrspace(4) getelementptr ([32 x i8], ptr addrspace(4) @printed.str.size32, i64 0, i64 15), i32 [[N:%.*]]) ; R600-NEXT: ret void ; ; GCN-LABEL: @test_print_string_indexed( @@ -1900,7 +1900,7 @@ entry: define amdgpu_kernel void @test_print_string_indexed_oob(i32 %n) { ; R600-LABEL: @test_print_string_indexed_oob( ; R600-NEXT: entry: -; R600-NEXT: [[PRINTF:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) @.str, ptr addrspace(4) getelementptr inbounds ([32 x i8], ptr addrspace(4) @printed.str.size32, i64 1, i64 0), i32 [[N:%.*]]) +; R600-NEXT: [[PRINTF:%.*]] = call i32 (ptr addrspace(4), ...) @printf(ptr addrspace(4) @.str, ptr addrspace(4) getelementptr ([32 x i8], ptr addrspace(4) @printed.str.size32, i64 0, i64 32), i32 [[N:%.*]]) ; R600-NEXT: ret void ; ; GCN-LABEL: @test_print_string_indexed_oob( diff --git a/llvm/test/Linker/comdat-largest.ll b/llvm/test/Linker/comdat-largest.ll index 02cdfe41ccb9..9c69cccb4b4c 100644 --- a/llvm/test/Linker/comdat-largest.ll +++ b/llvm/test/Linker/comdat-largest.ll @@ -41,7 +41,7 @@ target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32" $foo = comdat largest @foo = linkonce_odr unnamed_addr constant [1 x ptr] [ptr @bar], comdat($foo) -; CHECK: @foo = alias ptr, getelementptr inbounds ([2 x ptr], ptr @some_name, i32 0, i32 1) +; CHECK: @foo = alias ptr, getelementptr ([2 x ptr], ptr @some_name, i32 0, i32 1) declare void @bar() unnamed_addr diff --git a/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt-inseltpoison.ll b/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt-inseltpoison.ll index 469d818af28f..3c5c07f3516c 100644 --- a/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt-inseltpoison.ll +++ b/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt-inseltpoison.ll @@ -73,7 +73,7 @@ define @test_global_array( %indxs, @global_struct_splat( %mask) #0 { ; CHECK-LABEL: @global_struct_splat( -; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.masked.gather.nxv4i32.nxv4p0( shufflevector ( insertelement ( poison, ptr getelementptr inbounds ([[STRUCT_A:%.*]], ptr @c, i64 0, i32 1), i64 0), poison, zeroinitializer), i32 4, [[MASK:%.*]], undef) +; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.masked.gather.nxv4i32.nxv4p0( shufflevector ( insertelement ( poison, ptr getelementptr ([[STRUCT_A:%.*]], ptr @c, i64 0, i32 1), i64 0), poison, zeroinitializer), i32 4, [[MASK:%.*]], undef) ; CHECK-NEXT: ret [[TMP1]] ; %1 = insertelement poison, ptr @c, i32 0 diff --git a/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt.ll b/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt.ll index 6444f6adcdcc..36cd69ed01ed 100644 --- a/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt.ll +++ b/llvm/test/Transforms/CodeGenPrepare/AArch64/gather-scatter-opt.ll @@ -73,7 +73,7 @@ define @test_global_array( %indxs, @global_struct_splat( %mask) #0 { ; CHECK-LABEL: @global_struct_splat( -; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.masked.gather.nxv4i32.nxv4p0( shufflevector ( insertelement ( poison, ptr getelementptr inbounds ([[STRUCT_A:%.*]], ptr @c, i64 0, i32 1), i64 0), poison, zeroinitializer), i32 4, [[MASK:%.*]], undef) +; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.masked.gather.nxv4i32.nxv4p0( shufflevector ( insertelement ( poison, ptr getelementptr ([[STRUCT_A:%.*]], ptr @c, i64 0, i32 1), i64 0), poison, zeroinitializer), i32 4, [[MASK:%.*]], undef) ; CHECK-NEXT: ret [[TMP1]] ; %1 = insertelement undef, ptr @c, i32 0 diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt-inseltpoison.ll b/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt-inseltpoison.ll index e62ba5d5a7f5..124ce321e181 100644 --- a/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt-inseltpoison.ll +++ b/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt-inseltpoison.ll @@ -76,7 +76,7 @@ define <4 x i32> @test_global_array(<4 x i64> %indxs) { define <4 x i32> @global_struct_splat() { ; CHECK-LABEL: @global_struct_splat( -; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> , i32 4, <4 x i1> , <4 x i32> undef) +; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> , i32 4, <4 x i1> , <4 x i32> undef) ; CHECK-NEXT: ret <4 x i32> [[TMP1]] ; %1 = insertelement <4 x ptr> poison, ptr @c, i32 0 diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt.ll b/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt.ll index 7899477afdb2..6c9c844a4ebd 100644 --- a/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt.ll +++ b/llvm/test/Transforms/CodeGenPrepare/X86/gather-scatter-opt.ll @@ -75,7 +75,7 @@ define <4 x i32> @test_global_array(<4 x i64> %indxs) { define <4 x i32> @global_struct_splat() { ; CHECK-LABEL: @global_struct_splat( -; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> , i32 4, <4 x i1> , <4 x i32> undef) +; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> , i32 4, <4 x i1> , <4 x i32> undef) ; CHECK-NEXT: ret <4 x i32> [[TMP1]] ; %1 = insertelement <4 x ptr> undef, ptr @c, i32 0 diff --git a/llvm/test/Transforms/GlobalOpt/globalsra-opaque-ptr.ll b/llvm/test/Transforms/GlobalOpt/globalsra-opaque-ptr.ll index 0591a14c10a2..4dbd9e6e7de1 100644 --- a/llvm/test/Transforms/GlobalOpt/globalsra-opaque-ptr.ll +++ b/llvm/test/Transforms/GlobalOpt/globalsra-opaque-ptr.ll @@ -8,12 +8,12 @@ @g = internal global %T zeroinitializer ;. -; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal unnamed_addr global [[T:%.*]] zeroinitializer +; CHECK: @g = internal unnamed_addr global %T zeroinitializer ;. define void @test1() { ; CHECK-LABEL: @test1( -; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([[T:%.*]], ptr @g, i64 0, i32 1), align 4 -; CHECK-NEXT: store i32 2, ptr getelementptr inbounds ([[T]], ptr @g, i64 0, i32 2), align 4 +; CHECK-NEXT: store i32 1, ptr getelementptr ([[T:%.*]], ptr @g, i64 0, i32 1), align 4 +; CHECK-NEXT: store i32 2, ptr getelementptr ([[T]], ptr @g, i64 0, i32 2), align 4 ; CHECK-NEXT: ret void ; store i32 1, ptr getelementptr (%T, ptr @g, i64 0, i32 1) @@ -23,7 +23,7 @@ define void @test1() { define i32 @load1() { ; CHECK-LABEL: @load1( -; CHECK-NEXT: [[V:%.*]] = load i32, ptr getelementptr inbounds ([[T:%.*]], ptr @g, i64 0, i32 1), align 4 +; CHECK-NEXT: [[V:%.*]] = load i32, ptr getelementptr ([[T:%.*]], ptr @g, i64 0, i32 1), align 4 ; CHECK-NEXT: ret i32 [[V]] ; %v = load i32, ptr getelementptr (%T, ptr @g, i64 0, i32 1) @@ -32,7 +32,7 @@ define i32 @load1() { define i64 @load2() { ; CHECK-LABEL: @load2( -; CHECK-NEXT: [[V:%.*]] = load i64, ptr getelementptr inbounds ([[T:%.*]], ptr @g, i64 0, i32 2), align 4 +; CHECK-NEXT: [[V:%.*]] = load i64, ptr getelementptr ([[T:%.*]], ptr @g, i64 0, i32 2), align 4 ; CHECK-NEXT: ret i64 [[V]] ; %v = load i64, ptr getelementptr (%T, ptr @g, i64 0, i32 2) diff --git a/llvm/test/Transforms/GlobalSplit/basic.ll b/llvm/test/Transforms/GlobalSplit/basic.ll index eb1515741763..c297547d2042 100644 --- a/llvm/test/Transforms/GlobalSplit/basic.ll +++ b/llvm/test/Transforms/GlobalSplit/basic.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -; CHECK: @vtt = constant [3 x ptr] [ptr @global.0, ptr getelementptr inbounds (i8, ptr @global.0, i64 8), ptr @global.1] +; CHECK: @vtt = constant [3 x ptr] [ptr @global.0, ptr getelementptr (i8, ptr @global.0, i64 8), ptr @global.1] @vtt = constant [3 x ptr] [ ptr getelementptr inrange(0, 16) ({ [2 x ptr], [1 x ptr] }, ptr @global, i32 0, i32 0, i32 0), ptr getelementptr inrange(-8, 8) ({ [2 x ptr], [1 x ptr] }, ptr @global, i32 0, i32 0, i32 1), @@ -27,7 +27,7 @@ define ptr @f1() { ; CHECK: define ptr @f2() define ptr @f2() { - ; CHECK-NEXT: ret ptr getelementptr inbounds (i8, ptr @global.0, i64 8) + ; CHECK-NEXT: ret ptr getelementptr (i8, ptr @global.0, i64 8) ret ptr getelementptr inrange(-8, 8) ({ [2 x ptr], [1 x ptr] }, ptr @global, i32 0, i32 0, i32 1) } diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-address-space.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-address-space.ll index 4290e4f70588..7f0fcd0b97ab 100644 --- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-address-space.ll +++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-address-space.ll @@ -93,7 +93,7 @@ bb: define amdgpu_kernel void @nested_const_expr() #0 { ; CHECK-LABEL: define amdgpu_kernel void @nested_const_expr( ; CHECK-SAME: ) #[[ATTR0]] { -; CHECK-NEXT: store i32 1, ptr addrspace(3) getelementptr inbounds ([10 x float], ptr addrspace(3) @array, i64 0, i64 1), align 4 +; CHECK-NEXT: store i32 1, ptr addrspace(3) getelementptr ([10 x float], ptr addrspace(3) @array, i64 0, i64 1), align 4 ; CHECK-NEXT: ret void ; store i32 1, ptr bitcast (ptr getelementptr ([10 x float], ptr addrspacecast (ptr addrspace(3) @array to ptr), i64 0, i64 1) to ptr), align 4 diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll index dc36e936fca5..2f6640ce9854 100644 --- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll +++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/infer-getelementptr.ll @@ -20,7 +20,7 @@ define void @simplified_constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) { define void @constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) { ; CHECK-LABEL: @constexpr_gep_addrspacecast( -; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr inbounds ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] +; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] ; CHECK-NEXT: store double 1.000000e+00, ptr addrspace(3) [[GEP0]], align 8 ; CHECK-NEXT: ret void ; @@ -32,7 +32,7 @@ define void @constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) { define void @constexpr_gep_gep_addrspacecast(i64 %idx0, i64 %idx1) { ; CHECK-LABEL: @constexpr_gep_gep_addrspacecast( -; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr inbounds ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] +; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds double, ptr addrspace(3) [[GEP0]], i64 [[IDX1:%.*]] ; CHECK-NEXT: store double 1.000000e+00, ptr addrspace(3) [[GEP1]], align 8 ; CHECK-NEXT: ret void @@ -74,9 +74,9 @@ define amdgpu_kernel void @vector_gep(<4 x ptr addrspace(3)> %array) nounwind { define void @repeated_constexpr_gep_addrspacecast(i64 %idx0, i64 %idx1) { ; CHECK-LABEL: @repeated_constexpr_gep_addrspacecast( -; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr inbounds ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] +; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX0:%.*]] ; CHECK-NEXT: store double 1.000000e+00, ptr addrspace(3) [[GEP0]], align 8 -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr inbounds ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX1:%.*]] +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds double, ptr addrspace(3) getelementptr ([648 x double], ptr addrspace(3) @lds, i64 0, i64 384), i64 [[IDX1:%.*]] ; CHECK-NEXT: store double 1.000000e+00, ptr addrspace(3) [[GEP1]], align 8 ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions-inseltpoison.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions-inseltpoison.ll index 9a100c2ab5f7..5a2244b9796e 100644 --- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions-inseltpoison.ll +++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions-inseltpoison.ll @@ -8,7 +8,7 @@ ; Should generate flat load ; CHECK-LABEL: @generic_address_bitcast_const( -; CHECK: %vecload1 = load <2 x double>, ptr addrspace(1) getelementptr inbounds ([100 x double], ptr addrspace(1) @data, i64 0, i64 4), align 8 +; CHECK: %vecload1 = load <2 x double>, ptr addrspace(1) getelementptr ([100 x double], ptr addrspace(1) @data, i64 0, i64 4), align 8 define amdgpu_kernel void @generic_address_bitcast_const(i64 %arg0, ptr addrspace(1) nocapture %results) #0 { entry: %tmp1 = call i32 @llvm.amdgcn.workitem.id.x() diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions.ll index 59e3766cc107..d2b4b98cc80b 100644 --- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions.ll +++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/old-pass-regressions.ll @@ -8,7 +8,7 @@ ; Should generate flat load ; CHECK-LABEL: @generic_address_bitcast_const( -; CHECK: %vecload1 = load <2 x double>, ptr addrspace(1) getelementptr inbounds ([100 x double], ptr addrspace(1) @data, i64 0, i64 4), align 8 +; CHECK: %vecload1 = load <2 x double>, ptr addrspace(1) getelementptr ([100 x double], ptr addrspace(1) @data, i64 0, i64 4), align 8 define amdgpu_kernel void @generic_address_bitcast_const(i64 %arg0, ptr addrspace(1) nocapture %results) #0 { entry: %tmp1 = call i32 @llvm.amdgcn.workitem.id.x() diff --git a/llvm/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll b/llvm/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll index 23c5f99e5d08..753e7b505317 100644 --- a/llvm/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll +++ b/llvm/test/Transforms/InferAddressSpaces/NVPTX/bug31948.ll @@ -11,11 +11,11 @@ define void @bug31948(float %a, ptr nocapture readnone %x, ptr nocapture readnon ; CHECK-LABEL: define void @bug31948( ; CHECK-SAME: float [[A:%.*]], ptr nocapture readnone [[X:%.*]], ptr nocapture readnone [[Y:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr addrspace(3) getelementptr inbounds ([[STRUCT_BAR:%.*]], ptr addrspace(3) @var1, i64 0, i32 1), align 8 +; CHECK-NEXT: [[TMP:%.*]] = load ptr, ptr addrspace(3) getelementptr ([[STRUCT_BAR:%.*]], ptr addrspace(3) @var1, i64 0, i32 1), align 8 ; CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[TMP]], align 4 ; CHECK-NEXT: [[CONV1:%.*]] = fadd float [[TMP1]], 1.000000e+00 ; CHECK-NEXT: store float [[CONV1]], ptr [[TMP]], align 4 -; CHECK-NEXT: store i32 32, ptr addrspace(3) getelementptr inbounds ([[STRUCT_BAR]], ptr addrspace(3) @var1, i64 0, i32 1), align 4 +; CHECK-NEXT: store i32 32, ptr addrspace(3) getelementptr ([[STRUCT_BAR]], ptr addrspace(3) @var1, i64 0, i32 1), align 4 ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/InferAlignment/gep-array.ll b/llvm/test/Transforms/InferAlignment/gep-array.ll index 6f6051144b71..5008e38a119d 100644 --- a/llvm/test/Transforms/InferAlignment/gep-array.ll +++ b/llvm/test/Transforms/InferAlignment/gep-array.ll @@ -40,8 +40,8 @@ define void @simple_pair(i64 %idx) { define void @load_nested() { ; CHECK-LABEL: define void @load_nested() { ; CHECK-NEXT: [[X_0:%.*]] = load i32, ptr @array.array, align 16 -; CHECK-NEXT: [[X_1:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4 -; CHECK-NEXT: [[X_2:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8 +; CHECK-NEXT: [[X_1:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4 +; CHECK-NEXT: [[X_2:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8 ; CHECK-NEXT: [[X_3:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4 ; CHECK-NEXT: [[X_4:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 16 ; CHECK-NEXT: ret void @@ -57,8 +57,8 @@ define void @load_nested() { define void @store_nested() { ; CHECK-LABEL: define void @store_nested() { ; CHECK-NEXT: store i32 1, ptr @array.array, align 16 -; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4 -; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8 +; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4 +; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8 ; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4 ; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 16 ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/InstCombine/gep-vector.ll b/llvm/test/Transforms/InstCombine/gep-vector.ll index f058338fbf7c..4d20323b7896 100644 --- a/llvm/test/Transforms/InstCombine/gep-vector.ll +++ b/llvm/test/Transforms/InstCombine/gep-vector.ll @@ -5,7 +5,7 @@ define <2 x ptr> @vectorindex1() { ; CHECK-LABEL: @vectorindex1( -; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> zeroinitializer) +; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> ) ; %1 = getelementptr inbounds [64 x [8192 x i8]], ptr @block, i64 0, <2 x i64> , i64 8192 ret <2 x ptr> %1 @@ -13,7 +13,7 @@ define <2 x ptr> @vectorindex1() { define <2 x ptr> @vectorindex2() { ; CHECK-LABEL: @vectorindex2( -; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> ) +; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> ) ; %1 = getelementptr inbounds [64 x [8192 x i8]], ptr @block, i64 0, i64 1, <2 x i64> ret <2 x ptr> %1 @@ -21,7 +21,7 @@ define <2 x ptr> @vectorindex2() { define <2 x ptr> @vectorindex3() { ; CHECK-LABEL: @vectorindex3( -; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> ) +; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds ([64 x [8192 x i8]], ptr @block, <2 x i64> zeroinitializer, <2 x i64> , <2 x i64> ) ; %1 = getelementptr inbounds [64 x [8192 x i8]], ptr @block, i64 0, <2 x i64> , <2 x i64> ret <2 x ptr> %1 diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/vectorgep-crash.ll b/llvm/test/Transforms/InstSimplify/ConstProp/vectorgep-crash.ll index 00ee7f8a92b2..2be619828e9e 100644 --- a/llvm/test/Transforms/InstSimplify/ConstProp/vectorgep-crash.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/vectorgep-crash.ll @@ -64,7 +64,7 @@ define <2 x ptr> @constant_undef_index() { define <2 x ptr> @constant_inbounds() { ; CHECK-LABEL: define <2 x ptr> @constant_inbounds() { -; CHECK-NEXT: ret <2 x ptr> getelementptr inbounds (i8, ptr @g, <2 x i64> ) +; CHECK-NEXT: ret <2 x ptr> getelementptr (i8, ptr @g, <2 x i64> ) ; %gep = getelementptr i8, ptr @g, <2 x i64> ret <2 x ptr> %gep diff --git a/llvm/test/Transforms/InstSimplify/vector_gep.ll b/llvm/test/Transforms/InstSimplify/vector_gep.ll index 79aa9f13d1ea..a1d0bd379aa7 100644 --- a/llvm/test/Transforms/InstSimplify/vector_gep.ll +++ b/llvm/test/Transforms/InstSimplify/vector_gep.ll @@ -67,7 +67,7 @@ define <4 x ptr> @test5() { define <16 x ptr> @test6() { ; CHECK-LABEL: define <16 x ptr> @test6() { -; CHECK-NEXT: ret <16 x ptr> getelementptr inbounds ([24 x [42 x [3 x i32]]], ptr @v, <16 x i64> zeroinitializer, <16 x i64> zeroinitializer, <16 x i64> , <16 x i64> zeroinitializer) +; CHECK-NEXT: ret <16 x ptr> getelementptr ([24 x [42 x [3 x i32]]], ptr @v, <16 x i64> zeroinitializer, <16 x i64> zeroinitializer, <16 x i64> , <16 x i64> zeroinitializer) ; %VectorGep = getelementptr [24 x [42 x [3 x i32]]], ptr @v, i64 0, i64 0, <16 x i64> , i64 0 ret <16 x ptr> %VectorGep diff --git a/llvm/test/Transforms/NewGVN/2007-07-26-InterlockingLoops.ll b/llvm/test/Transforms/NewGVN/2007-07-26-InterlockingLoops.ll index 52b4a595b58a..0111266d03fd 100644 --- a/llvm/test/Transforms/NewGVN/2007-07-26-InterlockingLoops.ll +++ b/llvm/test/Transforms/NewGVN/2007-07-26-InterlockingLoops.ll @@ -8,7 +8,7 @@ define i32 @NextRootMove(i32 %wtm, i32 %x, i32 %y, i32 %z) { ; CHECK-SAME: (i32 [[WTM:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 -; CHECK-NEXT: [[TMP17618:%.*]] = load ptr, ptr getelementptr inbounds ([65 x ptr], ptr @last, i32 0, i32 1), align 4 +; CHECK-NEXT: [[TMP17618:%.*]] = load ptr, ptr getelementptr ([65 x ptr], ptr @last, i32 0, i32 1), align 4 ; CHECK-NEXT: store ptr [[TMP17618]], ptr [[A]], align 8 ; CHECK-NEXT: br label [[COND_TRUE116:%.*]] ; CHECK: cond_true116: diff --git a/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir b/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir index be8145dc9075..f263180d4240 100644 --- a/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-constant-indexing-device-region.mlir @@ -37,6 +37,6 @@ module attributes {omp.is_target_device = true} { // CHECK: store ptr %[[ARG1]], ptr %[[ARG1_ALLOCA]], align 8 // CHECK: %[[LOAD_ARG1_ALLOCA:.*]] = load ptr, ptr %[[ARG1_ALLOCA]], align 8 // CHECK: store i32 20, ptr %[[LOAD_ARG1_ALLOCA]], align 4 -// CHECK: %[[GEP_ARG1_ALLOCA:.*]] = getelementptr inbounds [10 x i32], ptr %[[LOAD_ARG1_ALLOCA]], i32 0, i64 4 +// CHECK: %[[GEP_ARG1_ALLOCA:.*]] = getelementptr [10 x i32], ptr %[[LOAD_ARG1_ALLOCA]], i32 0, i64 4 // CHECK: store i32 10, ptr %[[GEP_ARG1_ALLOCA]], align 4 diff --git a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir index 429bb379ee1b..9b46f84e5050 100644 --- a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir @@ -66,9 +66,9 @@ module attributes {omp.is_target_device = false} { // CHECK: define void @_QQmain() // CHECK: %[[SCALAR_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8 -// CHECK: %[[FULL_ARR_SIZE5:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @[[FULL_ARR_GLOB]], i32 0, i32 7, i64 0, i32 1), align 4 +// CHECK: %[[FULL_ARR_SIZE5:.*]] = load i64, ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @[[FULL_ARR_GLOB]], i32 0, i32 7, i64 0, i32 1), align 4 // CHECK: %[[FULL_ARR_SIZE4:.*]] = sub i64 %[[FULL_ARR_SIZE5]], 1 -// CHECK: %[[ARR_SECT_OFFSET3:.*]] = load i64, ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @[[ARR_SECT_GLOB]], i32 0, i32 7, i64 0, i32 0), align 4 +// CHECK: %[[ARR_SECT_OFFSET3:.*]] = load i64, ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @[[ARR_SECT_GLOB]], i32 0, i32 7, i64 0, i32 0), align 4 // CHECK: %[[ARR_SECT_OFFSET2:.*]] = sub i64 2, %[[ARR_SECT_OFFSET3]] // CHECK: %[[ARR_SECT_SIZE4:.*]] = sub i64 5, %[[ARR_SECT_OFFSET3]] // CHECK: %[[SCALAR_BASE:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 0, i32 0 @@ -86,8 +86,8 @@ module attributes {omp.is_target_device = false} { // CHECK: %[[LARR_SECT:.*]] = load ptr, ptr @_QFEsect_arr, align 8 // CHECK: %[[ARR_SECT_PTR:.*]] = getelementptr inbounds i32, ptr %[[LARR_SECT]], i64 %[[ARR_SECT_OFFSET1]] // CHECK: %[[SCALAR_PTR_LOAD:.*]] = load ptr, ptr %[[SCALAR_BASE]], align 8 -// CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEfull_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -// CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr inbounds ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEsect_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEfull_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEsect_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) // CHECK: %[[SCALAR_DESC_SZ4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 1 // CHECK: %[[SCALAR_DESC_SZ3:.*]] = ptrtoint ptr %[[SCALAR_DESC_SZ4]] to i64 // CHECK: %[[SCALAR_DESC_SZ2:.*]] = ptrtoint ptr %[[SCALAR_ALLOCA]] to i64 -- GitLab From 1ac592c4e7b4ba7c680af9286ad79ed27ad628f1 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Thu, 30 May 2024 03:43:27 -0300 Subject: [PATCH 017/243] [clang] fix merging of UsingShadowDecl (#80245) [clang] fix merging of UsingShadowDecl Previously, when deciding if two UsingShadowDecls where mergeable, we would incorrectly only look for both pointing to the exact redecla ration, whereas the correct thing is to look for declarations to the same entity. This problem has existed as far back as 2013, introduced in commit fd8634a09de71. This problem could manifest itself as ODR check false positives when importing modules. Fixes: #80252 --- clang/docs/ReleaseNotes.rst | 3 +++ clang/lib/AST/ASTContext.cpp | 2 +- clang/test/Modules/cxx20-decls.cppm | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 44035f48cb3f..9dc93f53fe71 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -813,6 +813,9 @@ Bug Fixes to C++ Support - Clang now allows ``@$``` in raw string literals. Fixes (#GH93130). - Fix an assertion failure when checking invalid ``this`` usage in the wrong context. (Fixes #GH91536). - Clang no longer models dependent NTTP arguments as ``TemplateParamObjectDecl`` s. Fixes (#GH84052). +- Fix incorrect merging of modules which contain using declarations which shadow + other declarations. This could manifest as ODR checker false positives. + Fixes (`#80252 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 06780ceba407..73d3b152c49f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6794,7 +6794,7 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { // Using shadow declarations with the same target match. if (const auto *USX = dyn_cast(X)) { const auto *USY = cast(Y); - return USX->getTargetDecl() == USY->getTargetDecl(); + return declaresSameEntity(USX->getTargetDecl(), USY->getTargetDecl()); } // Using declarations with the same qualifier match. (We already know that diff --git a/clang/test/Modules/cxx20-decls.cppm b/clang/test/Modules/cxx20-decls.cppm index 9f0c40685b68..0e8b59708ab4 100644 --- a/clang/test/Modules/cxx20-decls.cppm +++ b/clang/test/Modules/cxx20-decls.cppm @@ -28,8 +28,8 @@ using xxx = baz::foo; // CHECK-NEXT: NamespaceDecl 0x[[BAZ_REDECL_ADDR:[^ ]*]] prev 0x[[BAZ_ADDR:[^ ]*]] // CHECK: TypeAliasDecl 0x[[ALIAS_REDECL_ADDR:[^ ]*]] prev 0x[[ALIAS_ADDR:[^ ]*]] // FIXME: UsingShadowDecl should have been merged -// CHECK: UsingShadowDecl 0x{{[^ ]*}} <{{.*}}> col:{{.*}} imported in A. hidden implicit TypeAlias 0x[[ALIAS_REDECL_ADDR]] 'foo' +// CHECK: UsingShadowDecl 0x{{[^ ]*}} prev 0x[[SHADOW_ADDR:[^ ]*]] {{.*}} imported in A. {{.*}} 'foo' // CHECK-LABEL: Dumping baz: // CHECK-NEXT: NamespaceDecl 0x[[BAZ_ADDR]] <{{.*}}> line:{{.*}} baz -// CHECK: UsingShadowDecl 0x[[SHADOW_ADDR:[^ ]*]] <{{.*}}> col:{{.*}} implicit TypeAlias 0x[[ALIAS_ADDR]] 'foo' +// CHECK: UsingShadowDecl 0x[[SHADOW_ADDR]] {{.*}} 'foo' -- GitLab From 73f4c2547dc3d1b6a453d3c4388648b122554dd1 Mon Sep 17 00:00:00 2001 From: Freddy Ye Date: Thu, 30 May 2024 14:47:47 +0800 Subject: [PATCH 018/243] [X86] Support EGPR for inline assembly. (#92338) "jR": explicitly enables EGPR "r", "l", "q": enables/disables EGPR w/wo -mapx-inline-asm-use-gpr32 "jr": explicitly enables GPR with -mapx-inline-asm-use-gpr32 -mapx-inline-asm-use-gpr32 will also define a new macro: `__APX_INLINE_ASM_USE_GPR32__` GCC patches: https://gcc.gnu.org/pipermail/gcc-patches/2023-September/631183.html https://gcc.gnu.org/pipermail/gcc-patches/2023-September/631186.html [[PATCH v2] x86: Define _APX_INLINE_ASM_USE_GPR32_ (gnu.org)](https://gcc.gnu.org/pipermail/gcc-patches/2024-April/649003.html) Reference: https://gcc.godbolt.org/z/nPPvbY6r4 --- clang/include/clang/Driver/Options.td | 2 + clang/lib/Basic/Targets/X86.cpp | 30 +++++++ clang/lib/Basic/Targets/X86.h | 1 + clang/lib/Driver/ToolChains/Arch/X86.cpp | 2 + .../Driver/x86-apx-inline-asm-use-gpr32.cpp | 3 + clang/test/Preprocessor/x86_target_features.c | 5 ++ llvm/docs/LangRef.rst | 10 ++- llvm/lib/Target/X86/X86.td | 3 + llvm/lib/Target/X86/X86ISelLowering.cpp | 83 +++++++++++++++++-- .../test/CodeGen/X86/apx/asm-constraint-jR.ll | 17 ++++ .../test/CodeGen/X86/apx/asm-constraint-jr.ll | 28 +++++++ llvm/test/CodeGen/X86/apx/asm-constraint.ll | 19 +++-- 12 files changed, 186 insertions(+), 17 deletions(-) create mode 100644 clang/test/Driver/x86-apx-inline-asm-use-gpr32.cpp create mode 100644 llvm/test/CodeGen/X86/apx/asm-constraint-jR.ll create mode 100644 llvm/test/CodeGen/X86/apx/asm-constraint-jr.ll diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4119e69c8554..1637a114fcce 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6280,6 +6280,8 @@ def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; def mno_apxf : Flag<["-"], "mno-apxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; +def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group, + HelpText<"Enable use of GPR32 in inline assembly for APX">; } // let Flags = [TargetSpecific] // VE feature flags diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 08e44360bfbe..34d249ed27ce 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -441,6 +441,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasFullBFloat16 = true; } else if (Feature == "+egpr") { HasEGPR = true; + } else if (Feature == "+inline-asm-use-gpr32") { + HasInlineAsmUseGPR32 = true; } else if (Feature == "+push2pop2") { HasPush2Pop2 = true; } else if (Feature == "+ppx") { @@ -963,6 +965,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, // Condition here is aligned with the feature set of mapxf in Options.td if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD && HasCCMP && HasNF) Builder.defineMacro("__APX_F__"); + if (HasEGPR && HasInlineAsmUseGPR32) + Builder.defineMacro("__APX_INLINE_ASM_USE_GPR32__"); // Each case falls through to the previous one here. switch (SSELevel) { @@ -1478,6 +1482,18 @@ bool X86TargetInfo::validateAsmConstraint( case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; + case 'j': + Name++; + switch (*Name) { + default: + return false; + case 'r': + Info.setAllowsRegister(); + return true; + case 'R': + Info.setAllowsRegister(); + return true; + } case '@': // CC condition changes. if (auto Len = matchAsmCCConstraint(Name)) { @@ -1749,6 +1765,20 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { // to the next constraint. return std::string("^") + std::string(Constraint++, 2); } + case 'j': + switch (Constraint[1]) { + default: + // Break from inner switch and fall through (copy single char), + // continue parsing after copying the current constraint into + // the return string. + break; + case 'r': + case 'R': + // "^" hints llvm that this is a 2 letter constraint. + // "Constraint++" is used to promote the string iterator + // to the next constraint. + return std::string("^") + std::string(Constraint++, 2); + } [[fallthrough]]; default: return std::string(1, *Constraint); diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 0633b7e0da96..9b2ae87adb2e 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -172,6 +172,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasCCMP = false; bool HasNF = false; bool HasCF = false; + bool HasInlineAsmUseGPR32 = false; protected: llvm::X86::CPUKind CPU = llvm::X86::CK_None; diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 8295d001ec6f..75f9c99d5d0b 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -310,4 +310,6 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back("+prefer-no-gather"); if (Args.hasArg(options::OPT_mno_scatter)) Features.push_back("+prefer-no-scatter"); + if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32)) + Features.push_back("+inline-asm-use-gpr32"); } diff --git a/clang/test/Driver/x86-apx-inline-asm-use-gpr32.cpp b/clang/test/Driver/x86-apx-inline-asm-use-gpr32.cpp new file mode 100644 index 000000000000..a45140d96e66 --- /dev/null +++ b/clang/test/Driver/x86-apx-inline-asm-use-gpr32.cpp @@ -0,0 +1,3 @@ +/// Tests -mapx-inline-asm-use-gpr32 +// RUN: %clang -target x86_64-unknown-linux-gnu -c -mapx-inline-asm-use-gpr32 -### %s 2>&1 | FileCheck --check-prefix=GPR32 %s +// GPR32: "-target-feature" "+inline-asm-use-gpr32" diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c index 6c08b379c938..3e63e2c77fdd 100644 --- a/clang/test/Preprocessor/x86_target_features.c +++ b/clang/test/Preprocessor/x86_target_features.c @@ -763,3 +763,8 @@ // NF: #define __NF__ 1 // PPX: #define __PPX__ 1 // PUSH2POP2: #define __PUSH2POP2__ 1 + +// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=NOUSEGPR32 %s +// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=egpr -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=USEGPR32 %s +// NOUSEGPR32-NOT: #define __APX_INLINE_ASM_USE_GPR32__ 1 +// USEGPR32: #define __APX_INLINE_ASM_USE_GPR32__ 1 diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 7b64c477d13c..c58f7f7140e4 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5428,10 +5428,12 @@ X86: - ``Z``: An immediate 32-bit unsigned integer. - ``q``: An 8, 16, 32, or 64-bit register which can be accessed as an 8-bit ``l`` integer register. On X86-32, this is the ``a``, ``b``, ``c``, and ``d`` - registers, and on X86-64, it is all of the integer registers. + registers, and on X86-64, it is all of the integer registers. When feature + `egpr` and `inline-asm-use-gpr32` are both on, it will be extended to gpr32. - ``Q``: An 8, 16, 32, or 64-bit register which can be accessed as an 8-bit ``h`` integer register. This is the ``a``, ``b``, ``c``, and ``d`` registers. -- ``r`` or ``l``: An 8, 16, 32, or 64-bit integer register. +- ``r`` or ``l``: An 8, 16, 32, or 64-bit integer register. When feature + `egpr` and `inline-asm-use-gpr32` are both on, it will be extended to gpr32. - ``R``: An 8, 16, 32, or 64-bit "legacy" integer register -- one which has existed since i386, and can be accessed without the REX prefix. - ``f``: A 32, 64, or 80-bit '387 FPU stack pseudo-register. @@ -5452,6 +5454,10 @@ X86: operand will get allocated only to RAX -- if two 32-bit operands are needed, you're better off splitting it yourself, before passing it to the asm statement. +- ``jr``: An 8, 16, 32, or 64-bit integer gpr16. It won't be extended to gpr32 + when feature `egpr` or `inline-asm-use-gpr32` is on. +- ``jR``: An 8, 16, 32, or 64-bit integer gpr32 when feature `egpr`` is on. + Otherwise, same as ``r``. XCore: diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td index 7e8133e3e1ac..628ff560017e 100644 --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -346,6 +346,9 @@ def FeatureNF : SubtargetFeature<"nf", "HasNF", "true", "Support status flags update suppression">; def FeatureCF : SubtargetFeature<"cf", "HasCF", "true", "Support conditional faulting">; +def FeatureUseGPR32InInlineAsm + : SubtargetFeature<"inline-asm-use-gpr32", "UseInlineAsmGPR32", "true", + "Enable use of GPR32 in inline assembly for APX">; // Ivy Bridge and newer processors have enhanced REP MOVSB and STOSB (aka // "string operations"). See "REP String Enhancement" in the Intel Software diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index ac30e8846be5..f5d0e1b15d7a 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -57840,6 +57840,15 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const { case '2': return C_RegisterClass; } + break; + case 'j': + switch (Constraint[1]) { + default: + break; + case 'r': + case 'R': + return C_RegisterClass; + } } } else if (parseConstraintCode(Constraint) != X86::COND_INVALID) return C_Other; @@ -57919,6 +57928,19 @@ X86TargetLowering::getSingleConstraintMatchWeight( break; } break; + case 'j': + if (StringRef(Constraint).size() != 2) + break; + switch (Constraint[1]) { + default: + return CW_Invalid; + case 'r': + case 'R': + if (CallOperandVal->getType()->isIntegerTy()) + Wt = CW_SpecificReg; + break; + } + break; case 'v': if ((Ty->getPrimitiveSizeInBits() == 512) && Subtarget.hasAVX512()) Wt = CW_Register; @@ -58218,6 +58240,10 @@ static bool isVKClass(const TargetRegisterClass &RC) { RC.hasSuperClassEq(&X86::VK64RegClass); } +static bool useEGPRInlineAsm(const X86Subtarget &Subtarget) { + return Subtarget.hasEGPR() && Subtarget.useInlineAsmGPR32(); +} + std::pair X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, @@ -58258,13 +58284,21 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, case 'q': // GENERAL_REGS in 64-bit mode, Q_REGS in 32-bit mode. if (Subtarget.is64Bit()) { if (VT == MVT::i8 || VT == MVT::i1) - return std::make_pair(0U, &X86::GR8_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR8RegClass + : &X86::GR8_NOREX2RegClass); if (VT == MVT::i16) - return std::make_pair(0U, &X86::GR16_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR16RegClass + : &X86::GR16_NOREX2RegClass); if (VT == MVT::i32 || VT == MVT::f32) - return std::make_pair(0U, &X86::GR32_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR32RegClass + : &X86::GR32_NOREX2RegClass); if (VT != MVT::f80 && !VT.isVector()) - return std::make_pair(0U, &X86::GR64_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR64RegClass + : &X86::GR64_NOREX2RegClass); break; } [[fallthrough]]; @@ -58283,14 +58317,22 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, case 'r': // GENERAL_REGS case 'l': // INDEX_REGS if (VT == MVT::i8 || VT == MVT::i1) - return std::make_pair(0U, &X86::GR8_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR8RegClass + : &X86::GR8_NOREX2RegClass); if (VT == MVT::i16) - return std::make_pair(0U, &X86::GR16_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR16RegClass + : &X86::GR16_NOREX2RegClass); if (VT == MVT::i32 || VT == MVT::f32 || (!VT.isVector() && !Subtarget.is64Bit())) - return std::make_pair(0U, &X86::GR32_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR32RegClass + : &X86::GR32_NOREX2RegClass); if (VT != MVT::f80 && !VT.isVector()) - return std::make_pair(0U, &X86::GR64_NOREX2RegClass); + return std::make_pair(0U, useEGPRInlineAsm(Subtarget) + ? &X86::GR64RegClass + : &X86::GR64_NOREX2RegClass); break; case 'R': // LEGACY_REGS if (VT == MVT::i8 || VT == MVT::i1) @@ -58514,6 +58556,31 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, } break; } + } else if (Constraint.size() == 2 && Constraint[0] == 'j') { + switch (Constraint[1]) { + default: + break; + case 'r': + if (VT == MVT::i8 || VT == MVT::i1) + return std::make_pair(0U, &X86::GR8_NOREX2RegClass); + if (VT == MVT::i16) + return std::make_pair(0U, &X86::GR16_NOREX2RegClass); + if (VT == MVT::i32 || VT == MVT::f32) + return std::make_pair(0U, &X86::GR32_NOREX2RegClass); + if (VT != MVT::f80 && !VT.isVector()) + return std::make_pair(0U, &X86::GR64_NOREX2RegClass); + break; + case 'R': + if (VT == MVT::i8 || VT == MVT::i1) + return std::make_pair(0U, &X86::GR8RegClass); + if (VT == MVT::i16) + return std::make_pair(0U, &X86::GR16RegClass); + if (VT == MVT::i32 || VT == MVT::f32) + return std::make_pair(0U, &X86::GR32RegClass); + if (VT != MVT::f80 && !VT.isVector()) + return std::make_pair(0U, &X86::GR64RegClass); + break; + } } if (parseConstraintCode(Constraint) != X86::COND_INVALID) diff --git a/llvm/test/CodeGen/X86/apx/asm-constraint-jR.ll b/llvm/test/CodeGen/X86/apx/asm-constraint-jR.ll new file mode 100644 index 000000000000..32b84915c679 --- /dev/null +++ b/llvm/test/CodeGen/X86/apx/asm-constraint-jR.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: not llc -mtriple=x86_64 %s 2>&1 | FileCheck %s --check-prefix=ERR +; RUN: llc -mtriple=x86_64 -mattr=+egpr < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -mattr=+egpr,+inline-asm-use-gpr32 < %s | FileCheck %s +; RUN: not llc -mtriple=x86_64 -mattr=+inline-asm-use-gpr32 %s 2>&1 | FileCheck %s --check-prefix=ERR + +; ERR: error: inline assembly requires more registers than available + +define void @constraint_jR_test() nounwind { +; CHECK-LABEL: constraint_jR_test: +; CHECK: addq %r16, %rax +entry: + %reg = alloca i64, align 8 + %0 = load i64, ptr %reg, align 8 + call void asm sideeffect "add $0, %rax", "^jR,~{rax},~{rbx},~{rbp},~{rcx},~{rdx},~{rdi},~{rsi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(i64 %0) + ret void +} diff --git a/llvm/test/CodeGen/X86/apx/asm-constraint-jr.ll b/llvm/test/CodeGen/X86/apx/asm-constraint-jr.ll new file mode 100644 index 000000000000..0c6d6a78cfb1 --- /dev/null +++ b/llvm/test/CodeGen/X86/apx/asm-constraint-jr.ll @@ -0,0 +1,28 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: not llc -mtriple=x86_64 < %s >%t1 2>%t2 +; RUN: FileCheck %s <%t1 +; RUN: FileCheck %s <%t2 --check-prefix=ERR +; RUN: not llc -mattr=+egpr -mtriple=x86_64 < %s >%t1 2>%t2 +; RUN: FileCheck %s <%t1 +; RUN: FileCheck %s <%t2 --check-prefix=ERR +; RUN: not llc -mattr=+egpr,+inline-asm-use-gpr32 -mtriple=x86_64 < %s >%t1 2>%t2 +; RUN: FileCheck %s <%t1 +; RUN: FileCheck %s <%t2 --check-prefix=ERR + +; CHECK: addq %r8, %rax +define void @constraint_jr_test() nounwind { +entry: + %reg = alloca i64, align 8 + %0 = load i64, ptr %reg, align 8 + call void asm sideeffect "add $0, %rax", "^jr,~{rax},~{rbx},~{rbp},~{rcx},~{rdx},~{rdi},~{rsi},~{dirflag},~{fpsr},~{flags}"(i64 %0) + ret void +} + +; ERR: error: inline assembly requires more registers than available +define void @constraint_jr_test_err() nounwind { +entry: + %reg = alloca i64, align 8 + %0 = load i64, ptr %reg, align 8 + call void asm sideeffect "add $0, %rax", "^jr,~{rax},~{rbx},~{rbp},~{rcx},~{rdx},~{rdi},~{rsi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(i64 %0) + ret void +} diff --git a/llvm/test/CodeGen/X86/apx/asm-constraint.ll b/llvm/test/CodeGen/X86/apx/asm-constraint.ll index 9b81cbf29c25..114e8152e975 100644 --- a/llvm/test/CodeGen/X86/apx/asm-constraint.ll +++ b/llvm/test/CodeGen/X86/apx/asm-constraint.ll @@ -1,21 +1,26 @@ ; Check r16-r31 can not be used with 'q','r','l' constraint for backward compatibility. -; RUN: not llc < %s -mtriple=x86_64-unknown-unknown -mattr=+egpr 2>&1 | FileCheck %s +; RUN: not llc -mtriple=x86_64 < %s 2>&1 | FileCheck %s --check-prefix=ERR +; RUN: not llc -mtriple=x86_64 -mattr=+egpr < %s 2>&1 | FileCheck %s --check-prefix=ERR +; RUN: llc -mtriple=x86_64 -mattr=+egpr,+inline-asm-use-gpr32 < %s | FileCheck %s define void @q() { -; CHECK: error: inline assembly requires more registers than available - %a = call i32 asm sideeffect "movq %rax, $0", "=q,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() +; ERR: error: inline assembly requires more registers than available +; CHECK: movq %rax, %r16 + %a = call i64 asm sideeffect "movq %rax, $0", "=q,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() ret void } define void @r() { -; CHECK: error: inline assembly requires more registers than available - %a = call i32 asm sideeffect "movq %rax, $0", "=r,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() +; ERR: error: inline assembly requires more registers than available +; CHECK: movq %rax, %r16 + %a = call i64 asm sideeffect "movq %rax, $0", "=r,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() ret void } define void @l() { -; CHECK: error: inline assembly requires more registers than available - %a = call i32 asm sideeffect "movq %rax, $0", "=l,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() +; ERR: error: inline assembly requires more registers than available +; CHECK: movq %rax, %r16 + %a = call i64 asm sideeffect "movq %rax, $0", "=l,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{rbp},~{rsp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() ret void } -- GitLab From 7f524f7ef2e9a7086d8e578c313cf1118c997922 Mon Sep 17 00:00:00 2001 From: Shengchen Kan Date: Thu, 30 May 2024 14:17:16 +0800 Subject: [PATCH 019/243] [X86][CodeGen] Simplify the code in foldMemoryOperandImpl, NFCI In preparation for the coming NDD -> RMW fold. --- llvm/lib/Target/X86/X86InstrInfo.cpp | 67 +++++++++++----------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp index 3e391da80788..be51e089ce09 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.cpp +++ b/llvm/lib/Target/X86/X86InstrInfo.cpp @@ -7132,7 +7132,7 @@ static void updateOperandRegConstraints(MachineFunction &MF, } } -static MachineInstr *FuseTwoAddrInst(MachineFunction &MF, unsigned Opcode, +static MachineInstr *fuseTwoAddrInst(MachineFunction &MF, unsigned Opcode, ArrayRef MOs, MachineBasicBlock::iterator InsertPt, MachineInstr &MI, @@ -7161,7 +7161,7 @@ static MachineInstr *FuseTwoAddrInst(MachineFunction &MF, unsigned Opcode, return MIB; } -static MachineInstr *FuseInst(MachineFunction &MF, unsigned Opcode, +static MachineInstr *fuseInst(MachineFunction &MF, unsigned Opcode, unsigned OpNo, ArrayRef MOs, MachineBasicBlock::iterator InsertPt, MachineInstr &MI, const TargetInstrInfo &TII, @@ -7231,7 +7231,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom( : (MI.getOpcode() == X86::VINSERTPSrr) ? X86::VINSERTPSrm : X86::INSERTPSrm; MachineInstr *NewMI = - FuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, PtrOffset); + fuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, PtrOffset); NewMI->getOperand(NewMI->getNumOperands() - 1).setImm(NewImm); return NewMI; } @@ -7253,7 +7253,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom( : (MI.getOpcode() == X86::VMOVHLPSrr) ? X86::VMOVLPSrm : X86::MOVLPSrm; MachineInstr *NewMI = - FuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, 8); + fuseInst(MF, NewOpCode, OpNum, MOs, InsertPt, MI, *this, 8); return NewMI; } } @@ -7268,7 +7268,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandCustom( unsigned RCSize = TRI.getRegSizeInBits(*RC) / 8; if ((Size == 0 || Size >= 16) && RCSize >= 16 && Alignment < Align(16)) { MachineInstr *NewMI = - FuseInst(MF, X86::MOVHPDrm, OpNum, MOs, InsertPt, MI, *this); + fuseInst(MF, X86::MOVHPDrm, OpNum, MOs, InsertPt, MI, *this); return NewMI; } } @@ -7328,30 +7328,30 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl( ArrayRef MOs, MachineBasicBlock::iterator InsertPt, unsigned Size, Align Alignment, bool AllowCommute) const { bool isSlowTwoMemOps = Subtarget.slowTwoMemOps(); - bool isTwoAddrFold = false; + unsigned Opc = MI.getOpcode(); // For CPUs that favor the register form of a call or push, // do not fold loads into calls or pushes, unless optimizing for size // aggressively. if (isSlowTwoMemOps && !MF.getFunction().hasMinSize() && - (MI.getOpcode() == X86::CALL32r || MI.getOpcode() == X86::CALL64r || - MI.getOpcode() == X86::PUSH16r || MI.getOpcode() == X86::PUSH32r || - MI.getOpcode() == X86::PUSH64r)) + (Opc == X86::CALL32r || Opc == X86::CALL64r || Opc == X86::PUSH16r || + Opc == X86::PUSH32r || Opc == X86::PUSH64r)) return nullptr; // Avoid partial and undef register update stalls unless optimizing for size. if (!MF.getFunction().hasOptSize() && - (hasPartialRegUpdate(MI.getOpcode(), Subtarget, /*ForLoadFold*/ true) || + (hasPartialRegUpdate(Opc, Subtarget, /*ForLoadFold*/ true) || shouldPreventUndefRegUpdateMemFold(MF, MI))) return nullptr; unsigned NumOps = MI.getDesc().getNumOperands(); - bool isTwoAddr = - NumOps > 1 && MI.getDesc().getOperandConstraint(1, MCOI::TIED_TO) != -1; + bool IsTwoAddr = NumOps > 1 && OpNum < 2 && MI.getOperand(0).isReg() && + MI.getOperand(1).isReg() && + MI.getOperand(0).getReg() == MI.getOperand(1).getReg(); // FIXME: AsmPrinter doesn't know how to handle // X86II::MO_GOT_ABSOLUTE_ADDRESS after folding. - if (MI.getOpcode() == X86::ADD32ri && + if (Opc == X86::ADD32ri && MI.getOperand(2).getTargetFlags() == X86II::MO_GOT_ABSOLUTE_ADDRESS) return nullptr; @@ -7360,7 +7360,7 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl( // instructions. if (MOs.size() == X86::AddrNumOperands && MOs[X86::AddrDisp].getTargetFlags() == X86II::MO_GOTTPOFF && - MI.getOpcode() != X86::ADD64rr) + Opc != X86::ADD64rr) return nullptr; // Don't fold loads into indirect calls that need a KCFI check as we'll @@ -7368,36 +7368,23 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl( if (MI.isCall() && MI.getCFIType()) return nullptr; - MachineInstr *NewMI = nullptr; - // Attempt to fold any custom cases we have. - if (MachineInstr *CustomMI = foldMemoryOperandCustom( - MF, MI, OpNum, MOs, InsertPt, Size, Alignment)) + if (auto *CustomMI = foldMemoryOperandCustom(MF, MI, OpNum, MOs, InsertPt, + Size, Alignment)) return CustomMI; - const X86FoldTableEntry *I = nullptr; + if (Opc == X86::MOV32r0) + if (auto *NewMI = MakeM0Inst(*this, X86::MOV32mi, MOs, InsertPt, MI)) + return NewMI; // Folding a memory location into the two-address part of a two-address // instruction is different than folding it other places. It requires // replacing the *two* registers with the memory location. - if (isTwoAddr && NumOps >= 2 && OpNum < 2 && MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(0).getReg() == MI.getOperand(1).getReg()) { - I = lookupTwoAddrFoldTable(MI.getOpcode()); - isTwoAddrFold = true; - } else { - if (OpNum == 0) { - if (MI.getOpcode() == X86::MOV32r0) { - NewMI = MakeM0Inst(*this, X86::MOV32mi, MOs, InsertPt, MI); - if (NewMI) - return NewMI; - } - } - - I = lookupFoldTable(MI.getOpcode(), OpNum); - } + const X86FoldTableEntry *I = + IsTwoAddr ? lookupTwoAddrFoldTable(Opc) : lookupFoldTable(Opc, OpNum); - if (I != nullptr) { + MachineInstr *NewMI = nullptr; + if (I) { unsigned Opcode = I->DstOp; if (Alignment < Align(1ULL << ((I->Flags & TB_ALIGN_MASK) >> TB_ALIGN_SHIFT))) @@ -7428,10 +7415,8 @@ MachineInstr *X86InstrInfo::foldMemoryOperandImpl( return nullptr; } - if (isTwoAddrFold) - NewMI = FuseTwoAddrInst(MF, Opcode, MOs, InsertPt, MI, *this); - else - NewMI = FuseInst(MF, Opcode, OpNum, MOs, InsertPt, MI, *this); + NewMI = IsTwoAddr ? fuseTwoAddrInst(MF, Opcode, MOs, InsertPt, MI, *this) + : fuseInst(MF, Opcode, OpNum, MOs, InsertPt, MI, *this); if (NarrowToMOV32rm) { // If this is the special case where we use a MOV32rm to load a 32-bit @@ -8231,7 +8216,7 @@ X86InstrInfo::foldMemoryBroadcast(MachineFunction &MF, MachineInstr &MI, if (auto *I = lookupBroadcastFoldTable(MI.getOpcode(), OpNum)) return matchBroadcastSize(*I, BitsSize) - ? FuseInst(MF, I->DstOp, OpNum, MOs, InsertPt, MI, *this) + ? fuseInst(MF, I->DstOp, OpNum, MOs, InsertPt, MI, *this) : nullptr; if (AllowCommute) { -- GitLab From c7acca1cb06f3850590363fb729a3c03a43170dd Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 30 May 2024 07:15:14 +0000 Subject: [PATCH 020/243] [lldb] Fix collisions between two breakpad tests symtab-sorted-by-size.test was using the same output file name as symtab.test. --- .../Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test b/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test index 83b80236705e..98052ea20bed 100644 --- a/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test +++ b/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test @@ -1,5 +1,5 @@ -# RUN: yaml2obj %S/Inputs/basic-elf.yaml -o %T/symtab.out -# RUN: %lldb %T/symtab.out -o "target symbols add -s symtab.out %S/Inputs/symtab.syms" \ +# RUN: yaml2obj %S/Inputs/basic-elf.yaml -o %T/symtab-sorted-by-size.out +# RUN: %lldb %T/symtab-sorted-by-size.out -o "target symbols add -s symtab-sorted-by-size.out %S/Inputs/symtab.syms" \ # RUN: -s %s | FileCheck %s # CHECK: num_symbols = 4 (sorted by size): @@ -8,4 +8,4 @@ # CHECK: [ 2] 0 X Code 0x00000000004000b0 0x0000000000000010 0x00000000 f1 # CHECK: [ 3] 0 X Code 0x00000000004000c0 0x0000000000000010 0x00000000 f2 -image dump symtab -s size symtab.out +image dump symtab -s size symtab-sorted-by-size.out -- GitLab From 6f2794afeb3c76293cc91cb9f8ae8c90a2ba8b3e Mon Sep 17 00:00:00 2001 From: Freddy Ye Date: Thu, 30 May 2024 15:25:08 +0800 Subject: [PATCH 021/243] Fix build warning for '[X86] Support EGPR for inline assembly. (#92338)' (#93777) --- clang/lib/Basic/Targets/X86.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 34d249ed27ce..036a655a4d07 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1765,6 +1765,7 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { // to the next constraint. return std::string("^") + std::string(Constraint++, 2); } + [[fallthrough]]; case 'j': switch (Constraint[1]) { default: -- GitLab From e398383f9a05ec6f3766e5ab49dd862a72325ba6 Mon Sep 17 00:00:00 2001 From: jeanPerier Date: Thu, 30 May 2024 09:30:27 +0200 Subject: [PATCH 022/243] [flang][fir] add codegen for fir.load of assumed-rank fir.box (#93569) - Update LLVM type conversion of assumed-rank fir.box/class to generate the type of the maximum ranked descriptor. That way, alloca for assumed rank descriptor copies are always big enough. This is needed in the fir.load case that generates a new storage for the value - Add a "computeBoxSize" helper to compute the dynamic size of a descriptor. - Use that size to generate an llvm.memcpy intrinsic to copy the input descriptor into the new storage. Looking at https://reviews.llvm.org/D108221?id=404635, it seems valid to add the TBAA node on the memcpy, which I did. In a further patch, I think we should likely always use a memcpy since LLVM seems to have a better time optimizing it than fir.load/fir.store patterns. --- .../flang/Optimizer/CodeGen/FIROpPatterns.h | 6 +++ .../flang/Optimizer/CodeGen/TypeConverter.h | 6 +++ flang/lib/Optimizer/CodeGen/CodeGen.cpp | 39 ++++++++++++------- flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp | 31 +++++++++++++++ flang/lib/Optimizer/CodeGen/TypeConverter.cpp | 9 ++++- flang/test/Fir/convert-to-llvm.fir | 25 ++++++++++++ flang/test/Fir/tbaa.fir | 34 ++++++++++++++-- 7 files changed, 130 insertions(+), 20 deletions(-) diff --git a/flang/include/flang/Optimizer/CodeGen/FIROpPatterns.h b/flang/include/flang/Optimizer/CodeGen/FIROpPatterns.h index 510ff7299891..211acdc8a38e 100644 --- a/flang/include/flang/Optimizer/CodeGen/FIROpPatterns.h +++ b/flang/include/flang/Optimizer/CodeGen/FIROpPatterns.h @@ -125,6 +125,12 @@ protected: mlir::ConversionPatternRewriter &rewriter, unsigned maskValue) const; + /// Compute the descriptor size in bytes. The result is not guaranteed to be a + /// compile time constant if the box is for an assumed rank, in which case the + /// box rank will be read. + mlir::Value computeBoxSize(mlir::Location, TypePair boxTy, mlir::Value box, + mlir::ConversionPatternRewriter &rewriter) const; + template mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty, mlir::ConversionPatternRewriter &rewriter, diff --git a/flang/include/flang/Optimizer/CodeGen/TypeConverter.h b/flang/include/flang/Optimizer/CodeGen/TypeConverter.h index 79b3bfe4e80e..58803a5cc404 100644 --- a/flang/include/flang/Optimizer/CodeGen/TypeConverter.h +++ b/flang/include/flang/Optimizer/CodeGen/TypeConverter.h @@ -123,10 +123,16 @@ public: mlir::Type baseFIRType, mlir::Type accessFIRType, mlir::LLVM::GEPOp gep) const; + const mlir::DataLayout &getDataLayout() const { + assert(dataLayout && "must be set in ctor"); + return *dataLayout; + } + private: KindMapping kindMapping; std::unique_ptr specifics; std::unique_ptr tbaaBuilder; + const mlir::DataLayout *dataLayout; }; } // namespace fir diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 664453ebaf2f..59aa9216b707 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -2863,23 +2863,32 @@ struct LoadOpConversion : public fir::FIROpConversion { // descriptor value into a new descriptor temp. auto inputBoxStorage = adaptor.getOperands()[0]; mlir::Location loc = load.getLoc(); - fir::SequenceType seqTy = fir::unwrapUntilSeqType(boxTy); - // fir.box of assumed rank do not have a storage - // size that is know at compile time. The copy needs to be runtime driven - // depending on the actual dynamic rank or type. - if (seqTy && seqTy.hasUnknownShape()) - TODO(loc, "loading or assumed rank fir.box"); - auto boxValue = - rewriter.create(loc, llvmLoadTy, inputBoxStorage); - if (std::optional optionalTag = load.getTbaa()) - boxValue.setTBAATags(*optionalTag); - else - attachTBAATag(boxValue, boxTy, boxTy, nullptr); auto newBoxStorage = genAllocaAndAddrCastWithType(loc, llvmLoadTy, defaultAlign, rewriter); - auto storeOp = - rewriter.create(loc, boxValue, newBoxStorage); - attachTBAATag(storeOp, boxTy, boxTy, nullptr); + // TODO: always generate llvm.memcpy, LLVM is better at optimizing it than + // aggregate loads + stores. + if (boxTy.isAssumedRank()) { + + TypePair boxTypePair{boxTy, llvmLoadTy}; + mlir::Value boxSize = + computeBoxSize(loc, boxTypePair, inputBoxStorage, rewriter); + auto memcpy = rewriter.create( + loc, newBoxStorage, inputBoxStorage, boxSize, /*isVolatile=*/false); + if (std::optional optionalTag = load.getTbaa()) + memcpy.setTBAATags(*optionalTag); + else + attachTBAATag(memcpy, boxTy, boxTy, nullptr); + } else { + auto boxValue = rewriter.create(loc, llvmLoadTy, + inputBoxStorage); + if (std::optional optionalTag = load.getTbaa()) + boxValue.setTBAATags(*optionalTag); + else + attachTBAATag(boxValue, boxTy, boxTy, nullptr); + auto storeOp = + rewriter.create(loc, boxValue, newBoxStorage); + attachTBAATag(storeOp, boxTy, boxTy, nullptr); + } rewriter.replaceOp(load, newBoxStorage); } else { auto loadOp = rewriter.create( diff --git a/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp b/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp index 8c726d547491..72e072db3743 100644 --- a/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp +++ b/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp @@ -240,6 +240,37 @@ mlir::Value ConvertFIRToLLVMPattern::genBoxAttributeCheck( maskRes, c0); } +mlir::Value ConvertFIRToLLVMPattern::computeBoxSize( + mlir::Location loc, TypePair boxTy, mlir::Value box, + mlir::ConversionPatternRewriter &rewriter) const { + auto firBoxType = mlir::dyn_cast(boxTy.fir); + assert(firBoxType && "must be a BaseBoxType"); + const mlir::DataLayout &dl = lowerTy().getDataLayout(); + if (!firBoxType.isAssumedRank()) + return genConstantOffset(loc, rewriter, dl.getTypeSize(boxTy.llvm)); + fir::BaseBoxType firScalarBoxType = firBoxType.getBoxTypeWithNewShape(0); + mlir::Type llvmScalarBoxType = + lowerTy().convertBoxTypeAsStruct(firScalarBoxType); + llvm::TypeSize scalarBoxSizeCst = dl.getTypeSize(llvmScalarBoxType); + mlir::Value scalarBoxSize = + genConstantOffset(loc, rewriter, scalarBoxSizeCst); + mlir::Value rawRank = getRankFromBox(loc, boxTy, box, rewriter); + mlir::Value rank = + integerCast(loc, rewriter, scalarBoxSize.getType(), rawRank); + mlir::Type llvmDimsType = getBoxEleTy(boxTy.llvm, {kDimsPosInBox, 1}); + llvm::TypeSize sizePerDimCst = dl.getTypeSize(llvmDimsType); + assert((scalarBoxSizeCst + sizePerDimCst == + dl.getTypeSize(lowerTy().convertBoxTypeAsStruct( + firBoxType.getBoxTypeWithNewShape(1)))) && + "descriptor layout requires adding padding for dim field"); + mlir::Value sizePerDim = genConstantOffset(loc, rewriter, sizePerDimCst); + mlir::Value dimsSize = rewriter.create( + loc, sizePerDim.getType(), sizePerDim, rank); + mlir::Value size = rewriter.create( + loc, scalarBoxSize.getType(), scalarBoxSize, dimsSize); + return size; +} + // Find the Block in which the alloca should be inserted. // The order to recursively find the proper block: // 1. An OpenMP Op that will be outlined. diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp index 729ece6fc177..07d3bd713ce4 100644 --- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp +++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp @@ -14,6 +14,7 @@ #include "flang/Optimizer/CodeGen/TypeConverter.h" #include "DescriptorModel.h" +#include "flang/Common/Fortran.h" #include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done #include "flang/Optimizer/CodeGen/TBAABuilder.h" #include "flang/Optimizer/CodeGen/Target.h" @@ -36,7 +37,8 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA, module.getContext(), getTargetTriple(module), getKindMapping(module), getTargetCPU(module), getTargetFeatures(module), dl)), tbaaBuilder(std::make_unique(module->getContext(), applyTBAA, - forceUnifiedTBAATree)) { + forceUnifiedTBAATree)), + dataLayout{&dl} { LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n"); // Each conversion should return a value of type mlir::Type. @@ -243,7 +245,10 @@ mlir::Type LLVMTypeConverter::convertBoxTypeAsStruct(BaseBoxType box, // [dims] if (rank == unknownRank()) { if (auto seqTy = mlir::dyn_cast(ele)) - rank = seqTy.getDimension(); + if (seqTy.hasUnknownShape()) + rank = Fortran::common::maxRank; + else + rank = seqTy.getDimension(); else rank = 0; } diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir index 369d4bd3029b..81810aa4bfc7 100644 --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -931,6 +931,31 @@ func.func @test_load_box(%addr : !fir.ref>>) { // ----- +func.func @test_assumed_rank_load(%arg0: !fir.ref>>) -> () { + %0 = fir.load %arg0 : !fir.ref>> + fir.call @some_assumed_rank_func(%0) : (!fir.box>) -> () + return +} +func.func private @some_assumed_rank_func(!fir.box>) -> () + +// CHECK-LABEL: llvm.func @test_assumed_rank_load( +// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr) { +// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(1 : i32) : i32 +// GENERIC: %[[VAL_2:.*]] = llvm.alloca %[[VAL_1]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr +// AMDGPU: %[[VAL_2A:.*]] = llvm.alloca %[[VAL_1]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr<5> +// AMDGPU: %[[VAL_2:.*]] = llvm.addrspacecast %[[VAL_2A]] : !llvm.ptr<5> to !llvm.ptr +// CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_4:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> +// CHECK: %[[VAL_5:.*]] = llvm.load %[[VAL_4]] : !llvm.ptr -> i8 +// CHECK: %[[VAL_6:.*]] = llvm.sext %[[VAL_5]] : i8 to i32 +// CHECK: %[[VAL_7:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_8:.*]] = llvm.mul %[[VAL_7]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_9:.*]] = llvm.add %[[VAL_3]], %[[VAL_8]] : i32 +// CHECK: "llvm.intr.memcpy"(%[[VAL_2]], %[[VAL_0]], %[[VAL_9]]) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> () +// CHECK: llvm.call @some_assumed_rank_func(%[[VAL_2]]) : (!llvm.ptr) -> () + +// ----- + // Test `fir.box_rank` conversion. func.func @extract_rank(%arg0: !fir.box>) -> i32 { diff --git a/flang/test/Fir/tbaa.fir b/flang/test/Fir/tbaa.fir index f4f23d35cba2..5800e608da41 100644 --- a/flang/test/Fir/tbaa.fir +++ b/flang/test/Fir/tbaa.fir @@ -247,7 +247,7 @@ func.func @tbaa(%arg0: !fir.box>) -> i32 { // CHECK-LABEL: llvm.func @tbaa( // CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr) -> i32 { -// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> +// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> // CHECK: %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8 // CHECK: %[[VAL_3:.*]] = llvm.sext %[[VAL_2]] : i8 to i32 // CHECK: llvm.return %[[VAL_3]] : i32 @@ -267,7 +267,7 @@ func.func @tbaa(%arg0: !fir.box>) -> i1 { // CHECK-LABEL: llvm.func @tbaa( // CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr) -> i1 { -// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> +// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> // CHECK: %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8 // CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(0 : i64) : i8 // CHECK: %[[VAL_4:.*]] = llvm.icmp "ne" %[[VAL_2]], %[[VAL_3]] : i8 @@ -307,7 +307,7 @@ func.func @tbaa(%arg0: !fir.box>) -> i1 { // CHECK-LABEL: llvm.func @tbaa( // CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr) -> i1 { -// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> +// CHECK: %[[VAL_1:.*]] = llvm.getelementptr %[[VAL_0]][0, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> // CHECK: %[[VAL_2:.*]] = llvm.load %[[VAL_1]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i32 // CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(2 : i32) : i32 // CHECK: %[[VAL_4:.*]] = llvm.and %[[VAL_2]], %[[VAL_3]] : i32 @@ -379,3 +379,31 @@ func.func @tbaa(%arg0: !fir.ref>>) -> () { + %0 = fir.load %arg0 : !fir.ref>> + fir.call @some_assumed_rank_func(%0) : (!fir.box>) -> () + return +} +func.func private @some_assumed_rank_func(!fir.box>) -> () + +// CHECK-DAG: #[[ROOT:.*]] = #llvm.tbaa_root +// CHECK-DAG: #[[ANYACC:.*]] = #llvm.tbaa_type_desc}> +// CHECK-DAG: #[[BOXMEM:.*]] = #llvm.tbaa_type_desc}> +// CHECK-DAG: #[[$BOXT:.*]] = #llvm.tbaa_tag + +// CHECK-LABEL: llvm.func @test_assumed_rank_load( +// CHECK-SAME: %[[VAL_0:.*]]: !llvm.ptr) { +// CHECK: %[[VAL_1:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK: %[[VAL_2:.*]] = llvm.alloca %[[VAL_1]] x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr +// CHECK: %[[VAL_3:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_4:.*]] = llvm.getelementptr %[[VAL_0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<15 x array<3 x i64>>)> +// CHECK: %[[VAL_5:.*]] = llvm.load %[[VAL_4]] {tbaa = [#[[$BOXT]]]} : !llvm.ptr -> i8 +// CHECK: %[[VAL_6:.*]] = llvm.sext %[[VAL_5]] : i8 to i32 +// CHECK: %[[VAL_7:.*]] = llvm.mlir.constant(24 : i32) : i32 +// CHECK: %[[VAL_8:.*]] = llvm.mul %[[VAL_7]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_9:.*]] = llvm.add %[[VAL_3]], %[[VAL_8]] : i32 +// CHECK: "llvm.intr.memcpy"(%[[VAL_2]], %[[VAL_0]], %[[VAL_9]]) <{isVolatile = false, tbaa = [#[[$BOXT]]]}> : (!llvm.ptr, !llvm.ptr, i32) -> () +// CHECK: llvm.call @some_assumed_rank_func(%[[VAL_2]]) : (!llvm.ptr) -> () -- GitLab From 74faa402ccf118ca9ee1434ce385c9a018014a6a Mon Sep 17 00:00:00 2001 From: jeanPerier Date: Thu, 30 May 2024 09:31:18 +0200 Subject: [PATCH 023/243] [flang] lower allocatable assumed-rank specification parts (#93682) Lower allocatable and pointers specification parts. Nothing special is required to allocate the descriptor given they are required to be dummy arguments, however, care must be taken with INTENT(OUT) to use the runtime to deallocate them (inlined fir.embox + store is not possible). --- flang/lib/Lower/Allocatable.cpp | 2 +- flang/lib/Lower/ConvertVariable.cpp | 3 +- .../HLFIR/convert-variable-assumed-rank.f90 | 58 +++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/flang/lib/Lower/Allocatable.cpp b/flang/lib/Lower/Allocatable.cpp index 61f4bbd856a8..068f5d25967c 100644 --- a/flang/lib/Lower/Allocatable.cpp +++ b/flang/lib/Lower/Allocatable.cpp @@ -831,7 +831,7 @@ genDeallocate(fir::FirOpBuilder &builder, const Fortran::semantics::Symbol *symbol = nullptr) { bool isCudaSymbol = symbol && Fortran::semantics::HasCUDAAttr(*symbol); // Deallocate intrinsic types inline. - if (!box.isDerived() && !box.isPolymorphic() && + if (!box.isDerived() && !box.isPolymorphic() && !box.hasAssumedRank() && !box.isUnlimitedPolymorphic() && !errorManager.hasStatSpec() && !useAllocateRuntime && !box.isPointer() && !isCudaSymbol) { // Pointers must use PointerDeallocate so that their deallocations diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 8e9c1d640c33..c15d6b682bdb 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1901,8 +1901,6 @@ void Fortran::lower::mapSymbolAttributes( // First deal with pointers and allocatables, because their handling here // is the same regardless of their rank. if (Fortran::semantics::IsAllocatableOrPointer(sym)) { - if (isAssumedRank) - TODO(loc, "assumed-rank pointer or allocatable"); // Get address of fir.box describing the entity. // global mlir::Value boxAlloc = preAlloc; @@ -1910,6 +1908,7 @@ void Fortran::lower::mapSymbolAttributes( if (!boxAlloc) if (Fortran::lower::SymbolBox symbox = symMap.lookupSymbol(sym)) boxAlloc = symbox.getAddr(); + assert((boxAlloc || !isAssumedRank) && "assumed-ranks cannot be local"); // local if (!boxAlloc) boxAlloc = createNewLocal(converter, loc, var, preAlloc); diff --git a/flang/test/Lower/HLFIR/convert-variable-assumed-rank.f90 b/flang/test/Lower/HLFIR/convert-variable-assumed-rank.f90 index 748c15be8449..cd65696ca5ed 100644 --- a/flang/test/Lower/HLFIR/convert-variable-assumed-rank.f90 +++ b/flang/test/Lower/HLFIR/convert-variable-assumed-rank.f90 @@ -32,6 +32,23 @@ subroutine test_with_attrs(x) real, target, optional :: x(..) call takes_real(x) end subroutine + +subroutine test_simple_allocatable(x) + real, allocatable :: x(..) +end subroutine + +subroutine test_simple_pointer(x) + real, pointer :: x(..) +end subroutine + +subroutine test_intentout(x) + real, intent(out), allocatable :: x(..) +end subroutine + +subroutine test_assumed_length_alloc(x) + character(*), allocatable :: x(..) +end subroutine + ! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_intrinsic( ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "x"}) { ! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope @@ -67,4 +84,45 @@ end subroutine ! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope ! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMassumed_rank_testsFtest_with_attrsEx"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) ! CHECK: fir.call @_QPtakes_real(%[[VAL_2]]#0) fastmath : (!fir.box>) -> () + +! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_simple_allocatable( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>> {fir.bindc_name = "x"}) { +! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMassumed_rank_testsFtest_simple_allocatableEx"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: return +! CHECK: } + +! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_simple_pointer( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>> {fir.bindc_name = "x"}) { +! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMassumed_rank_testsFtest_simple_pointerEx"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: return +! CHECK: } + +! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_intentout( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>> {fir.bindc_name = "x"}) { +! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMassumed_rank_testsFtest_intentoutEx"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) +! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]]#1 : !fir.ref>>> +! CHECK: %[[VAL_4:.*]] = fir.box_addr %[[VAL_3]] : (!fir.box>>) -> !fir.heap> +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.heap>) -> i64 +! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i64 +! CHECK: %[[VAL_7:.*]] = arith.cmpi ne, %[[VAL_5]], %[[VAL_6]] : i64 +! CHECK: fir.if %[[VAL_7]] { +! CHECK: %[[VAL_8:.*]] = arith.constant false +! CHECK: %[[VAL_9:.*]] = fir.absent !fir.box +! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]]#1 : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAAllocatableDeallocate(%[[VAL_12]], %[[VAL_8]], %[[VAL_9]], %{{.*}}, %{{.*}}) fastmath : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK: } +! CHECK: return +! CHECK: } + +! CHECK-LABEL: func.func @_QMassumed_rank_testsPtest_assumed_length_alloc( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>> {fir.bindc_name = "x"}) { +! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref>>>> +! CHECK: %[[VAL_3:.*]] = fir.box_elesize %[[VAL_2]] : (!fir.box>>>) -> index +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_3]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMassumed_rank_testsFtest_assumed_length_allocEx"} : (!fir.ref>>>>, index, !fir.dscope) -> (!fir.ref>>>>, !fir.ref>>>>) +! CHECK: return +! CHECK: } end module -- GitLab From 0eb4bf2faf4125d4d279463390a753c8c36a6937 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Thu, 30 May 2024 04:39:21 -0300 Subject: [PATCH 024/243] [clang] CWG150: add tests and change to unreleased (#93758) --- clang/test/CXX/drs/cwg1xx.cpp | 40 +++++++++++++++++++++++++++++++++++ clang/www/cxx_dr_status.html | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp index 6bc63760f833..b39cc21fa491 100644 --- a/clang/test/CXX/drs/cwg1xx.cpp +++ b/clang/test/CXX/drs/cwg1xx.cpp @@ -753,6 +753,46 @@ namespace cwg148 { // cwg148: yes // cwg149: na +namespace cwg150 { // cwg150: 19 + namespace p1 { + template + class ARG { }; + + template class PARM> + void f(PARM) { } + + void g() { + ARG x; + f(x); + } + } // namespace p1 + + namespace p2 { + template