Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SelectionDAG] Use unaligned store/load to move AVX registers onto stack for insertelement #82130

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Nirhar
Copy link
Contributor

@Nirhar Nirhar commented Feb 17, 2024

Prior to this patch, SelectionDAG generated aligned move onto stacks for AVX registers when the function was marked as a no-realign-stack function. This lead to misalignment between the stack and the instruction generated. This patch fixes the issue. There was a similar issue reported for extractelement which was fixed in a6614ec

@llvmbot llvmbot added backend:X86 llvm:SelectionDAG SelectionDAGISel as well labels Feb 17, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Feb 17, 2024

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-llvm-selectiondag

Author: Manish Kausik H (Nirhar)

Changes

Prior to this patch, SelectionDAG generated aligned move onto stacks for AVX registers when the function was marked as a no-realign-stack function. This lead to misalignment between the stack and the instruction generated. This patch fixes the issue. There was a similar issue reported for extractelement which was fixed in #a6614ec5b7c1dbfc4b847884c5de780cf75e8e9c


Full diff: https://github.com/llvm/llvm-project/pull/82130.diff

2 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (+35-32)
  • (added) llvm/test/CodeGen/X86/unaligned-insert-into-vector-through-stack.ll (+18)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 892bfbd62f0d02..e58adf867ac790 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -363,6 +363,19 @@ SDValue SelectionDAGLegalize::ExpandConstant(ConstantSDNode *CP) {
   return Result;
 }
 
+// Helper function that generates an MMO that considers the alignment of the
+// stack, and the size of the stack object
+static MachineMemOperand *getStackAlignedMMO(SDValue StackPtr,
+                                             MachineFunction &MF,
+                                             bool isObjectScalable) {
+  auto &MFI = MF.getFrameInfo();
+  int FI = cast<FrameIndexSDNode>(StackPtr)->getIndex();
+  MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, FI);
+  uint64_t ObjectSize = isObjectScalable ? ~UINT64_C(0) : MFI.getObjectSize(FI);
+  return MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
+                                 ObjectSize, MFI.getObjectAlign(FI));
+}
+
 /// Some target cannot handle a variable insertion index for the
 /// INSERT_VECTOR_ELT instruction.  In this case, it
 /// is necessary to spill the vector being inserted into to memory, perform
@@ -384,23 +397,23 @@ SDValue SelectionDAGLegalize::PerformInsertVectorEltInMemory(SDValue Vec,
   EVT VT    = Tmp1.getValueType();
   EVT EltVT = VT.getVectorElementType();
   SDValue StackPtr = DAG.CreateStackTemporary(VT);
-
-  int SPFI = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
+  MachineMemOperand *AlignedMMO = getStackAlignedMMO(
+      StackPtr, DAG.getMachineFunction(), EltVT.isScalableVector());
 
   // Store the vector.
-  SDValue Ch = DAG.getStore(
-      DAG.getEntryNode(), dl, Tmp1, StackPtr,
-      MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI));
+  SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, AlignedMMO);
 
   SDValue StackPtr2 = TLI.getVectorElementPointer(DAG, StackPtr, VT, Tmp3);
 
   // Store the scalar value.
-  Ch = DAG.getTruncStore(
-      Ch, dl, Tmp2, StackPtr2,
-      MachinePointerInfo::getUnknownStack(DAG.getMachineFunction()), EltVT);
-  // Load the updated vector.
-  return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo::getFixedStack(
-                                               DAG.getMachineFunction(), SPFI));
+  Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, EltVT, AlignedMMO);
+
+  Align ElementAlignment = std::min(cast<StoreSDNode>(Ch)->getAlign(),
+                                    DAG.getDataLayout().getPrefTypeAlign(
+                                        VT.getTypeForEVT(*DAG.getContext())));
+
+  return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo(),
+                     ElementAlignment);
 }
 
 SDValue SelectionDAGLegalize::ExpandINSERT_VECTOR_ELT(SDValue Vec, SDValue Val,
@@ -1378,19 +1391,6 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
   }
 }
 
