Skip to content

Conversation

@dsandersllvm
Copy link
Collaborator

@dsandersllvm dsandersllvm commented Oct 6, 2025

While debugging the tests for #155000 I found it helpful to have both sides
of the simulated gdb-rsp traffic rather than just the responses so I've extended
the packetLog in MockGDBServerResponder to record traffic in both directions.
Tests have been updated accordingly

@llvmbot
Copy link
Member

llvmbot commented Oct 6, 2025

@llvm/pr-subscribers-lldb

Author: Daniel Sanders (dsandersllvm)

Changes

While debugging the tests for #155000 I found it helpful to have both sides
of the simulated gdb-rsp traffic rather than just the responses so I've added
a packetLog to MockGDBServer. The existing response-only one in
MockGDBServerResponder is used by tests so I chose not to change it


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

1 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/gdbclientutils.py (+47-27)
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index b603c35c8df09..0395dcc5246f1 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
 import ctypes
 import errno
 import io
@@ -5,6 +6,7 @@
 import socket
 import traceback
 from lldbsuite.support import seven
+from typing import Optional, Literal
 
 
 def checksum(message):
@@ -86,8 +88,8 @@ class MockGDBServerResponder:
     handles any packet not recognized in the common packet handling code.
     """
 
-    registerCount = 40
-    packetLog = None
+    registerCount: int = 40
+    packetLog: Optional[list[str]] = None
 
     class RESPONSE_DISCONNECT:
         pass
@@ -103,6 +105,7 @@ def respond(self, packet):
         Return the unframed packet data that the server should issue in response
         to the given packet received from the client.
         """
+        assert self.packetLog is not None
         self.packetLog.append(packet)
         if packet is MockGDBServer.PACKET_INTERRUPT:
             return self.interrupt()
@@ -242,7 +245,7 @@ def qProcessInfo(self):
     def qHostInfo(self):
         return "ptrsize:8;endian:little;"
 
-    def qEcho(self):
+    def qEcho(self, _: int):
         return "E04"
 
     def qQueryGDBServer(self):
@@ -263,10 +266,10 @@ def A(self, packet):
     def D(self, packet):
         return "OK"
 
-    def readRegisters(self):
+    def readRegisters(self) -> str:
         return "00000000" * self.registerCount
 
-    def readRegister(self, register):
+    def readRegister(self, register: int) -> str:
         return "00000000"
 
     def writeRegisters(self, registers_hex):
@@ -306,7 +309,8 @@ def haltReason(self):
         # SIGINT is 2, return type is 2 digit hex string
         return "S02"
 
-    def qXferRead(self, obj, annex, offset, length):
+    def qXferRead(self, obj: str, annex: str, offset: int,
+                  length: int) -> tuple[str | None, bool]:
         return None, False
 
     def _qXferResponse(self, data, has_more):
@@ -374,15 +378,17 @@ class UnexpectedPacketException(Exception):
         pass
 
 
-class ServerChannel:
+class ServerChannel(ABC):
     """
     A wrapper class for TCP or pty-based server.
     """
 
-    def get_connect_address(self):
+    @abstractmethod
+    def get_connect_address(self) -> str:
         """Get address for the client to connect to."""
 
-    def get_connect_url(self):
+    @abstractmethod
+    def get_connect_url(self) -> str:
         """Get URL suitable for process connect command."""
 
     def close_server(self):
@@ -394,10 +400,12 @@ def accept(self):
     def close_connection(self):
         """Close all resources used by the accepted connection."""
 
-    def recv(self):
+    @abstractmethod
+    def recv(self) -> bytes:
         """Receive a data packet from the connected client."""
 
-    def sendall(self, data):
+    @abstractmethod
+    def sendall(self, data: bytes) -> None:
         """Send the data to the connected client."""
 
 
@@ -428,11 +436,11 @@ def close_connection(self):
         self._connection.close()
         self._connection = None
 
-    def recv(self):
+    def recv(self) -> bytes:
         assert self._connection is not None
         return self._connection.recv(4096)
 
-    def sendall(self, data):
+    def sendall(self, data: bytes) -> None:
         assert self._connection is not None
         return self._connection.sendall(data)
 
@@ -444,10 +452,10 @@ def __init__(self):
         )[0]
         super().__init__(family, type, proto, addr)
 
-    def get_connect_address(self):
+    def get_connect_address(self) -> str:
         return "[{}]:{}".format(*self._server_socket.getsockname())
 
-    def get_connect_url(self):
+    def get_connect_url(self) -> str:
         return "connect://" + self.get_connect_address()
 
 
@@ -455,10 +463,10 @@ class UnixServerSocket(ServerSocket):
     def __init__(self, addr):
         super().__init__(socket.AF_UNIX, socket.SOCK_STREAM, 0, addr)
 
-    def get_connect_address(self):
+    def get_connect_address(self) -> str:
         return self._server_socket.getsockname()
 
-    def get_connect_url(self):
+    def get_connect_url(self) -> str:
         return "unix-connect://" + self.get_connect_address()
 
 
@@ -472,7 +480,7 @@ def __init__(self):
         self._primary = io.FileIO(primary, "r+b")
         self._secondary = io.FileIO(secondary, "r+b")
 
-    def get_connect_address(self):
+    def get_connect_address(self) -> str:
         libc = ctypes.CDLL(None)
         libc.ptsname.argtypes = (ctypes.c_int,)
         libc.ptsname.restype = ctypes.c_char_p
@@ -485,7 +493,7 @@ def close_server(self):
         self._secondary.close()
         self._primary.close()
 
-    def recv(self):
+    def recv(self) -> bytes:
         try:
             return self._primary.read(4096)
         except OSError as e:
@@ -494,8 +502,8 @@ def recv(self):
                 return b""
             raise
 
-    def sendall(self, data):
-        return self._primary.write(data)
+    def sendall(self, data: bytes) -> None:
+        self._primary.write(data)
 
 
 class MockGDBServer:
@@ -513,10 +521,12 @@ class MockGDBServer:
     _receivedData = None
     _receivedDataOffset = None
     _shouldSendAck = True
+    packetLog: list[tuple[Literal["recv"] | Literal["send"], str | bytes]]
 
     def __init__(self, socket):
         self._socket = socket
         self.responder = MockGDBServerResponder()
+        self.packetLog = []
 
     def start(self):
         # Start a thread that waits for a client connection.
@@ -528,18 +538,21 @@ def stop(self):
             self._thread.join()
             self._thread = None
 
-    def get_connect_address(self):
+    def get_connect_address(self) -> str:
+        assert self._socket is not None
         return self._socket.get_connect_address()
 
-    def get_connect_url(self):
+    def get_connect_url(self) -> str:
+        assert self._socket is not None
         return self._socket.get_connect_url()
 
     def run(self):
+        assert self._socket is not None
         # For testing purposes, we only need to worry about one client
         # connecting just one time.
         try:
             self._socket.accept()
-        except:
+        except Exception:
             traceback.print_exc()
             return
         self._shouldSendAck = True
@@ -554,7 +567,7 @@ def run(self):
                 self._receive(data)
         except self.TerminateConnectionException:
             pass
-        except Exception as e:
+        except Exception:
             print(
                 "An exception happened when receiving the response from the gdb server. Closing the client..."
             )
