Skip to content

Commit 5027ed1

Browse files
committed
[GlobalISel] Optimize ULEB128 usage
- Remove some cases where ULEB128 isn't needed - Add a fastDecodeULEB128 tailored for GlobalISel which does unchecked decoding optimized for the common case, which is 1 byte values. Previous LEB128 decode function was about 45 instructions on X86 assuming it got inlined for our use case & the error checks got optimized out. This "fast" one is 23 instruction.
1 parent 8480c93 commit 5027ed1

File tree

5 files changed

+82
-13
lines changed

5 files changed

+82
-13
lines changed

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ enum {
168168
/// operand.
169169
/// - InsnID(ULEB128) - Instruction ID
170170
/// - MMOIdx(ULEB128) - MMO index
171-
/// - NumAddrSpace(ULEB128) - Number of valid address spaces
171+
/// - NumAddrSpace(1) - Number of valid address spaces
172172
/// - AddrSpaceN(ULEB128) - An allowed space of the memory access
173173
/// - AddrSpaceN+1 ...
174174
GIM_CheckMemoryAddressSpace,
@@ -177,7 +177,7 @@ enum {
177177
/// memory operand.
178178
/// - InsnID(ULEB128) - Instruction ID
179179
/// - MMOIdx(ULEB128) - MMO index
180-
/// - MinAlign(ULEB128) - Minimum acceptable alignment
180+
/// - MinAlign(1) - Minimum acceptable alignment
181181
GIM_CheckMemoryAlignment,
182182

183183
/// Check the size of the memory access for the given machine memory operand
@@ -713,6 +713,27 @@ class GIMatchTableExecutor {
713713
memcpy(&Ret, MatchTable, sizeof(Ret));
714714
return Ret;
715715
}
716+
717+
public:
718+
// Faster ULEB128 decoder tailored for the Match Table Executor.
719+
//
720+
// - Arguments are fixed to avoid mid-function checks.
721+
// - Unchecked execution, assumes no error.
722+
// - Fast common case handling (1 byte values).
723+
LLVM_ATTRIBUTE_ALWAYS_INLINE static uint64_t
724+
fastDecodeULEB128(const uint8_t *__restrict MatchTable,
725+
uint64_t &CurrentIdx) {
726+
uint64_t Value = MatchTable[CurrentIdx] & 0x7f;
727+
if (LLVM_UNLIKELY(MatchTable[CurrentIdx++] >= 128)) {
728+
unsigned Shift = 7;
729+
do {
730+
uint64_t Slice = MatchTable[CurrentIdx] & 0x7f;
731+
Value += Slice << Shift;
732+
Shift += 7;
733+
} while (MatchTable[CurrentIdx++] >= 128);
734+
}
735+
return Value;
736+
}
716737
};
717738

718739
} // end namespace llvm

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,7 @@ bool GIMatchTableExecutor::executeMatchTable(
100100
};
101101

102102
const auto readULEB = [&]() {
103-
unsigned N = 0;
104-
uint64_t Val = decodeULEB128(MatchTable + CurrentIdx, &N);
105-
CurrentIdx += N;
106-
return Val;
103+
return fastDecodeULEB128(MatchTable, CurrentIdx);
107104
};
108105

