LLVM: lib/CodeGen/AtomicExpandPass.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

53#include

54#include

55#include

56

57using namespace llvm;

58

59#define DEBUG_TYPE "atomic-expand"

60

61namespace {

62

63class AtomicExpandImpl {

66

67private:

71 bool tryExpandAtomicLoad(LoadInst *LI);

72 bool expandAtomicLoadToLL(LoadInst *LI);

73 bool expandAtomicLoadToCmpXchg(LoadInst *LI);

75 bool tryExpandAtomicStore(StoreInst *SI);

76 void expandAtomicStore(StoreInst *SI);

83 void expandAtomicOpToLLSC(

87 void expandPartwordAtomicRMW(

91 void expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI);

93

95 static Value *insertRMWCmpXchgLoop(

101

105

107 Value *PointerOperand, Value *ValueOperand,

111 void expandAtomicLoadToLibcall(LoadInst *LI);

112 void expandAtomicStoreToLibcall(StoreInst *LI);

115

116 friend bool

119

121

122public:

124};

125

126class AtomicExpandLegacy : public FunctionPass {

127public:

128 static char ID;

129

132 }

133

135};

136

137

138struct ReplacementIRBuilder

139 : IRBuilder<InstSimplifyFolder, IRBuilderCallbackInserter> {

140 MDNode *MMRAMD = nullptr;

141

142

143

150 if (BB->getParent()->getAttributes().hasFnAttr(Attribute::StrictFP))

152

153 MMRAMD = I->getMetadata(LLVMContext::MD_mmra);

154 }

155

158 I->setMetadata(LLVMContext::MD_mmra, MMRAMD);

159 }

160};

161

162}

163

164char AtomicExpandLegacy::ID = 0;

165

167

169 "Expand Atomic instructions", false, false)

173

174

177 return DL.getTypeStoreSize(LI->getType());

178}

179

182 return DL.getTypeStoreSize(SI->getValueOperand()->getType());

183}

184

188}

189

193}

194

195

199 Source.getAllMetadata(MD);

202

203 for (auto [ID, N] : MD) {

204 switch (ID) {

205 case LLVMContext::MD_dbg:

206 case LLVMContext::MD_tbaa:

207 case LLVMContext::MD_tbaa_struct:

208 case LLVMContext::MD_alias_scope:

209 case LLVMContext::MD_noalias:

210 case LLVMContext::MD_noalias_addrspace:

211 case LLVMContext::MD_access_group:

212 case LLVMContext::MD_mmra:

214 break;

215 default:

216 if (ID == Ctx.getMDKindID("amdgpu.no.remote.memory"))

218 else if (ID == Ctx.getMDKindID("amdgpu.no.fine.grained.memory"))

220

221

222

223 break;

224 }

225 }

226}

227

228

229

230

231template

234 Align Alignment = I->getAlign();

235 return Alignment >= Size &&

237}

238

239bool AtomicExpandImpl::processAtomicInstr(Instruction *I) {

240 auto *LI = dyn_cast(I);

241 auto *SI = dyn_cast(I);

242 auto *RMWI = dyn_cast(I);

243 auto *CASI = dyn_cast(I);

244

245 bool MadeChange = false;

246

247

248 if (LI) {

249 if (!LI->isAtomic())

250 return false;

251

253 expandAtomicLoadToLibcall(LI);

254 return true;

255 }

256

257 if (TLI->shouldCastAtomicLoadInIR(LI) ==

258 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {

259 I = LI = convertAtomicLoadToIntegerType(LI);

260 MadeChange = true;

261 }

262 } else if (SI) {

263 if (SI->isAtomic())

264 return false;

265

267 expandAtomicStoreToLibcall(SI);

268 return true;

269 }

270

271 if (TLI->shouldCastAtomicStoreInIR(SI) ==

272 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {

273 I = SI = convertAtomicStoreToIntegerType(SI);

274 MadeChange = true;

275 }

276 } else if (RMWI) {

278 expandAtomicRMWToLibcall(RMWI);

279 return true;

280 }

281

282 if (TLI->shouldCastAtomicRMWIInIR(RMWI) ==

283 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {

284 I = RMWI = convertAtomicXchgToIntegerType(RMWI);

285 MadeChange = true;

286 }

287 } else if (CASI) {

289 expandAtomicCASToLibcall(CASI);

290 return true;

291 }

292

293

294

295 if (CASI->getCompareOperand()->getType()->isPointerTy()) {

296

297

298 I = CASI = convertCmpXchgToIntegerType(CASI);

299 MadeChange = true;

300 }

301 } else

302 return false;

303

304 if (TLI->shouldInsertFencesForAtomic(I)) {

305 auto FenceOrdering = AtomicOrdering::Monotonic;

307 FenceOrdering = LI->getOrdering();

308 LI->setOrdering(AtomicOrdering::Monotonic);

310 FenceOrdering = SI->getOrdering();

311 SI->setOrdering(AtomicOrdering::Monotonic);

314 FenceOrdering = RMWI->getOrdering();

315 RMWI->setOrdering(AtomicOrdering::Monotonic);

316 } else if (CASI &&

317 TLI->shouldExpandAtomicCmpXchgInIR(CASI) ==

318 TargetLoweringBase::AtomicExpansionKind::None &&

322

323

324

325

326 FenceOrdering = CASI->getMergedOrdering();

327 CASI->setSuccessOrdering(AtomicOrdering::Monotonic);

328 CASI->setFailureOrdering(AtomicOrdering::Monotonic);

329 }

330

331 if (FenceOrdering != AtomicOrdering::Monotonic) {

332 MadeChange |= bracketInstWithFences(I, FenceOrdering);

333 }

334 } else if (I->hasAtomicStore() &&

335 TLI->shouldInsertTrailingFenceForAtomicStore(I)) {

336 auto FenceOrdering = AtomicOrdering::Monotonic;

337 if (SI)

338 FenceOrdering = SI->getOrdering();

339 else if (RMWI)

340 FenceOrdering = RMWI->getOrdering();

341 else if (CASI && TLI->shouldExpandAtomicCmpXchgInIR(CASI) !=

342 TargetLoweringBase::AtomicExpansionKind::LLSC)

343

344 FenceOrdering = CASI->getSuccessOrdering();

345

347 if (auto TrailingFence =

348 TLI->emitTrailingFence(Builder, I, FenceOrdering)) {

349 TrailingFence->moveAfter(I);

350 MadeChange = true;

351 }

352 }

353

354 if (LI)

355 MadeChange |= tryExpandAtomicLoad(LI);

356 else if (SI)

357 MadeChange |= tryExpandAtomicStore(SI);

358 else if (RMWI) {

359

360

361

362

363

364 if (isIdempotentRMW(RMWI) && simplifyIdempotentRMW(RMWI)) {

365 MadeChange = true;

366

367 } else {

368 MadeChange |= tryExpandAtomicRMW(RMWI);

369 }

370 } else if (CASI)

371 MadeChange |= tryExpandAtomicCmpXchg(CASI);

372

373 return MadeChange;

374}

375

377 const auto *Subtarget = TM->getSubtargetImpl(F);

378 if (!Subtarget->enableAtomicExpand())

379 return false;

380 TLI = Subtarget->getTargetLowering();

381 DL = &F.getDataLayout();

382

383 bool MadeChange = false;

384

