Skip to content

Commit 8675074

Browse files
frederick-vs-jamahesh-attarde
authored andcommitted
[CodeGen] Get rid of incorrect std template specializations (llvm#160804)
This patch renames comparators - from `std::equal_to<llvm::rdf::RegisterRef>` to `llvm::rdf::RegisterRefEqualTo`, and - from `std::less<llvm::rdf::RegisterRef>` to `llvm::rdf::RegisterRefLess`. The original specializations don't satisfy the requirements for the original `std` templates by being stateful and non-default-constructible, so they make the program have UB due to C++17 [namespace.std]/2, C++20/23 [namespace.std]/5. > A program may explicitly instantiate a class template defined in the standard library only if the declaration > - depends on the name of at least one program-defined type, and > - the instantiation meets the standard library requirements for the original template.
1 parent f72548c commit 8675074

File tree

6 files changed

+74
-36
lines changed

6 files changed

+74
-36
lines changed

llvm/include/llvm/CodeGen/RDFGraph.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ struct NodeAllocator {
447447
AllocatorTy MemPool;
448448
};
449449

450-
using RegisterSet = std::set<RegisterRef>;
450+
using RegisterSet = std::set<RegisterRef, RegisterRefLess>;
451451

452452
struct TargetOperandInfo {
453453
TargetOperandInfo(const TargetInstrInfo &tii) : TII(tii) {}

llvm/include/llvm/CodeGen/RDFRegisters.h

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,33 @@ struct PhysicalRegisterInfo {
199199
std::vector<AliasInfo> AliasInfos;
200200
};
201201

202+
struct RegisterRefEqualTo {
203+
constexpr RegisterRefEqualTo(const llvm::rdf::PhysicalRegisterInfo &pri)
204+
: PRI(&pri) {}
205+
206+
bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
207+
return PRI->equal_to(A, B);
208+
}
209+
210+
private:
211+
// Make it a pointer just in case. See comment in `RegisterRefLess` below.
212+
const llvm::rdf::PhysicalRegisterInfo *PRI;
213+
};
214+
215+
struct RegisterRefLess {
216+
constexpr RegisterRefLess(const llvm::rdf::PhysicalRegisterInfo &pri)
217+
: PRI(&pri) {}
218+
219+
bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
220+
return PRI->less(A, B);
221+
}
222+
223+
private:
224+
// Make it a pointer because apparently some versions of MSVC use std::swap
225+
// on the comparator object.
226+
const llvm::rdf::PhysicalRegisterInfo *PRI;
227+
};
228+
202229
struct RegisterAggr {
203230
RegisterAggr(const PhysicalRegisterInfo &pri)
204231
: Units(pri.getTRI().getNumRegUnits()), PRI(pri) {}
@@ -334,42 +361,17 @@ template <> struct hash<llvm::rdf::RegisterAggr> {
334361
}
335362
};
336363

337-
template <> struct equal_to<llvm::rdf::RegisterRef> {
338-
constexpr equal_to(const llvm::rdf::PhysicalRegisterInfo &pri) : PRI(&pri) {}
339-
340-
bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
341-
return PRI->equal_to(A, B);
342-
}
343-
344-
private:
345-
// Make it a pointer just in case. See comment in `less` below.
346-
const llvm::rdf::PhysicalRegisterInfo *PRI;
347-
};
348-
349364
template <> struct equal_to<llvm::rdf::RegisterAggr> {
350365
bool operator()(const llvm::rdf::RegisterAggr &A,
351366
const llvm::rdf::RegisterAggr &B) const {
352367
return A == B;
353368
}
354369
};
355370

356-
template <> struct less<llvm::rdf::RegisterRef> {
357-
constexpr less(const llvm::rdf::PhysicalRegisterInfo &pri) : PRI(&pri) {}
358-
359-
bool operator()(llvm::rdf::RegisterRef A, llvm::rdf::RegisterRef B) const {
360-
return PRI->less(A, B);
361-
}
362-
363-
private:
364-
// Make it a pointer because apparently some versions of MSVC use std::swap
365-
// on the std::less specialization.
366-
const llvm::rdf::PhysicalRegisterInfo *PRI;
367-
};
368-
369371
} // namespace std
370372

371373
namespace llvm::rdf {
372-
using RegisterSet = std::set<RegisterRef, std::less<RegisterRef>>;
374+
using RegisterSet = std::set<RegisterRef, RegisterRefLess>;
373375
} // namespace llvm::rdf
374376

375377
#endif // LLVM_CODEGEN_RDFREGISTERS_H