-// Helper function that generates an MMO that considers the alignment of the
-// stack, and the size of the stack object
-static MachineMemOperand *getStackAlignedMMO(SDValue StackPtr,
-                                             MachineFunction &MF,
-                                             bool isObjectScalable) {
-  auto &MFI = MF.getFrameInfo();
-  int FI = cast<FrameIndexSDNode>(StackPtr)->getIndex();
-  MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(MF, FI);
-  uint64_t ObjectSize = isObjectScalable ? ~UINT64_C(0) : MFI.getObjectSize(FI);
-  return MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
-                                 ObjectSize, MFI.getObjectAlign(FI));
-}
-
 SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) {
   SDValue Vec = Op.getOperand(0);
   SDValue Idx = Op.getOperand(1);
@@ -1488,24 +1488,27 @@ SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) {
   EVT VecVT = Vec.getValueType();
   EVT SubVecVT = Part.getValueType();
   SDValue StackPtr = DAG.CreateStackTemporary(VecVT);
-  int FI = cast<FrameIndexSDNode>(StackPtr.getNode())->getIndex();
-  MachinePointerInfo PtrInfo =
-      MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI);
+  MachineMemOperand *AlignedMMO = getStackAlignedMMO(
+      StackPtr, DAG.getMachineFunction(), VecVT.isScalableVector());
 
   // First store the whole vector.
-  SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo);
+  SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, AlignedMMO);
 
   // Then store the inserted part.
   SDValue SubStackPtr =
       TLI.getVectorSubVecPointer(DAG, StackPtr, VecVT, SubVecVT, Idx);
 
   // Store the subvector.
-  Ch = DAG.getStore(
-      Ch, dl, Part, SubStackPtr,
-      MachinePointerInfo::getUnknownStack(DAG.getMachineFunction()));
+  Ch = DAG.getStore(Ch, dl, Part, SubStackPtr, AlignedMMO);
+
+  Align ElementAlignment =
+      std::min(cast<StoreSDNode>(Ch)->getAlign(),
+               DAG.getDataLayout().getPrefTypeAlign(
+                   Op.getValueType().getTypeForEVT(*DAG.getContext())));
 
   // Finally, load the updated vector.
-  return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, PtrInfo);
+  return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, MachinePointerInfo(),
+                     ElementAlignment);
 }
 
 SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) {
diff --git a/llvm/test/CodeGen/X86/unaligned-insert-into-vector-through-stack.ll b/llvm/test/CodeGen/X86/unaligned-insert-into-vector-through-stack.ll
new file mode 100644
index 00000000000000..01e4d02acda18e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/unaligned-insert-into-vector-through-stack.ll
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+
+define <8 x i32> @foo(<8 x i32> %arg1, i32 %n) #0 {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vmovups %ymm0, -{{[0-9]+}}(%rsp)
+; CHECK-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT:    andl $7, %edi
+; CHECK-NEXT:    movl $42, -40(%rsp,%rdi,4)
+; CHECK-NEXT:    vmovups -{{[0-9]+}}(%rsp), %ymm0
+; CHECK-NEXT:    retq
+entry:
+  %a = insertelement <8 x i32> %arg1, i32 42, i32 %n
+  ret <8 x i32> %a
+}
+
+attributes #0 = { "no-realign-stack" "target-cpu"="haswell" }

@Nirhar
Copy link
Contributor Author

Nirhar commented Feb 17, 2024

@RKSimon @danilaml @arsenm for your reviews

@Nirhar
Copy link
Contributor Author

Nirhar commented Feb 17, 2024

We seem to have 2 different functions that essentially do the same job of spilling the vector onto the stack for inserting into it, which are:

SDValue PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx,

and
SDValue ExpandInsertToVectorThroughStack(SDValue Op);

As a suggestion for a different PR, I think we can get rid of one of them, or call one through the other.

…ack for `insertelement`

