Skip to content

Commit ae715b0

Browse files
committed
[LLVM] Change Intrinsic::ID to encode target and intrinsic index
Change `Intrinsic::ID` enum values to encode an 8-bit target index in upper 16-bits and a 16-bit intrinsic index (within the target) in lower 16-bits. This change is in preparation for being able to disable intrinsics for targets that are not enabled.
1 parent cfde4fb commit ae715b0

30 files changed

+440
-220
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ enum {
275275
/// Check the operand is a specific intrinsic ID
276276
/// - InsnID(ULEB128) - Instruction ID
277277
/// - OpIdx(ULEB128) - Operand index
278-
/// - IID(2) - Expected Intrinsic ID
278+
/// - IID(4) - Expected Intrinsic ID
279279
GIM_CheckIntrinsicID,
280280

281281
/// Check the operand is a specific predicate
@@ -411,7 +411,7 @@ enum {
411411

412412
/// Adds an intrinsic ID to the specified instruction.
413413
/// - InsnID(ULEB128) - Instruction ID to modify
414-
/// - IID(2) - Intrinsic ID
414+
/// - IID(4) - Intrinsic ID
415415
GIR_AddIntrinsicID,
416416

417417
/// Marks the implicit def of a register as dead.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ bool GIMatchTableExecutor::executeMatchTable(
889889
case GIM_CheckIntrinsicID: {
890890
uint64_t InsnID = readULEB();
891891
uint64_t OpIdx = readULEB();
892-
uint16_t Value = readU16();
892+
uint32_t Value = readU32();
893893
DEBUG_WITH_TYPE(TgtExecutor::getName(),
894894
dbgs() << CurrentIdx << ": GIM_CheckIntrinsicID(MIs["
895895
<< InsnID << "]->getOperand(" << OpIdx
@@ -1185,7 +1185,7 @@ bool GIMatchTableExecutor::executeMatchTable(
11851185
}
11861186
case GIR_AddIntrinsicID: {
11871187
uint64_t InsnID = readULEB();
1188-
uint16_t Value = readU16();
1188+
uint32_t Value = readU32();
11891189
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
11901190
OutMIs[InsnID].addIntrinsicID((Intrinsic::ID)Value);
11911191
DEBUG_WITH_TYPE(TgtExecutor::getName(),

llvm/include/llvm/IR/Intrinsics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,17 @@ namespace Intrinsic {
4747
#define GET_INTRINSIC_ENUM_VALUES
4848
#include "llvm/IR/IntrinsicEnums.inc"
4949
#undef GET_INTRINSIC_ENUM_VALUES
50+
end_id = ~0U,
5051
};
5152

53+
// Returns if `id` is a valid intrinsic ID. Validity means that it value is
54+
// one of the values defined for the Intrinsic::ID enum.
55+
bool IsIntrinsicIDValid(ID id);
56+
57+
// Get the next valid ID. This is used in test cases that iterate over valid
58+
// intrinsic ID enums.
59+
ID GetNextValidIntrinsicID(ID id);
60+
5261
/// Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
5362
/// Note, this version is for intrinsics with no overloads. Use the other
5463
/// version of getName if overloads are required.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===- llvm/Support/IntrinsicID.h - Intrinsic ID encoding -------*- C++ -*-===//
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+
// This file contains functions to support intrinsic ID encoding. The
10+
// Intrinsic::ID enum value is constructed using a target prefix index in bits
11+
// 23-16 (8-bit) and an intrinsic index (index within the list of intrinsics for
12+
// tha target) in lower 16 bits. To support Intrinsic::ID 0 being not used, the
13+
// intrinsic index is encoded as Index + 1 for all targets.
14+
//
15+
// This file defines functions that encapsulate this encoding.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef LLVM_SUPPORT_INTRINSIC_ID_H
20+
#define LLVM_SUPPORT_INTRINSIC_ID_H
21+
22+
#include <limits>
23+
#include <optional>
24+
#include <utility>
25+
26+
namespace llvm::Intrinsic {
27+
typedef unsigned ID;
28+
29+
inline ID EncodeIntrinsicID(unsigned TargetIndex, unsigned IntrinsicIndex) {
30+
assert(IntrinsicIndex < std::numeric_limits<uint16_t>::max());
31+
assert(TargetIndex <= std::numeric_limits<uint8_t>::max());
32+
return (TargetIndex << 16) | (IntrinsicIndex + 1);
33+
}
34+
35+
inline std::pair<unsigned, unsigned> DecodeIntrinsicID(ID id) {
36+
unsigned IntrinsicIndex = id & 0xFFFF;
37+
unsigned TargetIndex = id >> 16;
38+
assert(IntrinsicIndex != 0);
39+
return {TargetIndex, IntrinsicIndex - 1};
40+
}
41+
42+
inline std::optional<std::pair<unsigned, unsigned>>
43+
DecodeIntrinsicIDNoFail(ID id) {
44+
unsigned IntrinsicIndex = id & 0xFFFF;
45+
unsigned TargetIndex = id >> 16;
46+
if (IntrinsicIndex == 0)
47+
return std::nullopt;
48+
return std::make_pair(TargetIndex, IntrinsicIndex - 1);
49+
}
50+
51+
} // end namespace llvm::Intrinsic
52+
53+
#endif // LLVM_SUPPORT_INTRINSIC_ID_H

llvm/lib/CodeGen/MachineOperand.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
992992
}
993993
case MachineOperand::MO_IntrinsicID: {
994994
Intrinsic::ID ID = getIntrinsicID();
995-
if (ID < Intrinsic::num_intrinsics)
995+
if (Intrinsic::IsIntrinsicIDValid(ID))
996996
OS << "intrinsic(@" << Intrinsic::getBaseName(ID) << ')';
997997
else if (IntrinsicInfo)
998998
OS << "intrinsic(@" << IntrinsicInfo->getName(ID) << ')';

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ bool MachineVerifier::verifyGIntrinsicSideEffects(const MachineInstr *MI) {
10551055
bool NoSideEffects = Opcode == TargetOpcode::G_INTRINSIC ||
10561056
Opcode == TargetOpcode::G_INTRINSIC_CONVERGENT;
10571057
unsigned IntrID = cast<GIntrinsic>(MI)->getIntrinsicID();
1058-
if (IntrID != 0 && IntrID < Intrinsic::num_intrinsics) {
1058+
if (IntrID != 0 && Intrinsic::IsIntrinsicIDValid(IntrID)) {
10591059
AttributeList Attrs = Intrinsic::getAttributes(
10601060
MF->getFunction().getContext(), static_cast<Intrinsic::ID>(IntrID));
10611061
bool DeclHasSideEffects = !Attrs.getMemoryEffects().doesNotAccessMemory();
@@ -1079,7 +1079,7 @@ bool MachineVerifier::verifyGIntrinsicConvergence(const MachineInstr *MI) {
10791079
bool NotConvergent = Opcode == TargetOpcode::G_INTRINSIC ||
10801080
Opcode == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS;
10811081
unsigned IntrID = cast<GIntrinsic>(MI)->getIntrinsicID();
1082-
if (IntrID != 0 && IntrID < Intrinsic::num_intrinsics) {
1082+
if (IntrID != 0 && Intrinsic::IsIntrinsicIDValid(IntrID)) {
10831083
AttributeList Attrs = Intrinsic::getAttributes(
10841084
MF->getFunction().getContext(), static_cast<Intrinsic::ID>(IntrID));
10851085
bool DeclIsConvergent = Attrs.hasFnAttr(Attribute::Convergent);

llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
160160
case ISD::INTRINSIC_W_CHAIN: {
161161
unsigned OpNo = getOpcode() == ISD::INTRINSIC_WO_CHAIN ? 0 : 1;
162162
unsigned IID = getOperand(OpNo)->getAsZExtVal();
163-
if (IID < Intrinsic::num_intrinsics)
163+
if (Intrinsic::IsIntrinsicIDValid(IID))
164164
return Intrinsic::getBaseName((Intrinsic::ID)IID).str();
165165
if (!G)
166166
return "Unknown intrinsic";

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4431,7 +4431,7 @@ void SelectionDAGISel::CannotYetSelect(SDNode *N) {
44314431
} else {
44324432
bool HasInputChain = N->getOperand(0).getValueType() == MVT::Other;
44334433
unsigned iid = N->getConstantOperandVal(HasInputChain);
4434-
if (iid < Intrinsic::num_intrinsics)
4434+
if (Intrinsic::IsIntrinsicIDValid(iid))
44354435
Msg << "intrinsic %" << Intrinsic::getBaseName((Intrinsic::ID)iid);
44364436
else if (const TargetIntrinsicInfo *TII = TM.getIntrinsicInfo())
44374437
Msg << "target intrinsic %" << TII->getName(iid);

llvm/lib/IR/Core.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2458,7 +2458,8 @@ unsigned LLVMGetIntrinsicID(LLVMValueRef Fn) {
24582458
}
24592459

24602460
static Intrinsic::ID llvm_map_to_intrinsic_id(unsigned ID) {
2461-
assert(ID < llvm::Intrinsic::num_intrinsics && "Intrinsic ID out of range");
2461+
assert(llvm::Intrinsic::IsIntrinsicIDValid(ID) &&
2462+
"Intrinsic ID out of range");
24622463
return llvm::Intrinsic::ID(ID);
24632464
}
24642465

llvm/lib/IR/Intrinsics.cpp

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,54 @@
3333
#include "llvm/IR/IntrinsicsXCore.h"
3434
#include "llvm/IR/Module.h"
3535
#include "llvm/IR/Type.h"
36+
#include "llvm/Support/IntrinsicID.h"
3637

3738
using namespace llvm;
39+
using namespace Intrinsic;
40+
41+
/// Table of per-target intrinsic name tables.
42+
#define GET_INTRINSIC_TARGET_DATA
43+
#include "llvm/IR/IntrinsicImpl.inc"
44+
#undef GET_INTRINSIC_TARGET_DATA
45+
size_t constexpr NumTargets = sizeof(TargetInfos) / sizeof(TargetInfos[0]);
46+
47+
// Returns true if the given intrinsic ID is valid, that is, its value is one
48+
// of the enum values defined for this intrinsic (including not_intrinsic).
49+
bool Intrinsic::IsIntrinsicIDValid(ID ID) {
50+
if (ID == Intrinsic::not_intrinsic)
51+
return true;
52+
auto Decoded = DecodeIntrinsicIDNoFail(ID);
53+
if (!Decoded)
54+
return false;
55+
unsigned TargetIdx = Decoded->first;
56+
unsigned IntrinsicIdx = Decoded->second;
57+
return TargetIdx < NumTargets && IntrinsicIdx < TargetInfos[TargetIdx].Count;
58+
}
59+
60+
// Returns linear index of ID if its valid, else returns 0.
61+
unsigned getLinearIndex(Intrinsic::ID ID) {
62+
auto Decoded = DecodeIntrinsicIDNoFail(ID);
63+
if (!Decoded)
64+
return 0;
65+
unsigned TargetIdx = Decoded->first;
66+
unsigned IntrinsicIdx = Decoded->second;
67+
return TargetInfos[TargetIdx].FirstLinearIndex + IntrinsicIdx;
68+
}
69+
70+
ID Intrinsic::GetNextValidIntrinsicID(Intrinsic::ID ID) {
71+
if (ID == Intrinsic::not_intrinsic)
72+
return EncodeIntrinsicID(0, 0);
73+
if (ID == Intrinsic::last_valid_intrinsic_id)
74+
return Intrinsic::end_id;
75+
if (ID == Intrinsic::end_id)
76+
llvm_unreachable("Cannot find the next valid intrisnic");
77+
auto [TargetIndex, IntrinsicIndex] = DecodeIntrinsicID(ID);
78+
if (IntrinsicIndex + 1 < TargetInfos[TargetIndex].Count)
79+
return EncodeIntrinsicID(TargetIndex, IntrinsicIndex + 1);
80+
if (TargetIndex + 1 < NumTargets)
81+
return EncodeIntrinsicID(TargetIndex + 1, 0);
82+
llvm_unreachable("Cannot find the next valid intrisnic");
83+
}
3884

3985
/// Table of string intrinsic names indexed by enum value.
4086
static constexpr const char *const IntrinsicNameTable[] = {
@@ -45,12 +91,12 @@ static constexpr const char *const IntrinsicNameTable[] = {
4591
};
4692

4793
StringRef Intrinsic::getBaseName(ID id) {
48-
assert(id < num_intrinsics && "Invalid intrinsic ID!");
49-
return IntrinsicNameTable[id];
94+
assert(IsIntrinsicIDValid(id) && "Invalid intrinsic ID!");
95+
return ArrayRef(IntrinsicNameTable)[getLinearIndex(id)];
5096
}
5197

5298
StringRef Intrinsic::getName(ID id) {
53-
assert(id < num_intrinsics && "Invalid intrinsic ID!");
99+
assert(IsIntrinsicIDValid(id) && "Invalid intrinsic ID!");
54100
assert(!Intrinsic::isOverloaded(id) &&
55101
"This version of getName does not support overloading");
56102
return getBaseName(id);
@@ -157,8 +203,7 @@ static std::string getMangledTypeStr(Type *Ty, bool &HasUnnamedType) {
157203
static std::string getIntrinsicNameImpl(Intrinsic::ID Id, ArrayRef<Type *> Tys,
158204
Module *M, FunctionType *FT,
159205
bool EarlyModuleCheck) {
160-
161-
assert(Id < Intrinsic::num_intrinsics && "Invalid intrinsic ID!");
206+
assert(IsIntrinsicIDValid(Id) && "Invalid intrinsic ID!");
162207
assert((Tys.empty() || Intrinsic::isOverloaded(Id)) &&
163208
"This version of getName is for overloaded intrinsics only");
164209
(void)EarlyModuleCheck;
@@ -450,11 +495,15 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
450495
#undef GET_INTRINSIC_GENERATOR_GLOBAL
451496

452497
void Intrinsic::getIntrinsicInfoTableEntries(
453-
ID id, SmallVectorImpl<IITDescriptor> &T) {
498+
ID IntrinsicID, SmallVectorImpl<IITDescriptor> &T) {
454499
static_assert(sizeof(IIT_Table[0]) == 2,
455500
"Expect 16-bit entries in IIT_Table");
501+
assert(IsIntrinsicIDValid(IntrinsicID));
502+
unsigned Idx = getLinearIndex(IntrinsicID);
503+
if (Idx == 0)
504+
return;
456505
// Check to see if the intrinsic's type was expressible by the table.
457-
uint16_t TableVal = IIT_Table[id - 1];
506+
uint16_t TableVal = IIT_Table[Idx - 1];
458507

459508
// Decode the TableVal into an array of IITValues.
460509
SmallVector<unsigned char> IITValues;
@@ -609,19 +658,20 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
609658
return FunctionType::get(ResultTy, ArgTys, false);
610659
}
611660

612-
bool Intrinsic::isOverloaded(ID id) {
661+
// Check if an intrinsic is overloaded or not using its linear index.
662+
static bool isOverloadedUsingLinearIndex(unsigned Idx) {
613663
#define GET_INTRINSIC_OVERLOAD_TABLE
614664
#include "llvm/IR/IntrinsicImpl.inc"
615665
#undef GET_INTRINSIC_OVERLOAD_TABLE
616666
}
617667

618-
/// Table of per-target intrinsic name tables.
619-
#define GET_INTRINSIC_TARGET_DATA
620-
#include "llvm/IR/IntrinsicImpl.inc"
621-
#undef GET_INTRINSIC_TARGET_DATA
668+
bool Intrinsic::isOverloaded(ID id) {
669+
assert(IsIntrinsicIDValid(id));
670+
return isOverloadedUsingLinearIndex(getLinearIndex(id));
671+
}
622672

623673
bool Intrinsic::isTargetIntrinsic(Intrinsic::ID IID) {
624-
return IID > TargetInfos[0].Count;
674+
return IID != Intrinsic::not_intrinsic && DecodeIntrinsicID(IID).first != 0;
625675
}
626676

627677
int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
@@ -683,7 +733,29 @@ findTargetSubtable(StringRef Name) {
683733
// We've either found the target or just fall back to the generic set, which
684734
// is always first.
685735
const auto &TI = It != Targets.end() && It->Name == Target ? *It : Targets[0];
686-
return {ArrayRef(&IntrinsicNameTable[1] + TI.Offset, TI.Count), TI.Name};
736+
unsigned LinearIndex = TI.FirstLinearIndex;
737+
return {ArrayRef(IntrinsicNameTable + LinearIndex, TI.Count), TI.Name};
738+
}
739+
740+
static Intrinsic::ID getIntrinsicIDFromIndex(unsigned Idx) {
741+
if (Idx == 0)
742+
return Intrinsic::not_intrinsic;
743+
744+
auto It =
745+
partition_point(TargetInfos, [Idx](const IntrinsicTargetInfo &Info) {
746+
return Info.FirstLinearIndex + Info.Count < Idx;
747+
});
748+
// Idx, if present, will be in the entry at It or It + 1.
749+
if (It == std::end(TargetInfos))
750+
return Intrinsic::not_intrinsic;
751+
unsigned TargetIndex = std::distance(std::begin(TargetInfos), It);
752+
if (It->FirstLinearIndex <= Idx && Idx < It->FirstLinearIndex + It->Count)
753+
return EncodeIntrinsicID(TargetIndex, Idx - It->FirstLinearIndex);
754+
++It;
755+
++TargetIndex;
756+
if (It->FirstLinearIndex <= Idx && Idx < It->FirstLinearIndex + It->Count)
757+
return EncodeIntrinsicID(TargetIndex, Idx - It->FirstLinearIndex);
758+
return Intrinsic::not_intrinsic;
687759
}
688760

689761
/// This does the actual lookup of an intrinsic ID which matches the given
@@ -693,19 +765,19 @@ Intrinsic::ID Intrinsic::lookupIntrinsicID(StringRef Name) {
693765
int Idx = Intrinsic::lookupLLVMIntrinsicByName(NameTable, Name, Target);
694766
if (Idx == -1)
695767
return Intrinsic::not_intrinsic;
696-
697-
// Intrinsic IDs correspond to the location in IntrinsicNameTable, but we have
698-
// an index into a sub-table.
768+
const auto MatchSize = strlen(NameTable[Idx]);
769+
// Adjust the index from sub-table index to index into the global table.
699770
int Adjust = NameTable.data() - IntrinsicNameTable;
700-
Intrinsic::ID ID = static_cast<Intrinsic::ID>(Idx + Adjust);
771+
Idx += Adjust;
701772

702773
// If the intrinsic is not overloaded, require an exact match. If it is
703774
// overloaded, require either exact or prefix match.
704-
const auto MatchSize = strlen(NameTable[Idx]);
705775
assert(Name.size() >= MatchSize && "Expected either exact or prefix match");
706776
bool IsExactMatch = Name.size() == MatchSize;
707-
return IsExactMatch || Intrinsic::isOverloaded(ID) ? ID
708-
: Intrinsic::not_intrinsic;
777+
Intrinsic::ID r = IsExactMatch || isOverloadedUsingLinearIndex(Idx)
778+
? getIntrinsicIDFromIndex(Idx)
779+
: Intrinsic::not_intrinsic;
780+
return r;
709781
}
710782

711783
/// This defines the "Intrinsic::getAttributes(ID id)" method.
@@ -1043,8 +1115,9 @@ bool Intrinsic::matchIntrinsicVarArg(
10431115

10441116
bool Intrinsic::getIntrinsicSignature(Intrinsic::ID ID, FunctionType *FT,
10451117
SmallVectorImpl<Type *> &ArgTys) {
1046-
if (!ID)
1118+
if (ID == Intrinsic::not_intrinsic)
10471119
return false;
1120+
assert(IsIntrinsicIDValid(ID));
10481121

10491122
SmallVector<Intrinsic::IITDescriptor, 8> Table;
10501123
getIntrinsicInfoTableEntries(ID, Table);

0 commit comments

Comments
 (0)