387

389

391 I = Next) {

393 Next = std::next(I);

394

395 if (processAtomicInstr(&Inst)) {

396 MadeChange = true;

397

398

399 BBE = F.end();

400 }

401 }

402 }

403

404 return MadeChange;

405}

406

407bool AtomicExpandLegacy::runOnFunction(Function &F) {

408

409 auto *TPC = getAnalysisIfAvailable();

410 if (!TPC)

411 return false;

413 AtomicExpandImpl AE;

414 return AE.run(F, TM);

415}

416

418 return new AtomicExpandLegacy();

419}

420

423 AtomicExpandImpl AE;

424

425 bool Changed = AE.run(F, TM);

426 if (!Changed)

428

430}

431

432bool AtomicExpandImpl::bracketInstWithFences(Instruction *I,

434 ReplacementIRBuilder Builder(I, *DL);

435

436 auto LeadingFence = TLI->emitLeadingFence(Builder, I, Order);

437

438 auto TrailingFence = TLI->emitTrailingFence(Builder, I, Order);

439

440

441 if (TrailingFence)

442 TrailingFence->moveAfter(I);

443

444 return (LeadingFence || TrailingFence);

445}

446

447

449AtomicExpandImpl::getCorrespondingIntegerType(Type *T, const DataLayout &DL) {

450 EVT VT = TLI->getMemValueType(DL, T);

454}

455

456

457

458

459LoadInst *AtomicExpandImpl::convertAtomicLoadToIntegerType(LoadInst *LI) {

461 Type *NewTy = getCorrespondingIntegerType(LI->getType(), M->getDataLayout());

462

463 ReplacementIRBuilder Builder(LI, *DL);

464

466

467 auto *NewLI = Builder.CreateLoad(NewTy, Addr);

468 NewLI->setAlignment(LI->getAlign());

469 NewLI->setVolatile(LI->isVolatile());

471 LLVM_DEBUG(dbgs() << "Replaced " << *LI << " with " << *NewLI << "\n");

472

473 Value *NewVal = Builder.CreateBitCast(NewLI, LI->getType());

476 return NewLI;

477}

478

480AtomicExpandImpl::convertAtomicXchgToIntegerType(AtomicRMWInst *RMWI) {

482

484 Type *NewTy =

485 getCorrespondingIntegerType(RMWI->getType(), M->getDataLayout());

486

487 ReplacementIRBuilder Builder(RMWI, *DL);

488

492 ? Builder.CreatePtrToInt(Val, NewTy)

493 : Builder.CreateBitCast(Val, NewTy);

494

498 NewRMWI->setVolatile(RMWI->isVolatile());

500 LLVM_DEBUG(dbgs() << "Replaced " << *RMWI << " with " << *NewRMWI << "\n");

501

503 ? Builder.CreateIntToPtr(NewRMWI, RMWI->getType())

504 : Builder.CreateBitCast(NewRMWI, RMWI->getType());

507 return NewRMWI;

508}

509

510bool AtomicExpandImpl::tryExpandAtomicLoad(LoadInst *LI) {

511 switch (TLI->shouldExpandAtomicLoadInIR(LI)) {

513 return false;

515 expandAtomicOpToLLSC(

519 return true;

521 return expandAtomicLoadToLL(LI);

523 return expandAtomicLoadToCmpXchg(LI);

526 return true;

527 default:

529 }

530}

531

532bool AtomicExpandImpl::tryExpandAtomicStore(StoreInst *SI) {

533 switch (TLI->shouldExpandAtomicStoreInIR(SI)) {

535 return false;

537 expandAtomicStore(SI);

538 return true;

541 return true;

542 default:

544 }

545}

546

547bool AtomicExpandImpl::expandAtomicLoadToLL(LoadInst *LI) {

548 ReplacementIRBuilder Builder(LI, *DL);

549

550

551

552

553 Value *Val = TLI->emitLoadLinked(Builder, LI->getType(),

555 TLI->emitAtomicCmpXchgNoStoreLLBalance(Builder);

556

559

560 return true;

561}

562

563bool AtomicExpandImpl::expandAtomicLoadToCmpXchg(LoadInst *LI) {

564 ReplacementIRBuilder Builder(LI, *DL);

568

572

573 Value *Pair = Builder.CreateAtomicCmpXchg(

574 Addr, DummyVal, DummyVal, LI->getAlign(), Order,

576 Value *Loaded = Builder.CreateExtractValue(Pair, 0, "loaded");

577

580

581 return true;

582}

583

584

585

586

587

588

589

590

591

592StoreInst *AtomicExpandImpl::convertAtomicStoreToIntegerType(StoreInst *SI) {

593 ReplacementIRBuilder Builder(SI, *DL);

594 auto *M = SI->getModule();

595 Type *NewTy = getCorrespondingIntegerType(SI->getValueOperand()->getType(),

596 M->getDataLayout());

597 Value *NewVal = Builder.CreateBitCast(SI->getValueOperand(), NewTy);

598

600

601 StoreInst *NewSI = Builder.CreateStore(NewVal, Addr);

604 NewSI->setAtomic(SI->getOrdering(), SI->getSyncScopeID());

605 LLVM_DEBUG(dbgs() << "Replaced " << *SI << " with " << *NewSI << "\n");

606 SI->eraseFromParent();

607 return NewSI;

608}

609

610void AtomicExpandImpl::expandAtomicStore(StoreInst *SI) {

611

612

613

614

615

616

617 ReplacementIRBuilder Builder(SI, *DL);

625 SI->getAlign(), RMWOrdering);

626 SI->eraseFromParent();

627

628

629 tryExpandAtomicRMW(AI);

630}

631

638

639

642 if (NeedBitcast) {

646 }

647

649 Addr, Loaded, NewVal, AddrAlign, MemOpOrder,

651 if (MetadataSrc)

653

656

657 if (NeedBitcast)

658 NewLoaded = Builder.CreateBitCast(NewLoaded, OrigTy);

659}

660

661bool AtomicExpandImpl::tryExpandAtomicRMW(AtomicRMWInst *AI) {

664 switch (Kind) {

666 return false;

668 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;

670 if (ValueSize < MinCASSize) {

671 expandPartwordAtomicRMW(AI,

673 } else {

677 };

680 }

681 return true;

682 }

684 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;

686 if (ValueSize < MinCASSize) {

687 expandPartwordAtomicRMW(AI,

689 } else {

693 ? "system"

696 ORE.emit([&]() {

698 << "A compare and swap loop was generated for an atomic "

700 << MemScope << " memory scope";

701 });

703 }

704 return true;

705 }

707 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;

709 if (ValueSize < MinCASSize) {

711

714 tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));

715 return true;

716 }

717 }

718 expandAtomicRMWToMaskedIntrinsic(AI);

719 return true;

720 }

722 TLI->emitBitTestAtomicRMWIntrinsic(AI);

723 return true;

724 }

726 TLI->emitCmpArithAtomicRMWIntrinsic(AI);

727 return true;

728 }

732 TLI->emitExpandAtomicRMW(AI);

733 return true;

734 default:

736 }

737}

738