Prior to this patch, SelectionDAG generated aligned move onto stacks for AVX registers
when the function was marked as a no-realign-stack function. This lead to misalignment
between the stack and the instruction generated. This patch fixes the issue. There was
a similar issue reported for `extractelement` which was fixed in #a6614ec5b7c1dbfc4b847884c5de780cf75e8e9c
Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff d2a26a7bd5fc7cc5752337b7f4f999642feb37dc 92a4d898c7c59e18e8527687eef606622c663c6c -- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
View the diff from clang-format here.
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 177784ab6a..195a74da12 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -404,7 +404,6 @@ SDValue SelectionDAGLegalize::PerformInsertVectorEltInMemory(SDValue Vec,
   // Store the vector.
   SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, AlignedMMO);
 
-
   SDValue StackPtr2 = TLI.getVectorElementPointer(DAG, StackPtr, VT, Tmp3);
 
   // Store the scalar value.

@RKSimon
Copy link
Collaborator

RKSimon commented Feb 20, 2024

ExpandInsertToVectorThroughStack is for INSERT_SUBVECTOR not INSERT_VECTOR_ELT, but I agree we can probably share more of the code between them.

@Nirhar
Copy link
Contributor Author

Nirhar commented Feb 20, 2024

We have about 10 Aarch64 Unit tests failing, all of them due to the following assertion failure:

AArch64Tests: /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h:576: void llvm::LegalizeRuleSet::aliasTo(unsigned int): Assertion `Rules.empty() && "Aliasing will discard rules"' failed.
 #0 0x00007feec86b1188 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:723:22
 #1 0x00007feec86b15a9 PrintStackTraceSignalHandler(void*) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:798:1
 #2 0x00007feec86aeb49 llvm::sys::RunSignalHandlers() /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Support/Signals.cpp:105:20
 #3 0x00007feec86b0a20 SignalHandler(int) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Support/Unix/Signals.inc:413:1
 #4 0x00007feec7c42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #5 0x00007feec7c969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #6 0x00007feec7c42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #7 0x00007feec7c287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #8 0x00007feec7c2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #9 0x00007feec7c39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#10 0x00007feecb9d2d42 llvm::LegalizeRuleSet::aliasTo(unsigned int) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h:577:13
#11 0x00007feecb9d16c1 llvm::LegalizerInfo::aliasActionDefinitions(unsigned int, unsigned int) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp:319:1
#12 0x00007feecb9d15c4 llvm::LegalizerInfo::getActionDefinitionsBuilder(std::initializer_list<unsigned int>) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp:305:3
#13 0x00007feecc0d6816 llvm::LegalizeRuleSet::legalFor(std::initializer_list<llvm::LLT>) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h:600:21
#14 0x00007feecc0d6816 llvm::AArch64LegalizerInfo::AArch64LegalizerInfo(llvm::AArch64Subtarget const&) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp:126:0
#15 0x00007feecc2b68d6 std::__uniq_ptr_impl<llvm::LegalizerInfo, std::default_delete<llvm::LegalizerInfo>>::reset(llvm::LegalizerInfo*) /usr/include/c++/11/bits/unique_ptr.h:179:16
#16 0x00007feecc2b68d6 std::unique_ptr<llvm::LegalizerInfo, std::default_delete<llvm::LegalizerInfo>>::reset(llvm::LegalizerInfo*) /usr/include/c++/11/bits/unique_ptr.h:456:12
#17 0x00007feecc2b68d6 llvm::AArch64Subtarget::AArch64Subtarget(llvm::Triple const&, llvm::StringRef, llvm::StringRef, llvm::StringRef, llvm::TargetMachine const&, bool, unsigned int, unsigned int, bool, bool, bool) /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/lib/Target/AArch64/AArch64Subtarget.cpp:333:0
#18 0x000055f3624367b3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_data() const /usr/include/c++/11/bits/basic_string.h:195:28
#19 0x000055f3624367b3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_is_local() const /usr/include/c++/11/bits/basic_string.h:230:23
#20 0x000055f3624367b3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_dispose() /usr/include/c++/11/bits/basic_string.h:239:18
#21 0x000055f3624367b3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string() /usr/include/c++/11/bits/basic_string.h:672:19
#22 0x000055f3624367b3 (anonymous namespace)::createInstrInfo(llvm::TargetMachine*) /usr/include/c++/11/bits/basic_string.h:671:7
#23 0x000055f362436edf function<InstSizes_STATEPOINT_Test::TestBody()::<lambda(llvm::AArch64InstrInfo&, llvm::MachineFunction&)> > /usr/include/c++/11/bits/std_function.h:437:19
#24 0x000055f362436edf InstSizes_STATEPOINT_Test::TestBody() /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/unittests/Target/AArch64/InstSizes.cpp:155:0
#25 0x00007feecbeb09ca testing::Test::Run() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:2687:50
#26 0x00007feecbeb09ca testing::Test::Run() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:2677:6
#27 0x00007feecbeb0bdd testing::TestInfo::Run() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:2836:14
#28 0x00007feecbeb7172 testing::TestSuite::Run() (.part.0) /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:3017:35
#29 0x00007feecbeb796f testing::internal::UnitTestImpl::RunAllTests() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:5921:41
#30 0x00007feecbea9fe1 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::_M_data() const /usr/include/c++/11/bits/basic_string.h:195:28
#31 0x00007feecbea9fe1 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::c_str() const /usr/include/c++/11/bits/basic_string.h:2321:23
#32 0x00007feecbea9fe1 testing::internal::ScopedPrematureExitFile::~ScopedPrematureExitFile() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:5055:26
#33 0x00007feecbea9fe1 testing::UnitTest::Run() /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/googletest/src/gtest.cc:5489:1
#34 0x00007feecc4c51ca main /home/nirhar/Documents/OpenSource/llvm/llvm-project/third-party/unittest/UnitTestMain/TestMain.cpp:56:1
#35 0x00007feec7c29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#36 0x00007feec7c29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#37 0x000055f36242d7d5 _start (/home/nirhar/Documents/OpenSource/llvm/llvm-project/build/unittests/Target/AArch64/./AArch64Tests+0xa7d5)

Is there a way to print the rules, so that I can investigate what those rules contain?

@arsenm
Copy link
Contributor

arsenm commented Feb 26, 2024

We have about 10 Aarch64 Unit tests failing, all of them due to the following assertion failure:

AArch64Tests: /home/nirhar/Documents/OpenSource/llvm/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h:576: void llvm::LegalizeRuleSet::aliasTo(unsigned int): Assertion `Rules.empty() && "Aliasing will discard rules"' failed.

