1 //===-- SPIRVStructurizer.cpp ----------------------*- 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 //===----------------------------------------------------------------------===// 10 11 #include "Analysis/SPIRVConvergenceRegionAnalysis.h" 12 #include "SPIRV.h" 13 #include "SPIRVStructurizerWrapper.h" 14 #include "SPIRVSubtarget.h" 15 #include "SPIRVTargetMachine.h" 16 #include "SPIRVUtils.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/ADT/SmallPtrSet.h" 19 #include "llvm/Analysis/LoopInfo.h" 20 #include "llvm/CodeGen/IntrinsicLowering.h" 21 #include "llvm/IR/CFG.h" 22 #include "llvm/IR/Dominators.h" 23 #include "llvm/IR/IRBuilder.h" 24 #include "llvm/IR/IntrinsicInst.h" 25 #include "llvm/IR/Intrinsics.h" 26 #include "llvm/IR/IntrinsicsSPIRV.h" 27 #include "llvm/IR/LegacyPassManager.h" 28 #include "llvm/InitializePasses.h" 29 #include "llvm/PassRegistry.h" 30 #include "llvm/Transforms/Utils.h" 31 #include "llvm/Transforms/Utils/Cloning.h" 32 #include "llvm/Transforms/Utils/LoopSimplify.h" 33 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h" 34 #include <queue> 35 #include <stack> 36 #include <unordered_set> 37 38 using namespace llvm; 39 using namespace SPIRV; 40 41 namespace llvm { 42 43 void initializeSPIRVStructurizerPass(PassRegistry &); 44 45 namespace { 46 47 using BlockSet = std::unordered_set<BasicBlock *>; 48 using Edge = std::pair<BasicBlock *, BasicBlock *>; 49 50 // Helper function to do a partial order visit from the block |Start|, calling 51 // |Op| on each visited node. 52 void partialOrderVisit(BasicBlock &Start, 53 std::function<bool(BasicBlock *)> Op) { 54 PartialOrderingVisitor V(*Start.getParent()); 55 V.partialOrderVisit(Start, Op); 56 } 57 58 // Returns the exact convergence region in the tree defined by `Node` for which 59 // `BB` is the header, nullptr otherwise. 60 const ConvergenceRegion *getRegionForHeader(const ConvergenceRegion *Node, 61 BasicBlock *BB) { 62 if (Node->Entry == BB) 63 return Node; 64 65 for (auto *Child : Node->Children) { 66 const auto *CR = getRegionForHeader(Child, BB); 67 if (CR != nullptr) 68 return CR; 69 } 70 return nullptr; 71 } 72 73 // Returns the single BasicBlock exiting the convergence region `CR`, 74 // nullptr if no such exit exists. 75 BasicBlock *getExitFor(const ConvergenceRegion *CR) { 76 std::unordered_set<BasicBlock *> ExitTargets; 77 for (BasicBlock *Exit : CR->Exits) { 78 for (BasicBlock *Successor : successors(Exit)) { 79 if (CR->Blocks.count(Successor) == 0) 80 ExitTargets.insert(Successor); 81 } 82 } 83 84 assert(ExitTargets.size() <= 1); 85 if (ExitTargets.size() == 0) 86 return nullptr; 87 88 return *ExitTargets.begin(); 89 } 90 91 // Returns the merge block designated by I if I is a merge instruction, nullptr 92 // otherwise. 93 BasicBlock *getDesignatedMergeBlock(Instruction *I) { 94 IntrinsicInst *II = dyn_cast_or_null<IntrinsicInst>(I); 95 if (II == nullptr) 96 return nullptr; 97 98 if (II->getIntrinsicID() != Intrinsic::spv_loop_merge && 99 II->getIntrinsicID() != Intrinsic::spv_selection_merge) 100 return nullptr; 101 102 BlockAddress *BA = cast<BlockAddress>(II->getOperand(0)); 103 return BA->getBasicBlock(); 104 } 105 106 // Returns the continue block designated by I if I is an OpLoopMerge, nullptr 107 // otherwise. 108 BasicBlock *getDesignatedContinueBlock(Instruction *I) { 109 IntrinsicInst *II = dyn_cast_or_null<IntrinsicInst>(I); 110 if (II == nullptr) 111 return nullptr; 112 113 if (II->getIntrinsicID() != Intrinsic::spv_loop_merge) 114 return nullptr; 115 116 BlockAddress *BA = cast<BlockAddress>(II->getOperand(1)); 117 return BA->getBasicBlock(); 118 } 119 120 // Returns true if Header has one merge instruction which designated Merge as 121 // merge block. 122 bool isDefinedAsSelectionMergeBy(BasicBlock &Header, BasicBlock &Merge) { 123 for (auto &I : Header) { 124 BasicBlock *MB = getDesignatedMergeBlock(&I); 125 if (MB == &Merge) 126 return true; 127 } 128 return false; 129 } 130 131 // Returns true if the BB has one OpLoopMerge instruction. 132 bool hasLoopMergeInstruction(BasicBlock &BB) { 133 for (auto &I : BB) 134 if (getDesignatedContinueBlock(&I)) 135 return true; 136 return false; 137 } 138 139 // Returns true is I is an OpSelectionMerge or OpLoopMerge instruction, false 140 // otherwise. 141 bool isMergeInstruction(Instruction *I) { 142 return getDesignatedMergeBlock(I) != nullptr; 143 } 144 145 // Returns all blocks in F having at least one OpLoopMerge or OpSelectionMerge 146 // instruction. 147 SmallPtrSet<BasicBlock *, 2> getHeaderBlocks(Function &F) { 148 SmallPtrSet<BasicBlock *, 2> Output; 149 for (BasicBlock &BB : F) { 150 for (Instruction &I : BB) { 151 if (getDesignatedMergeBlock(&I) != nullptr) 152 Output.insert(&BB); 153 } 154 } 155 return Output; 156 } 157 158 // Returns all basic blocks in |F| referenced by at least 1 159 // OpSelectionMerge/OpLoopMerge instruction. 160 SmallPtrSet<BasicBlock *, 2> getMergeBlocks(Function &F) { 161 SmallPtrSet<BasicBlock *, 2> Output; 162 for (BasicBlock &BB : F) { 163 for (Instruction &I : BB) { 164 BasicBlock *MB = getDesignatedMergeBlock(&I); 165 if (MB != nullptr) 166 Output.insert(MB); 167 } 168 } 169 return Output; 170 } 171 172 // Return all the merge instructions contained in BB. 173 // Note: the SPIR-V spec doesn't allow a single BB to contain more than 1 merge 174 // instruction, but this can happen while we structurize the CFG. 175 std::vector<Instruction *> getMergeInstructions(BasicBlock &BB) { 176 std::vector<Instruction *> Output; 177 for (Instruction &I : BB) 178 if (isMergeInstruction(&I)) 179 Output.push_back(&I); 180 return Output; 181 } 182 183 // Returns all basic blocks in |F| referenced as continue target by at least 1 184 // OpLoopMerge instruction. 185 SmallPtrSet<BasicBlock *, 2> getContinueBlocks(Function &F) { 186 SmallPtrSet<BasicBlock *, 2> Output; 187 for (BasicBlock &BB : F) { 188 for (Instruction &I : BB) { 189 BasicBlock *MB = getDesignatedContinueBlock(&I); 190 if (MB != nullptr) 191 Output.insert(MB); 192 } 193 } 194 return Output; 195 } 196 197 // Do a preorder traversal of the CFG starting from the BB |Start|. 198 // point. Calls |op| on each basic block encountered during the traversal. 199 void visit(BasicBlock &Start, std::function<bool(BasicBlock *)> op) { 200 std::stack<BasicBlock *> ToVisit; 201 SmallPtrSet<BasicBlock *, 8> Seen; 202 203 ToVisit.push(&Start); 204 Seen.insert(ToVisit.top()); 205 while (ToVisit.size() != 0) { 206 BasicBlock *BB = ToVisit.top(); 207 ToVisit.pop(); 208 209 if (!op(BB)) 210 continue; 211 212 for (auto Succ : successors(BB)) { 213 if (Seen.contains(Succ)) 214 continue; 215 ToVisit.push(Succ); 216 Seen.insert(Succ); 217 } 218 } 219 } 220 221 // Replaces the conditional and unconditional branch targets of |BB| by 222 // |NewTarget| if the target was |OldTarget|. This function also makes sure the 223 // associated merge instruction gets updated accordingly. 224 void replaceIfBranchTargets(BasicBlock *BB, BasicBlock *OldTarget, 225 BasicBlock *NewTarget) { 226 auto *BI = cast<BranchInst>(BB->getTerminator()); 227 228 // 1. Replace all matching successors. 229 for (size_t i = 0; i < BI->getNumSuccessors(); i++) { 230 if (BI->getSuccessor(i) == OldTarget) 231 BI->setSuccessor(i, NewTarget); 232 } 233 234 // Branch was unconditional, no fixup required. 235 if (BI->isUnconditional()) 236 return; 237 238 // Branch had 2 successors, maybe now both are the same? 239 if (BI->getSuccessor(0) != BI->getSuccessor(1)) 240 return; 241 242 // Note: we may end up here because the original IR had such branches. 243 // This means Target is not necessarily equal to NewTarget. 244 IRBuilder<> Builder(BB); 245 Builder.SetInsertPoint(BI); 246 Builder.CreateBr(BI->getSuccessor(0)); 247 BI->eraseFromParent(); 248 249 // The branch was the only instruction, nothing else to do. 250 if (BB->size() == 1) 251 return; 252 253 // Otherwise, we need to check: was there an OpSelectionMerge before this 254 // branch? If we removed the OpBranchConditional, we must also remove the 255 // OpSelectionMerge. This is not valid for OpLoopMerge: 256 IntrinsicInst *II = 257 dyn_cast<IntrinsicInst>(BB->getTerminator()->getPrevNode()); 258 if (!II || II->getIntrinsicID() != Intrinsic::spv_selection_merge) 259 return; 260 261 Constant *C = cast<Constant>(II->getOperand(0)); 262 II->eraseFromParent(); 263 if (!C->isConstantUsed()) 264 C->destroyConstant(); 265 } 266 267 // Replaces the target of branch instruction in |BB| with |NewTarget| if it 268 // was |OldTarget|. This function also fixes the associated merge instruction. 269 // Note: this function does not simplify branching instructions, it only updates 270 // targets. See also: simplifyBranches. 271 void replaceBranchTargets(BasicBlock *BB, BasicBlock *OldTarget, 272 BasicBlock *NewTarget) { 273 auto *T = BB->getTerminator(); 274 if (isa<ReturnInst>(T)) 275 return; 276 277 if (isa<BranchInst>(T)) 278 return replaceIfBranchTargets(BB, OldTarget, NewTarget); 279 280 if (auto *SI = dyn_cast<SwitchInst>(T)) { 281 for (size_t i = 0; i < SI->getNumSuccessors(); i++) { 282 if (SI->getSuccessor(i) == OldTarget) 283 SI->setSuccessor(i, NewTarget); 284 } 285 return; 286 } 287 288 assert(false && "Unhandled terminator type."); 289 } 290 291 } // anonymous namespace 292 293 // Given a reducible CFG, produces a structurized CFG in the SPIR-V sense, 294 // adding merge instructions when required. 295 class SPIRVStructurizer : public FunctionPass { 296 297 struct DivergentConstruct; 298 // Represents a list of condition/loops/switch constructs. 299 // See SPIR-V 2.11.2. Structured Control-flow Constructs for the list of 300 // constructs. 301 using ConstructList = std::vector<std::unique_ptr<DivergentConstruct>>; 302 303 // Represents a divergent construct in the SPIR-V sense. 304 // Such constructs are represented by a header (entry), a merge block (exit), 305 // and possibly a continue block (back-edge). A construct can contain other 306 // constructs, but their boundaries do not cross. 307 struct DivergentConstruct { 308 BasicBlock *Header = nullptr; 309 BasicBlock *Merge = nullptr; 310 BasicBlock *Continue = nullptr; 311 312 DivergentConstruct *Parent = nullptr; 313 ConstructList Children; 314 }; 315 316 // An helper class to clean the construct boundaries. 317 // It is used to gather the list of blocks that should belong to each 318 // divergent construct, and possibly modify CFG edges when exits would cross 319 // the boundary of multiple constructs. 320 struct Splitter { 321 Function &F; 322 LoopInfo &LI; 323 DomTreeBuilder::BBDomTree DT; 324 DomTreeBuilder::BBPostDomTree PDT; 325 326 Splitter(Function &F, LoopInfo &LI) : F(F), LI(LI) { invalidate(); } 327 328 void invalidate() { 329 PDT.recalculate(F); 330 DT.recalculate(F); 331 } 332 333 // Returns the list of blocks that belong to a SPIR-V loop construct, 334 // including the continue construct. 335 std::vector<BasicBlock *> getLoopConstructBlocks(BasicBlock *Header, 336 BasicBlock *Merge) { 337 assert(DT.dominates(Header, Merge)); 338 std::vector<BasicBlock *> Output; 339 partialOrderVisit(*Header, [&](BasicBlock *BB) { 340 if (BB == Merge) 341 return false; 342 if (DT.dominates(Merge, BB) || !DT.dominates(Header, BB)) 343 return false; 344 Output.push_back(BB); 345 return true; 346 }); 347 return Output; 348 } 349 350 // Returns the list of blocks that belong to a SPIR-V selection construct. 351 std::vector<BasicBlock *> 352 getSelectionConstructBlocks(DivergentConstruct *Node) { 353 assert(DT.dominates(Node->Header, Node->Merge)); 354 BlockSet OutsideBlocks; 355 OutsideBlocks.insert(Node->Merge); 356 357 for (DivergentConstruct *It = Node->Parent; It != nullptr; 358 It = It->Parent) { 359 OutsideBlocks.insert(It->Merge); 360 if (It->Continue) 361 OutsideBlocks.insert(It->Continue); 362 } 363 364 std::vector<BasicBlock *> Output; 365 partialOrderVisit(*Node->Header, [&](BasicBlock *BB) { 366 if (OutsideBlocks.count(BB) != 0) 367 return false; 368 if (DT.dominates(Node->Merge, BB) || !DT.dominates(Node->Header, BB)) 369 return false; 370 Output.push_back(BB); 371 return true; 372 }); 373 return Output; 374 } 375 376 // Returns the list of blocks that belong to a SPIR-V switch construct. 377 std::vector<BasicBlock *> getSwitchConstructBlocks(BasicBlock *Header, 378 BasicBlock *Merge) { 379 assert(DT.dominates(Header, Merge)); 380 381 std::vector<BasicBlock *> Output; 382 partialOrderVisit(*Header, [&](BasicBlock *BB) { 383 // the blocks structurally dominated by a switch header, 384 if (!DT.dominates(Header, BB)) 385 return false; 386 // excluding blocks structurally dominated by the switch header’s merge 387 // block. 388 if (DT.dominates(Merge, BB) || BB == Merge) 389 return false; 390 Output.push_back(BB); 391 return true; 392 }); 393 return Output; 394 } 395 396 // Returns the list of blocks that belong to a SPIR-V case construct. 397 std::vector<BasicBlock *> getCaseConstructBlocks(BasicBlock *Target, 398 BasicBlock *Merge) { 399 assert(DT.dominates(Target, Merge)); 400 401 std::vector<BasicBlock *> Output; 402 partialOrderVisit(*Target, [&](BasicBlock *BB) { 403 // the blocks structurally dominated by an OpSwitch Target or Default 404 // block 405 if (!DT.dominates(Target, BB)) 406 return false; 407 // excluding the blocks structurally dominated by the OpSwitch 408 // construct’s corresponding merge block. 409 if (DT.dominates(Merge, BB) || BB == Merge) 410 return false; 411 Output.push_back(BB); 412 return true; 413 }); 414 return Output; 415 } 416 417 // Splits the given edges by recreating proxy nodes so that the destination 418 // has unique incoming edges from this region. 419 // 420 // clang-format off 421 // 422 // In SPIR-V, constructs must have a single exit/merge. 423 // Given nodes A and B in the construct, a node C outside, and the following edges. 424 // A -> C 425 // B -> C 426 // 427 // In such cases, we must create a new exit node D, that belong to the construct to make is viable: 428 // A -> D -> C 429 // B -> D -> C 430 // 431 // This is fine (assuming C has no PHI nodes), but requires handling the merge instruction here. 432 // By adding a proxy node, we create a regular divergent shape which can easily be regularized later on. 433 // A -> D -> D1 -> C 434 // B -> D -> D2 -> C 435 // 436 // A, B, D belongs to the construct. D is the exit. D1 and D2 are empty. 437 // 438 // clang-format on 439 std::vector<Edge> 440 createAliasBlocksForComplexEdges(std::vector<Edge> Edges) { 441 std::unordered_set<BasicBlock *> Seen; 442 std::vector<Edge> Output; 443 Output.reserve(Edges.size()); 444 445 for (auto &[Src, Dst] : Edges) { 446 auto [Iterator, Inserted] = Seen.insert(Src); 447 if (!Inserted) { 448 // Src already a source node. Cannot have 2 edges from A to B. 449 // Creating alias source block. 450 BasicBlock *NewSrc = BasicBlock::Create( 451 F.getContext(), Src->getName() + ".new.src", &F); 452 replaceBranchTargets(Src, Dst, NewSrc); 453 IRBuilder<> Builder(NewSrc); 454 Builder.CreateBr(Dst); 455 Src = NewSrc; 456 } 457 458 Output.emplace_back(Src, Dst); 459 } 460 461 return Output; 462 } 463 464 AllocaInst *CreateVariable(Function &F, Type *Type, 465 BasicBlock::iterator Position) { 466 const DataLayout &DL = F.getDataLayout(); 467 return new AllocaInst(Type, DL.getAllocaAddrSpace(), nullptr, "reg", 468 Position); 469 } 470 471 // Given a construct defined by |Header|, and a list of exiting edges 472 // |Edges|, creates a new single exit node, fixing up those edges. 473 BasicBlock *createSingleExitNode(BasicBlock *Header, 474 std::vector<Edge> &Edges) { 475 476 std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges(Edges); 477 478 std::vector<BasicBlock *> Dsts; 479 std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex; 480 auto NewExit = BasicBlock::Create(F.getContext(), 481 Header->getName() + ".new.exit", &F); 482 IRBuilder<> ExitBuilder(NewExit); 483 for (auto &[Src, Dst] : FixedEdges) { 484 if (DstToIndex.count(Dst) != 0) 485 continue; 486 DstToIndex.emplace(Dst, ExitBuilder.getInt32(DstToIndex.size())); 487 Dsts.push_back(Dst); 488 } 489 490 if (Dsts.size() == 1) { 491 for (auto &[Src, Dst] : FixedEdges) { 492 replaceBranchTargets(Src, Dst, NewExit); 493 } 494 ExitBuilder.CreateBr(Dsts[0]); 495 return NewExit; 496 } 497 498 AllocaInst *Variable = CreateVariable(F, ExitBuilder.getInt32Ty(), 499 F.begin()->getFirstInsertionPt()); 500 for (auto &[Src, Dst] : FixedEdges) { 501 IRBuilder<> B2(Src); 502 B2.SetInsertPoint(Src->getFirstInsertionPt()); 503 B2.CreateStore(DstToIndex[Dst], Variable); 504 replaceBranchTargets(Src, Dst, NewExit); 505 } 506 507 llvm::Value *Load = 508 ExitBuilder.CreateLoad(ExitBuilder.getInt32Ty(), Variable); 509 510 // If we can avoid an OpSwitch, generate an OpBranch. Reason is some 511 // OpBranch are allowed to exist without a new OpSelectionMerge if one of 512 // the branch is the parent's merge node, while OpSwitches are not. 513 if (Dsts.size() == 2) { 514 Value *Condition = 515 ExitBuilder.CreateCmp(CmpInst::ICMP_EQ, DstToIndex[Dsts[0]], Load); 516 ExitBuilder.CreateCondBr(Condition, Dsts[0], Dsts[1]); 517 return NewExit; 518 } 519 520 SwitchInst *Sw = ExitBuilder.CreateSwitch(Load, Dsts[0], Dsts.size() - 1); 521 for (auto It = Dsts.begin() + 1; It != Dsts.end(); ++It) { 522 Sw->addCase(DstToIndex[*It], *It); 523 } 524 return NewExit; 525 } 526 }; 527 528 /// Create a value in BB set to the value associated with the branch the block 529 /// terminator will take. 530 Value *createExitVariable( 531 BasicBlock *BB, 532 const DenseMap<BasicBlock *, ConstantInt *> &TargetToValue) { 533 auto *T = BB->getTerminator(); 534 if (isa<ReturnInst>(T)) 535 return nullptr; 536 537 IRBuilder<> Builder(BB); 538 Builder.SetInsertPoint(T); 539 540 if (auto *BI = dyn_cast<BranchInst>(T)) { 541 542 BasicBlock *LHSTarget = BI->getSuccessor(0); 543 BasicBlock *RHSTarget = 544 BI->isConditional() ? BI->getSuccessor(1) : nullptr; 545 546 Value *LHS = TargetToValue.count(LHSTarget) != 0 547 ? TargetToValue.at(LHSTarget) 548 : nullptr; 549 Value *RHS = TargetToValue.count(RHSTarget) != 0 550 ? TargetToValue.at(RHSTarget) 551 : nullptr; 552 553 if (LHS == nullptr || RHS == nullptr) 554 return LHS == nullptr ? RHS : LHS; 555 return Builder.CreateSelect(BI->getCondition(), LHS, RHS); 556 } 557 558 // TODO: add support for switch cases. 559 llvm_unreachable("Unhandled terminator type."); 560 } 561 562 // Creates a new basic block in F with a single OpUnreachable instruction. 563 BasicBlock *CreateUnreachable(Function &F) { 564 BasicBlock *BB = BasicBlock::Create(F.getContext(), "unreachable", &F); 565 IRBuilder<> Builder(BB); 566 Builder.CreateUnreachable(); 567 return BB; 568 } 569 570 // Add OpLoopMerge instruction on cycles. 571 bool addMergeForLoops(Function &F) { 572 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 573 auto *TopLevelRegion = 574 getAnalysis<SPIRVConvergenceRegionAnalysisWrapperPass>() 575 .getRegionInfo() 576 .getTopLevelRegion(); 577 578 bool Modified = false; 579 for (auto &BB : F) { 580 // Not a loop header. Ignoring for now. 581 if (!LI.isLoopHeader(&BB)) 582 continue; 583 auto *L = LI.getLoopFor(&BB); 584 585 // This loop header is not the entrance of a convergence region. Ignoring 586 // this block. 587 auto *CR = getRegionForHeader(TopLevelRegion, &BB); 588 if (CR == nullptr) 589 continue; 590 591 IRBuilder<> Builder(&BB); 592 593 auto *Merge = getExitFor(CR); 594 // We are indeed in a loop, but there are no exits (infinite loop). 595 // This could be caused by a bad shader, but also could be an artifact 596 // from an earlier optimization. It is not always clear if structurally 597 // reachable means runtime reachable, so we cannot error-out. What we must 598 // do however is to make is legal on the SPIR-V point of view, hence 599 // adding an unreachable merge block. 600 if (Merge == nullptr) { 601 BranchInst *Br = cast<BranchInst>(BB.getTerminator()); 602 assert(Br && 603 "This assumes the branch is not a switch. Maybe that's wrong?"); 604 assert(cast<BranchInst>(BB.getTerminator())->isUnconditional()); 605 606 Merge = CreateUnreachable(F); 607 Builder.SetInsertPoint(Br); 608 Builder.CreateCondBr(Builder.getFalse(), Merge, Br->getSuccessor(0)); 609 Br->eraseFromParent(); 610 } 611 612 auto *Continue = L->getLoopLatch(); 613 614 Builder.SetInsertPoint(BB.getTerminator()); 615 auto MergeAddress = BlockAddress::get(Merge->getParent(), Merge); 616 auto ContinueAddress = BlockAddress::get(Continue->getParent(), Continue); 617 SmallVector<Value *, 2> Args = {MergeAddress, ContinueAddress}; 618 619 Builder.CreateIntrinsic(Intrinsic::spv_loop_merge, {}, {Args}); 620 Modified = true; 621 } 622 623 return Modified; 624 } 625 626 // Adds an OpSelectionMerge to the immediate dominator or each node with an 627 // in-degree of 2 or more which is not already the merge target of an 628 // OpLoopMerge/OpSelectionMerge. 629 bool addMergeForNodesWithMultiplePredecessors(Function &F) { 630 DomTreeBuilder::BBDomTree DT; 631 DT.recalculate(F); 632 633 bool Modified = false; 634 for (auto &BB : F) { 635 if (pred_size(&BB) <= 1) 636 continue; 637 638 if (hasLoopMergeInstruction(BB) && pred_size(&BB) <= 2) 639 continue; 640 641 assert(DT.getNode(&BB)->getIDom()); 642 BasicBlock *Header = DT.getNode(&BB)->getIDom()->getBlock(); 643 644 if (isDefinedAsSelectionMergeBy(*Header, BB)) 645 continue; 646 647 IRBuilder<> Builder(Header); 648 Builder.SetInsertPoint(Header->getTerminator()); 649 650 auto MergeAddress = BlockAddress::get(BB.getParent(), &BB); 651 createOpSelectMerge(&Builder, MergeAddress); 652 653 Modified = true; 654 } 655 656 return Modified; 657 } 658 659 // When a block has multiple OpSelectionMerge/OpLoopMerge instructions, sorts 660 // them to put the "largest" first. A merge instruction is defined as larger 661 // than another when its target merge block post-dominates the other target's 662 // merge block. (This ordering should match the nesting ordering of the source 663 // HLSL). 664 bool sortSelectionMerge(Function &F, BasicBlock &Block) { 665 std::vector<Instruction *> MergeInstructions; 666 for (Instruction &I : Block) 667 if (isMergeInstruction(&I)) 668 MergeInstructions.push_back(&I); 669 670 if (MergeInstructions.size() <= 1) 671 return false; 672 673 Instruction *InsertionPoint = *MergeInstructions.begin(); 674 675 PartialOrderingVisitor Visitor(F); 676 std::sort(MergeInstructions.begin(), MergeInstructions.end(), 677 [&Visitor](Instruction *Left, Instruction *Right) { 678 if (Left == Right) 679 return false; 680 BasicBlock *RightMerge = getDesignatedMergeBlock(Right); 681 BasicBlock *LeftMerge = getDesignatedMergeBlock(Left); 682 return !Visitor.compare(RightMerge, LeftMerge); 683 }); 684 685 for (Instruction *I : MergeInstructions) { 686 I->moveBefore(InsertionPoint->getIterator()); 687 InsertionPoint = I; 688 } 689 690 return true; 691 } 692 693 // Sorts selection merge headers in |F|. 694 // A is sorted before B if the merge block designated by B is an ancestor of 695 // the one designated by A. 696 bool sortSelectionMergeHeaders(Function &F) { 697 bool Modified = false; 698 for (BasicBlock &BB : F) { 699 Modified |= sortSelectionMerge(F, BB); 700 } 701 return Modified; 702 } 703 704 // Split basic blocks containing multiple OpLoopMerge/OpSelectionMerge 705 // instructions so each basic block contains only a single merge instruction. 706 bool splitBlocksWithMultipleHeaders(Function &F) { 707 std::stack<BasicBlock *> Work; 708 for (auto &BB : F) { 709 std::vector<Instruction *> MergeInstructions = getMergeInstructions(BB); 710 if (MergeInstructions.size() <= 1) 711 continue; 712 Work.push(&BB); 713 } 714 715 const bool Modified = Work.size() > 0; 716 while (Work.size() > 0) { 717 BasicBlock *Header = Work.top(); 718 Work.pop(); 719 720 std::vector<Instruction *> MergeInstructions = 721 getMergeInstructions(*Header); 722 for (unsigned i = 1; i < MergeInstructions.size(); i++) { 723 BasicBlock *NewBlock = 724 Header->splitBasicBlock(MergeInstructions[i], "new.header"); 725 726 if (getDesignatedContinueBlock(MergeInstructions[0]) == nullptr) { 727 BasicBlock *Unreachable = CreateUnreachable(F); 728 729 BranchInst *BI = cast<BranchInst>(Header->getTerminator()); 730 IRBuilder<> Builder(Header); 731 Builder.SetInsertPoint(BI); 732 Builder.CreateCondBr(Builder.getTrue(), NewBlock, Unreachable); 733 BI->eraseFromParent(); 734 } 735 736 Header = NewBlock; 737 } 738 } 739 740 return Modified; 741 } 742 743 // Adds an OpSelectionMerge to each block with an out-degree >= 2 which 744 // doesn't already have an OpSelectionMerge. 745 bool addMergeForDivergentBlocks(Function &F) { 746 DomTreeBuilder::BBPostDomTree PDT; 747 PDT.recalculate(F); 748 bool Modified = false; 749 750 auto MergeBlocks = getMergeBlocks(F); 751 auto ContinueBlocks = getContinueBlocks(F); 752 753 for (auto &BB : F) { 754 if (getMergeInstructions(BB).size() != 0) 755 continue; 756 757 std::vector<BasicBlock *> Candidates; 758 for (BasicBlock *Successor : successors(&BB)) { 759 if (MergeBlocks.contains(Successor)) 760 continue; 761 if (ContinueBlocks.contains(Successor)) 762 continue; 763 Candidates.push_back(Successor); 764 } 765 766 if (Candidates.size() <= 1) 767 continue; 768 769 Modified = true; 770 BasicBlock *Merge = Candidates[0]; 771 772 auto MergeAddress = BlockAddress::get(Merge->getParent(), Merge); 773 IRBuilder<> Builder(&BB); 774 Builder.SetInsertPoint(BB.getTerminator()); 775 createOpSelectMerge(&Builder, MergeAddress); 776 } 777 778 return Modified; 779 } 780 781 // Gather all the exit nodes for the construct header by |Header| and 782 // containing the blocks |Construct|. 783 std::vector<Edge> getExitsFrom(const BlockSet &Construct, 784 BasicBlock &Header) { 785 std::vector<Edge> Output; 786 visit(Header, [&](BasicBlock *Item) { 787 if (Construct.count(Item) == 0) 788 return false; 789 790 for (BasicBlock *Successor : successors(Item)) { 791 if (Construct.count(Successor) == 0) 792 Output.emplace_back(Item, Successor); 793 } 794 return true; 795 }); 796 797 return Output; 798 } 799 800 // Build a divergent construct tree searching from |BB|. 801 // If |Parent| is not null, this tree is attached to the parent's tree. 802 void constructDivergentConstruct(BlockSet &Visited, Splitter &S, 803 BasicBlock *BB, DivergentConstruct *Parent) { 804 if (Visited.count(BB) != 0) 805 return; 806 Visited.insert(BB); 807 808 auto MIS = getMergeInstructions(*BB); 809 if (MIS.size() == 0) { 810 for (BasicBlock *Successor : successors(BB)) 811 constructDivergentConstruct(Visited, S, Successor, Parent); 812 return; 813 } 814 815 assert(MIS.size() == 1); 816 Instruction *MI = MIS[0]; 817 818 BasicBlock *Merge = getDesignatedMergeBlock(MI); 819 BasicBlock *Continue = getDesignatedContinueBlock(MI); 820 821 auto Output = std::make_unique<DivergentConstruct>(); 822 Output->Header = BB; 823 Output->Merge = Merge; 824 Output->Continue = Continue; 825 Output->Parent = Parent; 826 827 constructDivergentConstruct(Visited, S, Merge, Parent); 828 if (Continue) 829 constructDivergentConstruct(Visited, S, Continue, Output.get()); 830 831 for (BasicBlock *Successor : successors(BB)) 832 constructDivergentConstruct(Visited, S, Successor, Output.get()); 833 834 if (Parent) 835 Parent->Children.emplace_back(std::move(Output)); 836 } 837 838 // Returns the blocks belonging to the divergent construct |Node|. 839 BlockSet getConstructBlocks(Splitter &S, DivergentConstruct *Node) { 840 assert(Node->Header && Node->Merge); 841 842 if (Node->Continue) { 843 auto LoopBlocks = S.getLoopConstructBlocks(Node->Header, Node->Merge); 844 return BlockSet(LoopBlocks.begin(), LoopBlocks.end()); 845 } 846 847 auto SelectionBlocks = S.getSelectionConstructBlocks(Node); 848 return BlockSet(SelectionBlocks.begin(), SelectionBlocks.end()); 849 } 850 851 // Fixup the construct |Node| to respect a set of rules defined by the SPIR-V 852 // spec. 853 bool fixupConstruct(Splitter &S, DivergentConstruct *Node) { 854 bool Modified = false; 855 for (auto &Child : Node->Children) 856 Modified |= fixupConstruct(S, Child.get()); 857 858 // This construct is the root construct. Does not represent any real 859 // construct, just a way to access the first level of the forest. 860 if (Node->Parent == nullptr) 861 return Modified; 862 863 // This node's parent is the root. Meaning this is a top-level construct. 864 // There can be multiple exists, but all are guaranteed to exit at most 1 865 // construct since we are at first level. 866 if (Node->Parent->Header == nullptr) 867 return Modified; 868 869 // Health check for the structure. 870 assert(Node->Header && Node->Merge); 871 assert(Node->Parent->Header && Node->Parent->Merge); 872 873 BlockSet ConstructBlocks = getConstructBlocks(S, Node); 874 auto Edges = getExitsFrom(ConstructBlocks, *Node->Header); 875 876 // No edges exiting the construct. 877 if (Edges.size() < 1) 878 return Modified; 879 880 bool HasBadEdge = Node->Merge == Node->Parent->Merge || 881 Node->Merge == Node->Parent->Continue; 882 // BasicBlock *Target = Edges[0].second; 883 for (auto &[Src, Dst] : Edges) { 884 // - Breaking from a selection construct: S is a selection construct, S is 885 // the innermost structured 886 // control-flow construct containing A, and B is the merge block for S 887 // - Breaking from the innermost loop: S is the innermost loop construct 888 // containing A, 889 // and B is the merge block for S 890 if (Node->Merge == Dst) 891 continue; 892 893 // Entering the innermost loop’s continue construct: S is the innermost 894 // loop construct containing A, and B is the continue target for S 895 if (Node->Continue == Dst) 896 continue; 897 898 // TODO: what about cases branching to another case in the switch? Seems 899 // to work, but need to double check. 900 HasBadEdge = true; 901 } 902 903 if (!HasBadEdge) 904 return Modified; 905 906 // Create a single exit node gathering all exit edges. 907 BasicBlock *NewExit = S.createSingleExitNode(Node->Header, Edges); 908 909 // Fixup this construct's merge node to point to the new exit. 910 // Note: this algorithm fixes inner-most divergence construct first. So 911 // recursive structures sharing a single merge node are fixed from the 912 // inside toward the outside. 913 auto MergeInstructions = getMergeInstructions(*Node->Header); 914 assert(MergeInstructions.size() == 1); 915 Instruction *I = MergeInstructions[0]; 916 BlockAddress *BA = cast<BlockAddress>(I->getOperand(0)); 917 if (BA->getBasicBlock() == Node->Merge) { 918 auto MergeAddress = BlockAddress::get(NewExit->getParent(), NewExit); 919 I->setOperand(0, MergeAddress); 920 } 921 922 // Clean up of the possible dangling BockAddr operands to prevent MIR 923 // comments about "address of removed block taken". 924 if (!BA->isConstantUsed()) 925 BA->destroyConstant(); 926 927 Node->Merge = NewExit; 928 // Regenerate the dom trees. 929 S.invalidate(); 930 return true; 931 } 932 933 bool splitCriticalEdges(Function &F) { 934 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 935 Splitter S(F, LI); 936 937 DivergentConstruct Root; 938 BlockSet Visited; 939 constructDivergentConstruct(Visited, S, &*F.begin(), &Root); 940 return fixupConstruct(S, &Root); 941 } 942 943 // Simplify branches when possible: 944 // - if the 2 sides of a conditional branch are the same, transforms it to an 945 // unconditional branch. 946 // - if a switch has only 2 distinct successors, converts it to a conditional 947 // branch. 948 bool simplifyBranches(Function &F) { 949 bool Modified = false; 950 951 for (BasicBlock &BB : F) { 952 SwitchInst *SI = dyn_cast<SwitchInst>(BB.getTerminator()); 953 if (!SI) 954 continue; 955 if (SI->getNumCases() > 1) 956 continue; 957 958 Modified = true; 959 IRBuilder<> Builder(&BB); 960 Builder.SetInsertPoint(SI); 961 962 if (SI->getNumCases() == 0) { 963 Builder.CreateBr(SI->getDefaultDest()); 964 } else { 965 Value *Condition = 966 Builder.CreateCmp(CmpInst::ICMP_EQ, SI->getCondition(), 967 SI->case_begin()->getCaseValue()); 968 Builder.CreateCondBr(Condition, SI->case_begin()->getCaseSuccessor(), 969 SI->getDefaultDest()); 970 } 971 SI->eraseFromParent(); 972 } 973 974 return Modified; 975 } 976 977 // Makes sure every case target in |F| is unique. If 2 cases branch to the 978 // same basic block, one of the targets is updated so it jumps to a new basic 979 // block ending with a single unconditional branch to the original target. 980 bool splitSwitchCases(Function &F) { 981 bool Modified = false; 982 983 for (BasicBlock &BB : F) { 984 SwitchInst *SI = dyn_cast<SwitchInst>(BB.getTerminator()); 985 if (!SI) 986 continue; 987 988 BlockSet Seen; 989 Seen.insert(SI->getDefaultDest()); 990 991 auto It = SI->case_begin(); 992 while (It != SI->case_end()) { 993 BasicBlock *Target = It->getCaseSuccessor(); 994 if (Seen.count(Target) == 0) { 995 Seen.insert(Target); 996 ++It; 997 continue; 998 } 999 1000 Modified = true; 1001 BasicBlock *NewTarget = 1002 BasicBlock::Create(F.getContext(), "new.sw.case", &F); 1003 IRBuilder<> Builder(NewTarget); 1004 Builder.CreateBr(Target); 1005 SI->addCase(It->getCaseValue(), NewTarget); 1006 It = SI->removeCase(It); 1007 } 1008 } 1009 1010 return Modified; 1011 } 1012 1013 // Removes blocks not contributing to any structured CFG. This assumes there 1014 // is no PHI nodes. 1015 bool removeUselessBlocks(Function &F) { 1016 std::vector<BasicBlock *> ToRemove; 1017 1018 auto MergeBlocks = getMergeBlocks(F); 1019 auto ContinueBlocks = getContinueBlocks(F); 1020 1021 for (BasicBlock &BB : F) { 1022 if (BB.size() != 1) 1023 continue; 1024 1025 if (isa<ReturnInst>(BB.getTerminator())) 1026 continue; 1027 1028 if (MergeBlocks.count(&BB) != 0 || ContinueBlocks.count(&BB) != 0) 1029 continue; 1030 1031 if (BB.getUniqueSuccessor() == nullptr) 1032 continue; 1033 1034 BasicBlock *Successor = BB.getUniqueSuccessor(); 1035 std::vector<BasicBlock *> Predecessors(predecessors(&BB).begin(), 1036 predecessors(&BB).end()); 1037 for (BasicBlock *Predecessor : Predecessors) 1038 replaceBranchTargets(Predecessor, &BB, Successor); 1039 ToRemove.push_back(&BB); 1040 } 1041 1042 for (BasicBlock *BB : ToRemove) 1043 BB->eraseFromParent(); 1044 1045 return ToRemove.size() != 0; 1046 } 1047 1048 bool addHeaderToRemainingDivergentDAG(Function &F) { 1049 bool Modified = false; 1050 1051 auto MergeBlocks = getMergeBlocks(F); 1052 auto ContinueBlocks = getContinueBlocks(F); 1053 auto HeaderBlocks = getHeaderBlocks(F); 1054 1055 DomTreeBuilder::BBDomTree DT; 1056 DomTreeBuilder::BBPostDomTree PDT; 1057 PDT.recalculate(F); 1058 DT.recalculate(F); 1059 1060 for (BasicBlock &BB : F) { 1061 if (HeaderBlocks.count(&BB) != 0) 1062 continue; 1063 if (succ_size(&BB) < 2) 1064 continue; 1065 1066 size_t CandidateEdges = 0; 1067 for (BasicBlock *Successor : successors(&BB)) { 1068 if (MergeBlocks.count(Successor) != 0 || 1069 ContinueBlocks.count(Successor) != 0) 1070 continue; 1071 if (HeaderBlocks.count(Successor) != 0) 1072 continue; 1073 CandidateEdges += 1; 1074 } 1075 1076 if (CandidateEdges <= 1) 1077 continue; 1078 1079 BasicBlock *Header = &BB; 1080 BasicBlock *Merge = PDT.getNode(&BB)->getIDom()->getBlock(); 1081 1082 bool HasBadBlock = false; 1083 visit(*Header, [&](const BasicBlock *Node) { 1084 if (DT.dominates(Header, Node)) 1085 return false; 1086 if (PDT.dominates(Merge, Node)) 1087 return false; 1088 if (Node == Header || Node == Merge) 1089 return true; 1090 1091 HasBadBlock |= MergeBlocks.count(Node) != 0 || 1092 ContinueBlocks.count(Node) != 0 || 1093 HeaderBlocks.count(Node) != 0; 1094 return !HasBadBlock; 1095 }); 1096 1097 if (HasBadBlock) 1098 continue; 1099 1100 Modified = true; 1101 1102 if (Merge == nullptr) { 1103 Merge = *successors(Header).begin(); 1104 IRBuilder<> Builder(Header); 1105 Builder.SetInsertPoint(Header->getTerminator()); 1106 1107 auto MergeAddress = BlockAddress::get(Merge->getParent(), Merge); 1108 createOpSelectMerge(&Builder, MergeAddress); 1109 continue; 1110 } 1111 1112 Instruction *SplitInstruction = Merge->getTerminator(); 1113 if (isMergeInstruction(SplitInstruction->getPrevNode())) 1114 SplitInstruction = SplitInstruction->getPrevNode(); 1115 BasicBlock *NewMerge = 1116 Merge->splitBasicBlockBefore(SplitInstruction, "new.merge"); 1117 1118 IRBuilder<> Builder(Header); 1119 Builder.SetInsertPoint(Header->getTerminator()); 1120 1121 auto MergeAddress = BlockAddress::get(NewMerge->getParent(), NewMerge); 1122 createOpSelectMerge(&Builder, MergeAddress); 1123 } 1124 1125 return Modified; 1126 } 1127 1128 public: 1129 static char ID; 1130 1131 SPIRVStructurizer() : FunctionPass(ID) { 1132 initializeSPIRVStructurizerPass(*PassRegistry::getPassRegistry()); 1133 }; 1134 1135 virtual bool runOnFunction(Function &F) override { 1136 bool Modified = false; 1137 1138 // In LLVM, Switches are allowed to have several cases branching to the same 1139 // basic block. This is allowed in SPIR-V, but can make structurizing SPIR-V 1140 // harder, so first remove edge cases. 1141 Modified |= splitSwitchCases(F); 1142 1143 // LLVM allows conditional branches to have both side jumping to the same 1144 // block. It also allows switched to have a single default, or just one 1145 // case. Cleaning this up now. 1146 Modified |= simplifyBranches(F); 1147 1148 // At this state, we should have a reducible CFG with cycles. 1149 // STEP 1: Adding OpLoopMerge instructions to loop headers. 1150 Modified |= addMergeForLoops(F); 1151 1152 // STEP 2: adding OpSelectionMerge to each node with an in-degree >= 2. 1153 Modified |= addMergeForNodesWithMultiplePredecessors(F); 1154 1155 // STEP 3: 1156 // Sort selection merge, the largest construct goes first. 1157 // This simplifies the next step. 1158 Modified |= sortSelectionMergeHeaders(F); 1159 1160 // STEP 4: As this stage, we can have a single basic block with multiple 1161 // OpLoopMerge/OpSelectionMerge instructions. Splitting this block so each 1162 // BB has a single merge instruction. 1163 Modified |= splitBlocksWithMultipleHeaders(F); 1164 1165 // STEP 5: In the previous steps, we added merge blocks the loops and 1166 // natural merge blocks (in-degree >= 2). What remains are conditions with 1167 // an exiting branch (return, unreachable). In such case, we must start from 1168 // the header, and add headers to divergent construct with no headers. 1169 Modified |= addMergeForDivergentBlocks(F); 1170 1171 // STEP 6: At this stage, we have several divergent construct defines by a 1172 // header and a merge block. But their boundaries have no constraints: a 1173 // construct exit could be outside of the parents' construct exit. Such 1174 // edges are called critical edges. What we need is to split those edges 1175 // into several parts. Each part exiting the parent's construct by its merge 1176 // block. 1177 Modified |= splitCriticalEdges(F); 1178 1179 // STEP 7: The previous steps possibly created a lot of "proxy" blocks. 1180 // Blocks with a single unconditional branch, used to create a valid 1181 // divergent construct tree. Some nodes are still requires (e.g: nodes 1182 // allowing a valid exit through the parent's merge block). But some are 1183 // left-overs of past transformations, and could cause actual validation 1184 // issues. E.g: the SPIR-V spec allows a construct to break to the parents 1185 // loop construct without an OpSelectionMerge, but this requires a straight 1186 // jump. If a proxy block lies between the conditional branch and the 1187 // parent's merge, the CFG is not valid. 1188 Modified |= removeUselessBlocks(F); 1189 1190 // STEP 8: Final fix-up steps: our tree boundaries are correct, but some 1191 // blocks are branching with no header. Those are often simple conditional 1192 // branches with 1 or 2 returning edges. Adding a header for those. 1193 Modified |= addHeaderToRemainingDivergentDAG(F); 1194 1195 // STEP 9: sort basic blocks to match both the LLVM & SPIR-V requirements. 1196 Modified |= sortBlocks(F); 1197 1198 return Modified; 1199 } 1200 1201 void getAnalysisUsage(AnalysisUsage &AU) const override { 1202 AU.addRequired<DominatorTreeWrapperPass>(); 1203 AU.addRequired<LoopInfoWrapperPass>(); 1204 AU.addRequired<SPIRVConvergenceRegionAnalysisWrapperPass>(); 1205 1206 AU.addPreserved<SPIRVConvergenceRegionAnalysisWrapperPass>(); 1207 FunctionPass::getAnalysisUsage(AU); 1208 } 1209 1210 void createOpSelectMerge(IRBuilder<> *Builder, BlockAddress *MergeAddress) { 1211 Instruction *BBTerminatorInst = Builder->GetInsertBlock()->getTerminator(); 1212 1213 MDNode *MDNode = BBTerminatorInst->getMetadata("hlsl.controlflow.hint"); 1214 1215 ConstantInt *BranchHint = llvm::ConstantInt::get(Builder->getInt32Ty(), 0); 1216 1217 if (MDNode) { 1218 assert(MDNode->getNumOperands() == 2 && 1219 "invalid metadata hlsl.controlflow.hint"); 1220 BranchHint = mdconst::extract<ConstantInt>(MDNode->getOperand(1)); 1221 1222 assert(BranchHint && "invalid metadata value for hlsl.controlflow.hint"); 1223 } 1224 1225 llvm::SmallVector<llvm::Value *, 2> Args = {MergeAddress, BranchHint}; 1226 1227 Builder->CreateIntrinsic(Intrinsic::spv_selection_merge, 1228 {MergeAddress->getType()}, {Args}); 1229 } 1230 }; 1231 } // namespace llvm 1232 1233 char SPIRVStructurizer::ID = 0; 1234 1235 INITIALIZE_PASS_BEGIN(SPIRVStructurizer, "spirv-structurizer", 1236 "structurize SPIRV", false, false) 1237 INITIALIZE_PASS_DEPENDENCY(LoopSimplify) 1238 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 1239 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) 1240 INITIALIZE_PASS_DEPENDENCY(SPIRVConvergenceRegionAnalysisWrapperPass) 1241 1242 INITIALIZE_PASS_END(SPIRVStructurizer, "spirv-structurizer", 1243 "structurize SPIRV", false, false) 1244 1245 FunctionPass *llvm::createSPIRVStructurizerPass() { 1246 return new SPIRVStructurizer(); 1247 } 1248 1249 PreservedAnalyses SPIRVStructurizerWrapper::run(Function &F, 1250 FunctionAnalysisManager &AF) { 1251 1252 auto FPM = legacy::FunctionPassManager(F.getParent()); 1253 FPM.add(createSPIRVStructurizerPass()); 1254 1255 if (!FPM.run(F)) 1256 return PreservedAnalyses::all(); 1257 PreservedAnalyses PA; 1258 PA.preserveSet<CFGAnalyses>(); 1259 return PA; 1260 } 1261