739namespace {

740

741struct PartwordMaskValues {

742

743 Type *WordType = nullptr;

745 Type *IntValueType = nullptr;

746 Value *AlignedAddr = nullptr;

747 Align AlignedAddrAlignment;

748

749 Value *ShiftAmt = nullptr;

751 Value *Inv_Mask = nullptr;

752};

753

756 auto PrintObj = [&O](auto *V) {

757 if (V)

758 O << *V;

759 else

760 O << "nullptr";

761 O << '\n';

762 };

763 O << "PartwordMaskValues {\n";

764 O << " WordType: ";

765 PrintObj(PMV.WordType);

766 O << " ValueType: ";

767 PrintObj(PMV.ValueType);

768 O << " AlignedAddr: ";

769 PrintObj(PMV.AlignedAddr);

770 O << " AlignedAddrAlignment: " << PMV.AlignedAddrAlignment.value() << '\n';

771 O << " ShiftAmt: ";

772 PrintObj(PMV.ShiftAmt);

773 O << " Mask: ";

774 PrintObj(PMV.Mask);

775 O << " Inv_Mask: ";

776 PrintObj(PMV.Inv_Mask);

777 O << "}\n";

778 return O;

779}

780

781}

782

783

784

785

786

787

788

789

790

791

792

793

794

795

796

797

798

802 unsigned MinWordSize) {

803 PartwordMaskValues PMV;

804

805 Module *M = I->getModule();

808 unsigned ValueSize = DL.getTypeStoreSize(ValueType);

809

810 PMV.ValueType = PMV.IntValueType = ValueType;

811 if (PMV.ValueType->isFloatingPointTy() || PMV.ValueType->isVectorTy())

812 PMV.IntValueType =

814

815 PMV.WordType = MinWordSize > ValueSize ? Type::getIntNTy(Ctx, MinWordSize * 8)

817 if (PMV.ValueType == PMV.WordType) {

818 PMV.AlignedAddr = Addr;

819 PMV.AlignedAddrAlignment = AddrAlign;

820 PMV.ShiftAmt = ConstantInt::get(PMV.ValueType, 0);

821 PMV.Mask = ConstantInt::get(PMV.ValueType, ~0, true);

822 return PMV;

823 }

824

825 PMV.AlignedAddrAlignment = Align(MinWordSize);

826

827 assert(ValueSize < MinWordSize);

828

830 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());

832

833 if (AddrAlign < MinWordSize) {

835 Intrinsic::ptrmask, {PtrTy, IntTy},

836 {Addr, ConstantInt::get(IntTy, ~(uint64_t)(MinWordSize - 1))}, nullptr,

837 "AlignedAddr");

838

840 PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");

841 } else {

842

843 PMV.AlignedAddr = Addr;

845 }

846

847 if (DL.isLittleEndian()) {

848

849 PMV.ShiftAmt = Builder.CreateShl(PtrLSB, 3);

850 } else {

851

852 PMV.ShiftAmt = Builder.CreateShl(

853 Builder.CreateXor(PtrLSB, MinWordSize - ValueSize), 3);

854 }

855

856 PMV.ShiftAmt = Builder.CreateTrunc(PMV.ShiftAmt, PMV.WordType, "ShiftAmt");

858 ConstantInt::get(PMV.WordType, (1 << (ValueSize * 8)) - 1), PMV.ShiftAmt,

859 "Mask");

860

861 PMV.Inv_Mask = Builder.CreateNot(PMV.Mask, "Inv_Mask");

862

863 return PMV;

864}

865

867 const PartwordMaskValues &PMV) {

868 assert(WideWord->getType() == PMV.WordType && "Widened type mismatch");

869 if (PMV.WordType == PMV.ValueType)

870 return WideWord;

871

872 Value *Shift = Builder.CreateLShr(WideWord, PMV.ShiftAmt, "shifted");

873 Value *Trunc = Builder.CreateTrunc(Shift, PMV.IntValueType, "extracted");

874 return Builder.CreateBitCast(Trunc, PMV.ValueType);

875}

876

878 Value *Updated, const PartwordMaskValues &PMV) {

879 assert(WideWord->getType() == PMV.WordType && "Widened type mismatch");

880 assert(Updated->getType() == PMV.ValueType && "Value type mismatch");

881 if (PMV.WordType == PMV.ValueType)

882 return Updated;

883

884 Updated = Builder.CreateBitCast(Updated, PMV.IntValueType);

885

886 Value *ZExt = Builder.CreateZExt(Updated, PMV.WordType, "extended");

888 Builder.CreateShl(ZExt, PMV.ShiftAmt, "shifted", true);

889 Value *And = Builder.CreateAnd(WideWord, PMV.Inv_Mask, "unmasked");

891 return Or;

892}

893

894

895

896

900 const PartwordMaskValues &PMV) {

901

902

903

904 switch (Op) {

906 Value *Loaded_MaskOut = Builder.CreateAnd(Loaded, PMV.Inv_Mask);

907 Value *FinalVal = Builder.CreateOr(Loaded_MaskOut, Shifted_Inc);

908 return FinalVal;

909 }

913 llvm_unreachable("Or/Xor/And handled by widenPartwordAtomicRMW");

917

919 Value *NewVal_Masked = Builder.CreateAnd(NewVal, PMV.Mask);

920 Value *Loaded_MaskOut = Builder.CreateAnd(Loaded, PMV.Inv_Mask);

921 Value *FinalVal = Builder.CreateOr(Loaded_MaskOut, NewVal_Masked);

922 return FinalVal;

923 }

936

937

938

942 return FinalVal;

943 }

944 default:

946 }

947}

948

949

950

951

952

953

954

955

956void AtomicExpandImpl::expandPartwordAtomicRMW(

958

962 tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));

963 return;

964 }

967

968 ReplacementIRBuilder Builder(AI, *DL);

969

970 PartwordMaskValues PMV =

972 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

973

974 Value *ValOperand_Shifted = nullptr;

977 Value *ValOp = Builder.CreateBitCast(AI->getValOperand(), PMV.IntValueType);

978 ValOperand_Shifted =

979 Builder.CreateShl(Builder.CreateZExt(ValOp, PMV.WordType), PMV.ShiftAmt,

980 "ValOperand_Shifted");

981 }

982

983 auto PerformPartwordOp = [&](IRBuilderBase &Builder, Value *Loaded) {

986 };

987

988 Value *OldResult;

990 OldResult = insertRMWCmpXchgLoop(

991 Builder, PMV.WordType, PMV.AlignedAddr, PMV.AlignedAddrAlignment,

993 } else {

995 OldResult = insertRMWLLSCLoop(Builder, PMV.WordType, PMV.AlignedAddr,

996 PMV.AlignedAddrAlignment, MemOpOrder,

997 PerformPartwordOp);

998 }

999

1003}

1004

1005

1007 ReplacementIRBuilder Builder(AI, *DL);

1009

1012 "Unable to widen operation");

1013

1014 PartwordMaskValues PMV =

1016 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

1017

1018 Value *ValOperand_Shifted =

1020 PMV.ShiftAmt, "ValOperand_Shifted");

1021

1022 Value *NewOperand;

1023

1025 NewOperand =

1026 Builder.CreateOr(ValOperand_Shifted, PMV.Inv_Mask, "AndOperand");

1027 else

1028 NewOperand = ValOperand_Shifted;

1029

1031 Op, PMV.AlignedAddr, NewOperand, PMV.AlignedAddrAlignment,

1033

1035

1039 return NewAI;

1040}

1041