This will be unrelated to this patch

Comment on lines +1509 to +1510
DAG.getDataLayout().getPrefTypeAlign(
Op.getValueType().getTypeForEVT(*DAG.getContext())));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the alignment of the actual frame index, not query the type preferred align

DAG.getDataLayout().getPrefTypeAlign(
VT.getTypeForEVT(*DAG.getContext())));

return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we represent this as FrameIndex base with unknown offset?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please elaborate on what is it that you want to represent this way? My knowledge on this API is still limited, hence I would not have understood your intent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reload of the entire vector, so there isn't any offset to consider. That is, the original MachinePointerInfo was correct. You should be able to use the MachinePointerInfo::getFixedStack as before

DAG.getDataLayout().getPrefTypeAlign(
VT.getTypeForEVT(*DAG.getContext())));

return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reload of the entire vector, so there isn't any offset to consider. That is, the original MachinePointerInfo was correct. You should be able to use the MachinePointerInfo::getFixedStack as before


Align ElementAlignment = std::min(cast<StoreSDNode>(Ch)->getAlign(),
DAG.getDataLayout().getPrefTypeAlign(
VT.getTypeForEVT(*DAG.getContext())));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of querying the preferred type alignment, this should use the alignment for the real stack object you have. It just happens that today DAG.CreateStackTemporary uses getPrefTypeAlign, but you should check what the MachineFrameInfo says the alignment is for the frame index

@RKSimon
Copy link
Collaborator

RKSimon commented Apr 2, 2024

@Nirhar reverse-ping

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 llvm:SelectionDAG SelectionDAGISel as well
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants