There is an important point missing about FIFO in the answers above.
When a message comes in to a topic/queue which doesn't have partitioning enabled, then FIFO is observed for message delivery*.
When you enable partitioning on a topic/queue and the SessionId is used for the partitioning key, then messages are no longer guaranteed to be FIFO in relation to each other, they are only guaranteed to be FIFO in relation to the partition they were divvied in to.
Fun fact, partitioning in general can have some interesting side-effects if you have a low number of subscribers to the same subscription/queue, as the partition reader assignments are done round-robin style, and if you have more partitions than subscribers, you can see messages being starved (needs verification from SB team, this is empirical from tests I have done on my own because my messages were being starved).
* As @Dan Rosanova pointed out above, if you have async processing or or multiple readers, then your message processing can't be guaranteed to be FIFO, but the order in which the messages were distributed to the processors is going to be FIFO.
When you use a Session message handler (which requires SessionId to be populated), you're taking it another step further and you're guaranteeing that the messages are processed in order, as the Session message handler takes a lock on the SessionId+MessageId rather than just the MessageId, thus ensuring no other messages within the same session are received by another processor.