llvm/lib/CodeGen/RDFLiveness.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,9 @@ void Liveness::computePhiInfo() {
652652
// defs, cache the result of subtracting these defs from a given register
653653
// ref.
654654
using RefHash = std::hash<RegisterRef>;
655-
using RefEqual = std::equal_to<RegisterRef>;
656-
using SubMap = std::unordered_map<RegisterRef, RegisterRef>;
655+
using RefEqual = RegisterRefEqualTo;
656+
using SubMap =
657+
std::unordered_map<RegisterRef, RegisterRef, RefHash, RefEqual>;
657658
std::unordered_map<RegisterAggr, SubMap> Subs;
658659
auto ClearIn = [](RegisterRef RR, const RegisterAggr &Mid, SubMap &SM) {
659660
if (Mid.empty())
@@ -868,7 +869,7 @@ void Liveness::computeLiveIns() {
868869
std::vector<RegisterRef> LV;
869870
for (const MachineBasicBlock::RegisterMaskPair &LI : B.liveins())
870871
LV.push_back(RegisterRef(LI.PhysReg, LI.LaneMask));
871-
llvm::sort(LV, std::less<RegisterRef>(PRI));
872+
llvm::sort(LV, RegisterRefLess(PRI));
872873
dbgs() << printMBBReference(B) << "\t rec = {";
873874
for (auto I : LV)
874875
dbgs() << ' ' << Print(I, DFG);
@@ -878,7 +879,7 @@ void Liveness::computeLiveIns() {
878879
LV.clear();
879880
for (RegisterRef RR : LiveMap[&B].refs())
880881
LV.push_back(RR);
881-
llvm::sort(LV, std::less<RegisterRef>(PRI));
882+
llvm::sort(LV, RegisterRefLess(PRI));
882883
dbgs() << "\tcomp = {";
883884
for (auto I : LV)
884885
dbgs() << ' ' << Print(I, DFG);

llvm/lib/Target/Hexagon/RDFCopy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ bool CopyPropagation::scanBlock(MachineBasicBlock *B) {
108108
for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG)) {
109109
if (DFG.IsCode<NodeAttrs::Stmt>(IA)) {
110110
NodeAddr<StmtNode*> SA = IA;
111-
EqualityMap EM(std::less<RegisterRef>(DFG.getPRI()));
111+
EqualityMap EM(RegisterRefLess(DFG.getPRI()));
112112
if (interpretAsCopy(SA.Addr->getCode(), EM))
113113
recordCopy(SA, EM);
114114
}

llvm/lib/Target/Hexagon/RDFCopy.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ class MachineInstr;
2525
namespace rdf {
2626

2727
struct CopyPropagation {
28-
CopyPropagation(DataFlowGraph &dfg) : MDT(dfg.getDT()), DFG(dfg),
29-
RDefMap(std::less<RegisterRef>(DFG.getPRI())) {}
28+
CopyPropagation(DataFlowGraph &dfg)
29+
: MDT(dfg.getDT()), DFG(dfg), RDefMap(RegisterRefLess(DFG.getPRI())) {}
3030

3131
virtual ~CopyPropagation() = default;
3232

@@ -35,7 +35,7 @@ namespace rdf {
3535
bool trace() const { return Trace; }
3636
DataFlowGraph &getDFG() { return DFG; }
3737

38-
using EqualityMap = std::map<RegisterRef, RegisterRef>;
38+
using EqualityMap = std::map<RegisterRef, RegisterRef, RegisterRefLess>;
3939
virtual bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM);
4040

4141
private:
@@ -45,7 +45,7 @@ namespace rdf {
4545
bool Trace = false;
4646

4747
// map: register -> (map: stmt -> reaching def)
48-
std::map<RegisterRef,std::map<NodeId,NodeId>> RDefMap;
48+
std::map<RegisterRef, std::map<NodeId, NodeId>, RegisterRefLess> RDefMap;
4949
// map: statement -> (map: dst reg -> src reg)
5050
std::map<NodeId, EqualityMap> CopyMap;
5151
std::vector<NodeId> Copies;

llvm/unittests/CodeGen/TypeTraitsTest.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "llvm/CodeGen/RDFRegisters.h"
910
#include "llvm/CodeGen/RegisterPressure.h"
1011
#include "llvm/CodeGen/ScheduleDAG.h"
1112
#include "llvm/CodeGen/SelectionDAGNodes.h"
1213
#include "llvm/CodeGen/SlotIndexes.h"
1314
#include "llvm/CodeGen/TargetPassConfig.h"
1415
#include "gtest/gtest.h"
16+
#include <functional>
1517
#include <type_traits>
18+
#include <utility>
1619

1720
using namespace llvm;
1821

@@ -23,3 +26,35 @@ static_assert(std::is_trivially_copyable_v<SDValue>, "trivially copyable");
2326
static_assert(std::is_trivially_copyable_v<SlotIndex>, "trivially copyable");
2427
static_assert(std::is_trivially_copyable_v<IdentifyingPassPtr>,
2528
"trivially copyable");
29+
30+
// https://llvm.org/PR105169
31+
// Verify that we won't accidently specialize std::less and std::equal_to in a
32+
// wrong way.
33+
// C++17 [namespace.std]/2, C++20/23 [namespace.std]/5:
34+
// A program may explicitly instantiate a template defined in the standard
35+
// library only if the declaration
36+
// - depends on the name of a user-defined type and
37+
// - the instantiation meets the standard library requirements for the
38+
// original template.
39+
template <class Fn> constexpr bool CheckStdCmpRequirements() {
40+
// std::less and std::equal_to are literal, default constructible, and
41+
// copyable classes.
42+
Fn f1;
43+
auto f2 = f1;
44+
auto f3 = std::move(f2);
45+
f2 = f3;
46+
f2 = std::move(f3);
47+
48+
// Properties held on all known implementations, although not guaranteed by
49+
// the standard.
50+
static_assert(std::is_empty_v<Fn>);
51+
static_assert(std::is_trivially_default_constructible_v<Fn>);
52+
static_assert(std::is_trivially_copyable_v<Fn>);
53+
54+
return true;
55+
}
56+
57+
static_assert(CheckStdCmpRequirements<std::less<rdf::RegisterRef>>(),
58+
"same as the original template");
59+
static_assert(CheckStdCmpRequirements<std::equal_to<rdf::RegisterRef>>(),
60+
"same as the original template");

0 commit comments

Comments
 (0)