@@ -587,7 +600,9 @@ def _parsePacket(self):
         Once a complete packet is found at the front of self._receivedData,
         its data is removed form self._receivedData.
         """
+        assert self._receivedData is not None
         data = self._receivedData
+        assert self._receivedDataOffset is not None
         i = self._receivedDataOffset
         data_len = len(data)
         if data_len == 0:
@@ -638,12 +653,17 @@ def _parsePacket(self):
         # can start on the next packet the next time around
         self._receivedData = data[i:]
         self._receivedDataOffset = 0
+        self.packetLog.append(("recv", packet))
         return packet
 
-    def _sendPacket(self, packet):
-        self._socket.sendall(seven.bitcast_to_bytes(frame_packet(packet)))
+    def _sendPacket(self, packet: str):
+        assert self._socket is not None
+        framed_packet = seven.bitcast_to_bytes(frame_packet(packet))
+        self.packetLog.append(("send", framed_packet))
+        self._socket.sendall(framed_packet)
 
     def _handlePacket(self, packet):
+        assert self._socket is not None
         if packet is self.PACKET_ACK:
             # Ignore ACKs from the client. For the future, we can consider
             # adding validation code to make sure the client only sends ACKs

@github-actions
Copy link

github-actions bot commented Oct 6, 2025

✅ With the latest revision this PR passed the Python code formatter.

@DavidSpickett
Copy link
Collaborator

I assume this is stacked on the other PR, please leave a comment saying so in future or configure whatever tool to do that for you.

found it helpful to have both sides of the simulated gdb-rsp traffic rather than just the responses

There's at least 4 sides here, so please clarify :)

From the client's point of view, it sends stuff and receives stuff. Then the server also has it's perspective.

So this change adds logging from the server's perspective?

Because you are adding send and receive, not just one. Which is what I first assumed when I saw "bidirectional" like it was only the sent packets and you're adding the received packets.

@DavidSpickett
Copy link
Collaborator

The existing response-only one in MockGDBServerResponder is used by tests so I chose not to change it

Ok so you could have added the sent packets to this but chose not to. That's why it looks a bit strange to me.

How does MockGDBServerResponder use the existing log and why did that push you to making a new one? I guess it's just blindly indexing it, making assumptions about ordering? (because it knows they're all one direction) Seems like we could fix that but idk how much work it would be.

@dsandersllvm
Copy link
Collaborator Author

I assume this is stacked on the other PR, please leave a comment saying so in future or configure whatever tool to do that for you.

Yes it is, sorry about that. I used to use phabricator for this back when that was the way to do reviews, I don't currently know of a tool that works with github PR's

found it helpful to have both sides of the simulated gdb-rsp traffic rather than just the responses

There's at least 4 sides here, so please clarify :)

From the client's point of view, it sends stuff and receives stuff. Then the server also has it's perspective.

So this change adds logging from the server's perspective?

Because you are adding send and receive, not just one. Which is what I first assumed when I saw "bidirectional" like it was only the sent packets and you're adding the received packets.

I meant that the mock server is logging both the packets it receives from the lldb client and the packets it sends back to it.

The existing response-only one in MockGDBServerResponder is used by tests so I chose not to change it

Ok so you could have added the sent packets to this but chose not to. That's why it looks a bit strange to me.

How does MockGDBServerResponder use the existing log and why did that push you to making a new one? I guess it's just blindly indexing it, making assumptions about ordering? (because it knows they're all one direction) Seems like we could fix that but idk how much work it would be.

I need to correct 'response-only' in my description there, it's 'receive only'. The function is called respond but it's logging the argument which is the packet it received.

It's all things that could be adapted to a log that keeps both sides, I just didn't want that part to be a prerequisite of the existing patches. It's mostly calling packetLog.index(...) with specific packets to confirm their presence and testing ranges based on that

            g_pos = self.server.responder.packetLog.index("g")
        ... 
        self.assertEqual(
            0,
            len(
                [
                    p
                    for p in self.server.responder.packetLog[g_pos:]
                    if p.startswith("p")
                ]
            ),
        )
        self.assertGreater(
            len([p for p in self.server.responder.packetLog if p.startswith("G")]), 0
        )

It's all stuff that can be adapted. It makes a bit more sense to me for the MockGDBServer to be keeping the packet log as that's the component that does the send/receive to/from the client but it'd be fine in either

@DavidSpickett
Copy link
Collaborator

Yes it is, sorry about that. I used to use phabricator for this back when that was the way to do reviews, I don't currently know of a tool that works with github PR's

I miss this feature too. We mention a couple of tools on https://llvm.org/docs/GitHub.html#using-graphite-for-stacked-pull-requests but I've not tried any of them myself.

I meant that the mock server is logging both the packets it receives from the lldb client and the packets it sends back to it.

Ok so we're only talking about the mock server here.

It's mostly calling packetLog.index(...) with specific packets to confirm their presence and testing ranges based on that

Reading the whole PR there are several confusing things (which predate your changes but still) in here. They only get worse when we add another log.

I would prefer you do this by extending the current log to include all packets. So that we have 1 log with 3 views. Sent, received and all. The existing code can all be changed to use the received view. Logging prints them all. Could leave out sent given that nothing will use it right now.

As a starting point (feel free to take this):

from collections.abc import Sequence

class PacketLog(object):
  SENT = 0
  RECEIVED = 1

  def __init__(self):
    self._sent = []
    self._received = []
    self._order = []

  def add_sent(self, packet):
    self._sent.append(packet)
    self._order.append(PacketLog.SENT)

  def add_received(self, packet):
    self._received.append(packet)
    self._order.append(PacketLog.RECEIVED)

  def __iter__(self):
    sent = iter(self._sent)
    received = iter(self._received)

    for direction in self._order:
      if direction == PacketLog.SENT:
        yield next(sent)
      else:
        yield next(received)

  class PacketView(Sequence):
    def __init__(self, packets):
      self.packets = packets

    def __getitem__(self, idx):
      return self.packets[idx]

    def __len__(self):
      return len(self.packets)

  @property
  def sent(self):
    return PacketLog.PacketView(self._sent)

  @property
  def received(self):
    return PacketLog.PacketView(self._received)

pl = PacketLog()
pl.add_sent("sent this thing 1")
pl.add_received("received this thing 2")
pl.add_sent("sent this thing 3")
pl.add_received("received this thing 4")

for p in pl:
  print(p)
print()

for p in pl.sent:
  print(p)
print(pl.sent.index("sent this thing 1"))
print(pl.sent[0])
print()

for p in pl.received:
  print(p)
print(pl.received[0])
print(pl.received.index("received this thing 4"))
print()
pl.received[1] = "345345345" # will error, don't let us modify the packets

Two lists so we keep the indexing, slicing, iterating we do now, and a third list for insertion order so the log prints them in the correct sequence. Wrapping the lists prevents us modifying them and making the order go out of sync.

There's some super fancy ways to do this but we're not too concerned about being Pythonic here.

Everything in this should be python 3.9. The docs say the minimum is 3.8
but there's existing code in this suite that needs 3.9 so I think 3.9 is
ok.

Issues:
qEcho() is passed an argument by the callers that the function didn't have
Several functions in the base class would silently do nothing if not
overriden. These now use @AbstractMethod to require overrides
sendall() had inconsistent return types between overrides
@dsandersllvm
Copy link
Collaborator Author

Updated to be a single packetLog in MockGDBServerResponder containing both sent and received packets and the tests have been updated so that they still only check the received packets.

Along the way I noticed that the RESPONSE_DISCONNECT and RESPONSE_NONE classes were being returned by responses. It's not technically wrong in python but mixing instances and classes in a list is a bit odd and it was making type hints tricky to write so these are now instances similar to how None is an instance.

I miss this feature too. We mention a couple of tools on https://llvm.org/docs/GitHub.html#using-graphite-for-stacked-pull-requests but I've not tried any of them myself.

Thanks, I'll give that a try for the next one

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

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

Some test is probably going to fail, but that's what we have buildbots for so I didn't look too closely at those changes.

Please fix the formatting and update the PR description to reflect the latest changes.

And I assume all the annotations are 3.8 compatible? At least according to vermin or pyright, whichever you prefer.

It used return either:
* str
* The RESPONSE_DISCONNECT class
* The RESPONSE_NONE class
* A list of the above three
it now returns:
* A list of str or SpecialResponse instances
The docstring is currently wrong about the packet log containing both sent
and received packets. This will be corrected in the next commit at which
point this function will be filtering to the received packets for
compatibility
@dsandersllvm
Copy link
Collaborator Author

Please fix the formatting and update the PR description to reflect the latest changes.

Done

And I assume all the annotations are 3.8 compatible? At least according to vermin or pyright, whichever you prefer.

Oops, I added a 3.12 line (the type alias) at some point. Corrected it to be 3.8 compatible.

❯ uvx vermin -v -t 3.8 lldb/packages/Python/lldbsuite/test/gdbclientutils.py lldb/packages/Python/lldbsuite/test/lldbgdbclient.py lldb/test/API/functionalities/gdb_remote_client/TestContinue.py lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteLoad.py lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py
Detecting python files..
Analyzing 6 files using 10 processes..
!2, 3.6      /Volumes/Data/llvm.org/lldb/llvm-project/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
!2, 3.0      /Volumes/Data/llvm.org/lldb/llvm-project/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py
~2, ~3       /Volumes/Data/llvm.org/lldb/llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestContinue.py
!2, 3.6      /Volumes/Data/llvm.org/lldb/llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py
2.4, 3.0     /Volumes/Data/llvm.org/lldb/llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteLoad.py
2.4, 3.0     /Volumes/Data/llvm.org/lldb/llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py

Tips:
- Generic or literal annotations might be in use. If so, try using: --eval-annotations
  But check the caveat section: https://github.com/netromdk/vermin#caveats
- You're using potentially backported modules: enum, typing
  If so, try using the following for better results: --backport enum --backport typing
- Since '# novm' or '# novermin' weren't used, a speedup can be achieved using: --no-parse-comments
(disable using: --no-tips)

Minimum required versions: 3.6
Incompatible versions:     2.x

@DavidSpickett DavidSpickett merged commit f188c97 into llvm:main Oct 21, 2025
9 of 10 checks passed
ronlieb added a commit to ROCm/llvm-project that referenced this pull request Oct 21, 2025
* [flang] Fix standalone build regression from llvm#161179 (llvm#164309)

Fix incorrect linking and dependencies introduced in llvm#161179 that break
standalone builds of Flang.

Signed-off-by: Michał Górny <[email protected]>

* [AMDGPU] Remove magic constants from V_PK_ADD_F32 pattern. NFC (llvm#164335)

* [AMDGPU] Update code sequence for CU-mode Release Fences in GFX10+ (llvm#161638)

They were previously optimized to not emit any waitcnt, which is
technically correct because there is no reordering of operations at
workgroup scope in CU mode for GFX10+.

This breaks transitivity however, for example if we have the following
sequence of events in one thread:

- some stores
- store atomic release syncscope("workgroup")
- barrier

then another thread follows with

- barrier
- load atomic acquire
- store atomic release syncscope("agent")

It does not work because, while the other thread sees the stores, it
cannot release them at the wider scope. Our release fences aren't strong
enough to "wait" on stores from other waves.

We also cannot strengthen our release fences any further to allow for
releasing other wave's stores because only GFX12 can do that with
`global_wb`. GFX10-11 do not have the writeback instruction.
It'd also add yet another level of complexity to code sequences, with
both acquire/release having CU-mode only alternatives.
Lastly, acq/rel are always used together. The price for synchronization
has to be paid either at the acq, or the rel. Strengthening the releases
would just make the memory model more complex but wouldn't help
performance.

So the choice here is to streamline the code sequences by making CU and
WGP mode emit almost identical (vL0 inv is not needed in CU mode) code
for release (or stronger) atomic ordering.

This also removes the `vm_vsrc(0)` wait before barriers. Now that the
release fence in CU mode is strong enough, it is no longer needed.

Supersedes llvm#160501
Solves SC1-6454

* [InstSimplify] Support ptrtoaddr in simplifyGEPInst() (llvm#164262)

This adds support for ptrtoaddr in the `ptradd p, ptrtoaddr(p2) -
ptrtoaddr(p) -> p2` fold.

This fold requires that p and p2 have the same underlying object
(otherwise the provenance may not be the same).

The argument I would like to make here is that because the underlying
objects are the same (and the pointers in the same address space), the
non-address bits of the pointer must be the same. Looking at some
specific cases of underlying object relationship:

 * phi/select: Trivially true.
* getelementptr: Only modifies address bits, non-address bits must
remain the same.
* addrspacecast round-trip cast: Must preserve all bits because we
optimize such round-trip casts away.
* non-interposable global alias: I'm a bit unsure about this one, but I
guess the alias and the aliasee must have the same non-address bits?
* various intrinsics like launder.invariant.group, ptrmask. I think
these all either preserve all pointer bits (like the invariant.group
ones) or at least the non-address bits (like ptrmask). There are some
interesting cases like amdgcn.make.buffer.rsrc, but those are cross
address-space.

-----

There is a second `gep (gep p, C), (sub 0, ptrtoint(p)) -> C` transform
in this function, which I am not extending to handle ptrtoaddr, adding
negative tests instead. This transform is overall dubious for provenance
reasons, but especially dubious with ptrtoaddr, as then we don't have
the guarantee that provenance of `p` has been exposed.

* [Hexagon] Add REQUIRES: asserts to test

This test uses -debug-only, so needs an assertion-enabled build.

* [AArch64] Combing scalar_to_reg into DUP if the DUP already exists (llvm#160499)

If we already have a dup(x) as part of the DAG along with a
scalar_to_vec(x), we can re-use the result of the dup to the
scalar_to_vec(x).

* [CAS] OnDiskGraphDB - fix MSVC "not all control paths return a value" warnings. NFC. (llvm#164369)

* Reapply "[libc++] Optimize __hash_table::erase(iterator, iterator)" (llvm#162850)

This reapplication fixes the use after free caused by not properly
updating the bucket list in one case.

Original commit message:
Instead of just calling the single element `erase` on every element of
the range, we can combine some of the operations in a custom
implementation. Specifically, we don't need to search for the previous
node or re-link the list every iteration. Removing this unnecessary work
results in some nice performance improvements:
```
-----------------------------------------------------------------------------------------------------------------------
Benchmark                                                                                             old           new
-----------------------------------------------------------------------------------------------------------------------
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/0                    457 ns        459 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/32                   995 ns        626 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/1024               18196 ns       7995 ns
std::unordered_set<int>::erase(iterator, iterator) (erase half the container)/8192              124722 ns      70125 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/0            456 ns        461 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/32          1183 ns        769 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/1024       27827 ns      18614 ns
std::unordered_set<std::string>::erase(iterator, iterator) (erase half the container)/8192      266681 ns     226107 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/0               455 ns        462 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/32              996 ns        659 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/1024          15963 ns       8108 ns
std::unordered_map<int, int>::erase(iterator, iterator) (erase half the container)/8192         136493 ns      71848 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/0               454 ns        455 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/32              985 ns        703 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/1024          16277 ns       9085 ns
std::unordered_multiset<int>::erase(iterator, iterator) (erase half the container)/8192         125736 ns      82710 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/0          457 ns        454 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/32        1091 ns        646 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/1024     17784 ns       7664 ns
std::unordered_multimap<int, int>::erase(iterator, iterator) (erase half the container)/8192    127098 ns      72806 ns
```


This reverts commit acc3a62.

* [TableGen] List the indices of sub-operands (llvm#163723)

Some instances of the `Operand` class used in Tablegen instruction
definitions expand to a cluster of multiple operands at the MC layer,
such as complex addressing modes involving base + offset + shift, or
clusters of operands describing conditional Arm instructions or
predicated MVE instructions. There's currently no convenient way for C++
code to know the offset of one of those sub-operands from the start of
the cluster: instead it just hard-codes magic numbers like `index+2`,
which is hard to read and fragile.

This patch adds an extra piece of output to `InstrInfoEmitter` to define
those instruction offsets, based on the name of the `Operand` class
instance in Tablegen, and the names assigned to the sub-operands in the
`MIOperandInfo` field. For example, if target Foo were to define

  def Bar : Operand {
    let MIOperandInfo = (ops GPR:$first, i32imm:$second);
    // ...
  }

then the new constants would be `Foo::SUBOP_Bar_first` and
`Foo::SUBOP_Bar_second`, defined as 0 and 1 respectively.

As an example, I've converted some magic numbers related to the MVE
predication operand types (`vpred_n` and its superset `vpred_r`) to use
the new named constants in place of the integer literals they previously
used. This is more verbose, but also clearer, because it explains why
the integer is chosen instead of what its value is.

* [lldb] Add bidirectional packetLog to gdbclientutils.py (llvm#162176)

While debugging the tests for llvm#155000 I found it helpful to have both
sides
of the simulated gdb-rsp traffic rather than just the responses so I've
extended
the packetLog in MockGDBServerResponder to record traffic in both
directions.
Tests have been updated accordingly

* [MLIR] [Vector] Added canonicalizer for folding from_elements + transpose (llvm#161841)

## Description
Adds a new canonicalizer that folds
`vector.from_elements(vector.transpose))` => `vector.from_elements`.
This canonicalization reorders the input elements for
`vector.from_elements`, adjusts the output shape to match the effect of
the transpose op and eliminating its need.

## Testing
Added a 2D vector lit test that verifies the working of the rewrite.

---------

Signed-off-by: Keshav Vinayak Jha <[email protected]>

* [DA] Add initial support for monotonicity check (llvm#162280)

The dependence testing functions in DA assume that the analyzed AddRec
does not wrap over the entire iteration space. For AddRecs that may
wrap, DA should conservatively return unknown dependence. However, no
validation is currently performed to ensure that this condition holds,
which can lead to incorrect results in some cases.

This patch introduces the notion of *monotonicity* and a validation
logic to check whether a SCEV is monotonic. The monotonicity check
classifies the SCEV into one of the following categories:

- Unknown: Nothing is known about the monotonicity of the SCEV.
- Invariant: The SCEV is loop-invariant.
- MultivariateSignedMonotonic: The SCEV doesn't wrap in a signed sense
for any iteration of the loops in the loop nest.

The current validation logic basically searches an affine AddRec
recursively and checks whether the `nsw` flag is present. Notably, it is
still unclear whether we should also have a category for unsigned
monotonicity.
The monotonicity check is still under development and disabled by
default for now. Since such a check is necessary to make DA sound, it
should be enabled by default once the functionality is sufficient.

Split off from llvm#154527.

* [VPlan] Use VPlan::getRegion to shorten code (NFC) (llvm#164287)

* [VPlan] Improve code using m_APInt (NFC) (llvm#161683)

* [SystemZ] Avoid trunc(add(X,X)) patterns (llvm#164378)

Replace with trunc(add(X,Y)) to avoid premature folding in upcoming patch llvm#164227

* [clang][CodeGen] Emit `llvm.tbaa.errno` metadata during module creation

Let Clang emit `llvm.tbaa.errno` metadata in order to let LLVM
carry out optimizations around errno-writing libcalls to, as
long as it is proved the involved memory location does not alias
`errno`.

Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.

* [LV][NFC] Remove undef from phi incoming values (llvm#163762)

Split off from PR llvm#163525, this standalone patch replaces
 use of undef as incoming PHI values with zero, in order
 to reduce the likelihood of contributors hitting the
 `undef deprecator` warning in github.

* [DA] Add option to enable specific dependence test only (llvm#164245)

PR llvm#157084 added an option `da-run-siv-routines-only` to run only SIV
routines in DA. This PR replaces that option with a more fine-grained
one that allows to select other than SIV routines as well. This option
is useful for regression testing of individual DA routines. This patch
also reorganizes regression tests that use `da-run-siv-routines-only`.

* [libcxx] Optimize `std::generate_n` for segmented iterators (llvm#164266)

Part of llvm#102817.

This is a natural follow-up to llvm#163006. We are forwarding
`std::generate_n` to `std::__for_each_n` (`std::for_each_n` needs
c++17), resulting in improved performance for segmented iterators.

before:

```
std::generate_n(deque<int>)/32          17.5 ns         17.3 ns     40727273
std::generate_n(deque<int>)/50          25.7 ns         25.5 ns     26352941
std::generate_n(deque<int>)/1024         490 ns          487 ns      1445161
std::generate_n(deque<int>)/8192        3908 ns         3924 ns       179200
```

after:

```
std::generate_n(deque<int>)/32          11.1 ns         11.0 ns     64000000
std::generate_n(deque<int>)/50          16.1 ns         16.0 ns     44800000
std::generate_n(deque<int>)/1024         291 ns          292 ns      2357895
std::generate_n(deque<int>)/8192        2269 ns         2250 ns       298667
```

* [BOLT] Check entry point address is not in constant island (llvm#163418)

There are cases where `addEntryPointAtOffset` is called with a given
`Offset` that points to an address within a constant island. This
triggers `assert(!isInConstantIsland(EntryPointAddress)` and causes BOLT
to crash. This patch adds a check which ignores functions that would add
such entry points and warns the user.

* [llvm][dwarfdump] Pretty-print DW_AT_language_version (llvm#164222)

In both verbose and non-verbose mode we will now use the
`llvm::dwarf::LanguageDescription` to turn the version into a human
readable string. In verbose mode we also display the raw version code
(similar to how we display addresses in verbose mode). To make the
version code and prettified easier to distinguish, we print the
prettified name in colour (if available), which is consistent with how
`DW_AT_language` is printed in colour.

Before:
```
0x0000000c: DW_TAG_compile_unit                                                                           
              DW_AT_language_name       (DW_LNAME_C)                                                      
              DW_AT_language_version    (201112)             
```
After:
```
0x0000000c: DW_TAG_compile_unit                                                                           
              DW_AT_language_name       (DW_LNAME_C)                                                      
              DW_AT_language_version    (201112 C11)                                                             
```

---------

Signed-off-by: Michał Górny <[email protected]>
Signed-off-by: Keshav Vinayak Jha <[email protected]>
Co-authored-by: Michał Górny <[email protected]>
Co-authored-by: Stanislav Mekhanoshin <[email protected]>
Co-authored-by: Pierre van Houtryve <[email protected]>
Co-authored-by: Nikita Popov <[email protected]>
Co-authored-by: David Green <[email protected]>
Co-authored-by: Simon Pilgrim <[email protected]>
Co-authored-by: Nikolas Klauser <[email protected]>
Co-authored-by: Simon Tatham <[email protected]>
Co-authored-by: Daniel Sanders <[email protected]>
Co-authored-by: Keshav Vinayak Jha <[email protected]>
Co-authored-by: Ryotaro Kasuga <[email protected]>
Co-authored-by: Ramkumar Ramachandra <[email protected]>
Co-authored-by: Antonio Frighetto <[email protected]>
Co-authored-by: David Sherwood <[email protected]>
Co-authored-by: Connector Switch <[email protected]>
Co-authored-by: Asher Dobrescu <[email protected]>
Co-authored-by: Michael Buch <[email protected]>
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
While debugging the tests for llvm#155000 I found it helpful to have both
sides
of the simulated gdb-rsp traffic rather than just the responses so I've
extended
the packetLog in MockGDBServerResponder to record traffic in both
directions.
Tests have been updated accordingly
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
While debugging the tests for llvm#155000 I found it helpful to have both
sides
of the simulated gdb-rsp traffic rather than just the responses so I've
extended
the packetLog in MockGDBServerResponder to record traffic in both
directions.
Tests have been updated accordingly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants