LLVM 24.0.0git
AtomicExpandPass.cpp
Go to the documentation of this file.
1//===- AtomicExpandPass.cpp - Expand atomic instructions ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a pass (at IR level) to replace atomic instructions with
10// __atomic_* library calls, or target specific instruction which implement the
11// same semantics in a way which better fits the target backend. This can
12// include the use of (intrinsic-based) load-linked/store-conditional loops,
13// AtomicCmpXchg, or type coercions.
14//
15//===----------------------------------------------------------------------===//
16
17#include "llvm/ADT/ArrayRef.h"
30#include "llvm/IR/Attributes.h"
31#include "llvm/IR/BasicBlock.h"
32#include "llvm/IR/Constant.h"
33#include "llvm/IR/Constants.h"
34#include "llvm/IR/DataLayout.h"
36#include "llvm/IR/Function.h"
37#include "llvm/IR/IRBuilder.h"
38#include "llvm/IR/Instruction.h"
40#include "llvm/IR/MDBuilder.h"
42#include "llvm/IR/Module.h"
44#include "llvm/IR/Type.h"
45#include "llvm/IR/User.h"
46#include "llvm/IR/Value.h"
48#include "llvm/Pass.h"
52#include "llvm/Support/Debug.h"
57#include <cassert>
58#include <cstdint>
59#include <iterator>
60
61using namespace llvm;
62
63#define DEBUG_TYPE "atomic-expand"
64
65namespace {
66
67class AtomicExpandImpl {
68 const TargetLowering *TLI = nullptr;
69 const LibcallLoweringInfo *LibcallLowering = nullptr;
70 const DataLayout *DL = nullptr;
71 bool SingleThreaded = false;
72
73private:
74 /// Callback type for emitting a cmpxchg instruction during RMW expansion.
75 /// Parameters: (Builder, Addr, Loaded, NewVal, AddrAlign, MemOpOrder,
76 /// SSID, IsVolatile, /* OUT */ Success, /* OUT */ NewLoaded,
77 /// MetadataSrc)
78 using CreateCmpXchgInstFun = function_ref<void(
80 SyncScope::ID, bool, Value *&, Value *&, Instruction *)>;
81
82 void handleFailure(Instruction &FailedInst, const Twine &Msg,
83 Instruction *DiagnosticInst = nullptr) const {
84 LLVMContext &Ctx = FailedInst.getContext();
85
86 // TODO: Do not use generic error type.
87 Ctx.emitError(DiagnosticInst ? DiagnosticInst : &FailedInst, Msg);
88
89 if (!FailedInst.getType()->isVoidTy())
90 FailedInst.replaceAllUsesWith(PoisonValue::get(FailedInst.getType()));
91 FailedInst.eraseFromParent();
92 }
93
94 template <typename Inst>
95 void handleUnsupportedAtomicSize(Inst *I, const Twine &AtomicOpName,
96 Instruction *DiagnosticInst = nullptr) const;
97
98 bool bracketInstWithFences(Instruction *I, AtomicOrdering Order);
99 bool tryInsertTrailingSeqCstFence(Instruction *AtomicI);
100 template <typename AtomicInst>
101 bool tryInsertFencesForAtomic(AtomicInst *AtomicI, bool OrderingRequiresFence,
102 AtomicOrdering NewOrdering);
103 IntegerType *getCorrespondingIntegerType(Type *T, const DataLayout &DL);
104 LoadInst *convertAtomicLoadToIntegerType(LoadInst *LI);
105 bool tryExpandAtomicLoad(LoadInst *LI);
106 bool expandAtomicLoadToLL(LoadInst *LI);
107 bool expandAtomicLoadToCmpXchg(LoadInst *LI);
108 StoreInst *convertAtomicStoreToIntegerType(StoreInst *SI);
109 bool tryExpandAtomicStore(StoreInst *SI);
110 void expandAtomicStoreToXChg(StoreInst *SI);
111 bool tryExpandAtomicRMW(AtomicRMWInst *AI);
112 void expandElementwiseAtomicRMW(AtomicRMWInst *AI);
113 void expandAtomicSubToAdd(AtomicRMWInst *AI);
114 AtomicRMWInst *convertAtomicXchgToIntegerType(AtomicRMWInst *RMWI);
115 Value *
116 insertRMWLLSCLoop(IRBuilderBase &Builder, Type *ResultTy, Value *Addr,
117 Align AddrAlign, AtomicOrdering MemOpOrder,
118 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp);
119 void expandAtomicOpToLLSC(
120 Instruction *I, Type *ResultTy, Value *Addr, Align AddrAlign,
121 AtomicOrdering MemOpOrder,
122 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp);
123 void expandPartwordAtomicRMW(
125 AtomicRMWInst *widenPartwordAtomicRMW(AtomicRMWInst *AI);
126 bool expandPartwordCmpXchg(AtomicCmpXchgInst *I);
127 void expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI);
128 void expandAtomicCmpXchgToMaskedIntrinsic(AtomicCmpXchgInst *CI);
129
130 AtomicCmpXchgInst *convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI);
131 Value *insertRMWCmpXchgLoop(
132 IRBuilderBase &Builder, Type *ResultType, Value *Addr, Align AddrAlign,
133 AtomicOrdering MemOpOrder, SyncScope::ID SSID, bool IsVolatile,
134 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp,
135 CreateCmpXchgInstFun CreateCmpXchg, Instruction *MetadataSrc);
136 bool tryExpandAtomicCmpXchg(AtomicCmpXchgInst *CI);
137
138 bool expandAtomicCmpXchg(AtomicCmpXchgInst *CI);
139 bool isIdempotentRMW(AtomicRMWInst *RMWI);
140 bool simplifyIdempotentRMW(AtomicRMWInst *RMWI);
141
142 bool expandAtomicOpToLibcall(Instruction *I, unsigned Size, Align Alignment,
143 Value *PointerOperand, Value *ValueOperand,
144 Value *CASExpected, AtomicOrdering Ordering,
145 AtomicOrdering Ordering2,
146 ArrayRef<RTLIB::Libcall> Libcalls);
147 void expandAtomicLoadToLibcall(LoadInst *LI);
148 void expandAtomicStoreToLibcall(StoreInst *LI);
149 void expandAtomicRMWToLibcall(AtomicRMWInst *I);
150 void expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
151 const Twine &AtomicOpName = "cmpxchg",
152 Instruction *DiagnosticInst = nullptr);
153
154 bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI,
155 CreateCmpXchgInstFun CreateCmpXchg);
156
157 bool lowerToNonAtomic(Instruction *I);
158 bool processAtomicInstr(Instruction *I);
159
160public:
161 bool run(Function &F, const ModuleLibcallLoweringInfo &LibcallResult,
162 const TargetMachine *TM);
163};
164
165class AtomicExpandLegacy : public FunctionPass {
166public:
167 static char ID; // Pass identification, replacement for typeid
168
169 AtomicExpandLegacy() : FunctionPass(ID) {}
170
171 void getAnalysisUsage(AnalysisUsage &AU) const override {
174 }
175
176 bool runOnFunction(Function &F) override;
177};
178
179// IRBuilder to be used for replacement atomic instructions.
180struct ReplacementIRBuilder
181 : IRBuilder<InstSimplifyFolder, IRBuilderCallbackInserter> {
182 MDNode *MMRAMD = nullptr;
183 MDNode *PCSectionsMD = nullptr;
184
185 // Preserves the DebugLoc from I, and preserves still valid metadata.
186 // Enable StrictFP builder mode when appropriate.
187 explicit ReplacementIRBuilder(Instruction *I, const DataLayout &DL)
188 : IRBuilder(
189 I->getIterator(), InstSimplifyFolder(DL),
190 IRBuilderCallbackInserter([this](Instruction *I) { addMD(I); })) {
191 if (I->getFunction()->hasFnAttribute(Attribute::StrictFP))
192 this->setIsFPConstrained(true);
193
194 MMRAMD = I->getMetadata(LLVMContext::MD_mmra);
195 PCSectionsMD = I->getMetadata(LLVMContext::MD_pcsections);
196 }
197
198 void addMD(Instruction *I) {
200 I->setMetadata(LLVMContext::MD_mmra, MMRAMD);
201 I->setMetadata(LLVMContext::MD_pcsections, PCSectionsMD);
202 }
203};
204
205} // end anonymous namespace
206
207char AtomicExpandLegacy::ID = 0;
208
209char &llvm::AtomicExpandID = AtomicExpandLegacy::ID;
210
212 "Expand Atomic instructions", false, false)
215INITIALIZE_PASS_END(AtomicExpandLegacy, DEBUG_TYPE,
216 "Expand Atomic instructions", false, false)
217
218// Helper functions to retrieve the size of atomic instructions.
219static unsigned getAtomicOpSize(LoadInst *LI) {
220 const DataLayout &DL = LI->getDataLayout();
221 return DL.getTypeStoreSize(LI->getType());
222}
223
224static unsigned getAtomicOpSize(StoreInst *SI) {
225 const DataLayout &DL = SI->getDataLayout();
226 return DL.getTypeStoreSize(SI->getValueOperand()->getType());
227}
228
229static unsigned getAtomicOpSize(AtomicRMWInst *RMWI) {
230 const DataLayout &DL = RMWI->getDataLayout();
231 return DL.getTypeStoreSize(RMWI->getValOperand()->getType());
232}
233
234static unsigned getAtomicOpSize(AtomicCmpXchgInst *CASI) {
235 const DataLayout &DL = CASI->getDataLayout();
236 return DL.getTypeStoreSize(CASI->getCompareOperand()->getType());
237}
238
239/// Copy metadata that's safe to preserve when widening atomics.
241 const Instruction &Source) {
243 Source.getAllMetadata(MD);
244 LLVMContext &Ctx = Dest.getContext();
245 MDBuilder MDB(Ctx);
246
247 for (auto [ID, N] : MD) {
248 switch (ID) {
249 case LLVMContext::MD_dbg:
250 case LLVMContext::MD_tbaa:
251 case LLVMContext::MD_tbaa_struct:
252 case LLVMContext::MD_alias_scope:
253 case LLVMContext::MD_mem_cache_hint:
254 case LLVMContext::MD_noalias:
255 case LLVMContext::MD_noalias_addrspace:
256 case LLVMContext::MD_access_group:
257 case LLVMContext::MD_mmra:
258 case LLVMContext::MD_atomic_ignore_denormal_mode:
259 Dest.setMetadata(ID, N);
260 break;
261 default:
262 if (ID == Ctx.getMDKindID("amdgpu.no.remote.memory"))
263 Dest.setMetadata(ID, N);
264 else if (ID == Ctx.getMDKindID("amdgpu.no.fine.grained.memory"))
265 Dest.setMetadata(ID, N);
266 else if (ID == Ctx.getMDKindID("amdgpu.cfs"))
267 Dest.setMetadata(ID, N);
268 break;
269 }
270 }
271}
272
273template <typename Inst>
274static bool atomicSizeSupported(const TargetLowering *TLI, Inst *I) {
275 unsigned Size = getAtomicOpSize(I);
276 Align Alignment = I->getAlign();
277 unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
278 return Size <= MaxSize && TLI->isAtomicAlignmentSupported(Alignment, Size);
279}
280
281template <typename Inst>
283 raw_ostream &OS) {
284 unsigned Size = getAtomicOpSize(I);
285 Align Alignment = I->getAlign();
286 bool NeedSeparator = false;
287
288 if (!TLI->isAtomicAlignmentSupported(Alignment, Size)) {
289 OS << "instruction alignment " << Alignment.value()
290 << " is smaller than the required " << Size
291 << "-byte alignment for this atomic operation";
292 NeedSeparator = true;
293 }
294
295 unsigned MaxSize = TLI->getMaxAtomicSizeInBitsSupported() / 8;
296 if (Size > MaxSize) {
297 if (NeedSeparator)
298 OS << "; ";
299 OS << "target supports atomics up to " << MaxSize
300 << " bytes, but this atomic accesses " << Size << " bytes";
301 }
302}
303
304template <typename Inst>
305void AtomicExpandImpl::handleUnsupportedAtomicSize(
306 Inst *I, const Twine &AtomicOpName, Instruction *DiagnosticInst) const {
307 assert(!atomicSizeSupported(TLI, I) && "expected unsupported atomic size");
308 SmallString<128> FailureReason;
309 raw_svector_ostream OS(FailureReason);
311 handleFailure(*I, Twine("unsupported ") + AtomicOpName + ": " + FailureReason,
312 DiagnosticInst);
313}
314
315bool AtomicExpandImpl::tryInsertTrailingSeqCstFence(Instruction *AtomicI) {
317 return false;
318
319 IRBuilder Builder(AtomicI);
320 if (auto *TrailingFence = TLI->emitTrailingFence(
321 Builder, AtomicI, AtomicOrdering::SequentiallyConsistent)) {
322 TrailingFence->moveAfter(AtomicI);
323 return true;
324 }
325 return false;
326}
327
328template <typename AtomicInst>
329bool AtomicExpandImpl::tryInsertFencesForAtomic(AtomicInst *AtomicI,
330 bool OrderingRequiresFence,
331 AtomicOrdering NewOrdering) {
332 bool ShouldInsertFences = TLI->shouldInsertFencesForAtomic(AtomicI);
333 if (OrderingRequiresFence && ShouldInsertFences) {
334 AtomicOrdering FenceOrdering = AtomicI->getOrdering();
335 AtomicI->setOrdering(NewOrdering);
336 return bracketInstWithFences(AtomicI, FenceOrdering);
337 }
338 if (!ShouldInsertFences)
339 return tryInsertTrailingSeqCstFence(AtomicI);
340 return false;
341}
342
343/// In a single-threaded environment, atomic operations can be lowered to their
344/// non-atomic equivalents: fences are removed, and atomic loads, stores, RMW,
345/// and cmpxchg become plain memory operations.
346bool AtomicExpandImpl::lowerToNonAtomic(Instruction *I) {
347 if (auto *FI = dyn_cast<FenceInst>(I)) {
348 FI->eraseFromParent();
349 return true;
350 }
351
352 if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(I))
353 return lowerAtomicCmpXchgInst(CXI);
354
355 if (auto *RMWI = dyn_cast<AtomicRMWInst>(I))
356 return lowerAtomicRMWInst(RMWI);
357
358 if (auto *LI = dyn_cast<LoadInst>(I)) {
359 if (LI->isAtomic()) {
360 LI->setAtomic(AtomicOrdering::NotAtomic);
361 LI->setElementwise(false);
362 return true;
363 }
364
365 return false;
366 }
367
368 if (auto *SI = dyn_cast<StoreInst>(I)) {
369 if (SI->isAtomic()) {
370 SI->setAtomic(AtomicOrdering::NotAtomic);
371 SI->setElementwise(false);
372 return true;
373 }
374
375 return false;
376 }
377
378 return false;
379}
380
381bool AtomicExpandImpl::processAtomicInstr(Instruction *I) {
382 if (SingleThreaded)
383 return lowerToNonAtomic(I);
384
385 if (auto *LI = dyn_cast<LoadInst>(I)) {
386 if (!LI->isAtomic())
387 return false;
388
389 if (!atomicSizeSupported(TLI, LI)) {
390 expandAtomicLoadToLibcall(LI);
391 return true;
392 }
393
394 bool MadeChange = false;
395 if (TLI->shouldCastAtomicLoadInIR(LI) ==
396 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {
397 LI = convertAtomicLoadToIntegerType(LI);
398 MadeChange = true;
399 }
400
401 MadeChange |=
402 tryInsertFencesForAtomic(LI, isAcquireOrStronger(LI->getOrdering()),
404
405 MadeChange |= tryExpandAtomicLoad(LI);
406 return MadeChange;
407 }
408
409 if (auto *SI = dyn_cast<StoreInst>(I)) {
410 if (!SI->isAtomic())
411 return false;
412
413 if (!atomicSizeSupported(TLI, SI)) {
414 expandAtomicStoreToLibcall(SI);
415 return true;
416 }
417
418 bool MadeChange = false;
419 if (TLI->shouldCastAtomicStoreInIR(SI) ==
420 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {
421 SI = convertAtomicStoreToIntegerType(SI);
422 MadeChange = true;
423 }
424
425 MadeChange |=
426 tryInsertFencesForAtomic(SI, isReleaseOrStronger(SI->getOrdering()),
428
429 MadeChange |= tryExpandAtomicStore(SI);
430 return MadeChange;
431 }
432
433 if (auto *RMWI = dyn_cast<AtomicRMWInst>(I)) {
434 bool IsElementwiseExpand =
435 RMWI->isElementwise() &&
436 TLI->shouldExpandAtomicRMWInIR(RMWI) ==
437 TargetLoweringBase::AtomicExpansionKind::Expand;
438
439 if (!atomicSizeSupported(TLI, RMWI)) {
440 // Elementwise expansion may split an atomicrmw into smaller, supported
441 // atomic sizes.
442 if (!IsElementwiseExpand) {
443 expandAtomicRMWToLibcall(RMWI);
444 return true;
445 }
446 }
447
448 bool MadeChange = false;
449 if (!IsElementwiseExpand &&
450 TLI->shouldCastAtomicRMWIInIR(RMWI) ==
451 TargetLoweringBase::AtomicExpansionKind::CastToInteger) {
452 RMWI = convertAtomicXchgToIntegerType(RMWI);
453 MadeChange = true;
454 }
455
456 MadeChange |= tryInsertFencesForAtomic(
457 RMWI, isStrongerThanMonotonic(RMWI->getOrdering()),
459
460 // There are two different ways of expanding RMW instructions:
461 // - into a load if it is idempotent
462 // - into a Cmpxchg/LL-SC loop otherwise
463 // we try them in that order.
464 MadeChange |= (isIdempotentRMW(RMWI) && simplifyIdempotentRMW(RMWI)) ||
465 tryExpandAtomicRMW(RMWI);
466 return MadeChange;
467 }
468
469 if (auto *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
470 if (!atomicSizeSupported(TLI, CASI)) {
471 expandAtomicCASToLibcall(CASI);
472 return true;
473 }
474
475 // TODO: when we're ready to make the change at the IR level, we can
476 // extend convertCmpXchgToInteger for floating point too.
477 bool MadeChange = false;
478 if (CASI->getCompareOperand()->getType()->isPointerTy()) {
479 // TODO: add a TLI hook to control this so that each target can
480 // convert to lowering the original type one at a time.
481 CASI = convertCmpXchgToIntegerType(CASI);
482 MadeChange = true;
483 }
484
485 auto CmpXchgExpansion = TLI->shouldExpandAtomicCmpXchgInIR(CASI);
486 if (TLI->shouldInsertFencesForAtomic(CASI)) {
487 if (CmpXchgExpansion == TargetLoweringBase::AtomicExpansionKind::None &&
488 (isReleaseOrStronger(CASI->getSuccessOrdering()) ||
489 isAcquireOrStronger(CASI->getSuccessOrdering()) ||
490 isAcquireOrStronger(CASI->getFailureOrdering()))) {
491 // If a compare and swap is lowered to LL/SC, we can do smarter fence
492 // insertion, with a stronger one on the success path than on the
493 // failure path. As a result, fence insertion is directly done by
494 // expandAtomicCmpXchg in that case.
495 AtomicOrdering FenceOrdering = CASI->getMergedOrdering();
496 AtomicOrdering CASOrdering =
498 CASI->setSuccessOrdering(CASOrdering);
499 CASI->setFailureOrdering(CASOrdering);
500 MadeChange |= bracketInstWithFences(CASI, FenceOrdering);
501 }
502 } else if (CmpXchgExpansion !=
503 TargetLoweringBase::AtomicExpansionKind::LLSC) {
504 // CmpXchg LLSC is handled in expandAtomicCmpXchg().
505 MadeChange |= tryInsertTrailingSeqCstFence(CASI);
506 }
507
508 MadeChange |= tryExpandAtomicCmpXchg(CASI);
509 return MadeChange;
510 }
511
512 return false;
513}
514
515bool AtomicExpandImpl::run(Function &F,
516 const ModuleLibcallLoweringInfo &LibcallResult,
517 const TargetMachine *TM) {
518 SingleThreaded = F.getParent()->getThreadModel() == ThreadModel::Single;
519
520 const auto *Subtarget = TM->getSubtargetImpl(F);
521 // In a single-threaded environment atomics are lowered to non-atomic form
522 if (!SingleThreaded && !Subtarget->enableAtomicExpand())
523 return false;
524 TLI = Subtarget->getTargetLowering();
525 LibcallLowering = &getLibcallLowering(LibcallResult, *Subtarget);
526 DL = &F.getDataLayout();
527
528 bool MadeChange = false;
529
530 for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) {
531 BasicBlock *BB = &*BBI;
532
534
535 for (BasicBlock::reverse_iterator I = BB->rbegin(), E = BB->rend(); I != E;
536 I = Next) {
537 Instruction &Inst = *I;
538 Next = std::next(I);
539
540 if (processAtomicInstr(&Inst)) {
541 MadeChange = true;
542
543 // New blocks may have been inserted.
544 BBE = F.end();
545 }
546 }
547 }
548
549 return MadeChange;
550}
551
552bool AtomicExpandLegacy::runOnFunction(Function &F) {
553
554 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
555 if (!TPC)
556 return false;
557 auto *TM = &TPC->getTM<TargetMachine>();
558
559 const ModuleLibcallLoweringInfo &LibcallResult =
560 getAnalysis<LibcallLoweringInfoWrapper>().getResult(*F.getParent());
561 AtomicExpandImpl AE;
562 return AE.run(F, LibcallResult, TM);
563}
564
566 return new AtomicExpandLegacy();
567}
568
571 auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
572
573 const ModuleLibcallLoweringInfo *LibcallResult =
574 MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(*F.getParent());
575
576 if (!LibcallResult) {
577 F.getContext().emitError("'" + LibcallLoweringModuleAnalysis::name() +
578 "' analysis required");
579 return PreservedAnalyses::all();
580 }
581
582 AtomicExpandImpl AE;
583
584 bool Changed = AE.run(F, *LibcallResult, TM);
585 if (!Changed)
586 return PreservedAnalyses::all();
587
589}
590
591bool AtomicExpandImpl::bracketInstWithFences(Instruction *I,
592 AtomicOrdering Order) {
593 ReplacementIRBuilder Builder(I, *DL);
594
595 auto LeadingFence = TLI->emitLeadingFence(Builder, I, Order);
596
597 auto TrailingFence = TLI->emitTrailingFence(Builder, I, Order);
598 // We have a guard here because not every atomic operation generates a
599 // trailing fence.
600 if (TrailingFence)
601 TrailingFence->moveAfter(I);
602
603 return (LeadingFence || TrailingFence);
604}
605
606/// Get the iX type with the same bitwidth as T.
608AtomicExpandImpl::getCorrespondingIntegerType(Type *T, const DataLayout &DL) {
609 EVT VT = TLI->getMemValueType(DL, T);
610 unsigned BitWidth = VT.getStoreSizeInBits();
611 assert(BitWidth == VT.getSizeInBits() && "must be a power of two");
612 return IntegerType::get(T->getContext(), BitWidth);
613}
614
615/// Convert an atomic load of a non-integral type to an integer load of the
616/// equivalent bitwidth. See the function comment on
617/// convertAtomicStoreToIntegerType for background.
618LoadInst *AtomicExpandImpl::convertAtomicLoadToIntegerType(LoadInst *LI) {
619 auto *M = LI->getModule();
620 Type *NewTy = getCorrespondingIntegerType(LI->getType(), M->getDataLayout());
621
622 ReplacementIRBuilder Builder(LI, *DL);
623
624 Value *Addr = LI->getPointerOperand();
625
626 auto *NewLI = Builder.CreateLoad(NewTy, Addr, LI->getProperties());
627 LLVM_DEBUG(dbgs() << "Replaced " << *LI << " with " << *NewLI << "\n");
628
629 Value *NewVal = LI->getType()->isPtrOrPtrVectorTy()
630 ? Builder.CreateIntToPtr(NewLI, LI->getType())
631 : Builder.CreateBitCast(NewLI, LI->getType());
632 LI->replaceAllUsesWith(NewVal);
633 LI->eraseFromParent();
634 return NewLI;
635}
636
637AtomicRMWInst *
638AtomicExpandImpl::convertAtomicXchgToIntegerType(AtomicRMWInst *RMWI) {
640
641 auto *M = RMWI->getModule();
642 Type *NewTy =
643 getCorrespondingIntegerType(RMWI->getType(), M->getDataLayout());
644
645 ReplacementIRBuilder Builder(RMWI, *DL);
646
647 Value *Addr = RMWI->getPointerOperand();
648 Value *Val = RMWI->getValOperand();
649 Value *NewVal = Builder.CreateBitPreservingCastChain(*DL, Val, NewTy);
650
651 auto *NewRMWI = Builder.CreateAtomicRMW(AtomicRMWInst::Xchg, Addr, NewVal,
652 RMWI->getAlign(), RMWI->getOrdering(),
653 RMWI->getSyncScopeID());
654 NewRMWI->setVolatile(RMWI->isVolatile());
655 copyMetadataForAtomic(*NewRMWI, *RMWI);
656 LLVM_DEBUG(dbgs() << "Replaced " << *RMWI << " with " << *NewRMWI << "\n");
657
658 Value *NewRVal =
659 Builder.CreateBitPreservingCastChain(*DL, NewRMWI, RMWI->getType());
660 RMWI->replaceAllUsesWith(NewRVal);
661 RMWI->eraseFromParent();
662 return NewRMWI;
663}
664
665/// Generic Expand handling for elementwise vector atomicrmw instructions.
666/// Halve an `atomicrmw elementwise <N x T>` and feed each half back through the
667/// normal atomic expansion pipeline. The target's shouldExpandAtomicRMWInIR()
668/// is re-queried at the halved width and may return any expansion kind there
669/// (e.g. None to preserve as a native vector atomic, Expand to keep halving,
670/// CmpXChg to emit one wide cmpxchg loop at the halved width). Two cases:
671/// N == 1: collapse directly to one scalar atomicrmw T
672/// N > 1: split into two atomicrmw elementwise <N/2 x T> (low at Ptr, high
673/// at gep inbounds <N/2 x T>, Ptr, 1); reassemble via a
674/// shufflevector.
675/// Note that halving works because the vectors must always be a power of two.
676///
677/// Each new atomicrmw inherits the original ordering/syncscope/volatility and
678/// metadata, and is fed back through processAtomicInstr() so further expansion
679/// fires per-half.
680void AtomicExpandImpl::expandElementwiseAtomicRMW(AtomicRMWInst *AI) {
681 assert(AI->isElementwise());
682 auto *VecTy = cast<FixedVectorType>(AI->getType());
683 Type *LaneTy = VecTy->getElementType();
684 const unsigned NumLanes = VecTy->getNumElements();
685 Value *Ptr = AI->getPointerOperand();
686 Value *Val = AI->getValOperand();
687
688 ReplacementIRBuilder Builder(AI, *DL);
689 IntegerType *IdxTy =
690 DL->getIndexType(AI->getContext(), AI->getPointerAddressSpace());
691
692 auto CreateRMWInstruction = [&](Value *HalfPtr, Value *HalfVal, Align A,
693 bool Elementwise) -> AtomicRMWInst * {
694 auto *NewAI =
695 Builder.CreateAtomicRMW(AI->getOperation(), HalfPtr, HalfVal, A,
696 AI->getOrdering(), AI->getSyncScopeID());
697 NewAI->setVolatile(AI->isVolatile());
698 NewAI->setElementwise(Elementwise);
699 copyMetadataForAtomic(*NewAI, *AI);
700 return NewAI;
701 };
702
703 Constant *IdxZero = ConstantInt::get(IdxTy, 0);
704 Constant *IdxOne = ConstantInt::get(IdxTy, 1);
705
706 // N == 1: collapse to a single scalar atomicrmw T and wrap the result back
707 // into a <1 x T> vector.
708 if (NumLanes == 1) {
709 Value *LaneVal = Builder.CreateExtractElement(Val, IdxZero, "lane.val");
710 AtomicRMWInst *LaneRMW = CreateRMWInstruction(Ptr, LaneVal, AI->getAlign(),
711 /*Elementwise=*/false);
712 Value *Result = Builder.CreateInsertElement(PoisonValue::get(VecTy),
713 LaneRMW, IdxZero, "lane.old");
714 AI->replaceAllUsesWith(Result);
715 AI->eraseFromParent();
716 processAtomicInstr(LaneRMW);
717 return;
718 }
719
720 // N > 1: split into two <N/2 x T> elementwise atomicrmws and recurse via
721 // processAtomicInstr().
722 assert(isPowerOf2_32(NumLanes) &&
723 "elementwise atomicrmw vector length must be a power of two");
724 const unsigned HalfLanes = NumLanes / 2;
725 auto *HalfVecTy = FixedVectorType::get(LaneTy, HalfLanes);
726 const uint64_t HalfBytes = DL->getTypeStoreSize(HalfVecTy).getFixedValue();
727
728 Value *LoVal = Builder.CreateShuffleVector(
729 Val, createSequentialMask(0, HalfLanes, 0), "lo.val");
730 Value *HiVal = Builder.CreateShuffleVector(
731 Val, createSequentialMask(HalfLanes, HalfLanes, 0), "hi.val");
732
733 Value *HiPtr = Builder.CreateInBoundsGEP(HalfVecTy, Ptr, IdxOne, "hi.ptr");
734 Align LoAlign = AI->getAlign();
735 Align HiAlign = commonAlignment(LoAlign, HalfBytes);
736
737 AtomicRMWInst *LoRMW =
738 CreateRMWInstruction(Ptr, LoVal, LoAlign, /*Elementwise=*/true);
739 AtomicRMWInst *HiRMW =
740 CreateRMWInstruction(HiPtr, HiVal, HiAlign, /*Elementwise=*/true);
741
742 Value *Result = concatenateVectors(Builder, {LoRMW, HiRMW});
743 Result->setName("old");
744
745 AI->replaceAllUsesWith(Result);
746 AI->eraseFromParent();
747 processAtomicInstr(LoRMW);
748 processAtomicInstr(HiRMW);
749}
750
751bool AtomicExpandImpl::tryExpandAtomicLoad(LoadInst *LI) {
752 switch (TLI->shouldExpandAtomicLoadInIR(LI)) {
753 case TargetLoweringBase::AtomicExpansionKind::None:
754 return false;
755 case TargetLoweringBase::AtomicExpansionKind::LLSC:
756 expandAtomicOpToLLSC(
757 LI, LI->getType(), LI->getPointerOperand(), LI->getAlign(),
758 LI->getOrdering(),
759 [](IRBuilderBase &Builder, Value *Loaded) { return Loaded; });
760 return true;
761 case TargetLoweringBase::AtomicExpansionKind::LLOnly:
762 return expandAtomicLoadToLL(LI);
763 case TargetLoweringBase::AtomicExpansionKind::CmpXChg:
764 return expandAtomicLoadToCmpXchg(LI);
765 case TargetLoweringBase::AtomicExpansionKind::NotAtomic:
766 LI->setAtomic(AtomicOrdering::NotAtomic);
767 return true;
768 case TargetLoweringBase::AtomicExpansionKind::CustomExpand:
769 TLI->emitExpandAtomicLoad(LI);
770 return true;
771 default:
772 llvm_unreachable("Unhandled case in tryExpandAtomicLoad");
773 }
774}
775
776bool AtomicExpandImpl::tryExpandAtomicStore(StoreInst *SI) {
777 switch (TLI->shouldExpandAtomicStoreInIR(SI)) {
778 case TargetLoweringBase::AtomicExpansionKind::None:
779 return false;
780 case TargetLoweringBase::AtomicExpansionKind::CustomExpand:
781 TLI->emitExpandAtomicStore(SI);
782 return true;
783 case TargetLoweringBase::AtomicExpansionKind::Expand:
784 expandAtomicStoreToXChg(SI);
785 return true;
786 case TargetLoweringBase::AtomicExpansionKind::NotAtomic:
787 SI->setAtomic(AtomicOrdering::NotAtomic);
788 return true;
789 default:
790 llvm_unreachable("Unhandled case in tryExpandAtomicStore");
791 }
792}
793
794bool AtomicExpandImpl::expandAtomicLoadToLL(LoadInst *LI) {
795 ReplacementIRBuilder Builder(LI, *DL);
796
797 // On some architectures, load-linked instructions are atomic for larger
798 // sizes than normal loads. For example, the only 64-bit load guaranteed
799 // to be single-copy atomic by ARM is an ldrexd (A3.5.3).
800 Value *Val = TLI->emitLoadLinked(Builder, LI->getType(),
801 LI->getPointerOperand(), LI->getOrdering());
803
804 LI->replaceAllUsesWith(Val);
805 LI->eraseFromParent();
806
807 return true;
808}
809
810bool AtomicExpandImpl::expandAtomicLoadToCmpXchg(LoadInst *LI) {
811 ReplacementIRBuilder Builder(LI, *DL);
812 AtomicOrdering Order = LI->getOrdering();
813 if (Order == AtomicOrdering::Unordered)
814 Order = AtomicOrdering::Monotonic;
815
816 Value *Addr = LI->getPointerOperand();
817 Type *Ty = LI->getType();
818
819 // cmpxchg supports only integer and pointer operands. If the load type is
820 // FP or vector, run the cmpxchg on the same-sized integer and bitcast the
821 // result back; mirrors createCmpXchgInstFun.
822 bool NeedBitcast = Ty->isFloatingPointTy() || Ty->isVectorTy();
823 Type *CmpXchgTy = Ty;
824 if (NeedBitcast)
825 CmpXchgTy = Builder.getIntNTy(Ty->getPrimitiveSizeInBits());
826 Constant *DummyVal = Constant::getNullValue(CmpXchgTy);
827
828 AtomicCmpXchgInst *Pair = Builder.CreateAtomicCmpXchg(
829 Addr, DummyVal, DummyVal, LI->getAlign(), Order,
831 LI->getSyncScopeID());
832 Pair->setVolatile(LI->isVolatile());
833 Value *Loaded = Builder.CreateExtractValue(Pair, 0, "loaded");
834 if (NeedBitcast)
835 Loaded = Builder.CreateBitCast(Loaded, Ty);
836
837 LI->replaceAllUsesWith(Loaded);
838 LI->eraseFromParent();
839
840 return true;
841}
842
843/// Convert an atomic store of a non-integral type to an integer store of the
844/// equivalent bitwidth. We used to not support floating point or vector
845/// atomics in the IR at all. The backends learned to deal with the bitcast
846/// idiom because that was the only way of expressing the notion of a atomic
847/// float or vector store. The long term plan is to teach each backend to
848/// instruction select from the original atomic store, but as a migration
849/// mechanism, we convert back to the old format which the backends understand.
850/// Each backend will need individual work to recognize the new format.
851StoreInst *AtomicExpandImpl::convertAtomicStoreToIntegerType(StoreInst *SI) {
852 ReplacementIRBuilder Builder(SI, *DL);
853 auto *M = SI->getModule();
854 Type *NewTy = getCorrespondingIntegerType(SI->getValueOperand()->getType(),
855 M->getDataLayout());
856 Value *NewVal = SI->getValueOperand()->getType()->isPtrOrPtrVectorTy()
857 ? Builder.CreatePtrToInt(SI->getValueOperand(), NewTy)
858 : Builder.CreateBitCast(SI->getValueOperand(), NewTy);
859
860 Value *Addr = SI->getPointerOperand();
861
862 StoreInst *NewSI = Builder.CreateStore(NewVal, Addr, SI->getProperties());
863 copyMetadataForAtomic(*NewSI, *SI);
864 LLVM_DEBUG(dbgs() << "Replaced " << *SI << " with " << *NewSI << "\n");
865 SI->eraseFromParent();
866 return NewSI;
867}
868
869void AtomicExpandImpl::expandAtomicStoreToXChg(StoreInst *SI) {
870 // This function is only called on atomic stores that are too large to be
871 // atomic if implemented as a native store. So we replace them by an
872 // atomic swap, that can be implemented for example as a ldrex/strex on ARM
873 // or lock cmpxchg8/16b on X86, as these are atomic for larger sizes.
874 // It is the responsibility of the target to only signal expansion via
875 // shouldExpandAtomicRMW in cases where this is required and possible.
876 ReplacementIRBuilder Builder(SI, *DL);
877 AtomicOrdering Ordering = SI->getOrdering();
878 assert(Ordering != AtomicOrdering::NotAtomic);
879 AtomicOrdering RMWOrdering = Ordering == AtomicOrdering::Unordered
880 ? AtomicOrdering::Monotonic
881 : Ordering;
882 AtomicRMWInst *AI = Builder.CreateAtomicRMW(
883 AtomicRMWInst::Xchg, SI->getPointerOperand(), SI->getValueOperand(),
884 SI->getAlign(), RMWOrdering, SI->getSyncScopeID());
885 AI->setVolatile(SI->isVolatile());
886 SI->eraseFromParent();
887
888 // Now we have an appropriate swap instruction, lower it as usual.
889 tryExpandAtomicRMW(AI);
890}
891
892static void createCmpXchgInstFun(IRBuilderBase &Builder, Value *Addr,
893 Value *Loaded, Value *NewVal, Align AddrAlign,
894 AtomicOrdering MemOpOrder, SyncScope::ID SSID,
895 bool IsVolatile, Value *&Success,
896 Value *&NewLoaded, Instruction *MetadataSrc) {
897 Type *OrigTy = NewVal->getType();
898
899 // This code can go away when cmpxchg supports FP and vector types.
900 assert(!OrigTy->isPointerTy());
901 bool NeedBitcast = OrigTy->isFloatingPointTy() || OrigTy->isVectorTy();
902 if (NeedBitcast) {
903 IntegerType *IntTy = Builder.getIntNTy(OrigTy->getPrimitiveSizeInBits());
904 NewVal = Builder.CreateBitCast(NewVal, IntTy);
905 Loaded = Builder.CreateBitCast(Loaded, IntTy);
906 }
907
908 AtomicCmpXchgInst *Pair = Builder.CreateAtomicCmpXchg(
909 Addr, Loaded, NewVal, AddrAlign, MemOpOrder,
911 Pair->setVolatile(IsVolatile);
912 if (MetadataSrc)
913 copyMetadataForAtomic(*Pair, *MetadataSrc);
914
915 Success = Builder.CreateExtractValue(Pair, 1, "success");
916 NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded");
917
918 if (NeedBitcast)
919 NewLoaded = Builder.CreateBitCast(NewLoaded, OrigTy);
920}
921
922void AtomicExpandImpl::expandAtomicSubToAdd(AtomicRMWInst *AI) {
923 ReplacementIRBuilder Builder(AI, *DL);
925 Value *NewVal;
926
927 switch (AI->getOperation()) {
929 NewOp = AtomicRMWInst::Add;
930 NewVal = Builder.CreateNeg(AI->getValOperand(), "neg");
931 break;
933 NewOp = AtomicRMWInst::FAdd;
934 NewVal = Builder.CreateFNeg(AI->getValOperand(), "fneg");
935 break;
936 default:
937 llvm_unreachable("unsupported atomicrmw expansion");
938 }
939
940 AI->setOperation(NewOp);
941 AI->setOperand(1, NewVal);
942}
943
944bool AtomicExpandImpl::tryExpandAtomicRMW(AtomicRMWInst *AI) {
945 LLVMContext &Ctx = AI->getModule()->getContext();
946 TargetLowering::AtomicExpansionKind Kind = TLI->shouldExpandAtomicRMWInIR(AI);
947 switch (Kind) {
948 case TargetLoweringBase::AtomicExpansionKind::None:
949 return false;
950 case TargetLoweringBase::AtomicExpansionKind::LLSC: {
951 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
952 unsigned ValueSize = getAtomicOpSize(AI);
953 if (ValueSize < MinCASSize) {
954 expandPartwordAtomicRMW(AI,
955 TargetLoweringBase::AtomicExpansionKind::LLSC);
956 } else {
957 auto PerformOp = [&](IRBuilderBase &Builder, Value *Loaded) {
958 return buildAtomicRMWValue(AI->getOperation(), Builder, Loaded,
959 AI->getValOperand());
960 };
961 expandAtomicOpToLLSC(AI, AI->getType(), AI->getPointerOperand(),
962 AI->getAlign(), AI->getOrdering(), PerformOp);
963 }
964 return true;
965 }
966 case TargetLoweringBase::AtomicExpansionKind::CmpXChg: {
967 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
968 unsigned ValueSize = getAtomicOpSize(AI);
969 if (ValueSize < MinCASSize) {
970 expandPartwordAtomicRMW(AI,
971 TargetLoweringBase::AtomicExpansionKind::CmpXChg);
972 } else {
974 Ctx.getSyncScopeNames(SSNs);
975 auto MemScope = SSNs[AI->getSyncScopeID()].empty()
976 ? "system"
977 : SSNs[AI->getSyncScopeID()];
978 OptimizationRemarkEmitter ORE(AI->getFunction());
979 ORE.emit([&]() {
980 return OptimizationRemark(DEBUG_TYPE, "Passed", AI)
981 << "A compare and swap loop was generated for an atomic "
982 << AI->getOperationName(AI->getOperation()) << " operation at "
983 << MemScope << " memory scope";
984 });
985 expandAtomicRMWToCmpXchg(AI, createCmpXchgInstFun);
986 }
987 return true;
988 }
989 case TargetLoweringBase::AtomicExpansionKind::MaskedIntrinsic: {
990 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
991 unsigned ValueSize = getAtomicOpSize(AI);
992 if (ValueSize < MinCASSize) {
994 // Widen And/Or/Xor and give the target another chance at expanding it.
997 tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));
998 return true;
999 }
1000 }
1001 expandAtomicRMWToMaskedIntrinsic(AI);
1002 return true;
1003 }
1004 case TargetLoweringBase::AtomicExpansionKind::BitTestIntrinsic: {
1006 return true;
1007 }
1008 case TargetLoweringBase::AtomicExpansionKind::CmpArithIntrinsic: {
1010 return true;
1011 }
1012 case TargetLoweringBase::AtomicExpansionKind::Expand:
1013 if (AI->isElementwise()) {
1014 expandElementwiseAtomicRMW(AI);
1015 return true;
1016 }
1017 expandAtomicSubToAdd(AI);
1018 return true;
1019 case TargetLoweringBase::AtomicExpansionKind::NotAtomic:
1020 return lowerAtomicRMWInst(AI);
1021 case TargetLoweringBase::AtomicExpansionKind::CustomExpand:
1022 TLI->emitExpandAtomicRMW(AI);
1023 return true;
1024 default:
1025 llvm_unreachable("Unhandled case in tryExpandAtomicRMW");
1026 }
1027}
1028
1029namespace {
1030
1031struct PartwordMaskValues {
1032 // These three fields are guaranteed to be set by createMaskInstrs.
1033 Type *WordType = nullptr;
1034 Type *ValueType = nullptr;
1035 Type *IntValueType = nullptr;
1036 Value *AlignedAddr = nullptr;
1037 Align AlignedAddrAlignment;
1038 // The remaining fields can be null.
1039 Value *ShiftAmt = nullptr;
1040 Value *Mask = nullptr;
1041 Value *Inv_Mask = nullptr;
1042};
1043
1044[[maybe_unused]]
1045raw_ostream &operator<<(raw_ostream &O, const PartwordMaskValues &PMV) {
1046 auto PrintObj = [&O](auto *V) {
1047 if (V)
1048 O << *V;
1049 else
1050 O << "nullptr";
1051 O << '\n';
1052 };
1053 O << "PartwordMaskValues {\n";
1054 O << " WordType: ";
1055 PrintObj(PMV.WordType);
1056 O << " ValueType: ";
1057 PrintObj(PMV.ValueType);
1058 O << " AlignedAddr: ";
1059 PrintObj(PMV.AlignedAddr);
1060 O << " AlignedAddrAlignment: " << PMV.AlignedAddrAlignment.value() << '\n';
1061 O << " ShiftAmt: ";
1062 PrintObj(PMV.ShiftAmt);
1063 O << " Mask: ";
1064 PrintObj(PMV.Mask);
1065 O << " Inv_Mask: ";
1066 PrintObj(PMV.Inv_Mask);
1067 O << "}\n";
1068 return O;
1069}
1070
1071} // end anonymous namespace
1072
1073/// This is a helper function which builds instructions to provide
1074/// values necessary for partword atomic operations. It takes an
1075/// incoming address, Addr, and ValueType, and constructs the address,
1076/// shift-amounts and masks needed to work with a larger value of size
1077/// WordSize.
1078///
1079/// AlignedAddr: Addr rounded down to a multiple of WordSize
1080///
1081/// ShiftAmt: Number of bits to right-shift a WordSize value loaded
1082/// from AlignAddr for it to have the same value as if
1083/// ValueType was loaded from Addr.
1084///
1085/// Mask: Value to mask with the value loaded from AlignAddr to
1086/// include only the part that would've been loaded from Addr.
1087///
1088/// Inv_Mask: The inverse of Mask.
1089static PartwordMaskValues createMaskInstrs(IRBuilderBase &Builder,
1091 Value *Addr, Align AddrAlign,
1092 unsigned MinWordSize) {
1093 PartwordMaskValues PMV;
1094
1095 Module *M = I->getModule();
1096 LLVMContext &Ctx = M->getContext();
1097 const DataLayout &DL = M->getDataLayout();
1098 unsigned ValueSize = DL.getTypeStoreSize(ValueType);
1099
1100 PMV.ValueType = PMV.IntValueType = ValueType;
1101 if (PMV.ValueType->isFloatingPointTy() || PMV.ValueType->isVectorTy())
1102 PMV.IntValueType =
1103 Type::getIntNTy(Ctx, ValueType->getPrimitiveSizeInBits());
1104
1105 PMV.WordType = MinWordSize > ValueSize ? Type::getIntNTy(Ctx, MinWordSize * 8)
1106 : ValueType;
1107 if (PMV.ValueType == PMV.WordType) {
1108 PMV.AlignedAddr = Addr;
1109 PMV.AlignedAddrAlignment = AddrAlign;
1110 PMV.ShiftAmt = ConstantInt::get(PMV.ValueType, 0);
1111 PMV.Mask = ConstantInt::get(PMV.ValueType, ~0, /*isSigned*/ true);
1112 return PMV;
1113 }
1114
1115 PMV.AlignedAddrAlignment = Align(MinWordSize);
1116
1117 assert(ValueSize < MinWordSize);
1118
1119 PointerType *PtrTy = cast<PointerType>(Addr->getType());
1120 IntegerType *IntTy = DL.getIndexType(Ctx, PtrTy->getAddressSpace());
1121 Value *PtrLSB;
1122
1123 if (AddrAlign < MinWordSize) {
1124 PMV.AlignedAddr = Builder.CreateIntrinsic(
1125 Intrinsic::ptrmask, {PtrTy, IntTy},
1126 {Addr, ConstantInt::getSigned(IntTy, ~(uint64_t)(MinWordSize - 1))},
1127 nullptr, "AlignedAddr");
1128
1129 Value *AddrInt = Builder.CreatePtrToInt(Addr, IntTy);
1130 PtrLSB = Builder.CreateAnd(AddrInt, MinWordSize - 1, "PtrLSB");
1131 } else {
1132 // If the alignment is high enough, the LSB are known 0.
1133 PMV.AlignedAddr = Addr;
1134 PtrLSB = ConstantInt::getNullValue(IntTy);
1135 }
1136
1137 if (DL.isLittleEndian()) {
1138 // turn bytes into bits
1139 PMV.ShiftAmt = Builder.CreateShl(PtrLSB, 3);
1140 } else {
1141 // turn bytes into bits, and count from the other side.
1142 PMV.ShiftAmt = Builder.CreateShl(
1143 Builder.CreateXor(PtrLSB, MinWordSize - ValueSize), 3);
1144 }
1145
1146 PMV.ShiftAmt = Builder.CreateTrunc(PMV.ShiftAmt, PMV.WordType, "ShiftAmt");
1147 PMV.Mask = Builder.CreateShl(
1148 ConstantInt::get(PMV.WordType, (1 << (ValueSize * 8)) - 1), PMV.ShiftAmt,
1149 "Mask");
1150
1151 PMV.Inv_Mask = Builder.CreateNot(PMV.Mask, "Inv_Mask");
1152
1153 return PMV;
1154}
1155
1156static Value *extractMaskedValue(IRBuilderBase &Builder, Value *WideWord,
1157 const PartwordMaskValues &PMV) {
1158 assert(WideWord->getType() == PMV.WordType && "Widened type mismatch");
1159 if (PMV.WordType == PMV.ValueType)
1160 return WideWord;
1161
1162 Value *Shift = Builder.CreateLShr(WideWord, PMV.ShiftAmt, "shifted");
1163 Value *Trunc = Builder.CreateTrunc(Shift, PMV.IntValueType, "extracted");
1164 return Builder.CreateBitCast(Trunc, PMV.ValueType);
1165}
1166
1167static Value *insertMaskedValue(IRBuilderBase &Builder, Value *WideWord,
1168 Value *Updated, const PartwordMaskValues &PMV) {
1169 assert(WideWord->getType() == PMV.WordType && "Widened type mismatch");
1170 assert(Updated->getType() == PMV.ValueType && "Value type mismatch");
1171 if (PMV.WordType == PMV.ValueType)
1172 return Updated;
1173
1174 Updated = Builder.CreateBitCast(Updated, PMV.IntValueType);
1175
1176 Value *ZExt = Builder.CreateZExt(Updated, PMV.WordType, "extended");
1177 Value *Shift =
1178 Builder.CreateShl(ZExt, PMV.ShiftAmt, "shifted", /*HasNUW*/ true);
1179 Value *And = Builder.CreateAnd(WideWord, PMV.Inv_Mask, "unmasked");
1180 Value *Or = Builder.CreateOr(And, Shift, "inserted");
1181 return Or;
1182}
1183
1184/// Emit IR to implement a masked version of a given atomicrmw
1185/// operation. (That is, only the bits under the Mask should be
1186/// affected by the operation)
1188 IRBuilderBase &Builder, Value *Loaded,
1189 Value *ValOperand_Shifted, Value *Inc,
1190 const PartwordMaskValues &PMV) {
1191 // TODO: update to use
1192 // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge in order
1193 // to merge bits from two values without requiring PMV.Inv_Mask.
1194
1197 "Or/Xor/And handled by widenPartwordAtomicRMW");
1198
1199 if (Op == AtomicRMWInst::Xchg) {
1200 // Clear all the bits we are exchanging out. These are the bits under the
1201 // mask. We can clear them with an `and` of the inverse mask.
1202 Value *Loaded_MaskOut = Builder.CreateAnd(Loaded, PMV.Inv_Mask);
1203 // Now that the prevous bits are cleared, we can swap in the new value with
1204 // an `or`.
1205 Value *FinalVal = Builder.CreateOr(Loaded_MaskOut, ValOperand_Shifted);
1206 return FinalVal;
1207 }
1208
1209 if (Op == AtomicRMWInst::Nand ||
1210 (!PMV.ValueType->isVectorTy() &&
1212 // For `Nand` and non-vector `Add` and `Sub`, we can perform the operation
1213 // on the entire word because the extra bits in the unmasked region don't
1214 // affect the computation in the masked region. The operation might still
1215 // overwrite the unmasked region (e.g. from integer overflow or underflow),
1216 // so we have to reapply the unmasked region afterwards.
1217 //
1218 // This trick doesn't work for vector `Add` and `Sub` because we use a
1219 // scalar operation on the entire word. Scalarizing vector `Add` and `Sub`
1220 // isn't legal because the vector versions may have element-wise overflows.
1221 // TODO: For these, can we use a wider vector op with additional lanes?
1222
1223 // Atomic operation across the entire word.
1224 Value *NewVal =
1225 buildAtomicRMWValue(Op, Builder, Loaded, ValOperand_Shifted);
1226 // Reapply the bits in the unmasked region.
1227 Value *NewVal_Masked = Builder.CreateAnd(NewVal, PMV.Mask);
1228 Value *Loaded_MaskOut = Builder.CreateAnd(Loaded, PMV.Inv_Mask);
1229 Value *FinalVal = Builder.CreateOr(Loaded_MaskOut, NewVal_Masked);
1230 return FinalVal;
1231 }
1232
1233 // All other ops operate on the sub-word size. Truncate down to the
1234 // original size, and expand out again after doing the operation. Bitcasts
1235 // will be inserted for FP values.
1236 assert(!ValOperand_Shifted);
1237 Value *Loaded_Extract = extractMaskedValue(Builder, Loaded, PMV);
1238 Value *NewVal = buildAtomicRMWValue(Op, Builder, Loaded_Extract, Inc);
1239 Value *FinalVal = insertMaskedValue(Builder, Loaded, NewVal, PMV);
1240 return FinalVal;
1241}
1242
1243/// Expand a sub-word atomicrmw operation into an appropriate
1244/// word-sized operation.
1245///
1246/// It will create an LL/SC or cmpxchg loop, as appropriate, the same
1247/// way as a typical atomicrmw expansion. The only difference here is
1248/// that the operation inside of the loop may operate upon only a
1249/// part of the value.
1250void AtomicExpandImpl::expandPartwordAtomicRMW(
1251 AtomicRMWInst *AI, TargetLoweringBase::AtomicExpansionKind ExpansionKind) {
1252 // Widen And/Or/Xor and give the target another chance at expanding it.
1256 tryExpandAtomicRMW(widenPartwordAtomicRMW(AI));
1257 return;
1258 }
1259 AtomicOrdering MemOpOrder = AI->getOrdering();
1260 SyncScope::ID SSID = AI->getSyncScopeID();
1261
1262 ReplacementIRBuilder Builder(AI, *DL);
1263
1264 PartwordMaskValues PMV =
1265 createMaskInstrs(Builder, AI, AI->getType(), AI->getPointerOperand(),
1266 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1267
1268 Value *ValOperand_Shifted = nullptr;
1269 bool NeedsShiftedOperand =
1271 (!PMV.ValueType->isVectorTy() &&
1273
1274 if (NeedsShiftedOperand) {
1275 Value *ValOp = Builder.CreateBitCast(AI->getValOperand(), PMV.IntValueType);
1276 ValOperand_Shifted =
1277 Builder.CreateShl(Builder.CreateZExt(ValOp, PMV.WordType), PMV.ShiftAmt,
1278 "ValOperand_Shifted");
1279 }
1280
1281 auto PerformPartwordOp = [&](IRBuilderBase &Builder, Value *Loaded) {
1282 return performMaskedAtomicOp(Op, Builder, Loaded, ValOperand_Shifted,
1283 AI->getValOperand(), PMV);
1284 };
1285
1286 Value *OldResult;
1287 if (ExpansionKind == TargetLoweringBase::AtomicExpansionKind::CmpXChg) {
1288 OldResult = insertRMWCmpXchgLoop(Builder, PMV.WordType, PMV.AlignedAddr,
1289 PMV.AlignedAddrAlignment, MemOpOrder, SSID,
1290 AI->isVolatile(), PerformPartwordOp,
1292 } else {
1293 assert(ExpansionKind == TargetLoweringBase::AtomicExpansionKind::LLSC);
1294 OldResult = insertRMWLLSCLoop(Builder, PMV.WordType, PMV.AlignedAddr,
1295 PMV.AlignedAddrAlignment, MemOpOrder,
1296 PerformPartwordOp);
1297 }
1298
1299 Value *FinalOldResult = extractMaskedValue(Builder, OldResult, PMV);
1300 AI->replaceAllUsesWith(FinalOldResult);
1301 AI->eraseFromParent();
1302}
1303
1304// Widen the bitwise atomicrmw (or/xor/and) to the minimum supported width.
1305AtomicRMWInst *AtomicExpandImpl::widenPartwordAtomicRMW(AtomicRMWInst *AI) {
1306 ReplacementIRBuilder Builder(AI, *DL);
1308
1310 Op == AtomicRMWInst::And) &&
1311 "Unable to widen operation");
1312
1313 PartwordMaskValues PMV =
1314 createMaskInstrs(Builder, AI, AI->getType(), AI->getPointerOperand(),
1315 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1316
1317 Value *ValOp = AI->getValOperand();
1318 if (ValOp->getType()->isVectorTy())
1319 // For vectors, bitcast to the integer type before extending. Note that
1320 // or/xor/and on vectors are equivalent to the same operation on an integer
1321 // that spans the vector, so we can use the integer type for the operation.
1322 ValOp = Builder.CreateBitCast(ValOp, PMV.IntValueType);
1323 Value *ValOperand_Shifted =
1324 Builder.CreateShl(Builder.CreateZExt(ValOp, PMV.WordType), PMV.ShiftAmt,
1325 "ValOperand_Shifted");
1326
1327 Value *NewOperand;
1328
1329 if (Op == AtomicRMWInst::And)
1330 NewOperand =
1331 Builder.CreateOr(ValOperand_Shifted, PMV.Inv_Mask, "AndOperand");
1332 else
1333 NewOperand = ValOperand_Shifted;
1334
1335 AtomicRMWInst *NewAI = Builder.CreateAtomicRMW(
1336 Op, PMV.AlignedAddr, NewOperand, PMV.AlignedAddrAlignment,
1337 AI->getOrdering(), AI->getSyncScopeID());
1338
1339 NewAI->setVolatile(AI->isVolatile());
1340 copyMetadataForAtomic(*NewAI, *AI);
1341
1342 Value *FinalOldResult = extractMaskedValue(Builder, NewAI, PMV);
1343 AI->replaceAllUsesWith(FinalOldResult);
1344 AI->eraseFromParent();
1345 return NewAI;
1346}
1347
1348bool AtomicExpandImpl::expandPartwordCmpXchg(AtomicCmpXchgInst *CI) {
1349 // The basic idea here is that we're expanding a cmpxchg of a
1350 // smaller memory size up to a word-sized cmpxchg. To do this, we
1351 // need to add a retry-loop for strong cmpxchg, so that
1352 // modifications to other parts of the word don't cause a spurious
1353 // failure.
1354
1355 // This generates code like the following:
1356 // [[Setup mask values PMV.*]]
1357 // %NewVal_Shifted = shl i32 %NewVal, %PMV.ShiftAmt
1358 // %Cmp_Shifted = shl i32 %Cmp, %PMV.ShiftAmt
1359 // %InitLoaded = load i32* %addr
1360 // %InitLoaded_MaskOut = and i32 %InitLoaded, %PMV.Inv_Mask
1361 // br partword.cmpxchg.loop
1362 // partword.cmpxchg.loop:
1363 // %Loaded_MaskOut = phi i32 [ %InitLoaded_MaskOut, %entry ],
1364 // [ %OldVal_MaskOut, %partword.cmpxchg.failure ]
1365 // %FullWord_NewVal = or i32 %Loaded_MaskOut, %NewVal_Shifted
1366 // %FullWord_Cmp = or i32 %Loaded_MaskOut, %Cmp_Shifted
1367 // %NewCI = cmpxchg i32* %PMV.AlignedAddr, i32 %FullWord_Cmp,
1368 // i32 %FullWord_NewVal success_ordering failure_ordering
1369 // %OldVal = extractvalue { i32, i1 } %NewCI, 0
1370 // %Success = extractvalue { i32, i1 } %NewCI, 1
1371 // br i1 %Success, label %partword.cmpxchg.end,
1372 // label %partword.cmpxchg.failure
1373 // partword.cmpxchg.failure:
1374 // %OldVal_MaskOut = and i32 %OldVal, %PMV.Inv_Mask
1375 // %ShouldContinue = icmp ne i32 %Loaded_MaskOut, %OldVal_MaskOut
1376 // br i1 %ShouldContinue, label %partword.cmpxchg.loop,
1377 // label %partword.cmpxchg.end
1378 // partword.cmpxchg.end:
1379 // %tmp1 = lshr i32 %OldVal, %PMV.ShiftAmt
1380 // %FinalOldVal = trunc i32 %tmp1 to i8
1381 // %tmp2 = insertvalue { i8, i1 } undef, i8 %FinalOldVal, 0
1382 // %Res = insertvalue { i8, i1 } %25, i1 %Success, 1
1383
1384 Value *Addr = CI->getPointerOperand();
1385 Value *Cmp = CI->getCompareOperand();
1386 Value *NewVal = CI->getNewValOperand();
1387
1388 BasicBlock *BB = CI->getParent();
1389 Function *F = BB->getParent();
1390 ReplacementIRBuilder Builder(CI, *DL);
1391 LLVMContext &Ctx = Builder.getContext();
1392
1393 BasicBlock *EndBB =
1394 BB->splitBasicBlock(CI->getIterator(), "partword.cmpxchg.end");
1395 auto FailureBB =
1396 BasicBlock::Create(Ctx, "partword.cmpxchg.failure", F, EndBB);
1397 auto LoopBB = BasicBlock::Create(Ctx, "partword.cmpxchg.loop", F, FailureBB);
1398
1399 // The split call above "helpfully" added a branch at the end of BB
1400 // (to the wrong place).
1401 std::prev(BB->end())->eraseFromParent();
1402 Builder.SetInsertPoint(BB);
1403
1404 PartwordMaskValues PMV =
1405 createMaskInstrs(Builder, CI, CI->getCompareOperand()->getType(), Addr,
1406 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1407
1408 // Shift the incoming values over, into the right location in the word.
1409 Value *NewVal_Shifted =
1410 Builder.CreateShl(Builder.CreateZExt(NewVal, PMV.WordType), PMV.ShiftAmt);
1411 Value *Cmp_Shifted =
1412 Builder.CreateShl(Builder.CreateZExt(Cmp, PMV.WordType), PMV.ShiftAmt);
1413
1414 // Load the entire current word, and mask into place the expected and new
1415 // values
1416 LoadInst *InitLoaded = Builder.CreateLoad(PMV.WordType, PMV.AlignedAddr);
1417 Value *InitLoaded_MaskOut = Builder.CreateAnd(InitLoaded, PMV.Inv_Mask);
1418 Builder.CreateBr(LoopBB);
1419
1420 // partword.cmpxchg.loop:
1421 Builder.SetInsertPoint(LoopBB);
1422 PHINode *Loaded_MaskOut = Builder.CreatePHI(PMV.WordType, 2);
1423 Loaded_MaskOut->addIncoming(InitLoaded_MaskOut, BB);
1424
1425 // The initial load must be atomic with the same synchronization scope
1426 // to avoid a data race with concurrent stores. If the instruction being
1427 // emulated is volatile, issue a volatile load.
1428 // addIncoming is done first so that any replaceAllUsesWith calls during
1429 // normalization correctly update the PHI incoming value.
1430 InitLoaded->setVolatile(CI->isVolatile());
1432 InitLoaded->setAtomic(AtomicOrdering::Monotonic, CI->getSyncScopeID());
1433 // The newly created load might need to be lowered further. Because it is
1434 // created in the same block as the atomicrmw, the AtomicExpand loop will
1435 // not process it again.
1436 processAtomicInstr(InitLoaded);
1437 }
1438
1439 // Mask/Or the expected and new values into place in the loaded word.
1440 Value *FullWord_NewVal = Builder.CreateOr(Loaded_MaskOut, NewVal_Shifted);
1441 Value *FullWord_Cmp = Builder.CreateOr(Loaded_MaskOut, Cmp_Shifted);
1442 AtomicCmpXchgInst *NewCI = Builder.CreateAtomicCmpXchg(
1443 PMV.AlignedAddr, FullWord_Cmp, FullWord_NewVal, PMV.AlignedAddrAlignment,
1445 NewCI->setVolatile(CI->isVolatile());
1446 // When we're building a strong cmpxchg, we need a loop, so you
1447 // might think we could use a weak cmpxchg inside. But, using strong
1448 // allows the below comparison for ShouldContinue, and we're
1449 // expecting the underlying cmpxchg to be a machine instruction,
1450 // which is strong anyways.
1451 NewCI->setWeak(CI->isWeak());
1452
1453 Value *OldVal = Builder.CreateExtractValue(NewCI, 0);
1454 Value *Success = Builder.CreateExtractValue(NewCI, 1);
1455
1456 if (CI->isWeak())
1457 Builder.CreateBr(EndBB);
1458 else
1459 Builder.CreateCondBr(Success, EndBB, FailureBB);
1460
1461 // partword.cmpxchg.failure:
1462 Builder.SetInsertPoint(FailureBB);
1463 // Upon failure, verify that the masked-out part of the loaded value
1464 // has been modified. If it didn't, abort the cmpxchg, since the
1465 // masked-in part must've.
1466 Value *OldVal_MaskOut = Builder.CreateAnd(OldVal, PMV.Inv_Mask);
1467 Value *ShouldContinue = Builder.CreateICmpNE(Loaded_MaskOut, OldVal_MaskOut);
1468 Builder.CreateCondBr(ShouldContinue, LoopBB, EndBB);
1469
1470 // Add the second value to the phi from above
1471 Loaded_MaskOut->addIncoming(OldVal_MaskOut, FailureBB);
1472
1473 // partword.cmpxchg.end:
1474 Builder.SetInsertPoint(CI);
1475
1476 Value *FinalOldVal = extractMaskedValue(Builder, OldVal, PMV);
1477 Value *Res = PoisonValue::get(CI->getType());
1478 Res = Builder.CreateInsertValue(Res, FinalOldVal, 0);
1479 Res = Builder.CreateInsertValue(Res, Success, 1);
1480
1481 CI->replaceAllUsesWith(Res);
1482 CI->eraseFromParent();
1483 return true;
1484}
1485
1486void AtomicExpandImpl::expandAtomicOpToLLSC(
1487 Instruction *I, Type *ResultType, Value *Addr, Align AddrAlign,
1488 AtomicOrdering MemOpOrder,
1489 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp) {
1490 ReplacementIRBuilder Builder(I, *DL);
1491 Value *Loaded = insertRMWLLSCLoop(Builder, ResultType, Addr, AddrAlign,
1492 MemOpOrder, PerformOp);
1493
1494 I->replaceAllUsesWith(Loaded);
1495 I->eraseFromParent();
1496}
1497
1498void AtomicExpandImpl::expandAtomicRMWToMaskedIntrinsic(AtomicRMWInst *AI) {
1499 ReplacementIRBuilder Builder(AI, *DL);
1500
1501 PartwordMaskValues PMV =
1502 createMaskInstrs(Builder, AI, AI->getType(), AI->getPointerOperand(),
1503 AI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1504
1505 // The value operand must be sign-extended for signed min/max so that the
1506 // target's signed comparison instructions can be used. Otherwise, just
1507 // zero-ext.
1508 Instruction::CastOps CastOp = Instruction::ZExt;
1509 AtomicRMWInst::BinOp RMWOp = AI->getOperation();
1510 if (RMWOp == AtomicRMWInst::Max || RMWOp == AtomicRMWInst::Min)
1511 CastOp = Instruction::SExt;
1512
1513 Value *ValOperand_Shifted = Builder.CreateShl(
1514 Builder.CreateCast(CastOp, AI->getValOperand(), PMV.WordType),
1515 PMV.ShiftAmt, "ValOperand_Shifted");
1516 Value *OldResult = TLI->emitMaskedAtomicRMWIntrinsic(
1517 Builder, AI, PMV.AlignedAddr, ValOperand_Shifted, PMV.Mask, PMV.ShiftAmt,
1518 AI->getOrdering());
1519 Value *FinalOldResult = extractMaskedValue(Builder, OldResult, PMV);
1520 AI->replaceAllUsesWith(FinalOldResult);
1521 AI->eraseFromParent();
1522}
1523
1524void AtomicExpandImpl::expandAtomicCmpXchgToMaskedIntrinsic(
1525 AtomicCmpXchgInst *CI) {
1526 ReplacementIRBuilder Builder(CI, *DL);
1527
1528 PartwordMaskValues PMV = createMaskInstrs(
1529 Builder, CI, CI->getCompareOperand()->getType(), CI->getPointerOperand(),
1530 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1531
1532 Value *CmpVal_Shifted = Builder.CreateShl(
1533 Builder.CreateZExt(CI->getCompareOperand(), PMV.WordType), PMV.ShiftAmt,
1534 "CmpVal_Shifted");
1535 Value *NewVal_Shifted = Builder.CreateShl(
1536 Builder.CreateZExt(CI->getNewValOperand(), PMV.WordType), PMV.ShiftAmt,
1537 "NewVal_Shifted");
1539 Builder, CI, PMV.AlignedAddr, CmpVal_Shifted, NewVal_Shifted, PMV.Mask,
1540 CI->getMergedOrdering());
1541 Value *FinalOldVal = extractMaskedValue(Builder, OldVal, PMV);
1542 Value *Res = PoisonValue::get(CI->getType());
1543 Res = Builder.CreateInsertValue(Res, FinalOldVal, 0);
1544 Value *Success = Builder.CreateICmpEQ(
1545 CmpVal_Shifted, Builder.CreateAnd(OldVal, PMV.Mask), "Success");
1546 Res = Builder.CreateInsertValue(Res, Success, 1);
1547
1548 CI->replaceAllUsesWith(Res);
1549 CI->eraseFromParent();
1550}
1551
1552Value *AtomicExpandImpl::insertRMWLLSCLoop(
1553 IRBuilderBase &Builder, Type *ResultTy, Value *Addr, Align AddrAlign,
1554 AtomicOrdering MemOpOrder,
1555 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp) {
1556 LLVMContext &Ctx = Builder.getContext();
1557 BasicBlock *BB = Builder.GetInsertBlock();
1558 Function *F = BB->getParent();
1559
1560 assert(AddrAlign >= F->getDataLayout().getTypeStoreSize(ResultTy) &&
1561 "Expected at least natural alignment at this point.");
1562
1563 // Given: atomicrmw some_op iN* %addr, iN %incr ordering
1564 //
1565 // The standard expansion we produce is:
1566 // [...]
1567 // atomicrmw.start:
1568 // %loaded = @load.linked(%addr)
1569 // %new = some_op iN %loaded, %incr
1570 // %stored = @store_conditional(%new, %addr)
1571 // %try_again = icmp i32 ne %stored, 0
1572 // br i1 %try_again, label %loop, label %atomicrmw.end
1573 // atomicrmw.end:
1574 // [...]
1575 BasicBlock *ExitBB =
1576 BB->splitBasicBlock(Builder.GetInsertPoint(), "atomicrmw.end");
1577 BasicBlock *LoopBB = BasicBlock::Create(Ctx, "atomicrmw.start", F, ExitBB);
1578
1579 // The split call above "helpfully" added a branch at the end of BB (to the
1580 // wrong place).
1581 std::prev(BB->end())->eraseFromParent();
1582 Builder.SetInsertPoint(BB);
1583 Builder.CreateBr(LoopBB);
1584
1585 // Start the main loop block now that we've taken care of the preliminaries.
1586 Builder.SetInsertPoint(LoopBB);
1587 Value *Loaded = TLI->emitLoadLinked(Builder, ResultTy, Addr, MemOpOrder);
1588
1589 Value *NewVal = PerformOp(Builder, Loaded);
1590
1591 Value *StoreSuccess =
1592 TLI->emitStoreConditional(Builder, NewVal, Addr, MemOpOrder);
1593 Value *TryAgain = Builder.CreateICmpNE(
1594 StoreSuccess, ConstantInt::get(IntegerType::get(Ctx, 32), 0), "tryagain");
1595
1596 Instruction *CondBr = Builder.CreateCondBr(TryAgain, LoopBB, ExitBB);
1597
1598 // Atomic RMW expands to a Load-linked / Store-Conditional loop, because it is
1599 // hard to predict precise branch weigths we mark the branch as "unknown"
1600 // (50/50) to prevent misleading optimizations.
1602
1603 Builder.SetInsertPoint(ExitBB->begin());
1604 return Loaded;
1605}
1606
1607/// Convert an atomic cmpxchg of a non-integral type to an integer cmpxchg of
1608/// the equivalent bitwidth. We used to not support pointer cmpxchg in the
1609/// IR. As a migration step, we convert back to what use to be the standard
1610/// way to represent a pointer cmpxchg so that we can update backends one by
1611/// one.
1612AtomicCmpXchgInst *
1613AtomicExpandImpl::convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI) {
1614 auto *M = CI->getModule();
1615 Type *NewTy = getCorrespondingIntegerType(CI->getCompareOperand()->getType(),
1616 M->getDataLayout());
1617
1618 ReplacementIRBuilder Builder(CI, *DL);
1619
1620 Value *Addr = CI->getPointerOperand();
1621
1622 Value *NewCmp = Builder.CreatePtrToInt(CI->getCompareOperand(), NewTy);
1623 Value *NewNewVal = Builder.CreatePtrToInt(CI->getNewValOperand(), NewTy);
1624
1625 auto *NewCI = Builder.CreateAtomicCmpXchg(
1626 Addr, NewCmp, NewNewVal, CI->getAlign(), CI->getSuccessOrdering(),
1627 CI->getFailureOrdering(), CI->getSyncScopeID());
1628 NewCI->setVolatile(CI->isVolatile());
1629 NewCI->setWeak(CI->isWeak());
1630 LLVM_DEBUG(dbgs() << "Replaced " << *CI << " with " << *NewCI << "\n");
1631
1632 Value *OldVal = Builder.CreateExtractValue(NewCI, 0);
1633 Value *Succ = Builder.CreateExtractValue(NewCI, 1);
1634
1635 OldVal = Builder.CreateIntToPtr(OldVal, CI->getCompareOperand()->getType());
1636
1637 Value *Res = PoisonValue::get(CI->getType());
1638 Res = Builder.CreateInsertValue(Res, OldVal, 0);
1639 Res = Builder.CreateInsertValue(Res, Succ, 1);
1640
1641 CI->replaceAllUsesWith(Res);
1642 CI->eraseFromParent();
1643 return NewCI;
1644}
1645
1646bool AtomicExpandImpl::expandAtomicCmpXchg(AtomicCmpXchgInst *CI) {
1647 AtomicOrdering SuccessOrder = CI->getSuccessOrdering();
1648 AtomicOrdering FailureOrder = CI->getFailureOrdering();
1649 Value *Addr = CI->getPointerOperand();
1650 BasicBlock *BB = CI->getParent();
1651 Function *F = BB->getParent();
1652 LLVMContext &Ctx = F->getContext();
1653 // If shouldInsertFencesForAtomic() returns true, then the target does not
1654 // want to deal with memory orders, and emitLeading/TrailingFence should take
1655 // care of everything. Otherwise, emitLeading/TrailingFence are no-op and we
1656 // should preserve the ordering.
1657 bool ShouldInsertFencesForAtomic = TLI->shouldInsertFencesForAtomic(CI);
1658 AtomicOrdering MemOpOrder = ShouldInsertFencesForAtomic
1659 ? AtomicOrdering::Monotonic
1660 : CI->getMergedOrdering();
1661
1662 // In implementations which use a barrier to achieve release semantics, we can
1663 // delay emitting this barrier until we know a store is actually going to be
1664 // attempted. The cost of this delay is that we need 2 copies of the block
1665 // emitting the load-linked, affecting code size.
1666 //
1667 // Ideally, this logic would be unconditional except for the minsize check
1668 // since in other cases the extra blocks naturally collapse down to the
1669 // minimal loop. Unfortunately, this puts too much stress on later
1670 // optimisations so we avoid emitting the extra logic in those cases too.
1671 bool HasReleasedLoadBB = !CI->isWeak() && ShouldInsertFencesForAtomic &&
1672 SuccessOrder != AtomicOrdering::Monotonic &&
1673 SuccessOrder != AtomicOrdering::Acquire &&
1674 !F->hasMinSize();
1675
1676 // There's no overhead for sinking the release barrier in a weak cmpxchg, so
1677 // do it even on minsize.
1678 // A fence between the LL and SC may clear the reservation on some targets.
1679 // Strong cmpxchg retries, but weak cmpxchg cannot recover.
1680 bool UseUnconditionalReleaseBarrier =
1681 (F->hasMinSize() && !CI->isWeak()) ||
1682 (CI->isWeak() && TLI->fenceClearsLoadLinkedReservation());
1683
1684 // Given: cmpxchg some_op iN* %addr, iN %desired, iN %new success_ord fail_ord
1685 //
1686 // The full expansion we produce is:
1687 // [...]
1688 // %aligned.addr = ...
1689 // cmpxchg.start:
1690 // %unreleasedload = @load.linked(%aligned.addr)
1691 // %unreleasedload.extract = extract value from %unreleasedload
1692 // %should_store = icmp eq %unreleasedload.extract, %desired
1693 // br i1 %should_store, label %cmpxchg.releasingstore,
1694 // label %cmpxchg.nostore
1695 // cmpxchg.releasingstore:
1696 // fence?
1697 // br label cmpxchg.trystore
1698 // cmpxchg.trystore:
1699 // %loaded.trystore = phi [%unreleasedload, %cmpxchg.releasingstore],
1700 // [%releasedload, %cmpxchg.releasedload]
1701 // %updated.new = insert %new into %loaded.trystore
1702 // %stored = @store_conditional(%updated.new, %aligned.addr)
1703 // %success = icmp eq i32 %stored, 0
1704 // br i1 %success, label %cmpxchg.success,
1705 // label %cmpxchg.releasedload/%cmpxchg.failure
1706 // cmpxchg.releasedload:
1707 // %releasedload = @load.linked(%aligned.addr)
1708 // %releasedload.extract = extract value from %releasedload
1709 // %should_store = icmp eq %releasedload.extract, %desired
1710 // br i1 %should_store, label %cmpxchg.trystore,
1711 // label %cmpxchg.failure
1712 // cmpxchg.success:
1713 // fence?
1714 // br label %cmpxchg.end
1715 // cmpxchg.nostore:
1716 // %loaded.nostore = phi [%unreleasedload, %cmpxchg.start],
1717 // [%releasedload,
1718 // %cmpxchg.releasedload/%cmpxchg.trystore]
1719 // @load_linked_fail_balance()?
1720 // br label %cmpxchg.failure
1721 // cmpxchg.failure:
1722 // fence?
1723 // br label %cmpxchg.end
1724 // cmpxchg.end:
1725 // %loaded.exit = phi [%loaded.nostore, %cmpxchg.failure],
1726 // [%loaded.trystore, %cmpxchg.trystore]
1727 // %success = phi i1 [true, %cmpxchg.success], [false, %cmpxchg.failure]
1728 // %loaded = extract value from %loaded.exit
1729 // %restmp = insertvalue { iN, i1 } undef, iN %loaded, 0
1730 // %res = insertvalue { iN, i1 } %restmp, i1 %success, 1
1731 // [...]
1732 BasicBlock *ExitBB = BB->splitBasicBlock(CI->getIterator(), "cmpxchg.end");
1733 auto FailureBB = BasicBlock::Create(Ctx, "cmpxchg.failure", F, ExitBB);
1734 auto NoStoreBB = BasicBlock::Create(Ctx, "cmpxchg.nostore", F, FailureBB);
1735 auto SuccessBB = BasicBlock::Create(Ctx, "cmpxchg.success", F, NoStoreBB);
1736 auto ReleasedLoadBB =
1737 BasicBlock::Create(Ctx, "cmpxchg.releasedload", F, SuccessBB);
1738 auto TryStoreBB =
1739 BasicBlock::Create(Ctx, "cmpxchg.trystore", F, ReleasedLoadBB);
1740 auto ReleasingStoreBB =
1741 BasicBlock::Create(Ctx, "cmpxchg.fencedstore", F, TryStoreBB);
1742 auto StartBB = BasicBlock::Create(Ctx, "cmpxchg.start", F, ReleasingStoreBB);
1743
1744 ReplacementIRBuilder Builder(CI, *DL);
1745
1746 // The split call above "helpfully" added a branch at the end of BB (to the
1747 // wrong place), but we might want a fence too. It's easiest to just remove
1748 // the branch entirely.
1749 std::prev(BB->end())->eraseFromParent();
1750 Builder.SetInsertPoint(BB);
1751 if (ShouldInsertFencesForAtomic && UseUnconditionalReleaseBarrier)
1752 TLI->emitLeadingFence(Builder, CI, SuccessOrder);
1753
1754 PartwordMaskValues PMV =
1755 createMaskInstrs(Builder, CI, CI->getCompareOperand()->getType(), Addr,
1756 CI->getAlign(), TLI->getMinCmpXchgSizeInBits() / 8);
1757 Builder.CreateBr(StartBB);
1758
1759 // Start the main loop block now that we've taken care of the preliminaries.
1760 Builder.SetInsertPoint(StartBB);
1761 Value *UnreleasedLoad =
1762 TLI->emitLoadLinked(Builder, PMV.WordType, PMV.AlignedAddr, MemOpOrder);
1763 Value *UnreleasedLoadExtract =
1764 extractMaskedValue(Builder, UnreleasedLoad, PMV);
1765 Value *ShouldStore = Builder.CreateICmpEQ(
1766 UnreleasedLoadExtract, CI->getCompareOperand(), "should_store");
1767
1768 // If the cmpxchg doesn't actually need any ordering when it fails, we can
1769 // jump straight past that fence instruction (if it exists).
1770 Builder.CreateCondBr(ShouldStore, ReleasingStoreBB, NoStoreBB,
1771 MDBuilder(F->getContext()).createLikelyBranchWeights());
1772
1773 Builder.SetInsertPoint(ReleasingStoreBB);
1774 if (ShouldInsertFencesForAtomic && !UseUnconditionalReleaseBarrier)
1775 TLI->emitLeadingFence(Builder, CI, SuccessOrder);
1776 Builder.CreateBr(TryStoreBB);
1777
1778 Builder.SetInsertPoint(TryStoreBB);
1779 PHINode *LoadedTryStore =
1780 Builder.CreatePHI(PMV.WordType, 2, "loaded.trystore");
1781 LoadedTryStore->addIncoming(UnreleasedLoad, ReleasingStoreBB);
1782 Value *NewValueInsert =
1783 insertMaskedValue(Builder, LoadedTryStore, CI->getNewValOperand(), PMV);
1784 Value *StoreSuccess = TLI->emitStoreConditional(Builder, NewValueInsert,
1785 PMV.AlignedAddr, MemOpOrder);
1786 StoreSuccess = Builder.CreateICmpEQ(
1787 StoreSuccess, ConstantInt::get(Type::getInt32Ty(Ctx), 0), "success");
1788 BasicBlock *RetryBB = HasReleasedLoadBB ? ReleasedLoadBB : StartBB;
1789 Builder.CreateCondBr(StoreSuccess, SuccessBB,
1790 CI->isWeak() ? FailureBB : RetryBB,
1791 MDBuilder(F->getContext()).createLikelyBranchWeights());
1792
1793 Builder.SetInsertPoint(ReleasedLoadBB);
1794 Value *SecondLoad;
1795 if (HasReleasedLoadBB) {
1796 SecondLoad =
1797 TLI->emitLoadLinked(Builder, PMV.WordType, PMV.AlignedAddr, MemOpOrder);
1798 Value *SecondLoadExtract = extractMaskedValue(Builder, SecondLoad, PMV);
1799 ShouldStore = Builder.CreateICmpEQ(SecondLoadExtract,
1800 CI->getCompareOperand(), "should_store");
1801
1802 // If the cmpxchg doesn't actually need any ordering when it fails, we can
1803 // jump straight past that fence instruction (if it exists).
1804 Builder.CreateCondBr(
1805 ShouldStore, TryStoreBB, NoStoreBB,
1806 MDBuilder(F->getContext()).createLikelyBranchWeights());
1807 // Update PHI node in TryStoreBB.
1808 LoadedTryStore->addIncoming(SecondLoad, ReleasedLoadBB);
1809 } else
1810 Builder.CreateUnreachable();
1811
1812 // Make sure later instructions don't get reordered with a fence if
1813 // necessary.
1814 Builder.SetInsertPoint(SuccessBB);
1815 if (ShouldInsertFencesForAtomic ||
1817 TLI->emitTrailingFence(Builder, CI, SuccessOrder);
1818 Builder.CreateBr(ExitBB);
1819
1820 Builder.SetInsertPoint(NoStoreBB);
1821 PHINode *LoadedNoStore =
1822 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.nostore");
1823 LoadedNoStore->addIncoming(UnreleasedLoad, StartBB);
1824 if (HasReleasedLoadBB)
1825 LoadedNoStore->addIncoming(SecondLoad, ReleasedLoadBB);
1826
1827 // In the failing case, where we don't execute the store-conditional, the
1828 // target might want to balance out the load-linked with a dedicated
1829 // instruction (e.g., on ARM, clearing the exclusive monitor).
1831 Builder.CreateBr(FailureBB);
1832
1833 Builder.SetInsertPoint(FailureBB);
1834 PHINode *LoadedFailure =
1835 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.failure");
1836 LoadedFailure->addIncoming(LoadedNoStore, NoStoreBB);
1837 if (CI->isWeak())
1838 LoadedFailure->addIncoming(LoadedTryStore, TryStoreBB);
1839 if (ShouldInsertFencesForAtomic)
1840 TLI->emitTrailingFence(Builder, CI, FailureOrder);
1841 Builder.CreateBr(ExitBB);
1842
1843 // Finally, we have control-flow based knowledge of whether the cmpxchg
1844 // succeeded or not. We expose this to later passes by converting any
1845 // subsequent "icmp eq/ne %loaded, %oldval" into a use of an appropriate
1846 // PHI.
1847 Builder.SetInsertPoint(ExitBB->begin());
1848 PHINode *LoadedExit =
1849 Builder.CreatePHI(UnreleasedLoad->getType(), 2, "loaded.exit");
1850 LoadedExit->addIncoming(LoadedTryStore, SuccessBB);
1851 LoadedExit->addIncoming(LoadedFailure, FailureBB);
1852 PHINode *Success = Builder.CreatePHI(Type::getInt1Ty(Ctx), 2, "success");
1853 Success->addIncoming(ConstantInt::getTrue(Ctx), SuccessBB);
1854 Success->addIncoming(ConstantInt::getFalse(Ctx), FailureBB);
1855
1856 // This is the "exit value" from the cmpxchg expansion. It may be of
1857 // a type wider than the one in the cmpxchg instruction.
1858 Value *LoadedFull = LoadedExit;
1859
1860 Builder.SetInsertPoint(std::next(Success->getIterator()));
1861 Value *Loaded = extractMaskedValue(Builder, LoadedFull, PMV);
1862
1863 // Look for any users of the cmpxchg that are just comparing the loaded value
1864 // against the desired one, and replace them with the CFG-derived version.
1866 for (auto *User : CI->users()) {
1867 ExtractValueInst *EV = dyn_cast<ExtractValueInst>(User);
1868 if (!EV)
1869 continue;
1870
1871 assert(EV->getNumIndices() == 1 && EV->getIndices()[0] <= 1 &&
1872 "weird extraction from { iN, i1 }");
1873
1874 if (EV->getIndices()[0] == 0)
1875 EV->replaceAllUsesWith(Loaded);
1876 else
1878
1879 PrunedInsts.push_back(EV);
1880 }
1881
1882 // We can remove the instructions now we're no longer iterating through them.
1883 for (auto *EV : PrunedInsts)
1884 EV->eraseFromParent();
1885
1886 if (!CI->use_empty()) {
1887 // Some use of the full struct return that we don't understand has happened,
1888 // so we've got to reconstruct it properly.
1889 Value *Res;
1890 Res = Builder.CreateInsertValue(PoisonValue::get(CI->getType()), Loaded, 0);
1891 Res = Builder.CreateInsertValue(Res, Success, 1);
1892
1893 CI->replaceAllUsesWith(Res);
1894 }
1895
1896 CI->eraseFromParent();
1897 return true;
1898}
1899
1900bool AtomicExpandImpl::isIdempotentRMW(AtomicRMWInst *RMWI) {
1901 if (RMWI->isVolatile())
1902 return false;
1903 // TODO: Add floating point support.
1904 auto C = dyn_cast<ConstantInt>(RMWI->getValOperand());
1905 if (!C)
1906 return false;
1907
1908 switch (RMWI->getOperation()) {
1909 case AtomicRMWInst::Add:
1910 case AtomicRMWInst::Sub:
1911 case AtomicRMWInst::Or:
1912 case AtomicRMWInst::Xor:
1913 return C->isZero();
1914 case AtomicRMWInst::And:
1915 return C->isMinusOne();
1916 case AtomicRMWInst::Min:
1917 return C->isMaxValue(true);
1918 case AtomicRMWInst::Max:
1919 return C->isMinValue(true);
1921 return C->isMaxValue(false);
1923 return C->isMinValue(false);
1924 default:
1925 return false;
1926 }
1927}
1928
1929bool AtomicExpandImpl::simplifyIdempotentRMW(AtomicRMWInst *RMWI) {
1930 if (auto ResultingLoad = TLI->lowerIdempotentRMWIntoFencedLoad(RMWI)) {
1931 tryExpandAtomicLoad(ResultingLoad);
1932 return true;
1933 }
1934 return false;
1935}
1936
1937Value *AtomicExpandImpl::insertRMWCmpXchgLoop(
1938 IRBuilderBase &Builder, Type *ResultTy, Value *Addr, Align AddrAlign,
1939 AtomicOrdering MemOpOrder, SyncScope::ID SSID, bool IsVolatile,
1940 function_ref<Value *(IRBuilderBase &, Value *)> PerformOp,
1941 CreateCmpXchgInstFun CreateCmpXchg, Instruction *MetadataSrc) {
1942 LLVMContext &Ctx = Builder.getContext();
1943 BasicBlock *BB = Builder.GetInsertBlock();
1944 Function *F = BB->getParent();
1945
1946 // Given: atomicrmw some_op iN* %addr, iN %incr ordering
1947 //
1948 // The standard expansion we produce is:
1949 // [...]
1950 // %init_loaded = load atomic iN* %addr
1951 // br label %loop
1952 // loop:
1953 // %loaded = phi iN [ %init_loaded, %entry ], [ %new_loaded, %loop ]
1954 // %new = some_op iN %loaded, %incr
1955 // %pair = cmpxchg iN* %addr, iN %loaded, iN %new
1956 // %new_loaded = extractvalue { iN, i1 } %pair, 0
1957 // %success = extractvalue { iN, i1 } %pair, 1
1958 // br i1 %success, label %atomicrmw.end, label %loop
1959 // atomicrmw.end:
1960 // [...]
1961 BasicBlock *ExitBB =
1962 BB->splitBasicBlock(Builder.GetInsertPoint(), "atomicrmw.end");
1963 BasicBlock *LoopBB = BasicBlock::Create(Ctx, "atomicrmw.start", F, ExitBB);
1964
1965 // The split call above "helpfully" added a branch at the end of BB (to the
1966 // wrong place), but we want a load. It's easiest to just remove
1967 // the branch entirely.
1968 std::prev(BB->end())->eraseFromParent();
1969 Builder.SetInsertPoint(BB);
1970 LoadInst *InitLoaded = Builder.CreateAlignedLoad(ResultTy, Addr, AddrAlign);
1971 Builder.CreateBr(LoopBB);
1972
1973 // Start the main loop block now that we've taken care of the preliminaries.
1974 Builder.SetInsertPoint(LoopBB);
1975 PHINode *Loaded = Builder.CreatePHI(ResultTy, 2, "loaded");
1976 Loaded->addIncoming(InitLoaded, BB);
1977
1978 // The initial load must be atomic with the same synchronization scope
1979 // to avoid a data race with concurrent stores. If the instruction being
1980 // emulated is volatile, issue a volatile load.
1981 // addIncoming is done first so that any replaceAllUsesWith calls during
1982 // normalization correctly update the PHI incoming value.
1983 InitLoaded->setVolatile(IsVolatile);
1985 InitLoaded->setAtomic(AtomicOrdering::Monotonic, SSID);
1986 // The newly created load might need to be lowered further. Because it is
1987 // created in the same block as the atomicrmw, the AtomicExpand loop will
1988 // not process it again.
1989 processAtomicInstr(InitLoaded);
1990 }
1991
1992 Value *NewVal = PerformOp(Builder, Loaded);
1993
1994 Value *NewLoaded = nullptr;
1995 Value *Success = nullptr;
1996
1997 CreateCmpXchg(Builder, Addr, Loaded, NewVal, AddrAlign,
1998 MemOpOrder == AtomicOrdering::Unordered
1999 ? AtomicOrdering::Monotonic
2000 : MemOpOrder,
2001 SSID, IsVolatile, Success, NewLoaded, MetadataSrc);
2002 assert(Success && NewLoaded);
2003
2004 Loaded->addIncoming(NewLoaded, LoopBB);
2005
2006 Instruction *CondBr = Builder.CreateCondBr(Success, ExitBB, LoopBB);
2007
2008 // Atomic RMW expands to a cmpxchg loop, Since precise branch weights
2009 // cannot be easily determined here, we mark the branch as "unknown" (50/50)
2010 // to prevent misleading optimizations.
2012
2013 Builder.SetInsertPoint(ExitBB->begin());
2014 return NewLoaded;
2015}
2016
2017bool AtomicExpandImpl::tryExpandAtomicCmpXchg(AtomicCmpXchgInst *CI) {
2018 unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8;
2019 unsigned ValueSize = getAtomicOpSize(CI);
2020
2021 switch (TLI->shouldExpandAtomicCmpXchgInIR(CI)) {
2022 default:
2023 llvm_unreachable("Unhandled case in tryExpandAtomicCmpXchg");
2024 case TargetLoweringBase::AtomicExpansionKind::None:
2025 if (ValueSize < MinCASSize)
2026 return expandPartwordCmpXchg(CI);
2027 return false;
2028 case TargetLoweringBase::AtomicExpansionKind::LLSC: {
2029 return expandAtomicCmpXchg(CI);
2030 }
2031 case TargetLoweringBase::AtomicExpansionKind::MaskedIntrinsic:
2032 expandAtomicCmpXchgToMaskedIntrinsic(CI);
2033 return true;
2034 case TargetLoweringBase::AtomicExpansionKind::NotAtomic:
2035 return lowerAtomicCmpXchgInst(CI);
2036 case TargetLoweringBase::AtomicExpansionKind::CustomExpand: {
2037 TLI->emitExpandAtomicCmpXchg(CI);
2038 return true;
2039 }
2040 }
2041}
2042
2043bool AtomicExpandImpl::expandAtomicRMWToCmpXchg(
2044 AtomicRMWInst *AI, CreateCmpXchgInstFun CreateCmpXchg) {
2045 ReplacementIRBuilder Builder(AI, AI->getDataLayout());
2046 Builder.setIsFPConstrained(
2047 AI->getFunction()->hasFnAttribute(Attribute::StrictFP));
2048
2049 // FIXME: If FP exceptions are observable, we should force them off for the
2050 // loop for the FP atomics.
2051 Value *Loaded = AtomicExpandImpl::insertRMWCmpXchgLoop(
2052 Builder, AI->getType(), AI->getPointerOperand(), AI->getAlign(),
2053 AI->getOrdering(), AI->getSyncScopeID(), AI->isVolatile(),
2054 [&](IRBuilderBase &Builder, Value *Loaded) {
2055 return buildAtomicRMWValue(AI->getOperation(), Builder, Loaded,
2056 AI->getValOperand());
2057 },
2058 CreateCmpXchg, /*MetadataSrc=*/AI);
2059
2060 AI->replaceAllUsesWith(Loaded);
2061 AI->eraseFromParent();
2062 return true;
2063}
2064
2065// In order to use one of the sized library calls such as
2066// __atomic_fetch_add_4, the alignment must be sufficient, the size
2067// must be one of the potentially-specialized sizes, and the value
2068// type must actually exist in C on the target (otherwise, the
2069// function wouldn't actually be defined.)
2070static bool canUseSizedAtomicCall(unsigned Size, Align Alignment,
2071 const DataLayout &DL) {
2072 // TODO: "LargestSize" is an approximation for "largest type that
2073 // you can express in C". It seems to be the case that int128 is
2074 // supported on all 64-bit platforms, otherwise only up to 64-bit
2075 // integers are supported. If we get this wrong, then we'll try to
2076 // call a sized libcall that doesn't actually exist. There should
2077 // really be some more reliable way in LLVM of determining integer
2078 // sizes which are valid in the target's C ABI...
2079 unsigned LargestSize = DL.getLargestLegalIntTypeSizeInBits() >= 64 ? 16 : 8;
2080 return Alignment >= Size &&
2081 (Size == 1 || Size == 2 || Size == 4 || Size == 8 || Size == 16) &&
2082 Size <= LargestSize;
2083}
2084
2085void AtomicExpandImpl::expandAtomicLoadToLibcall(LoadInst *I) {
2086 static const RTLIB::Libcall Libcalls[6] = {
2087 RTLIB::ATOMIC_LOAD, RTLIB::ATOMIC_LOAD_1, RTLIB::ATOMIC_LOAD_2,
2088 RTLIB::ATOMIC_LOAD_4, RTLIB::ATOMIC_LOAD_8, RTLIB::ATOMIC_LOAD_16};
2089 unsigned Size = getAtomicOpSize(I);
2090
2091 bool Expanded = expandAtomicOpToLibcall(
2092 I, Size, I->getAlign(), I->getPointerOperand(), nullptr, nullptr,
2093 I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
2094 if (!Expanded)
2095 handleUnsupportedAtomicSize(I, "atomic load");
2096}
2097
2098void AtomicExpandImpl::expandAtomicStoreToLibcall(StoreInst *I) {
2099 static const RTLIB::Libcall Libcalls[6] = {
2100 RTLIB::ATOMIC_STORE, RTLIB::ATOMIC_STORE_1, RTLIB::ATOMIC_STORE_2,
2101 RTLIB::ATOMIC_STORE_4, RTLIB::ATOMIC_STORE_8, RTLIB::ATOMIC_STORE_16};
2102 unsigned Size = getAtomicOpSize(I);
2103
2104 bool Expanded = expandAtomicOpToLibcall(
2105 I, Size, I->getAlign(), I->getPointerOperand(), I->getValueOperand(),
2106 nullptr, I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
2107 if (!Expanded)
2108 handleUnsupportedAtomicSize(I, "atomic store");
2109}
2110
2111void AtomicExpandImpl::expandAtomicCASToLibcall(AtomicCmpXchgInst *I,
2112 const Twine &AtomicOpName,
2113 Instruction *DiagnosticInst) {
2114 static const RTLIB::Libcall Libcalls[6] = {
2115 RTLIB::ATOMIC_COMPARE_EXCHANGE, RTLIB::ATOMIC_COMPARE_EXCHANGE_1,
2116 RTLIB::ATOMIC_COMPARE_EXCHANGE_2, RTLIB::ATOMIC_COMPARE_EXCHANGE_4,
2117 RTLIB::ATOMIC_COMPARE_EXCHANGE_8, RTLIB::ATOMIC_COMPARE_EXCHANGE_16};
2118 unsigned Size = getAtomicOpSize(I);
2119
2120 bool Expanded = expandAtomicOpToLibcall(
2121 I, Size, I->getAlign(), I->getPointerOperand(), I->getNewValOperand(),
2122 I->getCompareOperand(), I->getSuccessOrdering(), I->getFailureOrdering(),
2123 Libcalls);
2124 if (!Expanded)
2125 handleUnsupportedAtomicSize(I, AtomicOpName, DiagnosticInst);
2126}
2127
2129 static const RTLIB::Libcall LibcallsXchg[6] = {
2130 RTLIB::ATOMIC_EXCHANGE, RTLIB::ATOMIC_EXCHANGE_1,
2131 RTLIB::ATOMIC_EXCHANGE_2, RTLIB::ATOMIC_EXCHANGE_4,
2132 RTLIB::ATOMIC_EXCHANGE_8, RTLIB::ATOMIC_EXCHANGE_16};
2133 static const RTLIB::Libcall LibcallsAdd[6] = {
2134 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_ADD_1,
2135 RTLIB::ATOMIC_FETCH_ADD_2, RTLIB::ATOMIC_FETCH_ADD_4,
2136 RTLIB::ATOMIC_FETCH_ADD_8, RTLIB::ATOMIC_FETCH_ADD_16};
2137 static const RTLIB::Libcall LibcallsSub[6] = {
2138 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_SUB_1,
2139 RTLIB::ATOMIC_FETCH_SUB_2, RTLIB::ATOMIC_FETCH_SUB_4,
2140 RTLIB::ATOMIC_FETCH_SUB_8, RTLIB::ATOMIC_FETCH_SUB_16};
2141 static const RTLIB::Libcall LibcallsAnd[6] = {
2142 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_AND_1,
2143 RTLIB::ATOMIC_FETCH_AND_2, RTLIB::ATOMIC_FETCH_AND_4,
2144 RTLIB::ATOMIC_FETCH_AND_8, RTLIB::ATOMIC_FETCH_AND_16};
2145 static const RTLIB::Libcall LibcallsOr[6] = {
2146 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_OR_1,
2147 RTLIB::ATOMIC_FETCH_OR_2, RTLIB::ATOMIC_FETCH_OR_4,
2148 RTLIB::ATOMIC_FETCH_OR_8, RTLIB::ATOMIC_FETCH_OR_16};
2149 static const RTLIB::Libcall LibcallsXor[6] = {
2150 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_XOR_1,
2151 RTLIB::ATOMIC_FETCH_XOR_2, RTLIB::ATOMIC_FETCH_XOR_4,
2152 RTLIB::ATOMIC_FETCH_XOR_8, RTLIB::ATOMIC_FETCH_XOR_16};
2153 static const RTLIB::Libcall LibcallsNand[6] = {
2154 RTLIB::UNKNOWN_LIBCALL, RTLIB::ATOMIC_FETCH_NAND_1,
2155 RTLIB::ATOMIC_FETCH_NAND_2, RTLIB::ATOMIC_FETCH_NAND_4,
2156 RTLIB::ATOMIC_FETCH_NAND_8, RTLIB::ATOMIC_FETCH_NAND_16};
2157
2158 switch (Op) {
2160 llvm_unreachable("Should not have BAD_BINOP.");
2162 return ArrayRef(LibcallsXchg);
2163 case AtomicRMWInst::Add:
2164 return ArrayRef(LibcallsAdd);
2165 case AtomicRMWInst::Sub:
2166 return ArrayRef(LibcallsSub);
2167 case AtomicRMWInst::And:
2168 return ArrayRef(LibcallsAnd);
2169 case AtomicRMWInst::Or:
2170 return ArrayRef(LibcallsOr);
2171 case AtomicRMWInst::Xor:
2172 return ArrayRef(LibcallsXor);
2174 return ArrayRef(LibcallsNand);
2175 case AtomicRMWInst::Max:
2176 case AtomicRMWInst::Min:
2191 // No atomic libcalls are available for these.
2192 return {};
2193 }
2194 llvm_unreachable("Unexpected AtomicRMW operation.");
2195}
2196
2197void AtomicExpandImpl::expandAtomicRMWToLibcall(AtomicRMWInst *I) {
2198 ArrayRef<RTLIB::Libcall> Libcalls = GetRMWLibcall(I->getOperation());
2199
2200 unsigned Size = getAtomicOpSize(I);
2201
2202 bool Success = false;
2203 if (!Libcalls.empty())
2204 Success = expandAtomicOpToLibcall(
2205 I, Size, I->getAlign(), I->getPointerOperand(), I->getValOperand(),
2206 nullptr, I->getOrdering(), AtomicOrdering::NotAtomic, Libcalls);
2207
2208 // The expansion failed: either there were no libcalls at all for
2209 // the operation (min/max), or there were only size-specialized
2210 // libcalls (add/sub/etc) and we needed a generic. So, expand to a
2211 // CAS libcall, via a CAS loop, instead.
2212 if (!Success) {
2213 expandAtomicRMWToCmpXchg(
2214 I, [this, I](IRBuilderBase &Builder, Value *Addr, Value *Loaded,
2215 Value *NewVal, Align Alignment, AtomicOrdering MemOpOrder,
2216 SyncScope::ID SSID, bool IsVolatile, Value *&Success,
2217 Value *&NewLoaded, Instruction *MetadataSrc) {
2218 // Create the CAS instruction normally...
2219 AtomicCmpXchgInst *Pair = Builder.CreateAtomicCmpXchg(
2220 Addr, Loaded, NewVal, Alignment, MemOpOrder,
2222 Pair->setVolatile(IsVolatile);
2223 if (MetadataSrc)
2224 copyMetadataForAtomic(*Pair, *MetadataSrc);
2225
2226 Success = Builder.CreateExtractValue(Pair, 1, "success");
2227 NewLoaded = Builder.CreateExtractValue(Pair, 0, "newloaded");
2228
2229 // ...and then expand the CAS into a libcall.
2230 expandAtomicCASToLibcall(
2231 Pair,
2232 "atomicrmw " + AtomicRMWInst::getOperationName(I->getOperation()),
2233 MetadataSrc);
2234 });
2235 }
2236}
2237
2238// A helper routine for the above expandAtomic*ToLibcall functions.
2239//
2240// 'Libcalls' contains an array of enum values for the particular
2241// ATOMIC libcalls to be emitted. All of the other arguments besides
2242// 'I' are extracted from the Instruction subclass by the
2243// caller. Depending on the particular call, some will be null.
2244bool AtomicExpandImpl::expandAtomicOpToLibcall(
2245 Instruction *I, unsigned Size, Align Alignment, Value *PointerOperand,
2246 Value *ValueOperand, Value *CASExpected, AtomicOrdering Ordering,
2247 AtomicOrdering Ordering2, ArrayRef<RTLIB::Libcall> Libcalls) {
2248 assert(Libcalls.size() == 6);
2249
2250 LLVMContext &Ctx = I->getContext();
2251 Module *M = I->getModule();
2252 const DataLayout &DL = M->getDataLayout();
2253 IRBuilder<> Builder(I);
2254 IRBuilder<> AllocaBuilder(&I->getFunction()->getEntryBlock().front());
2255
2256 bool UseSizedLibcall = canUseSizedAtomicCall(Size, Alignment, DL);
2257 Type *SizedIntTy = Type::getIntNTy(Ctx, Size * 8);
2258
2259 if (M->getTargetTriple().isOSWindows() && M->getTargetTriple().isX86_64() &&
2260 Size == 16) {
2261 // x86_64 Windows passes i128 as an XMM vector; on return, it is in
2262 // XMM0, and as a parameter, it is passed indirectly. The generic lowering
2263 // rules handles this correctly if we pass it as a v2i64 rather than
2264 // i128. This is what Clang does in the frontend for such types as well
2265 // (see WinX86_64ABIInfo::classify in Clang).
2266 SizedIntTy = FixedVectorType::get(Type::getInt64Ty(Ctx), 2);
2267 }
2268
2269 const Align AllocaAlignment = DL.getPrefTypeAlign(SizedIntTy);
2270
2271 // TODO: Take the signature from RuntimeLibcallsInfo
2272 IntegerType *OrderingTy =
2273 Type::getIntNTy(Ctx, LibcallLowering->getRuntimeLibcallsInfo().getIntSize(
2274 M->getTargetTriple()));
2275 assert(Ordering != AtomicOrdering::NotAtomic && "expect atomic MO");
2276 Constant *OrderingVal = ConstantInt::get(OrderingTy, (int)toCABI(Ordering));
2277 Constant *Ordering2Val = nullptr;
2278 if (CASExpected) {
2279 assert(Ordering2 != AtomicOrdering::NotAtomic && "expect atomic MO");
2280 Ordering2Val = ConstantInt::get(OrderingTy, (int)toCABI(Ordering2));
2281 }
2282 bool HasResult = I->getType() != Type::getVoidTy(Ctx);
2283
2284 RTLIB::Libcall RTLibType;
2285 if (UseSizedLibcall) {
2286 switch (Size) {
2287 case 1:
2288 RTLibType = Libcalls[1];
2289 break;
2290 case 2:
2291 RTLibType = Libcalls[2];
2292 break;
2293 case 4:
2294 RTLibType = Libcalls[3];
2295 break;
2296 case 8:
2297 RTLibType = Libcalls[4];
2298 break;
2299 case 16:
2300 RTLibType = Libcalls[5];
2301 break;
2302 }
2303 } else if (Libcalls[0] != RTLIB::UNKNOWN_LIBCALL) {
2304 RTLibType = Libcalls[0];
2305 } else {
2306 // Can't use sized function, and there's no generic for this
2307 // operation, so give up.
2308 return false;
2309 }
2310
2311 RTLIB::LibcallImpl LibcallImpl = LibcallLowering->getLibcallImpl(RTLibType);
2312 if (LibcallImpl == RTLIB::Unsupported) {
2313 // This target does not implement the requested atomic libcall so give up.
2314 return false;
2315 }
2316
2317 // Build up the function call. There's two kinds. First, the sized
2318 // variants. These calls are going to be one of the following (with
2319 // N=1,2,4,8,16):
2320 // iN __atomic_load_N(iN *ptr, int ordering)
2321 // void __atomic_store_N(iN *ptr, iN val, int ordering)
2322 // iN __atomic_{exchange|fetch_*}_N(iN *ptr, iN val, int ordering)
2323 // bool __atomic_compare_exchange_N(iN *ptr, iN *expected, iN desired,
2324 // int success_order, int failure_order)
2325 //
2326 // Note that these functions can be used for non-integer atomic
2327 // operations, the values just need to be bitcast to integers on the
2328 // way in and out.
2329 //
2330 // And, then, the generic variants. They look like the following:
2331 // void __atomic_load(size_t size, void *ptr, void *ret, int ordering)
2332 // void __atomic_store(size_t size, void *ptr, void *val, int ordering)
2333 // void __atomic_exchange(size_t size, void *ptr, void *val, void *ret,
2334 // int ordering)
2335 // bool __atomic_compare_exchange(size_t size, void *ptr, void *expected,
2336 // void *desired, int success_order,
2337 // int failure_order)
2338 //
2339 // The different signatures are built up depending on the
2340 // 'UseSizedLibcall', 'CASExpected', 'ValueOperand', and 'HasResult'
2341 // variables.
2342
2343 AllocaInst *AllocaCASExpected = nullptr;
2344 AllocaInst *AllocaValue = nullptr;
2345 AllocaInst *AllocaResult = nullptr;
2346
2347 Type *ResultTy;
2349 AttributeList Attr;
2350
2351 // 'size' argument.
2352 if (!UseSizedLibcall) {
2353 // Note, getIntPtrType is assumed equivalent to size_t.
2354 Args.push_back(ConstantInt::get(DL.getIntPtrType(Ctx), Size));
2355 }
2356
2357 // 'ptr' argument.
2358 // note: This assumes all address spaces share a common libfunc
2359 // implementation and that addresses are convertable. For systems without
2360 // that property, we'd need to extend this mechanism to support AS-specific
2361 // families of atomic intrinsics.
2362 Value *PtrVal = PointerOperand;
2363 PtrVal = Builder.CreateAddrSpaceCast(PtrVal, PointerType::getUnqual(Ctx));
2364 Args.push_back(PtrVal);
2365
2366 // 'expected' argument, if present.
2367 if (CASExpected) {
2368 AllocaCASExpected = AllocaBuilder.CreateAlloca(CASExpected->getType());
2369 AllocaCASExpected->setAlignment(AllocaAlignment);
2370 Builder.CreateLifetimeStart(AllocaCASExpected);
2371 Builder.CreateAlignedStore(CASExpected, AllocaCASExpected, AllocaAlignment);
2372 Args.push_back(AllocaCASExpected);
2373 }
2374
2375 // 'val' argument ('desired' for cas), if present.
2376 if (ValueOperand) {
2377 if (UseSizedLibcall) {
2378 Value *IntValue =
2379 Builder.CreateBitPreservingCastChain(DL, ValueOperand, SizedIntTy);
2380 Args.push_back(IntValue);
2381 } else {
2382 AllocaValue = AllocaBuilder.CreateAlloca(ValueOperand->getType());
2383 AllocaValue->setAlignment(AllocaAlignment);
2384 Builder.CreateLifetimeStart(AllocaValue);
2385 Builder.CreateAlignedStore(ValueOperand, AllocaValue, AllocaAlignment);
2386 Args.push_back(AllocaValue);
2387 }
2388 }
2389
2390 // 'ret' argument.
2391 if (!CASExpected && HasResult && !UseSizedLibcall) {
2392 AllocaResult = AllocaBuilder.CreateAlloca(I->getType());
2393 AllocaResult->setAlignment(AllocaAlignment);
2394 Builder.CreateLifetimeStart(AllocaResult);
2395 Args.push_back(AllocaResult);
2396 }
2397
2398 // The ordering arguments are C ints, which may need to be extended.
2399 // FIXME: Once runtime libcall attribute derivation is centralized in
2400 // RuntimeLibcalls, TargetLibraryInfo should not be used here.
2401 Attribute::AttrKind OrderingExt =
2402 TargetLibraryInfo::getExtAttrForI32Param(M->getTargetTriple());
2403
2404 // 'ordering' ('success_order' for cas) argument.
2405 Args.push_back(OrderingVal);
2406 Attr = Attr.maybeAddParamAttribute(Ctx, Args.size() - 1, OrderingExt);
2407
2408 // 'failure_order' argument, if present.
2409 if (Ordering2Val) {
2410 Args.push_back(Ordering2Val);
2411 Attr = Attr.maybeAddParamAttribute(Ctx, Args.size() - 1, OrderingExt);
2412 }
2413
2414 // Now, the return type. FIXME: Properly add extension attributes.
2415 if (CASExpected) {
2416 ResultTy = Type::getInt1Ty(Ctx);
2417 Attr = Attr.addRetAttribute(Ctx, Attribute::ZExt);
2418 } else if (HasResult && UseSizedLibcall)
2419 ResultTy = SizedIntTy;
2420 else
2421 ResultTy = Type::getVoidTy(Ctx);
2422
2423 // Done with setting up arguments and return types, create the call:
2425 for (Value *Arg : Args)
2426 ArgTys.push_back(Arg->getType());
2427 FunctionType *FnType = FunctionType::get(ResultTy, ArgTys, false);
2428 FunctionCallee LibcallFn = M->getOrInsertFunction(
2430 Attr);
2431 CallInst *Call = Builder.CreateCall(LibcallFn, Args);
2432 Call->setAttributes(Attr);
2433 Value *Result = Call;
2434
2435 // And then, extract the results...
2436 if (ValueOperand && !UseSizedLibcall)
2437 Builder.CreateLifetimeEnd(AllocaValue);
2438
2439 if (CASExpected) {
2440 // The final result from the CAS is {load of 'expected' alloca, bool result
2441 // from call}
2442 Type *FinalResultTy = I->getType();
2443 Value *V = PoisonValue::get(FinalResultTy);
2444 Value *ExpectedOut = Builder.CreateAlignedLoad(
2445 CASExpected->getType(), AllocaCASExpected, AllocaAlignment);
2446 Builder.CreateLifetimeEnd(AllocaCASExpected);
2447 V = Builder.CreateInsertValue(V, ExpectedOut, 0);
2448 V = Builder.CreateInsertValue(V, Result, 1);
2450 } else if (HasResult) {
2451 Value *V;
2452 if (UseSizedLibcall) {
2453 // Add bitcasts from Result's scalar type to I's <n x ptr> vector type
2454 auto *PtrTy = dyn_cast<PointerType>(I->getType()->getScalarType());
2455 auto *VTy = dyn_cast<VectorType>(I->getType());
2456 if (VTy && PtrTy && !Result->getType()->isVectorTy()) {
2457 unsigned AS = PtrTy->getAddressSpace();
2458 Value *BC = Builder.CreateBitCast(
2459 Result, VTy->getWithNewType(DL.getIntPtrType(Ctx, AS)));
2460 V = Builder.CreateIntToPtr(BC, I->getType());
2461 } else
2462 V = Builder.CreateBitOrPointerCast(Result, I->getType());
2463 } else {
2464 V = Builder.CreateAlignedLoad(I->getType(), AllocaResult,
2465 AllocaAlignment);
2466 Builder.CreateLifetimeEnd(AllocaResult);
2467 }
2468 I->replaceAllUsesWith(V);
2469 }
2470 I->eraseFromParent();
2471 return true;
2472}
#define Success
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static Value * performMaskedAtomicOp(AtomicRMWInst::BinOp Op, IRBuilderBase &Builder, Value *Loaded, Value *ValOperand_Shifted, 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 void createCmpXchgInstFun(IRBuilderBase &Builder, Value *Addr, Value *Loaded, Value *NewVal, Align AddrAlign, AtomicOrdering MemOpOrder, SyncScope::ID SSID, bool IsVolatile, Value *&Success, Value *&NewLoaded, Instruction *MetadataSrc)
static Value * extractMaskedValue(IRBuilderBase &Builder, Value *WideWord, const PartwordMaskValues &PMV)
Expand Atomic static false unsigned getAtomicOpSize(LoadInst *LI)
static void writeUnsupportedAtomicSizeReason(const TargetLowering *TLI, Inst *I, raw_ostream &OS)
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...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
static bool isIdempotentRMW(AtomicRMWInst &RMWI)
Return true if and only if the given instruction does not modify the memory location referenced.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file provides utility for Memory Model Relaxation Annotations (MMRAs).
#define T
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file contains the declarations for profiling metadata utility functions.
const char * Msg
This file defines the SmallString class.
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
void setAlignment(Align Align)
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
An instruction that atomically checks whether a specified value is in a memory location,...
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.
AtomicOrdering getFailureOrdering() const
Returns the failure ordering constraint of this cmpxchg instruction.
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.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
an instruction that atomically reads a memory location, combines it with another value,...
bool isElementwise() const
Return true if this RMW has elementwise vector semantics.
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.
void setVolatile(bool V)
Specify whether this is a volatile RMW or not.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ FAdd
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ FMinimum
*p = minimum(old, v) minimum matches the behavior of llvm.minimum.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ FMaximum
*p = maximum(old, v) maximum matches the behavior of llvm.maximum.
@ FSub
*p = old - v
@ 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
@ FMaximumNum
*p = maximumnum(old, v) maximumnum matches the behavior of llvm.maximumnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
@ FMinimumNum
*p = minimumnum(old, v) minimumnum matches the behavior of llvm.minimumnum.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
void setOperation(BinOp Operation)
BinOp getOperation() const
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
static LLVM_ABI StringRef getOperationName(BinOp Op)
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
iterator end()
Definition BasicBlock.h:453
iterator begin()
Instruction iterator methods.
Definition BasicBlock.h:440
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
reverse_iterator rbegin()
Definition BasicBlock.h:456
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
InstListType::reverse_iterator reverse_iterator
Definition BasicBlock.h:172
reverse_iterator rend()
Definition BasicBlock.h:458
void setAttributes(AttributeList A)
Set the attributes for this call.
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
Definition Constants.h:135
static LLVM_ABI ConstantInt * getFalse(LLVMContext &Context)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
ArrayRef< unsigned > getIndices() const
unsigned getNumIndices() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:843
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
BasicBlockListType::iterator iterator
Definition Function.h:70
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNull=false)
Definition IRBuilder.h:2248
AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID=SyncScope::System)
Definition IRBuilder.h:1968
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2723
LLVM_ABI CallInst * CreateLifetimeStart(Value *Ptr)
Create a lifetime.start intrinsic.
LLVM_ABI CallInst * CreateLifetimeEnd(Value *Ptr)
Create a lifetime.end intrinsic.
LoadInst * CreateAlignedLoad(Type *Ty, Value *Ptr, MaybeAlign Align, const char *Name)
Definition IRBuilder.h:1934
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Definition IRBuilder.h:1212
UnreachableInst * CreateUnreachable()
Definition IRBuilder.h:1354
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2716
BasicBlock::iterator GetInsertPoint() const
Definition IRBuilder.h:176
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2238
Value * CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr, FMFSource FMFSource={})
Definition IRBuilder.h:2284
BasicBlock * GetInsertBlock() const
Definition IRBuilder.h:173
LLVM_ABI Value * CreateBitPreservingCastChain(const DataLayout &DL, Value *V, Type *NewTy)
Create a chain of casts to convert V to NewTy, preserving the bit pattern of V.
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:2386
UncondBrInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
Definition IRBuilder.h:1206
Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2332
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2547
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:2382
void setIsFPConstrained(bool IsCon)
Enable/Disable use of constrained floating point math.
Definition IRBuilder.h:294
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2243
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition IRBuilder.h:1907
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1507
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Definition IRBuilder.h:2121
LLVMContext & getContext() const
Definition IRBuilder.h:177
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1566
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2233
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2561
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:196
StoreInst * CreateAlignedStore(Value *Val, Value *Ptr, MaybeAlign Align, bool isVolatile=false)
Definition IRBuilder.h:1953
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
Definition IRBuilder.h:1588
AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System, bool Elementwise=false)
Definition IRBuilder.h:1981
Provides an 'InsertHelper' that calls a user-provided callback after performing the default insertion...
Definition IRBuilder.h:74
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI void moveAfter(Instruction *MovePos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
iterator_range< user_iterator > users()
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
LLVM_ABI void getSyncScopeNames(SmallVectorImpl< StringRef > &SSNs) const
getSyncScopeNames - Populates client supplied SmallVector with synchronization scope names registered...
Tracks which library functions to use for a particular subtarget or function.
const RTLIB::RuntimeLibcallsInfo & getRuntimeLibcallsInfo() const
RTLIB::LibcallImpl getLibcallImpl(RTLIB::Libcall Call) const
Return the lowering's selection of implementation call for Call.
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.
LoadStoreInstProperties getProperties() const
Returns the properties of this load instruction.
Align getAlign() const
Return the alignment of the access that is being performed.
Metadata node.
Definition Metadata.h:1081
Records a mapping from an opaque lowering context to its LibcallLoweringInfo.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
LLVMContext & getContext() const
Get the global data context.
Definition Module.h:332
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition Pass.cpp:114
static LLVM_ABI 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.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
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.
virtual Value * emitStoreConditional(IRBuilderBase &Builder, Value *Val, Value *Addr, AtomicOrdering Ord) const
Perform a store-conditional operation to Addr.
EVT getMemValueType(const DataLayout &DL, Type *Ty, bool AllowUnknown=false) const
virtual void emitBitTestAtomicRMWIntrinsic(AtomicRMWInst *AI) const
Perform a bit test atomicrmw using a target-specific intrinsic.
virtual bool isAtomicAlignmentSupported(Align Alignment, uint64_t SizeInBytes) const
Return true if the target supports an atomic access of SizeInBytes bytes at the given Alignment.
virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *RMW) const
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
virtual bool shouldInsertFencesForAtomic(const Instruction *I) const
Whether AtomicExpandPass should automatically insert fences and reduce ordering for this atomic.
virtual AtomicOrdering atomicOperationOrderAfterFenceSplit(const Instruction *I) const
virtual void emitExpandAtomicCmpXchg(AtomicCmpXchgInst *CI) const
Perform a cmpxchg expansion using a target-specific method.
unsigned getMinCmpXchgSizeInBits() const
Returns the size of the smallest cmpxchg or ll/sc instruction the backend supports.
virtual Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const
Perform a masked atomicrmw using a target-specific intrinsic.
virtual AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(const AtomicCmpXchgInst *AI) const
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
virtual Value * emitLoadLinked(IRBuilderBase &Builder, Type *ValueTy, Value *Addr, AtomicOrdering Ord) const
Perform a load-linked operation on Addr, returning a "Value *" with the corresponding pointee type.
virtual void emitExpandAtomicRMW(AtomicRMWInst *AI) const
Perform a atomicrmw expansion using a target-specific way.
virtual void emitAtomicCmpXchgNoStoreLLBalance(IRBuilderBase &Builder) const
virtual void emitExpandAtomicStore(StoreInst *SI) const
Perform a atomic store using a target-specific way.
virtual AtomicExpansionKind shouldCastAtomicRMWIInIR(AtomicRMWInst *RMWI) const
Returns how the given atomic atomicrmw should be cast by the IR-level AtomicExpand pass.
virtual bool shouldInsertTrailingSeqCstFenceForAtomicStore(const Instruction *I) const
Whether AtomicExpandPass should automatically insert a seq_cst trailing fence without reducing the or...
virtual AtomicExpansionKind shouldExpandAtomicLoadInIR(LoadInst *LI) const
Returns how the given (atomic) load should be expanded by the IR-level AtomicExpand pass.
virtual Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const
Perform a masked cmpxchg using a target-specific intrinsic.
virtual bool shouldIssueAtomicLoadForAtomicEmulationLoop(void) const
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.
virtual void emitExpandAtomicLoad(LoadInst *LI) const
Perform a atomic load using a target-specific way.
virtual AtomicExpansionKind shouldExpandAtomicStoreInIR(StoreInst *SI) const
Returns how the given (atomic) store should be expanded by the IR-level AtomicExpand pass into.
virtual bool fenceClearsLoadLinkedReservation() const
Whether a fence between the load-linked and the store-conditional can clear the reservation.
virtual void emitCmpArithAtomicRMWIntrinsic(AtomicRMWInst *AI) const
Perform a atomicrmw which the result is only used by comparison, using a target-specific intrinsic.
virtual AtomicExpansionKind shouldCastAtomicStoreInIR(StoreInst *SI) const
Returns how the given (atomic) store should be cast by the IR-level AtomicExpand pass into.
virtual Instruction * emitTrailingFence(IRBuilderBase &Builder, Instruction *Inst, AtomicOrdering Ord) const
virtual AtomicExpansionKind shouldCastAtomicLoadInIR(LoadInst *LI) const
Returns how the given (atomic) load should be cast by the IR-level AtomicExpand pass.
virtual Instruction * emitLeadingFence(IRBuilderBase &Builder, Instruction *Inst, AtomicOrdering Ord) const
Inserts in the IR a target-specific intrinsic specifying a fence.
virtual LoadInst * lowerIdempotentRMWIntoFencedLoad(AtomicRMWInst *RMWI) const
On some platforms, an AtomicRMW that never actually modifies the value (such as fetch_add of 0) can b...
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.
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Target-Independent Code Generator Pass Configuration Options.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:283
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
Definition Type.h:280
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
void setOperand(unsigned i, Value *Val)
Definition User.h:212
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
bool use_empty() const
Definition Value.h:348
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
self_iterator getIterator()
Definition ilist_node.h:123
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:83
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool canInstructionHaveMMRAs(const Instruction &I)
LLVM_ABI void setExplicitlyUnknownBranchWeightsIfProfiled(Instruction &I, StringRef PassName, const Function *F=nullptr)
Like setExplicitlyUnknownBranchWeights(...), but only sets unknown branch weights in the new instruct...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool isStrongerThanMonotonic(AtomicOrdering AO)
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
LLVM_ABI Value * concatenateVectors(IRBuilderBase &Builder, ArrayRef< Value * > Vecs)
Concatenate a list of vectors.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
bool isReleaseOrStronger(AtomicOrdering AO)
AtomicOrderingCABI toCABI(AtomicOrdering AO)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
LLVM_ABI const LibcallLoweringInfo & getLibcallLowering(const ModuleLibcallLoweringInfo &ModuleInfo, const TargetSubtargetInfo &Subtarget)
Resolve the LibcallLoweringInfo for Subtarget from the module-level ModuleInfo, applying the subtarge...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI 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.
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool isAcquireOrStronger(AtomicOrdering AO)
constexpr unsigned BitWidth
LLVM_ABI bool lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI)
Convert the given Cmpxchg into primitive load and compare.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI bool lowerAtomicRMWInst(AtomicRMWInst *RMWI)
Convert the given RMWI into primitive load and stores, assuming that doing so is legal.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI FunctionPass * createAtomicExpandLegacyPass()
AtomicExpandPass - At IR level this pass replace atomic instructions with __atomic_* library calls,...
LLVM_ABI llvm::SmallVector< int, 16 > createSequentialMask(unsigned Start, unsigned NumInts, unsigned NumUndefs)
Create a sequential shuffle mask.
LLVM_ABI char & AtomicExpandID
AtomicExpandID – Lowers atomic operations in terms of either cmpxchg load-linked/store-conditional lo...
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Extended Value Type.
Definition ValueTypes.h:35
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
TypeSize getStoreSizeInBits() const
Return the number of bits overwritten by a store of the specified value type.
Definition ValueTypes.h:435
Matching combinators.
static StringRef getLibcallImplName(RTLIB::LibcallImpl CallImpl)
Get the libcall routine name for the specified libcall implementation.
unsigned getIntSize(const Triple &TT) const
Get size of a C-level int or unsigned int, in bits.