1042bool AtomicExpandImpl::expandPartwordCmpXchg(AtomicCmpXchgInst *CI) {

1043

1044

1045

1046

1047

1048

1049

1050

1051

1052

1053

1054

1055

1056

1057

1058

1059

1060

1061

1062

1063

1064

1065

1066

1067

1068

1069

1070

1071

1072

1073

1074

1075

1076

1077

1081

1084 ReplacementIRBuilder Builder(CI, *DL);

1086

1089 auto FailureBB =

1091 auto LoopBB = BasicBlock::Create(Ctx, "partword.cmpxchg.loop", F, FailureBB);

1092

1093

1094

1095 std::prev(BB->end())->eraseFromParent();

1097

1098 PartwordMaskValues PMV =

1100 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

1101

1102

1103 Value *NewVal_Shifted =

1104 Builder.CreateShl(Builder.CreateZExt(NewVal, PMV.WordType), PMV.ShiftAmt);

1105 Value *Cmp_Shifted =

1107

1108

1109

1110 LoadInst *InitLoaded = Builder.CreateLoad(PMV.WordType, PMV.AlignedAddr);

1112 Value *InitLoaded_MaskOut = Builder.CreateAnd(InitLoaded, PMV.Inv_Mask);

1114

1115

1117 PHINode *Loaded_MaskOut = Builder.CreatePHI(PMV.WordType, 2);

1118 Loaded_MaskOut->addIncoming(InitLoaded_MaskOut, BB);

1119

1120

1121 Value *FullWord_NewVal = Builder.CreateOr(Loaded_MaskOut, NewVal_Shifted);

1122 Value *FullWord_Cmp = Builder.CreateOr(Loaded_MaskOut, Cmp_Shifted);

1124 PMV.AlignedAddr, FullWord_Cmp, FullWord_NewVal, PMV.AlignedAddrAlignment,

1127

1128

1129

1130

1131

1133

1136

1139 else

1141

1142

1144

1145

1146

1147 Value *OldVal_MaskOut = Builder.CreateAnd(OldVal, PMV.Inv_Mask);

1148 Value *ShouldContinue = Builder.CreateICmpNE(Loaded_MaskOut, OldVal_MaskOut);

1149 Builder.CreateCondBr(ShouldContinue, LoopBB, EndBB);

1150

1151

1152 Loaded_MaskOut->addIncoming(OldVal_MaskOut, FailureBB);

1153

1154

1156

1161

1164 return true;

1165}

1166

1167void AtomicExpandImpl::expandAtomicOpToLLSC(

1171 ReplacementIRBuilder Builder(I, *DL);

1172 Value *Loaded = insertRMWLLSCLoop(Builder, ResultType, Addr, AddrAlign,

1173 MemOpOrder, PerformOp);

1174

1175 I->replaceAllUsesWith(Loaded);

1176 I->eraseFromParent();

1177}

1178

1179void AtomicExpandImpl::expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI) {

1180 ReplacementIRBuilder Builder(AI, *DL);

1181

1182 PartwordMaskValues PMV =

1184 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

1185

1186

1187

1188

1192 CastOp = Instruction::SExt;

1193

1196 PMV.ShiftAmt, "ValOperand_Shifted");

1197 Value *OldResult = TLI->emitMaskedAtomicRMWIntrinsic(

1198 Builder, AI, PMV.AlignedAddr, ValOperand_Shifted, PMV.Mask, PMV.ShiftAmt,

1203}

1204

1205void AtomicExpandImpl::expandAtomicCmpXchgToMaskedIntrinsic(

1207 ReplacementIRBuilder Builder(CI, *DL);

1208

1211 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

1212

1215 "CmpVal_Shifted");

1218 "NewVal_Shifted");

1219 Value *OldVal = TLI->emitMaskedAtomicCmpXchgIntrinsic(

1220 Builder, CI, PMV.AlignedAddr, CmpVal_Shifted, NewVal_Shifted, PMV.Mask,

1226 CmpVal_Shifted, Builder.CreateAnd(OldVal, PMV.Mask), "Success");

1228

1231}

1232

1233Value *AtomicExpandImpl::insertRMWLLSCLoop(

1240

1242 F->getDataLayout().getTypeStoreSize(ResultTy) &&

1243 "Expected at least natural alignment at this point.");

1244

1245

1246

1247

1248

1249

1250

1251

1252

1253

1254

1255

1256

1260

1261

1262

1263 std::prev(BB->end())->eraseFromParent();

1266

1267

1269 Value *Loaded = TLI->emitLoadLinked(Builder, ResultTy, Addr, MemOpOrder);

1270

1271 Value *NewVal = PerformOp(Builder, Loaded);

1272

1273 Value *StoreSuccess =

1274 TLI->emitStoreConditional(Builder, NewVal, Addr, MemOpOrder);

1276 StoreSuccess, ConstantInt::get(IntegerType::get(Ctx, 32), 0), "tryagain");

1277 Builder.CreateCondBr(TryAgain, LoopBB, ExitBB);

1278

1280 return Loaded;

1281}

1282

1283

1284

1285

1286

1287

1289AtomicExpandImpl::convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI) {

1292 M->getDataLayout());

1293

1294 ReplacementIRBuilder Builder(CI, *DL);

1295

1297

1300

1306 LLVM_DEBUG(dbgs() << "Replaced " << *CI << " with " << *NewCI << "\n");

1307

1310

1312

1316

1319 return NewCI;

1320}

1321

1322bool AtomicExpandImpl::expandAtomicCmpXchg(AtomicCmpXchgInst *CI) {

1329

1330

1331

1332

1333 bool ShouldInsertFencesForAtomic = TLI->shouldInsertFencesForAtomic(CI);

1334 AtomicOrdering MemOpOrder = ShouldInsertFencesForAtomic

1337

1338

1339

1340

1341

1342

1343

1344

1345

1346

1347 bool HasReleasedLoadBB = !CI->isWeak() && ShouldInsertFencesForAtomic &&

1350 F->hasMinSize();

1351

1352

1353

1354 bool UseUnconditionalReleaseBarrier = F->hasMinSize() && !CI->isWeak();

1355

1356

1357

1358

1359

1360

1361

1362

1363

1364

1365

1366

1367

1368

1369

1370

1371

1372

1373

1374

1375

1376

1377

1378

1379

1380

1381

1382

1383

1384

1385

1386

1387

1388

1389

1390

1391

1392

1393

1394

1395

1396

1397

1398

1399

1400

1401

1402

1403

1406 auto NoStoreBB = BasicBlock::Create(Ctx, "cmpxchg.nostore", F, FailureBB);

1407 auto SuccessBB = BasicBlock::Create(Ctx, "cmpxchg.success", F, NoStoreBB);

1408 auto ReleasedLoadBB =

1410 auto TryStoreBB =

1412 auto ReleasingStoreBB =

1414 auto StartBB = BasicBlock::Create(Ctx, "cmpxchg.start", F, ReleasingStoreBB);

1415

1416 ReplacementIRBuilder Builder(CI, *DL);

1417

1418

1419

1420

1421 std::prev(BB->end())->eraseFromParent();

1423 if (ShouldInsertFencesForAtomic && UseUnconditionalReleaseBarrier)

1424 TLI->emitLeadingFence(Builder, CI, SuccessOrder);

1425

1426 PartwordMaskValues PMV =

1428 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);

1430

1431

1433 Value *UnreleasedLoad =

1434 TLI->emitLoadLinked(Builder, PMV.WordType, PMV.AlignedAddr, MemOpOrder);

1435 Value *UnreleasedLoadExtract =

1438 UnreleasedLoadExtract, CI->getCompareOperand(), "should_store");

1439

1440

1441

1442 Builder.CreateCondBr(ShouldStore, ReleasingStoreBB, NoStoreBB);

1443

1445 if (ShouldInsertFencesForAtomic && !UseUnconditionalReleaseBarrier)

1446 TLI->emitLeadingFence(Builder, CI, SuccessOrder);

1447 Builder.CreateBr(TryStoreBB);

1448

1450 PHINode *LoadedTryStore =

1451 Builder.CreatePHI(PMV.WordType, 2, "loaded.trystore");

1452 LoadedTryStore->addIncoming(UnreleasedLoad, ReleasingStoreBB);

1453 Value *NewValueInsert =

1455 Value *StoreSuccess = TLI->emitStoreConditional(Builder, NewValueInsert,

1456 PMV.AlignedAddr, MemOpOrder);

1458 StoreSuccess, ConstantInt::get(Type::getInt32Ty(Ctx), 0), "success");

1459 BasicBlock *RetryBB = HasReleasedLoadBB ? ReleasedLoadBB : StartBB;

1460 Builder.CreateCondBr(StoreSuccess, SuccessBB,

1461 CI->isWeak() ? FailureBB : RetryBB);

1462

1464 Value *SecondLoad;

1465 if (HasReleasedLoadBB) {

1466 SecondLoad =

1467 TLI->emitLoadLinked(Builder, PMV.WordType, PMV.AlignedAddr, MemOpOrder);

1469 ShouldStore = Builder.CreateICmpEQ(SecondLoadExtract,

1471

1472

1473

1474 Builder.CreateCondBr(ShouldStore, TryStoreBB, NoStoreBB);

1475

1476 LoadedTryStore->addIncoming(SecondLoad, ReleasedLoadBB);

1477 } else

1479

1480

1481

1483 if (ShouldInsertFencesForAtomic ||

1484 TLI->shouldInsertTrailingFenceForAtomicStore(CI))

1485 TLI->emitTrailingFence(Builder, CI, SuccessOrder);

1487

1489 PHINode *LoadedNoStore =

1490 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.nostore");

1491 LoadedNoStore->addIncoming(UnreleasedLoad, StartBB);

1492 if (HasReleasedLoadBB)

1493 LoadedNoStore->addIncoming(SecondLoad, ReleasedLoadBB);

1494

1495

1496

1497

1498 TLI->emitAtomicCmpXchgNoStoreLLBalance(Builder);

1499 Builder.CreateBr(FailureBB);

1500

1502 PHINode *LoadedFailure =

1503 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.failure");

1504 LoadedFailure->addIncoming(LoadedNoStore, NoStoreBB);

1506 LoadedFailure->addIncoming(LoadedTryStore, TryStoreBB);

1507 if (ShouldInsertFencesForAtomic)

1508 TLI->emitTrailingFence(Builder, CI, FailureOrder);

1510

1511

1512

1513

1514

1517 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.exit");

1518 LoadedExit->addIncoming(LoadedTryStore, SuccessBB);

1519 LoadedExit->addIncoming(LoadedFailure, FailureBB);

1523

1524

1525

1526 Value *LoadedFull = LoadedExit;

1527

1530

1531

1532

1534 for (auto *User : CI->users()) {

1536 if (!EV)

1537 continue;

1538

1540 "weird extraction from { iN, i1 }");

1541

1544 else

1546

1548 }

1549

1550

1551 for (auto *EV : PrunedInsts)

1553

1555

1556

1560

1562 }

1563

1565 return true;

1566}

1567

1568bool AtomicExpandImpl::isIdempotentRMW(AtomicRMWInst *RMWI) {

1569 auto C = dyn_cast(RMWI->getValOperand());

1570 if (C)

1571 return false;

1572

1574 switch (Op) {

1579 return C->isZero();

1581 return C->isMinusOne();

1582

1583 default:

1584 return false;

1585 }

1586}

1587

1588bool AtomicExpandImpl::simplifyIdempotentRMW(AtomicRMWInst *RMWI) {

1589 if (auto ResultingLoad = TLI->lowerIdempotentRMWIntoFencedLoad(RMWI)) {

1590 tryExpandAtomicLoad(ResultingLoad);

1591 return true;

1592 }

1593 return false;

1594}

1595

1596Value *AtomicExpandImpl::insertRMWCmpXchgLoop(

1604

1605

1606

1607

1608

1609

1610

1611

1612

1613

1614

1615

1616

1617

1618

1619

1623

1624

1625

1626

1627 std::prev(BB->end())->eraseFromParent();

1631

1632

1636

1637 Value *NewVal = PerformOp(Builder, Loaded);

1638

1639 Value *NewLoaded = nullptr;

1641

1642 CreateCmpXchg(Builder, Addr, Loaded, NewVal, AddrAlign,

1645 : MemOpOrder,

1646 SSID, Success, NewLoaded, MetadataSrc);

1648

1650

1652

1654 return NewLoaded;

1655}

1656

1657bool AtomicExpandImpl::tryExpandAtomicCmpXchg(AtomicCmpXchgInst *CI) {

1658 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;

1660

1661 switch (TLI->shouldExpandAtomicCmpXchgInIR(CI)) {

1662 default:

1663 llvm_unreachable("Unhandled case in tryExpandAtomicCmpXchg");

1665 if (ValueSize < MinCASSize)

1666 return expandPartwordCmpXchg(CI);

1667 return false;

1669 return expandAtomicCmpXchg(CI);

1670 }

1672 expandAtomicCmpXchgToMaskedIntrinsic(CI);

1673 return true;

1677 TLI->emitExpandAtomicCmpXchg(CI);

1678 return true;

1679 }

1680 }

1681}

1682

1683

1686 ReplacementIRBuilder Builder(AI, AI->getDataLayout());

1687 Builder.setIsFPConstrained(

1689

1690

1691

1692 Value *Loaded = AtomicExpandImpl::insertRMWCmpXchgLoop(

1696 return buildAtomicRMWValue(AI->getOperation(), Builder, Loaded,

1697 AI->getValOperand());

1698 },

1699 CreateCmpXchg, AI);

1700

1703 return true;

1704}

1705

1706

1707

1708

1709

1710

1713

1714

1715

1716

1717

1718

1719

1720 unsigned LargestSize = DL.getLargestLegalIntTypeSizeInBits() >= 64 ? 16 : 8;

1721 return Alignment >= Size &&

1723 Size <= LargestSize;

1724}

1725

1726void AtomicExpandImpl::expandAtomicLoadToLibcall(LoadInst *I) {

1728 RTLIB::ATOMIC_LOAD, RTLIB::ATOMIC_LOAD_1, RTLIB::ATOMIC_LOAD_2,

1729 RTLIB::ATOMIC_LOAD_4, RTLIB::ATOMIC_LOAD_8, RTLIB::ATOMIC_LOAD_16};

1731