109106
// Convenience function to return a signed value. This avoids
@@ -476,7 +473,7 @@ bool GIMatchTableExecutor::executeMatchTable(
476473
}
477474
case GIM_CheckAtomicOrdering: {
478475
uint64_t InsnID = readULEB();
479-
auto Ordering = (AtomicOrdering)readULEB();
476+
auto Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
480477
DEBUG_WITH_TYPE(TgtExecutor::getName(),
481478
dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs["
482479
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
@@ -493,7 +490,7 @@ bool GIMatchTableExecutor::executeMatchTable(
493490
}
494491
case GIM_CheckAtomicOrderingOrStrongerThan: {
495492
uint64_t InsnID = readULEB();
496-
auto Ordering = (AtomicOrdering)readULEB();
493+
auto Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
497494
DEBUG_WITH_TYPE(TgtExecutor::getName(),
498495
dbgs() << CurrentIdx
499496
<< ": GIM_CheckAtomicOrderingOrStrongerThan(MIs["
@@ -511,7 +508,7 @@ bool GIMatchTableExecutor::executeMatchTable(
511508
}
512509
case GIM_CheckAtomicOrderingWeakerThan: {
513510
uint64_t InsnID = readULEB();
514-
auto Ordering = (AtomicOrdering)readULEB();
511+
auto Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
515512
DEBUG_WITH_TYPE(TgtExecutor::getName(),
516513
dbgs() << CurrentIdx
517514
<< ": GIM_CheckAtomicOrderingWeakerThan(MIs["
@@ -531,7 +528,7 @@ bool GIMatchTableExecutor::executeMatchTable(
531528
uint64_t InsnID = readULEB();
532529
uint64_t MMOIdx = readULEB();
533530
// This accepts a list of possible address spaces.
534-
const uint64_t NumAddrSpace = readULEB();
531+
const uint64_t NumAddrSpace = MatchTable[CurrentIdx++];
535532

536533
if (State.MIs[InsnID]->getNumMemOperands() <= MMOIdx) {
537534
if (handleReject() == RejectAndGiveUp)
@@ -568,7 +565,7 @@ bool GIMatchTableExecutor::executeMatchTable(
568565
case GIM_CheckMemoryAlignment: {
569566
uint64_t InsnID = readULEB();
570567
uint64_t MMOIdx = readULEB();
571-
uint64_t MinAlign = readULEB();
568+
uint64_t MinAlign = MatchTable[CurrentIdx++];
572569

573570
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
574571

llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS
1515
add_llvm_unittest(GlobalISelTests
1616
ConstantFoldingTest.cpp
1717
CSETest.cpp
18+
GIMatchTableExecutorTest.cpp
1819
LegalizerTest.cpp
1920
LegalizerHelperTest.cpp
2021
LegalizerInfoTest.cpp
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===- GIMatchTableExecutorTest.cpp ---------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
10+
#include "gtest/gtest.h"
11+
12+
using namespace llvm;
13+
14+
TEST(GlobalISelLEB128Test, fastDecodeULEB128) {
15+
#define EXPECT_DECODE_ULEB128_EQ(EXPECTED, VALUE) \
16+
do { \
17+
uint64_t ActualSize = 0; \
18+
uint64_t Actual = GIMatchTableExecutor::fastDecodeULEB128( \
19+
reinterpret_cast<const uint8_t *>(VALUE), ActualSize); \
20+
EXPECT_EQ(sizeof(VALUE) - 1, ActualSize); \
21+
EXPECT_EQ(EXPECTED, Actual); \
22+
} while (0)
23+
24+
EXPECT_DECODE_ULEB128_EQ(0u, "\x00");
25+
EXPECT_DECODE_ULEB128_EQ(1u, "\x01");
26+
EXPECT_DECODE_ULEB128_EQ(63u, "\x3f");
27+
EXPECT_DECODE_ULEB128_EQ(64u, "\x40");
28+
EXPECT_DECODE_ULEB128_EQ(0x7fu, "\x7f");
29+
EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x01");
30+
EXPECT_DECODE_ULEB128_EQ(0x81u, "\x81\x01");
31+
EXPECT_DECODE_ULEB128_EQ(0x90u, "\x90\x01");
32+
EXPECT_DECODE_ULEB128_EQ(0xffu, "\xff\x01");
33+
EXPECT_DECODE_ULEB128_EQ(0x100u, "\x80\x02");
34+
EXPECT_DECODE_ULEB128_EQ(0x101u, "\x81\x02");
35+
EXPECT_DECODE_ULEB128_EQ(4294975616ULL, "\x80\xc1\x80\x80\x10");
36+
37+
// Decode ULEB128 with extra padding bytes
38+
EXPECT_DECODE_ULEB128_EQ(0u, "\x80\x00");
39+
EXPECT_DECODE_ULEB128_EQ(0u, "\x80\x80\x00");
40+
EXPECT_DECODE_ULEB128_EQ(0x7fu, "\xff\x00");
41+
EXPECT_DECODE_ULEB128_EQ(0x7fu, "\xff\x80\x00");
42+
EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x81\x00");
43+
EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x81\x80\x00");
44+
EXPECT_DECODE_ULEB128_EQ(0x80u, "\x80\x81\x80\x80\x80\x80\x80\x80\x80\x00");
45+
EXPECT_DECODE_ULEB128_EQ(0x80000000'00000000ul,
46+
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01");
47+
48+
#undef EXPECT_DECODE_ULEB128_EQ
49+
}

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,13 +1565,14 @@ bool MemoryAddressSpacePredicateMatcher::isIdentical(
15651565

15661566
void MemoryAddressSpacePredicateMatcher::emitPredicateOpcodes(
15671567
MatchTable &Table, RuleMatcher &Rule) const {
1568+
assert(AddrSpaces.size() < 255);
15681569
Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")
15691570
<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
15701571
<< MatchTable::Comment("MMO")
15711572
<< MatchTable::ULEB128Value(MMOIdx)
15721573
// Encode number of address spaces to expect.
15731574
<< MatchTable::Comment("NumAddrSpace")
1574-
<< MatchTable::ULEB128Value(AddrSpaces.size());
1575+
<< MatchTable::IntValue(1, AddrSpaces.size());
15751576
for (unsigned AS : AddrSpaces)
15761577
Table << MatchTable::Comment("AddrSpace") << MatchTable::ULEB128Value(AS);
15771578

@@ -1593,7 +1594,7 @@ void MemoryAlignmentPredicateMatcher::emitPredicateOpcodes(
15931594
Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
15941595
<< MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
15951596
<< MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
1596-
<< MatchTable::Comment("MinAlign") << MatchTable::ULEB128Value(MinAlign)
1597+
<< MatchTable::Comment("MinAlign") << MatchTable::IntValue(1, MinAlign)
15971598
<< MatchTable::LineBreak;
15981599
}
15991600

0 commit comments

Comments
 (0)