LLVM: include/llvm/IR/GenericConvergenceVerifierImpl.h Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26#ifndef LLVM_IR_GENERICCONVERGENCEVERIFIERIMPL_H

27#define LLVM_IR_GENERICCONVERGENCEVERIFIERIMPL_H

28

33

34#define Check(C, ...) \

35 do { \

36 if (!(C)) { \

37 reportFailure(__VA_ARGS__); \

38 return; \

39 } \

40 } while (false)

41

42#define CheckOrNull(C, ...) \

43 do { \

44 if (!(C)) { \

45 reportFailure(__VA_ARGS__); \

46 return {}; \

47 } \

48 } while (false)

49

50namespace llvm {

52 Tokens.clear();

53 CI.clear();

54 ConvergenceKind = NoConvergence;

55}

56

57template

59 SeenFirstConvOp = false;

60}

61

62template

64 ConvOpKind ConvOp = getConvOp(I);

65

66 auto *TokenDef = findAndCheckConvergenceTokenUsed(I);

67 switch (ConvOp) {

68 case CONV_ENTRY:

69 Check(isInsideConvergentFunction(I),

70 "Entry intrinsic can occur only in a convergent function.",

71 {Context.print(&I)});

72 Check(I.getParent()->isEntryBlock(),

73 "Entry intrinsic can occur only in the entry block.",

74 {Context.print(&I)});

75 Check(!SeenFirstConvOp,

76 "Entry intrinsic cannot be preceded by a convergent operation in the "

77 "same basic block.",

78 {Context.print(&I)});

79 [[fallthrough]];

80 case CONV_ANCHOR:

82 "Entry or anchor intrinsic cannot have a convergencectrl token "

83 "operand.",

84 {Context.print(&I)});

85 break;

86 case CONV_LOOP:

87 Check(TokenDef, "Loop intrinsic must have a convergencectrl token operand.",

88 {Context.print(&I)});

89 Check(!SeenFirstConvOp,

90 "Loop intrinsic cannot be preceded by a convergent operation in the "

91 "same basic block.",

92 {Context.print(&I)});

93 break;

94 default:

95 break;

96 }

97

98 if (ConvOp != CONV_NONE)

99 checkConvergenceTokenProduced(I);

100

101 if (isConvergent(I))

102 SeenFirstConvOp = true;

103

104 if (TokenDef || ConvOp != CONV_NONE) {

105 Check(ConvergenceKind != UncontrolledConvergence,

106 "Cannot mix controlled and uncontrolled convergence in the same "

107 "function.",

108 {Context.print(&I)});

109 ConvergenceKind = ControlledConvergence;

110 } else if (isConvergent(I)) {

111 Check(ConvergenceKind != ControlledConvergence,

112 "Cannot mix controlled and uncontrolled convergence in the same "

113 "function.",

114 {Context.print(&I)});

115 ConvergenceKind = UncontrolledConvergence;

116 }

117}

118

119template

120void GenericConvergenceVerifier::reportFailure(

122 FailureCB(Message);

123 if (OS) {

124 for (auto V : DumpedValues)

125 *OS << V << '\n';

126 }

127}

128

129template

131 assert(Context.getFunction());

132 const auto &F = *Context.getFunction();

133

136

137

138

139

140 CI.compute(const_cast<FunctionT &>(F));

141

144 Check(DT.dominates(Token->getParent(), User->getParent()),

145 "Convergence control token must dominate all its uses.",

146 {Context.print(Token), Context.print(User)});

147

149 "Convergence region is not well-nested.",

150 {Context.print(Token), Context.print(User)});

151 while (LiveTokens.back() != Token)

152 LiveTokens.pop_back();

153

154

155 auto *BB = User->getParent();

156 auto *BBCycle = CI.getCycle(BB);

157 if (!BBCycle)

158 return;

159

160 auto *DefBB = Token->getParent();

161 if (DefBB == BB || BBCycle->contains(DefBB)) {

162

163 return;

164 }

165

166 Check(getConvOp(*User) == CONV_LOOP,

167 "Convergence token used by an instruction other than "

168 "llvm.experimental.convergence.loop in a cycle that does "

169 "not contain the token's definition.",

170 {Context.print(User), CI.print(BBCycle)});

171

172 while (true) {

173 auto *Parent = BBCycle->getParentCycle();

174 if (!Parent || Parent->contains(DefBB))

175 break;

176 BBCycle = Parent;

177 };

178

179 Check(BBCycle->isReducible() && BB == BBCycle->getHeader(),

180 "Cycle heart must dominate all blocks in the cycle.",

181 {Context.print(User), Context.printAsOperand(BB), CI.print(BBCycle)});

183 "Two static convergence token uses in a cycle that does "

184 "not contain either token's definition.",

185 {Context.print(User), Context.print(CycleHearts[BBCycle]),

186 CI.print(BBCycle)});

187 CycleHearts[BBCycle] = User;

188 };

189

192 for (auto *BB : RPOT) {

193 LiveTokens.clear();

194 auto LTIt = LiveTokenMap.find(BB);

195 if (LTIt != LiveTokenMap.end()) {

196 LiveTokens = std::move(LTIt->second);

197 LiveTokenMap.erase(LTIt);

198 }

199

200 for (auto &I : *BB) {

201 if (auto *Token = Tokens.lookup(&I))

202 checkToken(Token, &I, LiveTokens);

203 if (getConvOp(I) != CONV_NONE)

205 }

206

207

209 auto *SuccNode = DT.getNode(Succ);

210 auto [LTIt, Inserted] = LiveTokenMap.try_emplace(Succ);

211 if (Inserted) {

212

213

214 for (auto LiveToken : LiveTokens) {

215 if (!DT.dominates(DT.getNode(LiveToken->getParent()), SuccNode))

216 break;

217 LTIt->second.push_back(LiveToken);

218 }

219 } else {

220

222 LTIt->second, [&LiveTokens](const InstructionT *Token) {

223 return llvm::is_contained(LiveTokens, Token);

224 });

225 LTIt->second.erase(It, LTIt->second.end());

226 }

227 }

228 }

229}

230

231}

232

233#endif

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

A verifier for the static rules of convergence control tokens that works with both LLVM IR and MIR.

This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

iterator find(const_arg_type_t< KeyT > Val)

std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)

bool erase(const KeyT &Val)

size_type count(const_arg_type_t< KeyT > Val) const

Return 1 if the specified key is in the map, 0 otherwise.

typename ContextT::InstructionT InstructionT

typename ContextT::DominatorTreeT DominatorTreeT

typename ContextT::BlockT BlockT

typename ContextT::FunctionT FunctionT

void verify(const DominatorTreeT &DT)

Definition GenericConvergenceVerifierImpl.h:130

void visit(const BlockT &BB)

Definition GenericConvergenceVerifierImpl.h:58

void clear()

Definition GenericConvergenceVerifierImpl.h:51

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

This is an optimization pass for GlobalISel generic memory operations.

auto successors(const MachineBasicBlock *BB)

auto partition(R &&Range, UnaryPredicate P)

Provide wrappers to std::partition which take ranges instead of having to pass begin/end explicitly.

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.