1732 bool expanded = expandAtomicOpToLibcall(

1733 I, Size, I->getAlign(), I->getPointerOperand(), nullptr, nullptr,

1735 if (!expanded)

1736 report_fatal_error("expandAtomicOpToLibcall shouldn't fail for Load");

1737}

1738

1739void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {

1741 RTLIB::ATOMIC_STORE, RTLIB::ATOMIC_STORE_1, RTLIB::ATOMIC_STORE_2,

1742 RTLIB::ATOMIC_STORE_4, RTLIB::ATOMIC_STORE_8, RTLIB::ATOMIC_STORE_16};

1744

1745 bool expanded = expandAtomicOpToLibcall(

1746 I, Size, I->getAlign(), I->getPointerOperand(), I->getValueOperand(),

1748 if (!expanded)

1749 report_fatal_error("expandAtomicOpToLibcall shouldn't fail for Store");

1750}

1751

1752void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I) {

1754 RTLIB::ATOMIC_COMPARE_EXCHANGE, RTLIB::ATOMIC_COMPARE_EXCHANGE_1,

1755 RTLIB::ATOMIC_COMPARE_EXCHANGE_2, RTLIB::ATOMIC_COMPARE_EXCHANGE_4,

1756 RTLIB::ATOMIC_COMPARE_EXCHANGE_8, RTLIB::ATOMIC_COMPARE_EXCHANGE_16};

1758

1759 bool expanded = expandAtomicOpToLibcall(

1760 I, Size, I->getAlign(), I->getPointerOperand(), I->getNewValOperand(),

1761 I->getCompareOperand(), I->getSuccessOrdering(), I->getFailureOrdering(),

1762 Libcalls);

1763 if (!expanded)

1764 report_fatal_error("expandAtomicOpToLibcall shouldn't fail for CAS");

1765}

1766

1769 RTLIB::ATOMIC_EXCHANGE, RTLIB::ATOMIC_EXCHANGE_1,

1770 RTLIB::ATOMIC_EXCHANGE_2, RTLIB::ATOMIC_EXCHANGE_4,

1771 RTLIB::ATOMIC_EXCHANGE_8, RTLIB::ATOMIC_EXCHANGE_16};

1773 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_ADD_1,

1774 RTLIB::ATOMIC_FETCH_ADD_2, RTLIB::ATOMIC_FETCH_ADD_4,

1775 RTLIB::ATOMIC_FETCH_ADD_8, RTLIB::ATOMIC_FETCH_ADD_16};

1777 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_SUB_1,

1778 RTLIB::ATOMIC_FETCH_SUB_2, RTLIB::ATOMIC_FETCH_SUB_4,

1779 RTLIB::ATOMIC_FETCH_SUB_8, RTLIB::ATOMIC_FETCH_SUB_16};

1781 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_AND_1,

1782 RTLIB::ATOMIC_FETCH_AND_2, RTLIB::ATOMIC_FETCH_AND_4,

1783 RTLIB::ATOMIC_FETCH_AND_8, RTLIB::ATOMIC_FETCH_AND_16};

1785 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_OR_1,

1786 RTLIB::ATOMIC_FETCH_OR_2, RTLIB::ATOMIC_FETCH_OR_4,

1787 RTLIB::ATOMIC_FETCH_OR_8, RTLIB::ATOMIC_FETCH_OR_16};

1789 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_XOR_1,

1790 RTLIB::ATOMIC_FETCH_XOR_2, RTLIB::ATOMIC_FETCH_XOR_4,

1791 RTLIB::ATOMIC_FETCH_XOR_8, RTLIB::ATOMIC_FETCH_XOR_16};

1793 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_NAND_1,

1794 RTLIB::ATOMIC_FETCH_NAND_2, RTLIB::ATOMIC_FETCH_NAND_4,

1795 RTLIB::ATOMIC_FETCH_NAND_8, RTLIB::ATOMIC_FETCH_NAND_16};

1796

1797 switch (Op) {

1801 return ArrayRef(LibcallsXchg);

1803 return ArrayRef(LibcallsAdd);

1805 return ArrayRef(LibcallsSub);

1807 return ArrayRef(LibcallsAnd);

1809 return ArrayRef(LibcallsOr);

1811 return ArrayRef(LibcallsXor);

1813 return ArrayRef(LibcallsNand);

1826

1827 return {};

1828 }

1830}

1831

1832void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {

1834

1836

1838 if (!Libcalls.empty())

1839 Success = expandAtomicOpToLibcall(

1840 I, Size, I->getAlign(), I->getPointerOperand(), I->getValOperand(),

1842

1843

1844

1845

1846

1853

1855 Addr, Loaded, NewVal, Alignment, MemOpOrder,

1857 if (MetadataSrc)

1859

1862

1863

1864 expandAtomicCASToLibcall(Pair);

1865 });

1866 }

1867}

1868

1869

1870

1871

1872

1873

1874

1875bool AtomicExpandImpl::expandAtomicOpToLibcall(

1880

1885 IRBuilder<> AllocaBuilder(&I->getFunction()->getEntryBlock().front());

1886

1889

1890 const Align AllocaAlignment = DL.getPrefTypeAlign(SizedIntTy);

1891

1892

1893

1898 Constant *Ordering2Val = nullptr;

1899 if (CASExpected) {

1901 Ordering2Val =

1903 }

1905

1907 if (UseSizedLibcall) {

1908 switch (Size) {

1909 case 1:

1910 RTLibType = Libcalls[1];

1911 break;

1912 case 2:

1913 RTLibType = Libcalls[2];

1914 break;

1915 case 4:

1916 RTLibType = Libcalls[3];

1917 break;

1918 case 8:

1919 RTLibType = Libcalls[4];

1920 break;

1921 case 16:

1922 RTLibType = Libcalls[5];

1923 break;

1924 }

1925 } else if (Libcalls[0] != RTLIB::UNKNOWN_LIBCALL) {

1926 RTLibType = Libcalls[0];

1927 } else {

1928

1929

1930 return false;

1931 }

1932

1933 if (!TLI->getLibcallName(RTLibType)) {

1934

1935 return false;

1936 }

1937

1938

1939

1940

1941

1942

1943

1944

1945

1946

1947

1948

1949

1950

1951

1952

1953

1954

1955

1956

1957

1958

1959

1960

1961

1962

1963

1964 AllocaInst *AllocaCASExpected = nullptr;

1967

1968 Type *ResultTy;

1971

1972

1973 if (!UseSizedLibcall) {

1974

1975 Args.push_back(ConstantInt::get(DL.getIntPtrType(Ctx), Size));

1976 }

1977

1978

1979

1980

1981

1982

1983 Value *PtrVal = PointerOperand;

1985 Args.push_back(PtrVal);

1986

1987

1988 if (CASExpected) {

1989 AllocaCASExpected = AllocaBuilder.CreateAlloca(CASExpected->getType());

1990 AllocaCASExpected->setAlignment(AllocaAlignment);

1992 Builder.CreateAlignedStore(CASExpected, AllocaCASExpected, AllocaAlignment);

1993 Args.push_back(AllocaCASExpected);

1994 }

1995

1996

1997 if (ValueOperand) {

1998 if (UseSizedLibcall) {

1999 Value *IntValue =

2001 Args.push_back(IntValue);

2002 } else {

2003 AllocaValue = AllocaBuilder.CreateAlloca(ValueOperand->getType());

2006 Builder.CreateAlignedStore(ValueOperand, AllocaValue, AllocaAlignment);

2007 Args.push_back(AllocaValue);

2008 }

2009 }

2010

2011

2012 if (!CASExpected && HasResult && !UseSizedLibcall) {

2013 AllocaResult = AllocaBuilder.CreateAlloca(I->getType());

2014 AllocaResult->setAlignment(AllocaAlignment);

2016 Args.push_back(AllocaResult);

2017 }

2018

2019

2020 Args.push_back(OrderingVal);

2021

2022

2023 if (Ordering2Val)

2024 Args.push_back(Ordering2Val);

2025

2026

2027 if (CASExpected) {

2030 } else if (HasResult && UseSizedLibcall)

2031 ResultTy = SizedIntTy;

2032 else

2034

2035

2037 for (Value *Arg : Args)

2038 ArgTys.push_back(Arg->getType());

2041 M->getOrInsertFunction(TLI->getLibcallName(RTLibType), FnType, Attr);

2043 Call->setAttributes(Attr);

2045

2046

2047 if (ValueOperand && !UseSizedLibcall)

2049

2050 if (CASExpected) {

2051

2052

2053 Type *FinalResultTy = I->getType();

2056 CASExpected->getType(), AllocaCASExpected, AllocaAlignment);

2060 I->replaceAllUsesWith(V);

2061 } else if (HasResult) {

2063 if (UseSizedLibcall)

2065 else {

2067 AllocaAlignment);

2069 }

2070 I->replaceAllUsesWith(V);

2071 }

2072 I->eraseFromParent();

2073 return true;

2074}

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Expand Atomic instructions

static Value * performMaskedAtomicOp(AtomicRMWInst::BinOp Op, IRBuilderBase &Builder, Value *Loaded, Value *Shifted_Inc, Value *Inc, const PartwordMaskValues &PMV)

Emit IR to implement a masked version of a given atomicrmw operation.

static PartwordMaskValues createMaskInstrs(IRBuilderBase &Builder, Instruction *I, Type *ValueType, Value *Addr, Align AddrAlign, unsigned MinWordSize)

This is a helper function which builds instructions to provide values necessary for partword atomic o...

static bool canUseSizedAtomicCall(unsigned Size, Align Alignment, const DataLayout &DL)

static Value * extractMaskedValue(IRBuilderBase &Builder, Value *WideWord, const PartwordMaskValues &PMV)

static void createCmpXchgInstFun(IRBuilderBase &Builder, Value *Addr, Value *Loaded, Value *NewVal, Align AddrAlign, AtomicOrdering MemOpOrder, SyncScope::ID SSID, Value *&Success, Value *&NewLoaded, Instruction *MetadataSrc)

Expand Atomic static false unsigned getAtomicOpSize(LoadInst *LI)

static bool atomicSizeSupported(const TargetLowering *TLI, Inst *I)

static Value * insertMaskedValue(IRBuilderBase &Builder, Value *WideWord, Value *Updated, const PartwordMaskValues &PMV)

static void copyMetadataForAtomic(Instruction &Dest, const Instruction &Source)

Copy metadata that's safe to preserve when widening atomics.

static ArrayRef< RTLIB::Libcall > GetRMWLibcall(AtomicRMWInst::BinOp Op)

Atomic ordering constants.

This file contains the simple types necessary to represent the attributes associated with functions a...

#define LLVM_ATTRIBUTE_UNUSED

This file contains the declarations for the subclasses of Constant, which represent the different fla...

Module.h This file contains the declarations for the Module class.

This file provides utility for Memory Model Relaxation Annotations (MMRAs).

#define INITIALIZE_PASS_DEPENDENCY(depName)

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallVector class.

This file describes how to lower LLVM code to machine code.

Target-Independent Code Generator Pass Configuration Options pass.

an instruction to allocate memory on the stack

void setAlignment(Align Align)

A container for analyses that lazily runs them and caches their results.

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

size_t size() const

size - Get the array size.

bool empty() const

empty - Check if the array is empty.

An instruction that atomically checks whether a specified value is in a memory location,...

Value * getNewValOperand()

AtomicOrdering getMergedOrdering() const

Returns a single ordering which is at least as strong as both the success and failure orderings for t...

void setWeak(bool IsWeak)

bool isVolatile() const

Return true if this is a cmpxchg from a volatile memory location.

Value * getCompareOperand()

AtomicOrdering getFailureOrdering() const

Returns the failure ordering constraint of this cmpxchg instruction.

Value * getPointerOperand()

static AtomicOrdering getStrongestFailureOrdering(AtomicOrdering SuccessOrdering)

Returns the strongest permitted ordering on failure, given the desired ordering on success.

Align getAlign() const

Return the alignment of the memory that is being allocated by the instruction.

bool isWeak() const

Return true if this cmpxchg may spuriously fail.

void setVolatile(bool V)

Specify whether this is a volatile cmpxchg.

AtomicOrdering getSuccessOrdering() const

Returns the success ordering constraint of this cmpxchg instruction.

SyncScope::ID getSyncScopeID() const

Returns the synchronization scope ID of this cmpxchg instruction.

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)

an instruction that atomically reads a memory location, combines it with another value,...

Align getAlign() const

Return the alignment of the memory that is being allocated by the instruction.

bool isVolatile() const

Return true if this is a RMW on a volatile memory location.

BinOp

This enumeration lists the possible modifications atomicrmw can make.

@ USubCond

Subtract only if no unsigned overflow.

@ Min

*p = old <signed v ? old : v

@ USubSat

*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.

@ UIncWrap

Increment one up to a maximum value.

@ Max

*p = old >signed v ? old : v

@ UMin

*p = old <unsigned v ? old : v

@ FMin

*p = minnum(old, v) minnum matches the behavior of llvm.minnum.

@ UMax

*p = old >unsigned v ? old : v

@ FMax

*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.

@ UDecWrap

Decrement one until a minimum value or zero.

Value * getPointerOperand()

BinOp getOperation() const

SyncScope::ID getSyncScopeID() const

Returns the synchronization scope ID of this rmw instruction.

static StringRef getOperationName(BinOp Op)

AtomicOrdering getOrdering() const

Returns the ordering constraint of this rmw instruction.

AttributeList addRetAttribute(LLVMContext &C, Attribute::AttrKind Kind) const

Add a return value attribute to the list.

LLVM Basic Block Representation.

iterator begin()

Instruction iterator methods.

reverse_iterator rbegin()

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="", bool Before=false)

Split the basic block into two basic blocks at the specified instruction.

InstListType::reverse_iterator reverse_iterator

const Function * getParent() const

Return the enclosing method, or null if none.

This class represents a function call, abstracting a target machine's calling convention.

This is the shared class of boolean and integer constants.

static ConstantInt * getTrue(LLVMContext &Context)

static ConstantInt * getFalse(LLVMContext &Context)

This is an important base class in LLVM.

static Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

This class represents an Operation in the Expression.

A parsed version of the target data layout string in and methods for querying it.

A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...

FunctionPass class - This class is used to implement most global optimizations.

virtual bool runOnFunction(Function &F)=0

runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.

static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)

This static method is the primary way of constructing a FunctionType.

BasicBlockListType::iterator iterator

bool hasFnAttribute(Attribute::AttrKind Kind) const

Return true if the function has the attribute.

Common base class shared among various IRBuilders.

AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID=SyncScope::System)

Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")

IntegerType * getIntNTy(unsigned N)

Fetch the type representing an N-bit integer.

LoadInst * CreateAlignedLoad(Type *Ty, Value *Ptr, MaybeAlign Align, const char *Name)

UnreachableInst * CreateUnreachable()

CallInst * CreateLifetimeStart(Value *Ptr, ConstantInt *Size=nullptr)

Create a lifetime.start intrinsic.

Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")

BasicBlock::iterator GetInsertPoint() const

Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")

Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)

Value * CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr, FMFSource FMFSource={})

BasicBlock * GetInsertBlock() const

Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")

void CollectMetadataToCopy(Instruction *Src, ArrayRef< unsigned > MetadataKinds)

Collect metadata with IDs MetadataKinds from Src which should be added to all created instructions.

CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")

Create a call to intrinsic ID with Args, mangled using Types.

Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")

PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")

Value * CreateNot(Value *V, const Twine &Name="")

Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")

void setIsFPConstrained(bool IsCon)

Enable/Disable use of constrained floating point math.

Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")

BranchInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)

Create a conditional 'br Cond, TrueDest, FalseDest' instruction.

LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)

Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...

Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)

LLVMContext & getContext() const

Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")

CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)

AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)

Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)

CallInst * CreateLifetimeEnd(Value *Ptr, ConstantInt *Size=nullptr)

Create a lifetime.end intrinsic.

Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")

BranchInst * CreateBr(BasicBlock *Dest)

Create an unconditional 'br label X' instruction.

void SetInsertPoint(BasicBlock *TheBB)

This specifies that created instructions should be appended to the end of the specified block.

StoreInst * CreateAlignedStore(Value *Val, Value *Ptr, MaybeAlign Align, bool isVolatile=false)

Value * CreateXor(Value *LHS, Value *RHS, const Twine &Name="")

Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="")

Provides an 'InsertHelper' that calls a user-provided callback after performing the default insertion...

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.

const Module * getModule() const

Return the module owning the function this instruction belongs to or nullptr it the function does not...

InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

const Function * getFunction() const

Return the function this instruction belongs to.

void setMetadata(unsigned KindID, MDNode *Node)

Set the metadata of the specified kind to the specified node.

const DataLayout & getDataLayout() const

Get the data layout of the module this instruction belongs to.

Class to represent integer types.

static IntegerType * get(LLVMContext &C, unsigned NumBits)

This static method is the primary way of constructing an IntegerType.

This is an important class for using LLVM in a threaded context.

unsigned getMDKindID(StringRef Name) const

getMDKindID - Return a unique non-zero ID for the specified metadata kind.

void getSyncScopeNames(SmallVectorImpl< StringRef > &SSNs) const

getSyncScopeNames - Populates client supplied SmallVector with synchronization scope names registered...

An instruction for reading from memory.

Value * getPointerOperand()

bool isVolatile() const

Return true if this is a load from a volatile memory location.

void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)

Sets the ordering constraint and the synchronization scope ID of this load instruction.

AtomicOrdering getOrdering() const

Returns the ordering constraint of this load instruction.

void setVolatile(bool V)

Specify whether this is a volatile load or not.

SyncScope::ID getSyncScopeID() const

Returns the synchronization scope ID of this load instruction.

Align getAlign() const

Return the alignment of the access that is being performed.

A Module instance is used to store all the information related to an LLVM module.

LLVMContext & getContext() const

Get the global data context.

void addIncoming(Value *V, BasicBlock *BB)

Add an incoming value to the end of the PHI list.

static PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

static PointerType * getUnqual(Type *ElementType)

This constructs a pointer to an object of the specified type in the default address space (address sp...

static PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

void push_back(const T &Elt)

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

An instruction for storing to memory.

void setVolatile(bool V)

Specify whether this is a volatile store or not.

void setAlignment(Align Align)

void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)

Sets the ordering constraint and the synchronization scope ID of this store instruction.

unsigned getMaxAtomicSizeInBitsSupported() const

Returns the maximum atomic operation size (in bits) supported by the backend.

AtomicExpansionKind

Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.

This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...

Primary interface to the complete machine description for the target machine.

Target-Independent Code Generator Pass Configuration Options.

The instances of the Type class are immutable: once they are created, they are never changed.

bool isVectorTy() const

True if this is an instance of VectorType.

bool isPointerTy() const

True if this is an instance of PointerType.

static IntegerType * getInt1Ty(LLVMContext &C)

static IntegerType * getIntNTy(LLVMContext &C, unsigned N)

static Type * getVoidTy(LLVMContext &C)

bool isFloatingPointTy() const

Return true if this is one of the floating-point types.

static IntegerType * getInt32Ty(LLVMContext &C)

static IntegerType * getInt64Ty(LLVMContext &C)

TypeSize getPrimitiveSizeInBits() const LLVM_READONLY

Return the basic size of this type if it is a primitive type.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

iterator_range< user_iterator > users()

LLVMContext & getContext() const

All values hold a context through their type.

An efficient, type-erasing, non-owning reference to a callable.

const ParentTy * getParent() const

self_iterator getIterator()

This class implements an extremely fast bulk output stream that can only output to a stream.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

constexpr char Args[]

Key for Kernel::Metadata::mArgs.

constexpr std::underlying_type_t< E > Mask()

Get a bitmask with 1s in all places up to the high-order bit of E's largest value.

@ C

The default llvm calling convention, compatible with C.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

Libcall

RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.

This is an optimization pass for GlobalISel generic memory operations.

void initializeAtomicExpandLegacyPass(PassRegistry &)

bool canInstructionHaveMMRAs(const Instruction &I)

bool isReleaseOrStronger(AtomicOrdering AO)

AtomicOrderingCABI toCABI(AtomicOrdering AO)

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

void report_fatal_error(Error Err, bool gen_crash_diag=true)

Report a serious error, calling any installed error handler.

Value * buildAtomicRMWValue(AtomicRMWInst::BinOp Op, IRBuilderBase &Builder, Value *Loaded, Value *Val)

Emit IR to implement the given atomicrmw operation on values in registers, returning the new value.

AtomicOrdering

Atomic ordering for LLVM's memory model.

bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI, CreateCmpXchgInstFun CreateCmpXchg)

Expand an atomic RMW instruction into a loop utilizing cmpxchg.

@ Or

Bitwise or logical OR of integers.

@ And

Bitwise or logical AND of integers.

raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)

bool isAcquireOrStronger(AtomicOrdering AO)

constexpr unsigned BitWidth

bool lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI)

Convert the given Cmpxchg into primitive load and compare.

bool lowerAtomicRMWInst(AtomicRMWInst *RMWI)

Convert the given RMWI into primitive load and stores, assuming that doing so is legal.

FunctionPass * createAtomicExpandLegacyPass()

AtomicExpandPass - At IR level this pass replace atomic instructions with __atomic_* library calls,...

PointerUnion< const Value *, const PseudoSourceValue * > ValueType

char & AtomicExpandID

AtomicExpandID – Lowers atomic operations in terms of either cmpxchg load-linked/store-conditional lo...

This struct is a compact representation of a valid (non-zero power of two) alignment.

TypeSize getSizeInBits() const

Return the size of the specified value type in bits.

TypeSize getStoreSizeInBits() const

Return the number of bits overwritten by a store of the specified value type.